Example #1
0
/******************************************************************************\
 When a widget is hidden, propagates up to the widget's parent and then to its
 parent and so on until mouse focus is claimed. Does nothing if the mouse is
 not within widget bounds.
\******************************************************************************/
static void focus_parent(i_widget_t *widget)
{
        i_widget_t *p;

        /* Propagate key focus up */
        if (I_widget_child_of(widget, key_focus)) {
                p = widget->parent;
                while (p) {
                        if (p->entry) {
                                key_focus = p;
                                break;
                        }
                        p = p->parent;
                }
        }

        /* Propagate mouse out events */
        if (!I_widget_child_of(widget, mouse_focus))
                return;
        p = mouse_focus;
        while (p != widget) {
                I_widget_event(p, I_EV_MOUSE_OUT);
                p = p->parent;
        }
        I_widget_event(p, I_EV_MOUSE_OUT);

        /* Propagate focus up */
        for (p = widget->parent; p; p = p->parent)
                if (check_mouse_focus(p))
                        return;
        mouse_focus = NULL;
}
Example #2
0
/******************************************************************************\
 Close the open ring.
\******************************************************************************/
void I_close_ring(void)
{
        I_widget_event(&ring_widget, I_EV_HIDE);
        I_widget_event(&detail_window.widget, I_EV_HIDE);
        detail_button = -1;
        detail_time = 0;
}
Example #3
0
/******************************************************************************\
 Find which button is being hovered over and configure the detail window.
\******************************************************************************/
static void detail_hover(void)
{
        int i;

        /* Find which button we are hovering over */
        for (i = 0; i < I_RING_ICONS; i++) {
                if (!button_widgets[i].widget.shown ||
                    !C_rect_contains(button_widgets[i].widget.origin,
                                     button_widgets[i].widget.size,
                                     i_mouse))
                        continue;

                /* Same button as before */
                if (detail_button == i)
                        return;

                /* Button changed, start a new hover timer */
                I_widget_event(&detail_window.widget, I_EV_HIDE);
                detail_button = i;
                detail_time = c_time_msec;
                return;
        }

        /* Missed all the buttons, close it */
        I_widget_event(&detail_window.widget, I_EV_HIDE);
        detail_button = -1;
        detail_time = 0;
}
Example #4
0
/******************************************************************************\
 Configure a specific player.
\******************************************************************************/
void I_configure_player(int index, const char *name, i_color_t color, bool host)
{
    C_assert(index >= 0 && index < PLAYERS);
    configure_player(index, name, color, host);
    I_widget_event(&players[index].box.widget, I_EV_CONFIGURE);

    /* Window may need repacking */
    I_widget_event(I_widget_top_level(&players[index].box.widget),
                   I_EV_CONFIGURE);
}
Example #5
0
/******************************************************************************\
 Discover the new mouse and key focus widgets.
\******************************************************************************/
static void find_focus(void)
{
        check_mouse_focus(mouse_focus);
        I_widget_event(&i_root, I_EV_MOUSE_FOCUS);
        if (!mouse_focus)
                return;

        /* Change keyboard focus */
        if (mouse_focus->state != I_WS_DISABLED && mouse_focus->entry)
                I_widget_event(mouse_focus, I_EV_KEY_FOCUS);
}
Example #6
0
/******************************************************************************\
 Popup widget event function.
\******************************************************************************/
static int popup_event(i_widget_t *widget, i_event_t event)
{
        c_vec2_t origin;
        float height;

        switch (event) {
        case I_EV_CONFIGURE:
                height = R_font_height(R_FONT_GUI) / r_scale_2d;
                if (height < 16.f)
                        height = 16.f;
                widget->size = C_vec2(0.f, height + i_border.value.n * 2.f);
                I_widget_pack(widget, I_PACK_H, I_FIT_BOTTOM);
                origin = C_vec2(r_width_2d / 2.f - widget->size.x / 2.f,
                                r_height_2d - widget->size.y -
                                i_border.value.n);
                R_window_cleanup(&popup_window);
                R_window_init(&popup_window, decor_popup);
                I_widget_move(widget, origin);
        case I_EV_MOVED:
                popup_window.sprite.size = widget->size;
                popup_window.sprite.origin = widget->origin;
                return FALSE;
        case I_EV_MOUSE_IN:
                popup_wait = TRUE;
                i_key_focus = NULL;
                break;
        case I_EV_MOUSE_OUT:
                popup_wait = FALSE;
                break;
        case I_EV_MOUSE_DOWN:
                if (i_mouse_button == SDL_BUTTON_RIGHT)
                        I_widget_event(&popup_widget, I_EV_HIDE);
                break;
        case I_EV_KEY_DOWN:
                if (i_key == SDLK_ESCAPE)
                        I_widget_event(&popup_widget, I_EV_HIDE);
                break;
        case I_EV_CLEANUP:
                R_window_cleanup(&popup_window);
                break;
        case I_EV_RENDER:
                if (popup_wait)
                        popup_time = c_time_msec;
                else if (c_time_msec - popup_time > POPUP_TIME)
                        I_widget_event(&popup_widget, I_EV_HIDE);
                popup_window.sprite.modulate.a = widget->fade;
                R_window_render(&popup_window);
                break;
        default:
                break;
        }
        return TRUE;
}
Example #7
0
/******************************************************************************\
 Update ping time and gold
\******************************************************************************/
void I_update_player(int player, int gold, short ping)
{
        char *buff;
        buff = C_va("% 5d", gold);
        C_strncpy_buf(players[player].gold.buffer, buff);
        buff = C_va("% 3d msec", ping);
        C_strncpy_buf(players[player].ping.buffer, buff);
        I_widget_event(&players[player].box.widget, I_EV_CONFIGURE);

        /* Window may need repacking */
        I_widget_event(I_widget_top_level(&players[player].box.widget),
                       I_EV_CONFIGURE);
}
Example #8
0
/******************************************************************************\
 Configure the popup widget to display a message from the queue.
\******************************************************************************/
static void popup_configure()
{
        if (!popup_messages[0].message[0]) {
                I_widget_event(&popup_widget, I_EV_HIDE);
                return;
        }
        I_label_configure(&popup_label, popup_messages[0].message);
        zoom_button.widget.state = popup_messages[0].has_goto_pos ?
                                   I_WS_READY : I_WS_DISABLED;
        I_widget_event(&popup_widget, I_EV_CONFIGURE);
        I_widget_event(&popup_widget, I_EV_SHOW);
        popup_time = c_time_msec;
}
Example #9
0
/******************************************************************************\
 Toolbar button handlers.
\******************************************************************************/
static void toolbar_button_click(i_button_t *button)
{
        i_toolbar_t *toolbar;
        i_window_t *window;

        toolbar = (i_toolbar_t *)button->data;
        window = toolbar->windows + (int)(button - toolbar->buttons);
        if (toolbar->open_window && toolbar->open_window->widget.shown) {
                I_widget_event(&toolbar->open_window->widget, I_EV_HIDE);
                if (toolbar->open_window == window) {
                        toolbar->open_window = NULL;
                        return;
                }
        }
        I_widget_event(&window->widget, I_EV_SHOW);
        toolbar->open_window = window;
}
Example #10
0
/******************************************************************************\
 Reset ring contents.
\******************************************************************************/
void I_reset_ring(void)
{
        int i;

        for (i = 0; i < I_RING_ICONS; i++) {
                I_widget_event(&button_widgets[i].widget, I_EV_HIDE);
                button_widgets[i].widget.fade = 0.f;
        }
        buttons = 0;
}
Example #11
0
/******************************************************************************\
 Toggle one of the toolbar's windows.
\******************************************************************************/
void I_toolbar_toggle(i_toolbar_t *toolbar, int i)
{
        i_window_t *window;

        if (!toolbar || i < 0 || i >= toolbar->children ||
            toolbar->buttons[i].widget.state == I_WS_DISABLED)
                return;
        if (toolbar->open_window && !toolbar->open_window->widget.shown)
                toolbar->open_window = NULL;
        window = toolbar->windows + i;
        if (toolbar->open_window == window) {
                I_widget_event(&window->widget, I_EV_HIDE);
                toolbar->open_window = NULL;
                return;
        }
        if (toolbar->open_window)
                I_widget_event(&toolbar->open_window->widget, I_EV_HIDE);
        I_widget_event(&window->widget, I_EV_SHOW);
        toolbar->open_window = window;
}
Example #12
0
/******************************************************************************\
 Propagates an event to all of the widget's children in order. This must be
 called from your event function if you want to propagate events to child
 widgets.
\******************************************************************************/
void I_widget_propagate(i_widget_t *widget, i_event_t event)
{
        i_widget_t *child, *child_next;

        child = widget->child;
        while (child) {
                child_next = child->next;
                I_widget_event(child, event);
                child = child_next;
        }
}
Example #13
0
/******************************************************************************\
 Configure detail widgets.
\******************************************************************************/
static void detail_configure(void)
{
        /* Set label text */
        I_label_configure(&detail_title, details[detail_button]);
        I_label_configure(&detail_sub_title, detail_subs[detail_button]);

        /* Position and size the window */
        detail_window.widget.size = C_vec2(128.f, 0.f);
        detail_window.widget.origin = ring_widget.origin;
        detail_window.widget.origin.x += ring_widget.size.x / 2.f -
                                         detail_window.widget.size.x /
                                         2.f;
        detail_window.widget.origin.y -= i_border.value.n;
        I_widget_event(&detail_window.widget, I_EV_CONFIGURE);

        /* Color sub title depending on if the button is pressable */
        detail_sub_title.color = I_COLOR_GOOD;
        if (button_widgets[detail_button].widget.state == I_WS_DISABLED)
                detail_sub_title.color = I_COLOR_BAD;

        I_widget_event(&detail_window.widget, I_EV_SHOW);
}
Example #14
0
/******************************************************************************\
 Toolbar event function.
\******************************************************************************/
int I_toolbar_event(i_toolbar_t *toolbar, i_event_t event)
{
        int i;

        switch (event) {
        case I_EV_CONFIGURE:

                /* The toolbar just has the child window widget so we basically
                   slave all the positioning and sizing to it */
                toolbar->window.widget.origin = toolbar->widget.origin;
                toolbar->window.widget.size = toolbar->widget.size;
                I_widget_event(&toolbar->window.widget, event);
                toolbar->widget.origin = toolbar->window.widget.origin;
                toolbar->widget.size = toolbar->window.widget.size;

                for (i = 0; i < toolbar->children; i++)
                        I_toolbar_position(toolbar, i);
                return FALSE;

        case I_EV_MOUSE_DOWN:
                if (i_mouse_button == SDL_BUTTON_RIGHT && toolbar->open_window)
                        I_widget_event(&toolbar->open_window->widget,
                                       I_EV_HIDE);
                break;
        case I_EV_KEY_DOWN:
                if (i_key == SDLK_ESCAPE && toolbar->open_window)
                        I_widget_event(&toolbar->open_window->widget,
                                       I_EV_HIDE);
                break;
        case I_EV_HIDE:
                for (i = 0; i < toolbar->children; i++)
                        I_widget_event(&toolbar->windows[i].widget, I_EV_HIDE);
                break;
        default:
                break;
        }
        return TRUE;
}
Example #15
0
/******************************************************************************\
 Enable or disable a toolbar's button.
\******************************************************************************/
void I_toolbar_enable(i_toolbar_t *toolbar, int i, bool enable)
{
        if (!toolbar || i < 0 || i >= toolbar->children)
                return;

        /* Disable the button and hide its window */
        if (!enable) {
                toolbar->buttons[i].widget.state = I_WS_DISABLED;
                toolbar->was_open[i] = toolbar->windows[i].widget.shown;
                I_widget_event(&toolbar->windows[i].widget, I_EV_HIDE);
                if (toolbar->open_window == toolbar->windows + i)
                        toolbar->open_window = NULL;
                return;
        }

        /* Enable the button */
        if (toolbar->buttons[i].widget.state != I_WS_DISABLED)
                return;
        toolbar->buttons[i].widget.state = I_WS_READY;
        if (toolbar->was_open[i] && !toolbar->open_window) {
                I_widget_event(&toolbar->windows[i].widget, I_EV_SHOW);
                toolbar->open_window = toolbar->windows + i;
        }
}
Example #16
0
/******************************************************************************\
 Show the ring UI centered on a world-space [origin].
\******************************************************************************/
void I_show_ring(i_ring_f _callback)
{
        int i;

        screen_origin = i_mouse;
        position_and_pack();
        I_widget_event(&ring_widget, I_EV_SHOW);
        callback = _callback;
        detail_button = -1;

        /* Set button widgets to activate on hover, they will clear this flag
           when they receive a mouse up event (from anywhere) */
        for (i = 0; i < I_RING_ICONS; i++)
                button_widgets[i].hover_activate = TRUE;
}
Example #17
0
/******************************************************************************\
 Call on a widget in hover or active state to check if the widget has mouse
 focus this frame. Will generate I_EV_MOUSE_OUT when applicable. Returns
 TRUE if the widget has mouse focus.
\******************************************************************************/
static bool check_mouse_focus(i_widget_t *widget)
{
        if (!widget)
                return FALSE;
        if (can_mouse_focus(widget)) {
                mouse_focus = widget;
                return TRUE;
        }
        while (widget->state == I_WS_HOVER || widget->state == I_WS_ACTIVE) {
                I_widget_event(widget, I_EV_MOUSE_OUT);
                if (!widget->parent || can_mouse_focus(widget->parent))
                        break;
                widget = widget->parent;
        }
        return FALSE;
}
Example #18
0
/******************************************************************************\
 Add a button to the ring.
\******************************************************************************/
void I_add_to_ring(i_ring_icon_t icon, int enabled, const char *title,
                   const char *sub)
{
        C_assert(icon >= 0 && icon < I_RING_ICONS);

        /* Show the button */
        if (!button_widgets[icon].widget.shown) {
                I_widget_event(&button_widgets[icon].widget, I_EV_SHOW);
                buttons++;
        }
        button_widgets[icon].widget.state = enabled ? I_WS_READY :
                                                      I_WS_DISABLED;

        /* Save the detail information */
        C_strncpy_buf(details[icon], title);
        C_strncpy_buf(detail_subs[icon], sub);
}
Example #19
0
/******************************************************************************\
 Configure the players window.
\******************************************************************************/
void I_configure_player_num(int num)
{
    int i;

    for (i = 0; i < num; i++) {
        players[i].box.widget.shown = TRUE;
        players[i].box.widget.pack_skip = FALSE;
        I_configure_player(i, NULL, I_COLOR, FALSE);
    }
    for (; i < PLAYERS; i++) {
        players[i].box.widget.shown = FALSE;
        players[i].box.widget.pack_skip = TRUE;
    }
    I_widget_event(&i_right_toolbar.windows[i_players_button].widget,
                   I_EV_CONFIGURE);
    I_toolbar_position(&i_right_toolbar, i_players_button);
}
Example #20
0
/******************************************************************************\
 Remove a widget from its parent container and free its memory.
\******************************************************************************/
void I_widget_remove(i_widget_t *widget, int cleanup)
{
        if (!widget)
                return;
        if (widget->parent) {
                i_widget_t *prev;

                prev = widget->parent->child;
                if (prev != widget) {
                        while (prev->next != widget) {
                                if (!prev->next)
                                        C_error("%s is not its parent's child",
                                                widget->name);
                                prev = prev->next;
                        }
                        prev->next = widget->next;
                } else
                        widget->parent->child = widget->next;
        }
        widget->parent = NULL;
        widget->next = NULL;
        if (cleanup)
                I_widget_event(widget, I_EV_CLEANUP);
}
Example #21
0
/******************************************************************************\
 Propagates an event up through its parents.
\******************************************************************************/
static void propagate_up(i_widget_t *widget, i_event_t event)
{
        for (; widget && widget->event_func; widget = widget->parent)
                if (widget->shown && widget->state != I_WS_DISABLED)
                        I_widget_event(widget, event);
}
Example #22
0
/******************************************************************************\
 Window widget event function.
\******************************************************************************/
int I_window_event(i_window_t *window, i_event_t event)
{
        switch (event) {
        case I_EV_CONFIGURE:
                R_window_cleanup(&window->window);
                I_widget_pack(&window->widget, window->pack_children,
                              window->fit);
                if (window->decorated) {
                        r_texture_t *decor;

                        decor = decor_window;
                        if (window->popup)
                                decor = decor_popup;
                        R_window_init(&window->window, decor);
                        window->window.sprite.origin = window->widget.origin;
                        window->window.sprite.size = window->widget.size;
                        R_sprite_cleanup(&window->hanger);
                        R_sprite_init(&window->hanger, hanger);
                        window->hanger.origin.y = window->widget.origin.y +
                                                  window->widget.size.y;
                        window->hanger.size.y = (float)i_border.value.n;
                }
                return FALSE;
        case I_EV_KEY_DOWN:
                if (i_key == SDLK_ESCAPE && window->auto_hide)
                        I_widget_event(&window->widget, I_EV_HIDE);
                break;
        case I_EV_MOUSE_IN:
                if (I_widget_child_of(&window->widget, i_key_focus))
                        break;
                i_key_focus = NULL;
                I_widget_propagate(&window->widget, I_EV_GRAB_FOCUS);
                break;
        case I_EV_MOVED:
                window->window.sprite.origin = window->widget.origin;
                window->hanger.origin.y = window->widget.origin.y +
                                          window->widget.size.y;
                break;
        case I_EV_MOUSE_DOWN:
                if (i_mouse_button == SDL_BUTTON_RIGHT && window->auto_hide)
                        I_widget_event(&window->widget, I_EV_HIDE);
                break;
        case I_EV_CLEANUP:
                R_window_cleanup(&window->window);
                R_sprite_cleanup(&window->hanger);
                break;
        case I_EV_RENDER:
                if (!window->decorated)
                        break;
                window->window.sprite.modulate.a = window->widget.fade;
                R_window_render(&window->window);
                if (!window->hanger_align)
                        break;
                window->hanger.origin.x = window->hanger_align->origin.x +
                                          window->hanger_align->size.x / 2 -
                                          window->hanger.size.x / 2;
                window->hanger.modulate.a = window->widget.fade;
                R_sprite_render(&window->hanger);
                break;
        default:
                break;
        }
        return TRUE;
}
Example #23
0
/******************************************************************************\
 Dispatches basic widget events and does some checks to see if the event
 applies to this widget. Cleans up resources on I_EV_CLEANUP and propagates
 the event to all child widgets.

 Key focus follows the mouse. Only one widget can have keyboard focus at any
 time and that is the last widget that the mouse cursor passed over that
 could take keyboard input.

 Events filter down through containers to child widgets. The ordering will call
 all of a widget's parent containers before calling the widget and will call
 all of the children of a widget before calling a sibling.

 Always call this function instead of a widget's class event function in order
 to ensure correct event filtering and propagation.
\******************************************************************************/
void I_widget_event(i_widget_t *widget, i_event_t event)
{
        if (!widget)
                return;
        if (!widget->name[0] || !widget->event_func) {
                if (event == I_EV_CLEANUP)
                        return;
                C_error("Propagated %s to uninitialized widget, parent is %s",
                        I_event_to_string(event),
                        widget->parent ? widget->parent->name : "NULL");
        }

        /* The only event an unconfigured widget can handle is I_EV_CONFIGURE */
        if (!widget->configured && event != I_EV_CONFIGURE) {
                if (widget->auto_configure)
                        I_widget_event(widget, I_EV_CONFIGURE);
                if (!widget->configured)
                        C_error("Propagated %s to unconfigured %s",
                                I_event_to_string(event), widget->name);
        }

        /* Print out the event in debug mode */
        if (i_debug.value.n >= 2)
                switch (event) {
                default:
                        C_trace("%s --> %s", I_event_to_string(event),
                                widget->name);
                case I_EV_RENDER:
                case I_EV_MOUSE_MOVE:
                case I_EV_MOUSE_FOCUS:
                case I_EV_GRAB_FOCUS:
                case I_EV_KEY_UP:
                case I_EV_MOUSE_UP:
                        break;
                }

        /* Before handling and propagating event to children */
        switch (event) {
        case I_EV_CLEANUP:
                if (c_mem_check.value.n)
                        C_trace("Freeing %s", widget->name);
                break;
        case I_EV_CONFIGURE:
                if (c_mem_check.value.n)
                        C_trace("Configuring %s", widget->name);
                break;
        case I_EV_GRAB_FOCUS:
                if (widget->entry && widget->shown &&
                    widget->state != I_WS_DISABLED)
                        key_focus = widget;
                break;
        case I_EV_HIDE:
                if (!widget->shown)
                        return;
                widget->shown = FALSE;
                widget->event_func(widget, event);
                focus_parent(widget);
                return;
        case I_EV_KEY_DOWN:
                if (widget->steal_keys &&
                    widget->state != I_WS_DISABLED && widget->shown &&
                    widget->state != I_WS_NO_FOCUS)
                        widget->event_func(widget, event);
                return;
        case I_EV_MOUSE_IN:
                if (widget->state == I_WS_READY)
                        widget->state = I_WS_HOVER;
                widget->event_func(widget, event);
                return;
        case I_EV_MOUSE_OUT:
                if (widget->state == I_WS_HOVER || widget->state == I_WS_ACTIVE)
                        widget->state = I_WS_READY;
                widget->event_func(widget, event);
                return;
        case I_EV_MOUSE_DOWN:
                widget->event_func(widget, event);
                return;
        case I_EV_MOUSE_FOCUS:
                if (!check_mouse_focus(widget))
                        return;
                break;
        case I_EV_MOUSE_MOVE:
                if (widget->state == I_WS_READY)
                        I_widget_event(widget, I_EV_MOUSE_IN);
                widget->event_func(widget, event);
                return;
        case I_EV_KEY_FOCUS:
                key_focus = mouse_focus;
                widget->event_func(widget, event);
                return;
        case I_EV_MOVED:
                C_error("I_EV_MOVED should only be generated by "
                        "I_widget_move()");
        case I_EV_RENDER:
                if (!i_debug.value.n && widget->parent &&
                    !C_rect_intersect(widget->origin, widget->size,
                                      widget->parent->origin,
                                      widget->parent->size))
                        return;
                if (i_fade.value.f > 0.f) {
                        float target, rate;

                        target = 0.f;

                        /* Widgets inherit the parent widget's fade */
                        if (widget->shown) {
                                target = 1.f;
                                if (widget->parent)
                                        target = widget->parent->fade;
                        }

                        rate = i_fade.value.f * c_frame_sec;
                        if (widget->state == I_WS_DISABLED) {
                                target *= 0.25f;
                                if (widget->fade <= 0.25f)
                                        rate *= 0.25f;
                        }
                        if (widget->fade < target) {
                                widget->fade += rate;
                                if (widget->fade > target)
                                        widget->fade = target;
                        } else if (widget->fade > target) {
                                widget->fade -= rate;
                                if (widget->fade < target)
                                        widget->fade = target;
                        }

                        /* Widget should never be less faded than its parent */
                        if (widget->parent &&
                            widget->parent->fade < widget->fade)
                                widget->fade = widget->parent->fade;

                        if (widget->fade <= 0.f)
                                return;
                } else if (!widget->shown)
                        return;
                break;
        case I_EV_SHOW:
                if (widget->shown)
                        return;
                widget->shown = TRUE;
                widget->event_func(widget, event);
                find_focus();
                return;
        default:
                break;
        }

        /* Call widget-specific event handler and propagate event down */
        if (widget->event_func(widget, event))
                I_widget_propagate(widget, event);

        /* After handling and propagation to children */
        switch (event) {
        case I_EV_CONFIGURE:
                widget->configured = TRUE;
                break;
        case I_EV_CLEANUP:
                focus_parent(widget);
                if (i_mouse_focus == widget)
                        i_mouse_focus = NULL;
                if (i_key_focus == widget)
                        i_key_focus = NULL;
                if (widget->heap)
                        C_free(widget);
                else
                        C_zero(widget);
                break;
        case I_EV_MOUSE_DOWN:
        case I_EV_MOUSE_UP:
                if (mouse_focus == widget && widget->state == I_WS_READY)
                        widget->state = I_WS_HOVER;
                break;
        default:
                break;
        }
}
Example #24
0
/******************************************************************************\
 Handle an SDL event. Does not allow multiple keys or mouse buttons to be
 pressed at the same time.
\******************************************************************************/
void I_dispatch(const SDL_Event *ev)
{
        SDLMod mod;
        i_event_t event;

        /* Update modifiers */
        mod = SDL_GetModState();
        i_key_shift = mod & KMOD_SHIFT;
        i_key_alt = mod & KMOD_ALT;
        i_key_ctrl = mod & KMOD_CTRL;

        /* Before dispatch */
        switch (ev->type) {
        case SDL_ACTIVEEVENT:

                /* If the mouse focus was lost, reset the cursor position */
                if (!ev->active.gain &&
                    (ev->active.state & SDL_APPMOUSEFOCUS))
                        i_mouse = C_vec2(-1.f, -1.f);

                return;
        case SDL_KEYDOWN:
                event = I_EV_KEY_DOWN;
                i_key = ev->key.keysym.sym;
                i_key_unicode = ev->key.keysym.unicode;
                if (i_debug.value.n > 0)
                        C_trace("SDL_KEYDOWN (%s%s)",
                                (i_key_shift ? "shift + " : ""),
                                I_key_string(i_key_unicode));
                if (!i_key) {
                        C_warning("SDL sent zero keysym");
                        return;
                }
                break;
        case SDL_KEYUP:
                event = I_EV_KEY_UP;
                i_key = ev->key.keysym.sym;
                if (i_debug.value.n > 0)
                        C_trace("SDL_KEYUP (%s%s)",
                                (i_key_shift ? "shift + " : ""),
                                I_key_string(i_key_unicode));
                break;
        case SDL_MOUSEMOTION:
                event = I_EV_MOUSE_MOVE;
                i_mouse.x = ev->motion.x / r_scale_2d;
                i_mouse.y = ev->motion.y / r_scale_2d;
                find_focus();
                break;
        case SDL_MOUSEBUTTONDOWN:
                event = I_EV_MOUSE_DOWN;
                i_mouse_button = ev->button.button;
                if (i_debug.value.n > 0)
                        C_trace("SDL_MOUSEBUTTONDOWN (%d)", i_mouse_button);
                check_mouse_focus(mouse_focus);
                break;
        case SDL_MOUSEBUTTONUP:
                event = I_EV_MOUSE_UP;
                i_mouse_button = ev->button.button;
                if (i_debug.value.n > 0)
                        C_trace("SDL_MOUSEBUTTONUP (%d)", i_mouse_button);
                check_mouse_focus(mouse_focus);
                break;
        default:
                return;
        }

        /* Update focus widgets for this event */
        i_key_focus = key_focus;
        i_mouse_focus = mouse_focus;

        /* Key and mouse down events are propagated back from the focused
           widget up the hierarchy */
        if (event == I_EV_KEY_DOWN) {
                I_global_key();
                if (i_key_focus) {
                        i_key_focus->event_func(i_key_focus, event);
                        propagate_up(i_key_focus->parent, event);
                }
        } else if (event == I_EV_MOUSE_DOWN || event == I_EV_MOUSE_MOVE)
                propagate_up(mouse_focus, event);

        /* Normal event propagation up from the root widget */
        else
                I_widget_event(&i_root, event);

        /* After dispatch */
        switch (ev->type) {
        case SDL_MOUSEBUTTONUP:
                i_mouse_button = 0;
                break;
        case SDL_KEYUP:
                i_key = 0;
                break;
        default:
                break;
        }
}