Example #1
0
void wtk_plot_set_grid(struct wtk_plot *plot,
		uint8_t axis_option,
		uint8_t axis_spacing_x, uint8_t axis_offset_x,
		uint8_t axis_spacing_y, uint8_t axis_offset_y,
		gfx_color_t axis_color,
		gfx_color_t axis_zero_color)
{
	Assert(plot);

	uint8_t height;
	struct win_area const *area;

	area = win_get_area(plot->container);
	/* Makes grid/axis fit inside the window border */
	height = area->size.y - 2;

	plot->axis_option = axis_option;
	plot->axis_spacing_x = axis_spacing_x;
	plot->axis_offset_x = axis_offset_x;
	plot->axis_spacing_y = wtk_rescale_value(axis_spacing_y,
			plot->maximum, height);

	plot->axis_offset_y = height - wtk_rescale_value(axis_offset_y,
			plot->maximum, height);

	plot->axis_color = axis_color;
	plot->axis_zero_color = axis_zero_color;
}
Example #2
0
/**
 * \brief Add a value to the end of the plot.
 *
 * Scales the input value to fit the plot dimensions and adds it to the end of
 * the ring buffer.
 *
 * \param plot Pointer to wtk_plot struct to set new value for.
 * \param value New value for the plot.
 *
 * \return True.
 */
bool wtk_plot_add_value(struct wtk_plot *plot, uint8_t value)
{
	uint8_t height;
	uint8_t maximum;
	struct win_area const *area;

	Assert(plot);
	Assert(value <= plot->maximum);
	Assert(plot->buffer_start < plot->num_datapoints);

	maximum = plot->maximum;

	area = win_get_area(plot->container);

	/* Makes the plot fit inside the window border. */
	height = area->size.y - 2;

	/* Rescales the added value to fit inside the plot */
	/* and stores it in the ring buffer. */
	*(plot->plot_buffer + plot->buffer_start)
		= height - wtk_rescale_value((value), maximum, height - 1);

	/* Increments ring buffer pointer and resets at end */
	plot->buffer_start++;
	if (plot->buffer_start >= plot->num_datapoints) {
		plot->buffer_start = 0;
	}

	return true;
}
/**
 * \brief Set new slider value.
 *
 * Updates the current value and issues a redrawing of the slider if its value
 * was indeed changed. In this case, the new position of the slider knob is
 * also computed.
 *
 * \param slider Pointer to wtk_slider struct to set new value for.
 * \param value New value for the slider.
 *
 * \return True if slider value was changed.
 */
bool wtk_slider_set_value(struct wtk_slider *slider, uint8_t value)
{
	struct win_area const   *area;
	uint8_t                 length;
	uint8_t                 option;

	assert(slider);
	assert(value <= slider->maximum);

	option = slider->option;

	if (option & WTK_SLIDER_INVERT) {
		value = slider->maximum - value;
	}

	if (slider->value != value) {
		slider->value = value;
		area = win_get_area(slider->container);

		/* Get length of slider from window.
		 * wtk_slider_create() asserts that this is an 8-bit value.
		 */
		if (option & WTK_SLIDER_VERTICAL) {
			length = area->size.y;
		} else {
			length = area->size.x;
		}

		length -= WTK_SLIDER_KNOB_WIDTH;
		slider->position = wtk_rescale_value(value, slider->maximum,
				length);

		win_redraw(slider->container);

		return true;
	} else {
		return false;
	}
}
Example #4
0
/**
 * \brief Set new progress bar value.
 *
 * Updates the current value and issues a redrawing of the progress bar if its
 * value was indeed changed. In this case, a new end position for the progress
 * bar's fill area is also computed.
 *
 * \param bar Pointer to wtk_progress_bar struct to set new value for.
 * \param value New value for the progress bar.
 *
 * \return True if progress bar's value was changed.
 */
bool wtk_progress_bar_set_value(struct wtk_progress_bar *bar, uint8_t value)
{
	uint8_t length;
	uint8_t option;
	uint8_t maximum;
	struct win_area const *area;

	Assert(bar);
	Assert(value <= bar->maximum);

	if (value != bar->value) {
		bar->value = value;
		option = bar->option;
		maximum = bar->maximum;
		area = win_get_area(bar->container);

		/* Get length of progress bar from window. */
		if (option & WTK_PROGRESS_BAR_VERTICAL) {
			length = area->size.y;
		} else {
			length = area->size.x;
		}

		length -= 2;

		if (option & WTK_PROGRESS_BAR_INVERT) {
			value = maximum - value;
		}

		bar->position = wtk_rescale_value(value, maximum, length);
		win_redraw(bar->container);

		return true;
	} else {
		return false;
	}
}
/**
 * \brief Create a new slider widget.
 *
 * Allocates the necessary memory and intializes the window and data for slider
 * widgets. If there is not enough memory, the function returns NULL.\n
 * To destroy a slider widget and all its contents, and free its memory, call
 * \ref win_destroy() on the slider's child reference, given by
 * \ref wtk_slider_as_child(), like this:
 * "win_destroy(wtk_slider_as_child(my_slider_ptr));".\par
 *
 * Slider widgets fill the specified area and perform a mapping of the slider
 * knob's position to a value between 0 and maximum. The length of the slider
 * cannot exceed 255 pixels.\par
 *
 * By default, the value 0 corresponds to the top-most position for a vertical
 * slider, and the left-most position for a horizontal one. The slider's
 * orientation and inversion of the value can be configured.\par
 *
 * A slider can be configured to issue command events whenever its value is
 * changed by a pointer and/or when a pointer releases it.\par
 *
 * Refer to <gfx/wtk.h> for available configuration options.
 *
 * \todo Revisit, support larger sliders and values given a config symbol.
 *
 * \param parent Pointer to parent win_window struct.
 * \param area Pointer to win_area struct with position and size of the slider.
 * \param maximum Maximum value of the slider.
 * \param value Initial value of the slider.
 * \param option Configuration options for slider.
 *               See \ref gfx_wtk_slider_options
 * \param command Command to send to parent window. Must be non-zero if used.
 *
 * \return Pointer to new slider, if memory allocation was successful.
 */
struct wtk_slider *wtk_slider_create(struct win_window *parent,
		struct win_area const *area, uint8_t maximum, uint8_t value,
		uint8_t option, win_command_t command)
{
	struct win_attributes   attr;
	struct wtk_slider       *slider;
	uint8_t                 length;

	// Do sanity check on parameters.
	assert(maximum > 0);
	assert(area);
	assert(parent);

	// Allocate memory for the control data.
	slider = membag_alloc(sizeof(struct wtk_slider));
	if (!slider) {
		goto outofmem_slider;
	}

	// Initialize the slider data.
	slider->state = WTK_SLIDER_NORMAL;
	slider->maximum = maximum;
	slider->value = value;
	slider->option = option;

	// Invert the initial value if slider is inverted.
	if (option & WTK_SLIDER_INVERT) {
		value = maximum - value;
	}

	slider->value = value;

	// Enforce a non-zero command value, if these are enabled.
	if (option & (WTK_SLIDER_CMD_MOVE | WTK_SLIDER_CMD_RELEASE)) {
		assert(command > 0);
		slider->command = command;
	}

	// Set up event handling for the widget window.
	attr.event_handler = wtk_slider_handler;
	attr.custom = slider;

	// Do a sanity check of the specified window area parameters.
	attr.area = *area;
	assert(attr.area.size.x > 0);
	assert(attr.area.size.y > 0);

	if (option & WTK_SLIDER_VERTICAL) {
		assert(attr.area.size.x > 3);
		assert(attr.area.size.x <= (uint8_t) ~ 0);
		assert(attr.area.size.y > WTK_SLIDER_KNOB_WIDTH);
		length = attr.area.size.y;
	} else {
		assert(attr.area.size.x > WTK_SLIDER_KNOB_WIDTH);
		assert(attr.area.size.y <= (uint8_t) ~ 0);
		assert(attr.area.size.y > 3);
		length = attr.area.size.x;
	}

	// Set slider knob position according to initial value.
	length -= WTK_SLIDER_KNOB_WIDTH;
	slider->position = wtk_rescale_value(value, maximum, length);

	/* All drawing is done in wtk_slider_handler() to reduce overhead.
	 * Slider has no transparent areas, so parent does not need redrawing.
	 */
	attr.background = NULL;
	attr.behavior = 0;

	// Create the widget window.
	slider->container = win_create(parent, &attr);
	if (!slider->container) {
		goto outofmem_container;
	}

	// Store absolute position
	win_translate_win_to_root(slider->container, &slider->root_pos);
	return slider;

outofmem_container:
	membag_free(slider);

outofmem_slider:
	return NULL;
}
/**
 * \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;
	}
}
Example #7
0
/**
 * \brief Create a new progress bar widget.
 *
 * Allocates the necessary memory and intializes the window and data for
 * progress bar widgets. If there is not enough memory, the function returns
 * NULL.\n To destroy a progress bar widget and all its contents, and free its
 * memory, call \ref win_destroy() on the progress bar's child reference, given
 * by \ref wtk_progress_bar_as_child(), like this:
 * "win_destroy(wtk_progress_bar_as_child(my_progress_bar_ptr));".\par
 *
 * Progress bar widgets divide their window area in two non-overlapping
 * rectangles: one with a fill color, and one with a background color.
 * The ratio between the two rectangles' sizes is given by the progress bar's
 * value relative to its maximum: a higher value gives a larger fill.\par
 *
 * By default, a vertically oriented progress bar fills from the top, while a
 * horizontal one fills from the left. The progress bar's orientation and fill
 * direction can both be configured at the time of creation. The fill and
 * background colors can be changed at runtime.\par
 *
 * Refer to <gfx/wtk.h> for available configuration options.
 *
 * \param parent Pointer to parent win_window struct.
 * \param area Pointer to win_area struct with position and size of the
 *             progress bar. Minimum size in both x and y direction is 3 pixels.
 * \param maximum Maximum value of the progress bar.
 * \param value Initial value of the progress bar.
 * \param fill_color Color for filled area.
 * \param background_color Color for background area.
 * \param option Configuration options for progress bar.
 *
 * \return Pointer to new progress bar, if memory allocation was successful.
 */
struct wtk_progress_bar *wtk_progress_bar_create(struct win_window *parent,
		struct win_area const *area, uint8_t maximum, uint8_t value,
		gfx_color_t fill_color, gfx_color_t background_color,
		uint8_t option)
{
	uint8_t length;

	/* Do sanity check on parameters. */
	Assert(maximum > 0);
	Assert(value <= maximum);
	Assert(area);
	Assert(parent);

	/* Attributes scratchpad. */
	struct win_attributes attr;

	/* Allocate memory for the control data. */
	struct wtk_progress_bar *bar
		= membag_alloc(sizeof(struct wtk_progress_bar));
	if (!bar) {
		goto outofmem_bar;
	}

	/* Initialize the progress bar data. */
	bar->maximum = maximum;
	bar->value = value;
	bar->option = option;

	/* Set the progress bar's colors and prepare the value for computation
	 * of the bar's end position according to the invert option.
	 */
	if (option & WTK_PROGRESS_BAR_INVERT) {
		bar->fill_color = background_color;
		bar->background_color = fill_color;
		value = maximum - value;
	} else {
		bar->fill_color = fill_color;
		bar->background_color = background_color;
	}

	/* Set up handling information. */
	attr.event_handler = wtk_progress_bar_handler;
	attr.custom = bar;

	/* Do sanity check of specified window area parameters
	 * according to the orientation of the progress bar.
	 */
	attr.area = *area;
	Assert(attr.area.size.x > 3);
	Assert(attr.area.size.y > 3);

	if (option & WTK_PROGRESS_BAR_VERTICAL) {
		Assert(attr.area.size.y < (uint8_t) ~0);
		length = attr.area.size.y;
	} else {
		Assert(attr.area.size.x < (uint8_t) ~0);
		length = attr.area.size.x;
	}

	length -= 2;

	/* Set the progress bar's end position. */
	bar->position = wtk_rescale_value(value, maximum, length);

	/* All drawing is done in wtk_progress_bar_handler() so no background is
	 * needed.
	 */
	attr.background = NULL;

	/* Since the widget has no transparent areas, the parent does not need
	 * to be redrawn.
	 */
	attr.behavior = 0;

	/* Create a new window for the progress bar. */
	bar->container = win_create(parent, &attr);
	if (!bar->container) {
		goto outofmem_container;
	}

	return bar;

outofmem_container:
	membag_free(bar);

outofmem_bar:
	return NULL;
}