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
);
22 static SDL_Cursor
*sdl_cursor_from_xpm(const char *image
[]);
23 static void set_widget_cursor(struct xuni_t
*xuni
);
25 static void set_loop_caption(panel_type_t mode
, struct xuni_t
*xuni
);
26 static void setup_theme_cursor(struct xuni_t
*xuni
, struct widget_t
*panel
);
27 static int get_event(int frameupdate
, SDL_Event
*event
);
28 static int process_event(SDL_Event
*event
, panel_type_t
*mode
,
30 static void scroll_listbox(struct xuni_t
*xuni
, int dir
);
31 static int set_loop_widget_sel(panel_type_t mode
, int xp
, int yp
,
32 int click
, struct xuni_t
*xuni
);
33 static int find_widget_accelerator(struct xuni_accelerator_t
*accel
,
34 SDL_keysym
*key
, struct xuni_t
*xuni
, panel_type_t
*mode
);
35 static int check_sdl_key_mod(SDLMod mod
, SDLMod now
);
36 static int event_mouse_button_up(int xp
, int yp
, panel_type_t
*mode
,
38 static int perform_loop_click(struct xuni_t
*xuni
, panel_type_t
*mode
,
39 struct widget_t
*widget
);
40 static int event_key_down(struct xuni_t
*xuni
, SDL_keysym
*keysym
,
41 panel_type_t
*mode
, int *handled
);
43 /*! Calls the registered initialization functions for \a widget and all of its
44 sub-widgets. Only operates on widgets of type panel.
46 \param xuni A pointer to the main xuni structure.
47 \param widget The widget to call the initialization function for, if it is
49 \param settings A pointer to the resource tree.
51 void call_init_funcs(struct xuni_t
*xuni
, struct widget_t
*widget
,
52 struct resource_t
*settings
) {
58 if(widget
->type
== WIDGET_PANEL
59 && widget
->p
.panel
->event
[PANEL_EVENT_INIT
].handler
) {
61 widget
->p
.panel
->event
[PANEL_EVENT_INIT
].p
.init
.settings
= settings
;
62 widget
->p
.panel
->event
[PANEL_EVENT_INIT
].p
.init
.panel
= widget
;
64 (*widget
->p
.panel
->event
[PANEL_EVENT_INIT
].handler
)
65 (xuni
, widget
->p
.panel
);
69 for(x
= 0; x
< widget
->compose
->widgets
; x
++) {
70 call_init_funcs(xuni
, widget
->compose
->widget
[x
], settings
);
75 void call_free_funcs(struct xuni_t
*xuni
, struct widget_t
*widget
) {
80 if(widget
->type
== WIDGET_PANEL
81 && widget
->p
.panel
->event
[PANEL_EVENT_FREE
].handler
) {
83 (*widget
->p
.panel
->event
[PANEL_EVENT_FREE
].handler
)
84 (xuni
, widget
->p
.panel
);
88 for(x
= 0; x
< widget
->compose
->widgets
; x
++) {
89 call_free_funcs(xuni
, widget
->compose
->widget
[x
]);
94 /* !!! Note that because of this function, the handler member of the structure
95 passed to panel event handlers is not defined.
97 int panel_event_recursive(struct xuni_t
*xuni
, struct panel_data_t
*data
,
98 enum panel_event_type_t type
, struct widget_t
*widget
) {
103 if(!widget
) return 0;
105 if(widget
->type
== WIDGET_PANEL
106 && widget
->p
.panel
->event
[type
].handler
) {
108 (*widget
->p
.panel
->event
[type
].handler
)(xuni
, data
);
111 if(widget
->compose
) {
112 for(x
= 0; x
< widget
->compose
->widgets
; x
++) {
113 r
= panel_event_recursive(xuni
, data
, type
,
114 widget
->compose
->widget
[x
]) || r
;
121 static int call_perform_click_func(struct xuni_t
*xuni
,
122 struct panel_data_t
*panel
, struct widget_t
*widget
, panel_type_t
*mode
) {
124 perform_widget_click(xuni
, widget
);
126 /*print_widget_backtrace(xuni->gui->sel.p.widget);*/
128 /* !!! quick fix to disallow clicking on a panel. Without this, for
129 example, clicking on the options graphics panel triggers the
130 fullscreen checkbox, as
131 PANEL_OPTIONS_GRAPHICS == WID_GRAPHICS_FULLSCREEN */
132 if(widget
&& panel
->event
[PANEL_EVENT_CLICK
].handler
133 && widget_nameid_access(xuni
->gui
->widget
, *mode
) != widget
) {
135 panel
->event
[PANEL_EVENT_CLICK
].p
.click
.mode
= mode
;
136 panel
->event
[PANEL_EVENT_CLICK
].p
.click
.widget
= widget
;
138 return (*panel
->event
[PANEL_EVENT_CLICK
].handler
)(xuni
, panel
);
144 void call_deactivate_func(struct xuni_t
*xuni
, struct widget_t
*widget
) {
145 struct widget_t
*base
= widget
;
147 while(base
&& base
->type
!= WIDGET_PANEL
) base
= base
->base
;
149 if(base
&& base
->p
.panel
->event
[PANEL_EVENT_DEACTIVATE
].handler
) {
150 base
->p
.panel
->event
[PANEL_EVENT_DEACTIVATE
].p
.deactivate
.widget
153 (*base
->p
.panel
->event
[PANEL_EVENT_DEACTIVATE
].handler
)
154 (xuni
, base
->p
.panel
);
158 /*#define HIDE_COMBOBOX_POPUPS*/
160 int default_panel_sel(struct xuni_t
*xuni
, struct panel_data_t
*data
) {
161 struct panel_event_sel_t
*sel
= &data
->event
[PANEL_EVENT_SEL
].p
.sel
;
163 return set_default_widget_sel(xuni
, sel
->mode
, sel
->xp
, sel
->yp
,
164 sel
->click
, data
->data
);
167 /* !!! this function is obsolete */
168 int set_default_widget_sel(struct xuni_t
*xuni
, panel_type_t mode
,
169 int xp
, int yp
, int click
, void *vdata
) {
171 #ifdef HIDE_COMBOBOX_POPUPS
172 struct widget_t
*widget
= xuni
->gui
->sel
.p
.widget
;
176 r
= set_widget_sel_repaint(&xuni
->gui
->sel
, xp
, yp
, click
,
177 widget_nameid_access(xuni
->gui
->widget
, mode
));
179 /*if(xuni->gui->sel.p.widget) {
180 printf("%s\n", xuni->gui->sel.p.widget->name);
183 #ifdef HIDE_COMBOBOX_POPUPS
184 /* Hide combobox popups that have become unselected. */
185 if(widget
&& widget
!= xuni
->gui
->sel
.p
.widget
) {
186 struct widget_t
*w
= xuni
->gui
->sel
.p
.widget
, *t
;
188 /* See if any comboboxes that were previously selected still are. */
190 if(w
->visibility
& WIDGET_VISIBILITY_VISIBLE
191 && w
->type
== WIDGET_COMBOBOX
) {
193 for(t
= widget
; t
; t
= t
->base
) {
203 /* If no comboboxes were selected and remain selected, hide the popups
204 for all comboboxes that were selected.
208 if(widget
->type
== WIDGET_COMBOBOX
) {
209 widget
->compose
->widget
[WID_COMBOBOX_DROPDOWN
]->visibility
210 &= ~WIDGET_VISIBILITY_VISIBLE
;
213 widget
= widget
->base
;
223 void set_panel_callbacks(struct widget_t
*widget
, void *vdata
,
225 panel_event_func_t init_func
,
226 panel_event_func_t start_func
,
227 panel_event_func_t event_func
,
228 panel_event_func_t set_widget_sel_func
,
229 panel_event_func_t perform_click_func
,
230 panel_event_func_t deactivate_func
,
231 panel_event_func_t paint_func
,
232 panel_event_func_t free_func
) {
234 widget
->p
.panel
->data
= vdata
;
235 widget
->p
.panel
->frameupdate
= frameupdate
;
237 widget
->p
.panel
->event
[PANEL_EVENT_INIT
].handler
= init_func
;
238 widget
->p
.panel
->event
[PANEL_EVENT_START
].handler
= start_func
;
239 widget
->p
.panel
->event
[PANEL_EVENT_EVENT
].handler
= event_func
;
240 widget
->p
.panel
->event
[PANEL_EVENT_SEL
].handler
= set_widget_sel_func
;
241 widget
->p
.panel
->event
[PANEL_EVENT_CLICK
].handler
= perform_click_func
;
242 widget
->p
.panel
->event
[PANEL_EVENT_DEACTIVATE
].handler
= deactivate_func
;
243 widget
->p
.panel
->event
[PANEL_EVENT_PAINT
].handler
= paint_func
;
244 widget
->p
.panel
->event
[PANEL_EVENT_FREE
].handler
= free_func
;
246 widget
->p
.panel
->nameid
= 0;
248 widget
->p
.panel
->accel
= 0;
252 void execute_callback(struct xuni_t
*xuni
, struct xuni_callback_t
*callback
) {
253 if(callback
&& callback
->func
) {
254 (*callback
->func
)(callback
->vdata
, xuni
);
258 /*! The main xuni loop. Indirectly calls all panel event-handling functions,
259 including initialization functions, event handlers, repaint functions,
262 This function should only be called once, after everything has been loaded
263 and set up. It should only return when the program is exiting -- but it
264 will return, so don't neglect that freeing code.
266 \param xuni The xuni structure, with most of the data required to display
267 and manage a Graphical User Interface (GUI, of course).
268 \param always A callback function that is executed for every loop of the
269 xuni event loop. Note that this can be called considerably more
270 frequently than repaint functions.
271 \param mode The panel to initially display.
273 void main_loop(struct xuni_t
*xuni
, struct xuni_callback_t
*always
,
276 panel_type_t pmode
= (size_t)-1;
277 struct panel_data_t
*panel
278 = widget_nameid_access(xuni
->gui
->widget
, mode
)->p
.panel
;
283 /*call_init_funcs(data, smode, font, theme, gui, settings);*/
285 SDL_initFramerate(&fpsm
);
286 SDL_setFramerate(&fpsm
, 30);
288 while(mode
!= (size_t)-1) {
289 execute_callback(xuni
, always
);
291 /*dump_widgets_need_repaint(xuni->gui->widget);*/
293 if(get_event(widget_nameid_access(xuni
->gui
->widget
, mode
)
294 ->p
.panel
->frameupdate
, &event
)) {
297 repaint
= process_event(&event
, &mode
, xuni
) || repaint
;
299 if(mode
== (size_t)-1) break;
300 } while(SDL_PollEvent(&event
));
302 if(mode
== (size_t)-1) break;
305 if(pmode
!= mode
) { /* !!! process_event() is called before the start_func */
306 panel
= widget_nameid_access(xuni
->gui
->widget
, mode
)->p
.panel
;
307 set_loop_caption(mode
, xuni
); /* !!! also pass pmode */
314 /* !!! this needs to go in a hover callback function of sorts */
315 set_widget_cursor(xuni
);
317 if(xuni
->smode
->focus
) {
318 if(repaint
|| panel
->frameupdate
) {
319 if(panel
->event
[PANEL_EVENT_PAINT
].handler
) {
320 panel
->event
[PANEL_EVENT_PAINT
].p
.paint
.mode
= mode
;
322 (*panel
->event
[PANEL_EVENT_PAINT
].handler
)(xuni
, panel
);
329 if(!xuni
->smode
->focus
|| panel
->frameupdate
) {
330 SDL_framerateDelay(&fpsm
);
334 set_caption("Quitting . . .");
336 /*panel_event_recursive(xuni, 0, PANEL_EVENT_FREE, xuni->gui->widget);*/
337 call_free_funcs(xuni
, xuni
->gui
->widget
);
340 /* An XPM image of a CURSOR_TEXT, used when the mouse is inside textboxes. */
341 static const char *text_cursor
[] = {
342 /* width height num_colors chars_per_pixel */
368 static SDL_Cursor
*sdl_cursor_from_xpm(const char *image
[]) {
370 Uint8 data
[4*16] = {0};
371 Uint8 mask
[4*16] = {0};
375 for(x
= 4; x
< 16 + 4; x
++) {
376 for(y
= 0; y
< 16; y
++) {
383 switch (image
[x
][y
]) {
397 sscanf(image
[x
], "%d,%d", &hot_x
, &hot_y
);
399 return SDL_CreateCursor(data
, mask
, 16, 16, hot_x
, hot_y
);
402 static void set_widget_cursor(struct xuni_t
*xuni
) {
405 if(xuni
->gui
->sel
.p
.widget
406 && xuni
->gui
->sel
.p
.widget
->type
== WIDGET_TEXTBOX
) {
410 else now
= CURSOR_NORMAL
;
412 if(xuni
->theme
->cursors
.which
!= now
) {
413 xuni
->theme
->cursors
.which
= now
;
415 if(xuni
->theme
->cursors
.which
) {
416 if(!xuni
->theme
->cursors
.text
) {
417 xuni
->theme
->cursors
.text
= sdl_cursor_from_xpm(text_cursor
);
418 /* save the normal cursor before it is overwritten */
419 xuni
->theme
->cursors
.normal
= SDL_GetCursor();
422 SDL_SetCursor(xuni
->theme
->cursors
.text
);
425 if(!xuni
->theme
->cursors
.normal
) {
426 xuni
->theme
->cursors
.normal
= SDL_GetCursor();
429 SDL_SetCursor(xuni
->theme
->cursors
.normal
);
434 static void set_loop_caption(panel_type_t mode
, struct xuni_t
*xuni
) {
435 struct widget_t
*panel
= widget_nameid_access(xuni
->gui
->widget
, mode
);
436 struct panel_data_t
*paneldata
= panel
->p
.panel
;
441 clear_gui(xuni
, mode
, 0);
443 /* !!! set all other panels to invisible */
444 widget_nameid_access(xuni
->gui
->widget
, mode
)->visibility
445 |= WIDGET_VISIBILITY_VISIBLE
;
447 if(paneldata
->event
[PANEL_EVENT_START
].handler
) {
448 (*paneldata
->event
[PANEL_EVENT_START
].handler
)(xuni
, paneldata
);
451 setup_theme_cursor(xuni
, widget_nameid_access(xuni
->gui
->widget
, mode
));
452 SDL_GetMouseState(&xp
, &yp
);
453 set_loop_widget_sel(mode
, xp
, yp
, xuni
->gui
->sel
.clickin
, xuni
);
456 static void setup_theme_cursor(struct xuni_t
*xuni
, struct widget_t
*panel
) {
457 struct widget_t
*cursor
;
459 if(!panel
->p
.panel
->frameupdate
) return;
461 cursor
= get_theme_widget(xuni
, THEME_DEFAULT_CURSOR
);
464 prepare_paint_image(xuni
, cursor
);
466 if(cursor
->p
.image
->image
) {
471 static int get_event(int frameupdate
, SDL_Event
*event
) {
472 return frameupdate
? SDL_PollEvent(event
) : SDL_WaitEvent(event
);
475 /* handled should not be used in some cases. For example, a widget might be
476 deselected by a mouse motion event, but a xuni application (like the
477 resource editor) might want to know about the mouse motion event just the
480 /*! Handles an event from the SDL. What happens depends on the event itself.
481 However, this function will always either deal with the event itself, call
482 the appropriate event handler function for the currently visible panel, or
483 perhaps do a little bit of both.
485 Some handled events include clicking inside widgets (implemented by
486 calling set_loop_widget_sel()), pressing special keypresses like
487 printscreen (see event_key_down()), and selecting widgets when the mouse
488 moves (set_loop_widget_sel()).
490 \param event The SDL_Event that needs to be dealt with.
491 \param mode The currently visible panel, which could be changed.
492 \param xuni The main xuni_t structure.
493 \return True if the screen needs to be repainted.
495 static int process_event(SDL_Event
*event
, panel_type_t
*mode
,
496 struct xuni_t
*xuni
) {
498 struct panel_data_t
*panel
499 = widget_nameid_access(xuni
->gui
->widget
, *mode
)->p
.panel
;
500 int repaint
= 0, handled
= 0;
502 switch(event
->type
) {
503 case SDL_MOUSEBUTTONDOWN
:
504 if(event
->button
.button
== SDL_BUTTON_WHEELUP
) {
505 scroll_listbox(xuni
, -1);
510 else if(event
->button
.button
== SDL_BUTTON_WHEELDOWN
) {
511 scroll_listbox(xuni
, 1);
517 if(event
->button
.button
!= 1) break;
519 repaint
= set_loop_widget_sel(*mode
, event
->button
.x
, event
->button
.y
,
522 if(repaint
) handled
= 1;
524 case SDL_MOUSEBUTTONUP
:
525 if(event
->button
.button
!= 1) break;
527 repaint
= event_mouse_button_up(event
->button
.x
, event
->button
.y
,
530 if(repaint
) handled
= 1;
532 case SDL_MOUSEMOTION
:
533 repaint
= set_loop_widget_sel(*mode
, event
->button
.x
, event
->button
.y
,
534 xuni
->gui
->sel
.clickin
, xuni
);
536 /*if(repaint) handled = 1;*/
538 case SDL_VIDEORESIZE
:
539 if(!resize_screen(xuni
->smode
, &event
->resize
)) {
540 widget_event(xuni
, xuni
->gui
->widget
, WIDGET_EVENT_RESCALE
);
542 xuni
->gui
->widget
->p
.panel
543 ->event
[PANEL_EVENT_EVENT
].p
.event
.mode
= mode
;
544 xuni
->gui
->widget
->p
.panel
545 ->event
[PANEL_EVENT_EVENT
].p
.event
.event
= event
;
547 panel_event_recursive(xuni
, xuni
->gui
->widget
->p
.panel
,
548 PANEL_EVENT_EVENT
, xuni
->gui
->widget
);
551 if(focus_changed(xuni
->smode
, SDL_APPACTIVE
)) {
552 if(xuni
->smode
->focus
) {
553 set_loop_caption(*mode
, xuni
);
563 case SDL_VIDEOEXPOSE
:
568 repaint
= event_key_down(xuni
, &event
->key
.keysym
, mode
, &handled
);
573 case SDL_ACTIVEEVENT
:
574 if(focus_changed(xuni
->smode
, SDL_APPACTIVE
| SDL_APPINPUTFOCUS
)) {
575 if(xuni
->smode
->focus
) {
577 SDL_GetMouseState(&x, &y);
578 printf("activated: %i,%i\n", x, y);*/
579 /* !!! this is only for the cursor */
580 set_loop_caption(*mode
, xuni
);
584 /* preserve any textbox data etc in the active widget */
585 clear_active(xuni
, &xuni
->gui
->active
, 1);
596 if(!handled
&& panel
->event
[PANEL_EVENT_EVENT
].handler
) {
597 panel
->event
[PANEL_EVENT_EVENT
].p
.event
.mode
= mode
;
598 panel
->event
[PANEL_EVENT_EVENT
].p
.event
.event
= event
;
600 repaint
|= (*panel
->event
[PANEL_EVENT_EVENT
].handler
)(xuni
, panel
);
607 static void scroll_listbox(struct xuni_t
*xuni
, int dir
) {
610 if(xuni
->gui
->sel
.p
.widget
611 && xuni
->gui
->sel
.p
.widget
->type
== WIDGET_LISTBOX
) {
613 move_scrollbar(xuni
, xuni
->gui
->sel
.p
.widget
->compose
->widget
614 [WID_LISTBOX_VSCROLL
], step
* dir
);
616 widget_event(xuni
, xuni
->gui
->sel
.p
.widget
, WIDGET_EVENT_REPOSITION
);
619 if(xuni
->gui
->sel
.p
.widget
620 && xuni
->gui
->sel
.p
.widget
->type
== WIDGET_SCROLLBAR
) {
622 move_scrollbar(xuni
, xuni
->gui
->sel
.p
.widget
, step
* dir
);
624 widget_event(xuni
, xuni
->gui
->sel
.p
.widget
->base
,
625 WIDGET_EVENT_REPOSITION
);
628 if(xuni
->gui
->sel
.p
.widget
&& xuni
->gui
->sel
.p
.widget
->base
629 && xuni
->gui
->sel
.p
.widget
->base
->type
== WIDGET_SCROLLBAR
) {
631 move_scrollbar(xuni
, xuni
->gui
->sel
.p
.widget
->base
, step
* dir
);
633 widget_event(xuni
, xuni
->gui
->sel
.p
.widget
->base
->base
,
634 WIDGET_EVENT_REPOSITION
);
638 static int set_loop_widget_sel(panel_type_t mode
, int xp
, int yp
,
639 int click
, struct xuni_t
*xuni
) {
641 struct panel_data_t
*panel
642 = widget_nameid_access(xuni
->gui
->widget
, mode
)->p
.panel
;
644 if(!panel
->event
[PANEL_EVENT_SEL
].handler
) return 0;
646 panel
->event
[PANEL_EVENT_SEL
].p
.sel
.mode
= mode
;
647 panel
->event
[PANEL_EVENT_SEL
].p
.sel
.xp
= xp
;
648 panel
->event
[PANEL_EVENT_SEL
].p
.sel
.yp
= yp
;
649 panel
->event
[PANEL_EVENT_SEL
].p
.sel
.click
= click
;
651 return (*panel
->event
[PANEL_EVENT_SEL
].handler
)(xuni
, panel
);
654 /*! Determines whether any accelerator key combinations have been or are being
655 pressed, and, if so, handles the click event.
657 \param accel This panel's accelerator array. Searched for accelerator
658 combinations matching the current keyboard state.
659 \param key The current keyboard state. Compared with accelerator
660 combinations for the current panel for matches.
661 \param xuni The xuni structure. Used to get a struct widget_t pointer to
663 \param mode The currently active panel. Only passed so that
664 call_perform_click_func() may be called.
666 static int find_widget_accelerator(struct xuni_accelerator_t
*accel
,
667 SDL_keysym
*key
, struct xuni_t
*xuni
, panel_type_t
*mode
) {
674 for(x
= 0; x
< accel
->n
; x
++) {
675 akey
= &accel
->key
[x
].key
;
676 if(akey
->sym
&& akey
->sym
== key
->sym
677 && check_sdl_key_mod(akey
->mod
, key
->mod
)) {
679 call_perform_click_func(xuni
,
680 widget_nameid_access(xuni
->gui
->widget
, *mode
)->p
.panel
,
681 accel
->key
[x
].widget
, mode
);
690 /* !!! needs to be reworked to allow OR, AND, NOT, etc. */
691 static int check_sdl_key_mod(SDLMod mod
, SDLMod now
) {
692 if(mod
!= KMOD_NONE
) {
693 if((mod
& KMOD_CTRL
) == KMOD_CTRL
) {
694 if(now
& KMOD_CTRL
) mod
&= ~KMOD_CTRL
;
697 if((mod
& KMOD_SHIFT
) == KMOD_SHIFT
) {
698 if(now
& KMOD_SHIFT
) mod
&= ~KMOD_SHIFT
;
701 if((mod
& KMOD_ALT
) == KMOD_ALT
) {
702 if(now
& KMOD_ALT
) mod
&= ~KMOD_ALT
;
707 if(now
!= mod
) return 0;
712 static int event_mouse_button_up(int xp
, int yp
, panel_type_t
*mode
,
713 struct xuni_t
*xuni
) {
715 struct panel_data_t
*panel
716 = widget_nameid_access(xuni
->gui
->widget
, *mode
)->p
.panel
;
717 int repaint
= 0, realclick
;
719 if(xuni
->gui
->sel
.p
.widget
&& xuni
->gui
->sel
.clickin
720 && pos_in_rect(xp
, yp
, xuni
->gui
->sel
.p
.widget
->pos
)) {
722 /*xuni->gui->sel.clickin = 0;*/
723 realclick
= !set_widget_sel(&xuni
->gui
->sel
, xp
, yp
, 1,
724 widget_nameid_access(xuni
->gui
->widget
, *mode
));
727 /* !!! return value ignored: repaint is always set to 1 */
728 call_perform_click_func(xuni
, panel
, xuni
->gui
->sel
.p
.widget
,
732 xuni
->gui
->sel
.wasin
= 1;
733 xuni
->gui
->sel
.clickin
= 0;
737 if(xuni
->gui
->sel
.p
.widget
&&
738 widget_can_be_active(xuni
->gui
->sel
.p
.widget
)) {
740 xuni
->gui
->active
= xuni
->gui
->sel
.p
;
741 activate_widget(xuni
->gui
->active
.widget
, xuni
, xp
, yp
);
742 enable_unicode(xuni
->gui
->active
.widget
);
744 else if(xuni
->gui
->active
.widget
) {
747 clear_active(xuni
, &xuni
->gui
->active
, 1);
750 if(*mode
!= (size_t)-1) {
751 set_loop_widget_sel(*mode
, xp
, yp
, xuni
->gui
->sel
.clickin
,
757 repaint
= set_loop_widget_sel(*mode
, xp
, yp
, 0, xuni
);
759 if(xuni
->gui
->active
.widget
&&
760 !pos_in_rect(xp
, yp
, xuni
->gui
->active
.widget
->pos
)) {
764 clear_active(xuni
, &xuni
->gui
->active
, 1);
771 static int perform_loop_click(struct xuni_t
*xuni
, panel_type_t
*mode
,
772 struct widget_t
*widget
) {
774 struct panel_data_t
*panel
775 = widget_nameid_access(xuni
->gui
->widget
, *mode
)->p
.panel
;
776 int repaint
, xp
= 0, yp
= 0; /* !!! */
778 /* !!! return value ignored: repaint is always set to 1 */
779 call_perform_click_func(xuni
, panel
, widget
, mode
);
781 xuni
->gui
->sel
.wasin
= 1;
782 xuni
->gui
->sel
.clickin
= 0;
785 if(xuni
->gui
->sel
.p
.widget
&&
786 widget_can_be_active(xuni
->gui
->sel
.p
.widget
)) {
788 xuni
->gui
->active
= xuni
->gui
->sel
.p
;
789 activate_widget(xuni
->gui
->active
.widget
, xuni
, xp
, yp
);
790 enable_unicode(xuni
->gui
->active
.widget
);
792 else if(xuni
->gui
->active
.widget
) {
795 clear_active(xuni
, &xuni
->gui
->active
, 1);
798 if(*mode
!= (size_t)-1) {
799 set_loop_widget_sel(*mode
, xp
, yp
, xuni
->gui
->sel
.clickin
,
806 /* Perhaps functions for handling these keypresses could be registered?
808 Note: a lot of debugging keypresses are here, usually F-keys.
810 /*! Handles the keypresses that are common to all xuni widgets. This includes:
811 - escape, which reverts widgets;
812 - tab and shift-tab, which cycle though widgets;
813 - enter, which might deactivate or select widgets; and
814 - printscreen, which saves a screenshot.
816 \param xuni A pointer to the main xuni structure.
817 \param keysym A structure describing the state of the keyboard, e.g. the
818 key that was pressed along with the state of any modifier keys etc.
819 \param mode The currently visible panel. This could be changed indirectly
820 in the call to perform_loop_click().
821 \param handled Set to true if the keypress described by \a keysym was
822 handled. If the keypress was handled, the xuni application will never
824 \return True if a repaint of the screen is required. This happens when,
825 for example, the keypress resulted in a widget being deactivated.
827 static int event_key_down(struct xuni_t
*xuni
, SDL_keysym
*keysym
,
828 panel_type_t
*mode
, int *handled
) {
832 switch(keysym
->sym
) {
834 if(xuni
->gui
->active
.widget
) {
835 clear_active(xuni
, &xuni
->gui
->active
, 0);
843 save_screenshot(xuni
->smode
->screen
);
848 if(keysym
->mod
& KMOD_ALT
) {
849 if(!toggle_fullscreen(xuni
->smode
)) repaint
= 1;
853 else if(xuni
->gui
->tab
.panel
!= (size_t)-1
854 && xuni
->gui
->tab
.sel
!= (size_t)-1) {
856 repaint
|= perform_loop_click(xuni
, mode
,
857 widget_nameid_follow(xuni
->gui
->widget
,
858 xuni
->gui
->tab
.panel
, xuni
->gui
->tab
.sel
,
864 if(xuni
->gui
->tab
.panel
== (size_t)-1) break;
866 if(keysym
->mod
& KMOD_SHIFT
) {
867 if(xuni
->gui
->tab
.sel
-- == (size_t)-1) {
869 widget_nameid_access(xuni
->gui
->widget
,
870 xuni
->gui
->tab
.panel
)->compose
->widgets
- 1;
874 if(++xuni
->gui
->tab
.sel
==
875 widget_nameid_access(xuni
->gui
->widget
,
876 xuni
->gui
->tab
.panel
)->compose
->widgets
) {
878 xuni
->gui
->tab
.sel
= (size_t)-1;
886 if(keysym
->mod
& KMOD_ALT
) {
887 if(!SDL_WM_IconifyWindow()) {
894 /* keypresses for debugging purposes */
896 if(xuni
->gui
->sel
.p
.widget
) {
897 print_widget_backtrace(xuni
, xuni
->gui
->sel
.p
.widget
);
903 if(xuni
->gui
->active
.widget
) {
904 print_widget_backtrace(xuni
, xuni
->gui
->active
.widget
);
911 print_sel_widgets(xuni
->gui
->widget
);
916 int x
, y
, xrel
, yrel
;
919 state
= SDL_GetMouseState(&x
, &y
);
920 SDL_GetRelativeMouseState(&xrel
, &yrel
);
922 printf("Mouse: at (%i,%i), moved (%i,%i), buttons %i%i%i\n",
923 x
, y
, xrel
, yrel
, state
& SDL_BUTTON(1),
924 state
& SDL_BUTTON(2), state
& SDL_BUTTON(3));
930 /* force a repaint */
934 if(xuni
->gui
->edit
.datawidget
) {
935 printf("textbox data: \"%s\"\n",
936 xuni
->gui
->edit
.datawidget
->p
.label
->text
);
938 else puts("No label selected");
941 if(xuni
->gui
->sel
.p
.widget
->type
== WIDGET_TEXTBOX
) {
942 printf("textbox leftpos: %i\n",
943 xuni
->gui
->sel
.p
.widget
->p
.textbox
->leftpos
);
947 move_scrollbar(xuni
, xuni
->gui
->widget
, 1);
953 if(*mode
!= (size_t)-1) {
954 if(!*handled
&& find_widget_accelerator(
955 widget_nameid_access(xuni
->gui
->widget
, *mode
)
956 ->p
.panel
->accel
, keysym
, xuni
, mode
)) {
961 if(xuni
->gui
->active
.widget
) {
962 repaint
= widget_process_character(xuni
, keysym
);
964 update_widget(xuni
, xuni
->gui
->active
.widget
);
968 if(repaint
) *handled
= 1;