/** * This function is a helper function for the wtk_frame_handler() function. * It is called when a pointer RELEASE event is sent to the container window. * This function completes the move operation if the RELEASE event was inside * the parent window's boundaries. * * \param frame Frame the received the event. * \param event Pointer event information. */ static void wtk_handle_frame_release(struct wtk_frame *frame, struct win_pointer_event const *event) { bool is_inside; switch (frame->state) { /* If we were moving when released, ungrab pointer and move if * release was inside parent window extents. */ case WTK_FRAME_MOVING: /* Ungrab pointer. */ wtk_stop_drag(&(event->last_pos)); win_grab_pointer(NULL); frame->state = WTK_FRAME_NORMAL; /* Check release position. */ is_inside = win_is_inside_window(win_get_parent(frame-> container), &(event->pos)); /* If inside, move frame according to drag distance. */ if (is_inside) { struct win_area area = *win_get_area(frame->container); area.pos.x += event->pos.x - wtk_drag_origin.x; area.pos.y += event->pos.y - wtk_drag_origin.y; win_set_area(frame->container, &area, WIN_ATTR_POSITION); } break; default: break; } }
/** * This function is a helper function for the wtk_frame_handler() function. * It is called when a pointer RELEASE event is sent to the resize window. * This function completes the resize operation if the RELEASE event was inside * the parent window's boundaries. * * \param frame Frame the received the event. * \param event Pointer event information. */ static void wtk_handle_resize_release(struct wtk_frame *frame, struct win_pointer_event const *event) { bool is_inside; switch (frame->state) { /* If we were resizing when released, ungrab pointer and resize * if release was inside parent window extents. */ case WTK_FRAME_RESIZING: /* Ungrab pointer. */ wtk_stop_drag(&(event->last_pos)); win_grab_pointer(NULL); frame->state = WTK_FRAME_NORMAL; /* Check release position. */ is_inside = win_is_inside_window(win_get_parent(frame-> container), &(event->pos)); /* If inside, resize frame according to drag distance. */ if (is_inside) { struct win_area contents_area = *win_get_area(frame->contents); contents_area.size.x += event->pos.x - wtk_drag_origin.x; contents_area.size.y += event->pos.y - wtk_drag_origin.y; wtk_resize_frame(frame, &contents_area); } break; default: break; } }
/** * This function is the window event handler for check box widgets. * It handles all events sent to the windows composing the widget. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_check_box_handler(struct win_window *win, enum win_event_type type, void const *data) { struct win_command_event command; /* Custom data for windows of a widget points back to the widget itself. */ struct wtk_check_box *check_box = (struct wtk_check_box *)win_get_custom_data(win); switch (type) { case WIN_EVENT_DRAW: { /* There should not be other windows in this widget. */ Assert(win == check_box->container); /* For DRAW events, the data parameter points to the * clipping region. */ struct win_clip_region const *clip = (struct win_clip_region const *)data; /* Draw check box square. */ gfx_draw_rect(clip->origin.x + WTK_CHECKBOX_BOX_X, clip->origin.y + WTK_CHECKBOX_BOX_Y, WTK_CHECKBOX_BOX_SIZE, WTK_CHECKBOX_BOX_SIZE, WTK_CHECKBOX_BOX_COLOR); /* Draw check box square background. */ if (WTK_CHECKBOX_BACKGROUND_COLOR != GFX_COLOR_TRANSPARENT) { gfx_draw_filled_rect(clip->origin.x + WTK_CHECKBOX_BOX_X + 1, clip->origin.y + WTK_CHECKBOX_BOX_Y + 1, WTK_CHECKBOX_BOX_SIZE - 2, WTK_CHECKBOX_BOX_SIZE - 2, WTK_CHECKBOX_BACKGROUND_COLOR); } /* Draw check box select marker if selected. */ if (check_box->selected) { gfx_draw_filled_rect(clip->origin.x + WTK_CHECKBOX_BOX_X + 2, clip->origin.y + WTK_CHECKBOX_BOX_Y + 2, WTK_CHECKBOX_BOX_SIZE - 4, WTK_CHECKBOX_BOX_SIZE - 4, WTK_CHECKBOX_SELECT_COLOR); } /* Draw caption. */ gfx_draw_string(check_box->caption, clip->origin.x + WTK_CHECKBOX_CAPTION_X, clip->origin.y + WTK_CHECKBOX_CAPTION_Y, &sysfont, GFX_COLOR_TRANSPARENT, WTK_CHECKBOX_CAPTION_COLOR); /* Always accept DRAW events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_POINTER: { /* There should not be other windows in this widget. */ Assert(win == check_box->container); /* For POINTER events, the data parameter points to the * pointer event information. */ struct win_pointer_event const *event = (struct win_pointer_event const *)data; switch (event->type) { case WIN_POINTER_PRESS: /* When check box pressed, grab pointer and * wait for release inside widget borders. * Other widgets won't get pointer events * before it is released, and the pointer * ungrabbed by us. */ if (check_box->state == WTK_CHECKBOX_NORMAL) { win_grab_pointer(check_box->container); check_box->state = WTK_CHECKBOX_PRESSED; win_redraw(check_box->container); } break; case WIN_POINTER_RELEASE: /* When check box released, take action only if * released inside widget extents. */ if (check_box->state == WTK_CHECKBOX_PRESSED) { bool is_inside; /* Ungrab pointer. */ win_grab_pointer(NULL); check_box->state = WTK_CHECKBOX_NORMAL; win_redraw(check_box->container); /* Check release position. */ is_inside = win_is_inside_window (check_box->container, &(event->pos)); /* Toggle check box if inside. */ if (is_inside) { wtk_check_box_toggle(check_box); /* Send non-zero command. */ if (check_box->command) { command.sender = check_box->container; command.recipient = check_box->container; command.data = check_box->command; win_queue_command_event (&command); } } } break; default: break; } /* Accept all POINTER events since all acitivity inside * the widget extents is relevant to us. */ return true; } case WIN_EVENT_DESTROY: /* There should not be other windows in this widget. */ Assert(win == check_box->container); /* Memory allocated for windows will be automatically destroyed * by the window system. We must destroy other allocations. */ membag_free(check_box->caption); membag_free(check_box); /* Always accept DESTROY events, as the return value is ignored * anyway for that event type. */ return true; default: /* Reject unknown event types. */ return false; } }
/** * This function is the window event handler for radio button widgets. * It handles all events sent to the windows composing the widget. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_radio_button_handler(struct win_window *win, enum win_event_type type, void const *data) { struct win_command_event command; /* Custom data for windows of a widget points back to the widget itself. */ struct wtk_radio_button *radio_button = (struct wtk_radio_button *)win_get_custom_data(win); switch (type) { case WIN_EVENT_DRAW: { /* For DRAW events, the data parameter points to the * clipping region. */ struct win_clip_region const *clip = (struct win_clip_region const *)data; /* There should not be other windows in this widget. */ Assert(win == radio_button->container); /* Draw radio button circle. */ gfx_draw_circle(clip->origin.x + WTK_RADIOBUTTON_BUTTON_X, clip->origin.y + WTK_RADIOBUTTON_BUTTON_Y, WTK_RADIOBUTTON_RADIUS, WTK_RADIOBUTTON_BUTTON_COLOR, GFX_WHOLE); /* Draw radio button filled circle background. */ if (WTK_RADIOBUTTON_BACKGROUND_COLOR != GFX_COLOR_TRANSPARENT) { gfx_draw_filled_circle(clip->origin.x + WTK_RADIOBUTTON_BUTTON_X, clip->origin.y + WTK_RADIOBUTTON_BUTTON_Y, WTK_RADIOBUTTON_RADIUS - 1, WTK_RADIOBUTTON_BACKGROUND_COLOR, GFX_WHOLE); } /* Draw radio button select marker if selected. */ if (radio_button->group->selected == radio_button) { gfx_draw_filled_circle(clip->origin.x + WTK_RADIOBUTTON_BUTTON_X, clip->origin.y + WTK_RADIOBUTTON_BUTTON_Y, WTK_RADIOBUTTON_RADIUS - 2, WTK_RADIOBUTTON_SELECT_COLOR, GFX_WHOLE); } /* Draw caption. */ gfx_draw_string(radio_button->caption, clip->origin.x + WTK_RADIOBUTTON_CAPTION_X, clip->origin.y + WTK_RADIOBUTTON_CAPTION_Y, &sysfont, GFX_COLOR_TRANSPARENT, WTK_RADIOBUTTON_CAPTION_COLOR); /* Always accept DRAW events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_POINTER: { /* There should not be other windows in this widget. */ Assert(win == radio_button->container); /* For POINTER events, the data parameter points to the * pointer event information. */ struct win_pointer_event const *event = (struct win_pointer_event const *)data; switch (event->type) { case WIN_POINTER_PRESS: /* When radio button pressed, grab pointer and * wait for release inside widget borders. * Other widgets won't get pointer events * before it is released, and the pointer * ungrabbed by us. */ if (radio_button->state == WTK_RADIOBUTTON_NORMAL) { win_grab_pointer(radio_button-> container); radio_button->state = WTK_RADIOBUTTON_PRESSED; win_redraw(radio_button->container); } break; case WIN_POINTER_RELEASE: /* When button released, take action only if * released inside widget extents. */ if (radio_button->state == WTK_RADIOBUTTON_PRESSED) { bool is_inside; /* Ungrab pointer. */ win_grab_pointer(NULL); radio_button->state = WTK_RADIOBUTTON_NORMAL; win_redraw(radio_button->container); /* Check release position. */ is_inside = win_is_inside_window (radio_button-> container, &(event->pos)); /* Select this radio button if inside. */ if (is_inside) { wtk_radio_button_select (radio_button); /* Send non-zero command. */ if (radio_button->command) { command.sender = radio_button-> container; command.recipient = radio_button-> container; command.data = radio_button->command; win_queue_command_event (&command); } } } break; default: break; } /* Accept all POINTER events since all acitivity inside * the widget extents is relevant to us. */ return true; } case WIN_EVENT_DESTROY: /* There should not be other windows in this widget. */ Assert(win == radio_button->container); /* Memory allocated for windows will be automatically destroyed * by the window system. We must destroy other allocations. */ membag_free(radio_button->caption); /* Destroy radio group as well if we are the last one in the * group. If not, remove ourselves from the group. */ --(radio_button->group->num_references); if (!radio_button->group->num_references) { membag_free(radio_button->group); } else { if (radio_button->group->selected == radio_button) { radio_button->group->selected = NULL; } } membag_free(radio_button); /* Always accept DESTROY events, as the return value is ignored * anyway for that event type. */ return true; default: /* Reject unknown event types. */ return false; } }
/** * This function is the window event handler for icon button widgets. * It handles all events sent to the windows composing the widget. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_icon_button_handler(struct win_window *win, enum win_event_type type, void const *data) { struct win_command_event command; /* Custom data for windows of a widget points back to the widget itself. */ struct wtk_icon_button *icon_button = (struct wtk_icon_button *)win_get_custom_data(win); switch (type) { case WIN_EVENT_DRAW: { /* For DRAW events, the data parameter points to the * clipping region. */ struct win_clip_region const *clip = (struct win_clip_region const *)data; struct win_area const *area = win_get_area(win); /* There should not be other windows in this widget. */ Assert(win == icon_button->container); /* Draw icon button select marker if selected. */ if (icon_button->group->selected == icon_button) { gfx_draw_rect(clip->origin.x, clip->origin.y, area->size.x, area->size.y, WTK_ICONBUTTON_SELECT_COLOR); } /* Always accept DRAW events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_POINTER: { /* There should not be other windows in this widget. */ Assert(win == icon_button->container); /* For POINTER events, the data parameter points to the * pointer event information. */ struct win_pointer_event const *event = (struct win_pointer_event const *)data; switch (event->type) { case WIN_POINTER_PRESS: /* When icon button pressed, grab pointer and * wait for release inside widget borders. * Other widgets won't get pointer events * before it is released, and the pointer * ungrabbed by us. */ if (icon_button->state == WTK_ICONBUTTON_NORMAL) { win_grab_pointer(icon_button->container); icon_button->state = WTK_ICONBUTTON_PRESSED; win_redraw(icon_button->container); } break; case WIN_POINTER_RELEASE: /* When button released, take action only if * released inside widget extents. */ if (icon_button->state == WTK_ICONBUTTON_PRESSED) { bool is_inside; /* Ungrab pointer. */ win_grab_pointer(NULL); icon_button->state = WTK_ICONBUTTON_NORMAL; win_redraw(icon_button->container); /* Check release position. */ is_inside = win_is_inside_window (icon_button-> container, &(event->pos)); /* Select this icon button if inside. */ if (is_inside) { wtk_icon_button_select (icon_button); /* Send non-zero command. */ if (icon_button->command) { command.sender = icon_button-> container; command.recipient = icon_button-> container; command.data = icon_button->command; win_queue_command_event (&command); } } } break; default: break; } /* Accept all POINTER events since all activity inside * the widget extents is relevant to us. */ return true; } case WIN_EVENT_DESTROY: /* There should not be other windows in this widget. */ Assert(win == icon_button->container); /* Destroy icon group as well if we are the last one in the * group. If not, remove ourselves from the group. */ --(icon_button->group->num_references); if (!icon_button->group->num_references) { membag_free(icon_button->group); } else { if (icon_button->group->selected == icon_button) { icon_button->group->selected = NULL; } } membag_free(icon_button); /* Always accept DESTROY events, as the return value is ignored * anyway for that event type. */ return true; default: /* Reject unknown event types. */ return false; } }
/** * This function is the window event handler for button widgets. * It handles all events sent to the windows composing the widget. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_button_handler(struct win_window *win, enum win_event_type type, void const *data) { /* Custom data for windows of a widget points back to the widget itself. */ struct wtk_button *button = (struct wtk_button *)win_get_custom_data(win); switch (type) { case WIN_EVENT_DRAW: { /* For DRAW events, the data parameter points to the * clipping region. */ struct win_clip_region const *clip = (struct win_clip_region const *)data; struct win_area const *area = win_get_area(win); /* Preare background and caption colors depending on state of * button. If pressed/highlighted, the colors are inverted. */ gfx_color_t background_color; gfx_color_t caption_color; /* There should not be other windows in this widget. */ Assert(win == button->container); switch (button->state) { case WTK_BUTTON_NORMAL: background_color = WTK_BUTTON_BACKGROUND_COLOR; caption_color = WTK_BUTTON_CAPTION_COLOR; break; case WTK_BUTTON_PRESSED: background_color = WTK_BUTTON_CAPTION_COLOR; caption_color = WTK_BUTTON_BACKGROUND_COLOR; break; default: Assert(false); background_color = WTK_BUTTON_BACKGROUND_COLOR; caption_color = WTK_BUTTON_CAPTION_COLOR; } /* Draw background. */ gfx_draw_filled_rect(clip->origin.x, clip->origin.y, area->size.x, area->size.y, background_color); /* Draw border. */ gfx_draw_rect(clip->origin.x, clip->origin.y, area->size.x, area->size.y, WTK_BUTTON_BORDER_COLOR); /* Draw caption. */ gfx_draw_string_aligned(button->caption, clip->origin.x + (area->size.x / 2), clip->origin.y + (area->size.y / 2), &sysfont, GFX_COLOR_TRANSPARENT, caption_color, TEXT_POS_CENTER, TEXT_ALIGN_CENTER); /* Always accept DRAW events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_POINTER: { /* There should not be other windows in this widget. */ Assert(win == button->container); /* For POINTER events, the data parameter points to the * pointer event information. */ struct win_pointer_event const *event = (struct win_pointer_event const *)data; switch (event->type) { case WIN_POINTER_PRESS: /* When button pressed, grab pointer and wait * for release inside button borders. Other * widgets won't get pointer events before it * is released, and the pointer ungrabbed by * us. */ if (button->state == WTK_BUTTON_NORMAL) { win_grab_pointer(button->container); button->state = WTK_BUTTON_PRESSED; win_redraw(button->container); } break; case WIN_POINTER_RELEASE: /* When button released, take action only if * released inside widget extents. */ if (button->state == WTK_BUTTON_PRESSED) { /* Ungrab pointer. */ win_grab_pointer(NULL); button->state = WTK_BUTTON_NORMAL; win_redraw(button->container); /* Check release position. */ bool isInside = win_is_inside_window (button->container, &(event->pos)); /* Send command event if inside. */ if (isInside) { struct win_command_event command; command.sender = button-> container; command.recipient = button-> container; command.data = button-> command; win_queue_command_event (&command); } } break; default: break; } /* Accept all POINTER events since all acitivity inside * the widget extents is relevant to us. */ return true; } case WIN_EVENT_DESTROY: { /* There should not be other windows in this widget. */ Assert(win == button->container); /* Memory allocated for windows will be automatically * destroyed by the window system. We must destroy * other allocations. */ membag_free(button->caption); membag_free(button); /* Always accept DESTROY events, as the return value is * ignored anyway for that event type. */ return true; } default: /* Reject unknown event types. */ return false; } }