Esempio n. 1
0
/**
 * 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;
	}
}
Esempio n. 2
0
/**
 * This function is a helper function for the wtk_frame_handler() function.
 * It is called when a pointer PRESS event is sent to the resize window.
 * This function prepares a drag operation.
 *
 * \param frame Frame the received the event.
 * \param event Pointer event information.
 */
static void wtk_handle_resize_press(struct wtk_frame *frame,
		struct win_pointer_event const *event)
{
	switch (frame->state) {
	/* If we are in normal state, prepare for resize drag. */
	case WTK_FRAME_NORMAL:
		wtk_prepare_drag(&(event->pos));
		win_grab_pointer(frame->resize);

		frame->state = WTK_FRAME_AWAITING_RESIZE;
		break;

	default:
		break;
	}
}
Esempio n. 3
0
/**
 * 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;
	}
}
Esempio n. 4
0
/**
 * 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;
	}
}
/**
 * \brief Slider event handler.
 *
 * This is the window event handler for slider widgets. It handles the three
 * relevant event types sent to a slider's container window, i.e., drawing,
 * pointer and destroy events.\par
 *
 * For POINTER events, the slider value is only updated when the pointer moves,
 * and not upon press or release events. The handler will grab the pointer and
 * allow for it to move outside the actual widget window and still control the
 * slider knob.
 *
 * \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_slider_handler(struct win_window *win, enum win_event_type type,
		void const *data)
{
	struct win_pointer_event const  *event;
	struct win_clip_region const    *clip;
	struct win_command_event        command;
	struct win_area const           *area;
	struct wtk_slider               *slider;
	struct win_point                origin;
	gfx_color_t                     knob_color;
	gfx_coord_t                     position;
	gfx_coord_t                     length;
	uint8_t                         option;
	uint8_t                         value;
	bool                            send_command;

	slider = (struct wtk_slider *)win_get_custom_data(win);

	// There should not be other windows in this widget.
	assert(win == slider->container);

	switch (type) {
	case WIN_EVENT_DRAW:
		/* For DRAW events, the data parameter points to the
		 * clipping region.
		 */
		clip = (struct win_clip_region const *)data;
		area = win_get_area(win);
		option = slider->option;

		if (slider->state == WTK_SLIDER_NORMAL) {
			knob_color = WTK_SLIDER_KNOB_COLOR_NORMAL;
		} else {
			knob_color = WTK_SLIDER_KNOB_COLOR_MOVING;
		}

		// Draw slider frame border.
		gfx_draw_rect(clip->origin.x,
				clip->origin.y,
				area->size.x,
				area->size.y, WTK_SLIDER_BORDER_COLOR);

		// Draw slider frame background within frame.
		gfx_draw_filled_rect(clip->origin.x + 1,
				clip->origin.y + 1,
				area->size.x - 2,
				area->size.y - 2, WTK_SLIDER_BACKGROUND_COLOR);

		// Draw the slider knob according to configured orientation.
		if (option & WTK_SLIDER_VERTICAL) {
			// Draw slider knob border.
			gfx_draw_rect(clip->origin.x,
					clip->origin.y + slider->position,
					area->size.x,
					WTK_SLIDER_KNOB_WIDTH,
					WTK_SLIDER_BORDER_COLOR);

			// Draw slider knob.
			gfx_draw_filled_rect(clip->origin.x + 1,
					clip->origin.y + slider->position + 1,
					area->size.x - 2,
					WTK_SLIDER_KNOB_WIDTH - 2, knob_color);
		} else {
			gfx_draw_rect(clip->origin.x + slider->position,
					clip->origin.y,
					WTK_SLIDER_KNOB_WIDTH,
					area->size.y, WTK_SLIDER_BORDER_COLOR);

			gfx_draw_filled_rect(clip->origin.x + slider->position
					+ 1,
					clip->origin.y + 1,
					WTK_SLIDER_KNOB_WIDTH - 2,
					area->size.y - 2, knob_color);
		}

		/* Always accept DRAW events, as the return value is ignored
		 * anyway for that event type.
		 */
		return true;


	case WIN_EVENT_POINTER:
		/* For POINTER events, the data parameter points to the pointer
		 * event information.
		 */
		event = (struct win_pointer_event const *)data;
		area = win_get_area(win);
		option = slider->option;
		send_command = false;
		origin = slider->root_pos;

		switch (event->type) {
		case WIN_POINTER_PRESS:
			/* Grab the pointer and redraw a highlighted slider.
			 * Slider value is not updated yet.
			 */
			if (slider->state == WTK_SLIDER_NORMAL) {
				slider->state = WTK_SLIDER_MOVING;
				win_grab_pointer(win);
				win_redraw(win);
			};

#if WTK_SLIDER_PARENT_MOVE_SUPPORT
			// Update root position.
			win_translate_win_to_root(win, &slider->root_pos);
#endif
			break;

		case WIN_POINTER_MOVE:
			/* The slider is only updated when the pointer moves
			 * and the window was previously pressed. The pointer
			 * does not need to remain within the window to control
			 * the knob as only the position along the slider's
			 * direction of orientation is used.
			 */
			if (slider->state == WTK_SLIDER_MOVING) {
				/* Get the position of the pointer relative to
				 * slider knob's origin, and the length of the
				 * slider itself.
				 */
				if (option & WTK_SLIDER_VERTICAL) {
					position = event->pos.y - origin.y;
					length = area->size.y;
				} else {
					position = event->pos.x - origin.x;
					length = area->size.x;
				}

				// Subtract offsets due to slider knob size.
				position -= WTK_SLIDER_KNOB_WIDTH / 2;
				length -= WTK_SLIDER_KNOB_WIDTH;

				/* Bound the value if pointer is outside window.
				 * Otherwise, compute the slider value from the
				 * knob position.
				 */
				if (position < 0) {
					value = 0;
				} else if (position > length) {
					value = slider->maximum;
				} else {
					value = wtk_rescale_value(position,
							length,
							slider->maximum);
				}

				// Update slider only if this is a new value.
				if (slider->value != value) {
					slider->value = value;

					/* Compute knob position from value to
					 * get correct positioning.
					 */
					slider->position =
							wtk_rescale_value(value,
							slider->maximum,
							length);

					if (option & WTK_SLIDER_CMD_MOVE) {
						send_command = true;
					}

					win_redraw(win);
				}
			}
			break;

		case WIN_POINTER_RELEASE:
			/* Release the pointer and redraw a normal slider.
			 * The slider's value is not updated. Hence, a pointer
			 * press directly followed by a release will leave the
			 * slider value unchanged.
			 */
			if (slider->state == WTK_SLIDER_MOVING) {
				slider->state = WTK_SLIDER_NORMAL;
				win_grab_pointer(NULL);
				win_redraw(win);

				if (option & WTK_SLIDER_CMD_RELEASE) {
					send_command = true;
				}
			}
			break;

		default:
			break;
		}

		// Prepare and send command, if it was flagged.
		if (send_command) {
			command.sender = slider->container;
			command.recipient = slider->container;
			command.data = slider->command;
			win_queue_command_event(&command);
		}

		/* Accept all POINTER events since all acitivity inside the
		 * widget window is relevant.
		 */
		return true;

	case WIN_EVENT_DESTROY:
		/* Memory allocated for windows will be automatically destroyed
		 * by the window system. We must destroy other allocations.
		 */
		membag_free(slider);

		/* Always accept DESTROY events, as the return value is ignored
		 * anyway for that event type.
		 */
		return true;

	default:
		// Reject unknown event types.
		return false;
	}
}
Esempio n. 6
0
/**
 * 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;
	}
}
Esempio n. 7
0
/**
 * 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;
	}
}
Esempio n. 8
0
/**
 * 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;
	}
}
Esempio n. 9
0
int main(int argc, char *argv[])
{
    byte keypress;

    client_init();

    if( argc > 1 )    /* Command line arguments */
	handle_cl_args(argc, argv);

    srand( time(NULL) );
    calc_lookup_tables(DEGREES);
    win_init();
    entity_init();
    if( (ent_img_loaded = (char *)malloc(num_entity_types)) == NULL ) {
	perror("Malloc");
	ERR_QUIT("Error allocating ent_img_loaded array", 1);
    } else {
	memset(ent_img_loaded, 0, num_entity_types);
    }

    /* Load client preferences from file */
    read_config_file( &client );
    /* Set view dimensions, which are calculated by tile width & heights */
    client.view_w = client.x_tiles * TILE_W;
    client.view_h = client.y_tiles * TILE_H;
    /* What the client WISHES their dimensions were (this may not be what
       it actually is, ie in demo's etc */
    client.desired_w = client.view_w;
    client.desired_h = client.view_h;

    weapon_type_init();
    particle_init();
    menu_init();

    cl_network_init();

    client.state = MENU;

    if( client.demo == DEMO_PLAY ) {
	cl_network_connect(NULL, 42);
	client.state = GAME_LOAD;
    }

    for( ; ; ) {
	switch( client.state ) {
	case MENU:
	    win_ungrab_pointer();
	    menu_driver();
	    break;

	case GAME_LOAD:
	    win_set_properties(VERSION, client.view_w, client.view_h+STATUS_H);
	    wait_till_expose(5);

	    /* Finished loading, we are ready to play */
	    cl_change_map(client.map, client.gamemode);
	    break;

	case GAME_RESUME: /* Resume game from menu */
	    win_set_properties(VERSION, client.view_w, client.view_h+STATUS_H);
	    wait_till_expose(5);
	    input_clear();
	    draw_status_bar();
	    cl_netmsg_send_ready(); /* Tell server new details */
	    cl_net_finish(); /* Send the NETMSG_READY to the server */
	    client.state = GAME_JOIN;

	    break;

	case GAME_JOIN:

        win_set_cursor( client.mousemode!=MOUSEMODE_ROTATE );
        win_set_cursor( 1 );


	    if( client.mousemode ) {
		win_grab_pointer();
	    }

	    text_buf_clear();
	    particle_clear();

	case GAME_PLAY:
	    cl_net_update();

	    if( client.state == GAME_PLAY ) { /* Maybe changed in net_update */
		draw_crosshair( my_entity );
		if( client.map_target_active )
		    draw_map_target( my_entity );

		text_buf_update();
		if( client.netstats )
		    cl_net_stats();

		win_update();

		/* Keyboard Input */
		client.dir = my_entity.dir;
		keypress = get_input();
		cl_netmsg_send_cl_update(keypress, client.dir);
	    }

	    cl_net_finish(); /* Send things that need sending */
	    cap_fps(client.fps);
	    break;

	case QUIT:
	    game_close();
	    image_close(); /* Free all the images */
	    win_close();
	    write_config_file(&client);
	    if( ent_img_loaded != NULL )
		free(ent_img_loaded);
	    exit(EXIT_SUCCESS);
	    break;
	}

    }

    return EXIT_SUCCESS;

}