Exemple #1
0
int
mon_rtc(int argc, char **argv){
  int time_buf_size =  MD_BUF_SIZE;
  char *time_buf;
  uint8_t yr, dt, mo, dw, hr, mn, sc;
  if(argc<2){
    printf("wrong number of args to set time\n");
    return -1;
  }
  if(strcmp(argv[1],"get")==0){
    time_buf = membag_alloc(time_buf_size);
    if(time_buf==NULL)
      core_panic();
    rtc_get_time_str(time_buf,time_buf_size);
    printf("Time: %s\n",time_buf);
    membag_free(time_buf);
  }
  else if(strcmp(argv[1],"set")==0){
    if(argc!=9){
      printf("please specify yr dt mo dw hr mn sc\n");
      return -1;
    }
    yr = atoi(argv[2]);
    mo = atoi(argv[3]);
    dt = atoi(argv[4]);
    dw = atoi(argv[5]);
    hr = atoi(argv[6]);
    mn = atoi(argv[7]);
    sc = atoi(argv[8]);
    if(i2c_rtc_set_time(sc,mn,hr,dw,dt,mo,yr)!=0)
      printf("error setting RTC\n");
    else{
      time_buf = membag_alloc(time_buf_size);
      if(time_buf==NULL)
	core_panic();
      rtc_get_time_str(time_buf,time_buf_size);
      printf("Set time to: %s\n",time_buf);
      membag_free(time_buf);
    }
  }
  else{
    printf("bad arguments to rtc\n");
    return -1;
  }
  return 0;
}
Exemple #2
0
/**
 * This function creates a new icon button widget. It allocates required memory
 * and initializes necessary windows to create the widget. If there is not enough
 * memory, the function returns NULL.
 * To destroy the widget and all its contents, and free its memory, call
 * win_destroy() on the icon button's child reference, given by
 * wtk_icon_button_as_child(), like this:
 * "win_destroy(wtk_icon_button_as_child(myButtonPtr));".
 * Usually it will be destroyed automatically when it's parent is destroyed.
 *
 * \param parent Parent window, possibly wtk_frame_as_parent(myFramePtr).
 * \param area Area of the internal contents.
 * \param icon Bitmap to draw as the icon.
 * \param selected Initial state of icon button, true if checked/selected.
 * \param group Icon button group to be a member of.
 * \param command Command to send to parent window. Must be non-zero to be
 *                enabled.
 *
 * \return Pointer to icon button, or NULL if failed.
 */
struct wtk_icon_button *wtk_icon_button_create(struct win_window *parent,
		struct win_area const *area, struct gfx_bitmap *icon,
		bool selected, struct wtk_icon_group *group, win_command_t command)
{
	struct wtk_icon_button *icon_button;
	struct win_attributes attr;

	Assert(group);
	Assert(area);
	Assert(icon);
	Assert(parent);

	/* Allocate memory for check box control data. */
	icon_button = membag_alloc(sizeof(struct wtk_icon_button));
	if (!icon_button) {
		goto outofmem_icon_button;
	}

	icon_button->state = WTK_ICONBUTTON_NORMAL;
	icon_button->group = group;
	icon_button->command = command;

	/* Handling information. */
	attr.event_handler = wtk_icon_button_handler;
	attr.custom = icon_button;

	/* Prepare container frame. */
	attr.area = *area;
	attr.background = icon;
	attr.behavior = 0;

	icon_button->container = win_create(parent, &attr);
	if (!icon_button->container) {
		goto outofmem_container;
	}

	/* Select the icon button in the group if either no icon button is
	 * currently selected (empty group), or the user has requested it takes
	 * over the selection */
	if (selected || (group->selected == NULL)) {
		/* Add ourselves to the icon group, take over selection if required. */
		wtk_icon_button_select(icon_button);
	}

	/* Make sure we haven't filled up the group reference count, and
	 * increment. */
	Assert(group->num_references < (wtk_icon_group_size_t)-1L);
	++(group->num_references);

	return icon_button;

outofmem_container:
	membag_free(icon_button);

outofmem_icon_button:
	return NULL;
}
Exemple #3
0
/**
 * This function starts the drag operation. It will allocate memory to store
 * the screen behind the drag handles and draw the handles themselves.
 * Do not call this function unless wtk_prepare_drag() has been called first
 * with the drag origin position.
 * If there is not enough memory, this function will no draw anything, but it
 * is still safe to call wtk_continue_drag() and wtk_stop_drag().
 *
 * \param pos Current position of drag target.
 */
static void wtk_start_drag(struct win_point const *pos)
{
	/* Allocate memory for bitmaps. */
	wtk_drag_origin_pixmap = membag_alloc(
			(WTK_DRAG_PIXMAP_SIZE * WTK_DRAG_PIXMAP_SIZE) *
			sizeof(gfx_color_t)
			);
	if (!wtk_drag_origin_pixmap) {
		goto outofmem_origin;
	}

	wtk_drag_target_pixmap = membag_alloc(
			(WTK_DRAG_PIXMAP_SIZE * WTK_DRAG_PIXMAP_SIZE) *
			sizeof(gfx_color_t)
			);
	if (!wtk_drag_target_pixmap) {
		goto outofmem_target;
	}

	/* Make sure we can draw on the entire screen, since dragging is not
	 * necessarily limited to within one window.
	 */
	gfx_set_clipping(0, 0, gfx_get_width() - 1, gfx_get_height() - 1);

	/* Store screen underneath and draw drag origin symbol. */
	gfx_get_pixmap(wtk_drag_origin_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0,
			wtk_drag_origin.x - WTK_DRAG_HANDLE_RADIUS,
			wtk_drag_origin.y - WTK_DRAG_HANDLE_RADIUS,
			WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE);

	gfx_draw_filled_circle(wtk_drag_origin.x, wtk_drag_origin.y,
			WTK_DRAG_HANDLE_RADIUS,
			WTK_DRAG_ORIGIN_COLOR, GFX_WHOLE);

	/* Store screen underneath and draw drag target symbol. */
	gfx_get_pixmap(wtk_drag_target_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0,
			pos->x - WTK_DRAG_HANDLE_RADIUS,
			pos->y - WTK_DRAG_HANDLE_RADIUS,
			WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE);

	gfx_draw_filled_circle(pos->x, pos->y,
			WTK_DRAG_HANDLE_RADIUS,
			WTK_DRAG_TARGET_COLOR, GFX_WHOLE);

	return;

outofmem_target:
	membag_free(wtk_drag_origin_pixmap);
	wtk_drag_origin_pixmap = NULL;

outofmem_origin:
	return;
}
/**
 * \brief Command event handler for the application's frame.
 *
 * This function handles the relevant command events for the application's
 * frame. In this application, only the exit-button requires handling, and will
 * cause an immediate exit from the application.
 *
 * \note The handler function of the \ref gfx_wtk "Widget toolkit" will destroy
 * the frame and the widgets when this function returns true.
 *
 * \param basic_frame Pointer to the application frame.
 * \param command_data Data for the command event.
 */
static bool tank_frame_handler(struct wtk_basic_frame *basic_frame,
		win_command_t command_data)
{
	switch ((enum tank_command_id)(uintptr_t)command_data) {
	case CMD_EXIT:
		// Stop the application timer first.
		timer_stop(CONFIG_TIMER_ID, &tank_ctx->timer);

		// Free all memory and return to desktop.
		memcpy(&sysfont, &tank_ctx->old_sysfont,
				sizeof(struct font));
		membag_free(tank_ctx);
		tank_ctx = NULL;
		app_desktop_restart();
		return true;

	default:
		break;
	}

	return false;
}
/** Set new caption for label, return false if out of mem. */
bool wtk_label_change(struct wtk_label *label, const char *caption)
{
	Assert(label);
	Assert(caption);

	uint8_t new_len = strlen(caption);
	uint8_t old_len = 0;

	if (caption) {
		old_len = strlen(label->caption);
	}

	/* Only free old memory if new length is longer than the
	 * previous label.
	 */
	if (new_len > old_len) {
		/* Free old caption, if present. */
		if (caption) {
			membag_free(label->caption);
		}

		/* Allocate memory for caption string, and copy text. */
		label->caption = membag_alloc((new_len + 1) * sizeof(char));
		if (!label->caption) {
			goto outofmem_caption;
		}
	}

	wtk_copy_string(label->caption, caption);

	/* Redraw if visible. */
	win_redraw(label->container);

	return true;

outofmem_caption:
	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;
	}
}
Exemple #7
0
/**
 * \brief Setup widget demo
 *
 * Allocates memory for the application context, and creates all widgets that
 * make up its interface. If memory allocation or widget creation fails, the
 * application exits immediately.
 *
 * \return Boolean true if the application was launched successfully, false if
 *         a memory allocation occurred.
 */
bool app_widget_launch(void)
{
	struct win_window *parent;
	struct win_area area;
	struct wtk_button *button;

	/* Create a new context for the GUI */
	widget_ctx = membag_alloc(sizeof(struct widget_context));
	if (!widget_ctx) {
		return false;
	}

	/* Initialize context data. */
	widget_ctx->frame_bg.type = GFX_BITMAP_SOLID;
	widget_ctx->frame_bg.data.color = GFX_COLOR(220, 220, 220);

	/* Set the area for the GUI window */
	area = win_get_attributes(win_get_root())->area;
	win_inflate_area(&area, -20);

	/* Create and show the main GUI frame */
	widget_ctx->frame = wtk_basic_frame_create(
			win_get_root(), &area, &widget_ctx->frame_bg, NULL,
			widget_frame_command_handler, widget_ctx);
	if (!widget_ctx->frame) {
		goto error_frame;
	}

	parent = wtk_basic_frame_as_child(widget_ctx->frame);
	win_show(parent);

	/* Set the background information for the plot widget */
	widget_ctx->plot_bg.type = GFX_BITMAP_SOLID;
	widget_ctx->plot_bg.data.color = GFX_COLOR_WHITE;

	/* Adjust area for the plot widget */
	area.size.y -= 80;
	area.size.x -= 40;

	/* Create and show the plot widget with vertical axis marks */
	widget_ctx->plot = wtk_plot_create(parent, &area, 100, 10, GFX_COLOR_RED,
			&widget_ctx->plot_bg, WTK_PLOT_LEFT_TO_RIGHT);
	if (!widget_ctx->plot) {
		goto error_widget;
	}
	wtk_plot_set_grid(widget_ctx->plot, WTK_PLOT_TICKS_VERTICAL,
			10, 0, 10, 0, GFX_COLOR_BLUE, GFX_COLOR_GREEN);
	win_show(wtk_plot_as_child(widget_ctx->plot));
	
	/* Adjust area for the slider widget */
	area.pos.y += area.size.y + 10;
	area.size.y = 40;
	area.size.x -= 60;
	
	/* Create and show the slider widget */
	widget_ctx->slider = wtk_slider_create(parent, &area, 100, 0,
			WTK_SLIDER_HORIZONTAL, (win_command_t)SLIDER_ID);	
	if (!widget_ctx->slider) {
		goto error_widget;
	}
	win_show(wtk_slider_as_child(widget_ctx->slider));	
	
	/* Adjust area for the button widget */
	area.pos.x += area.size.x + 10;
	area.size.x = 50;
	
	/* Create and show the button widget */
	button = wtk_button_create(parent, &area, "Add", (win_command_t)BUTTON_ID);	
	if (!button) {
		goto error_widget;
	}
	win_show(wtk_button_as_child(button));

	return true;

	/* Error handling to clean up allocations after an error */
error_widget:
	win_destroy(wtk_basic_frame_as_child(widget_ctx->frame));
error_frame:
	membag_free(widget_ctx);
	
	return false;
}
Exemple #8
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;
}
Exemple #9
0
/**
 * \brief Progress bar event handler.
 *
 * This is the window event handler for progress bar widgets. It handles the two
 * relevant event types sent to a progress bar's container window, i.e.,
 * drawing, and destroy events.
 *
 * \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_progress_bar_handler(struct win_window *win,
		enum win_event_type type, void const *data)
{
	struct win_clip_region const *clip;
	struct win_area const *area;
	struct wtk_progress_bar *bar;
	uint8_t position;
	uint8_t option;

	bar = (struct wtk_progress_bar *)win_get_custom_data(win);

	/* Window receiving the event should be the widget's containing window. */
	Assert(win == bar->container);

	switch (type) {
	case WIN_EVENT_DRAW:

		/* For DRAW events, the data parameter points to the clipping
		 * region. The window area parameter is needed because it
		 * contains the size of the widget.
		 */
		clip = (struct win_clip_region const *)data;
		area = win_get_area(win);

		position = bar->position;
		option = bar->option;

		/* Draw a window border. */
		gfx_draw_rect(clip->origin.x, clip->origin.y, area->size.x,
				area->size.y, WTK_PROGRESS_BAR_BORDER_COLOR);

		/* Draw progress bar interior according to orientation.
		 * An inverted progress bar is drawn in the same way as a
		 * non-inverted, as this option is handled in the functions
		 * for setting the bar's colors and value.
		 */
		if (option & WTK_PROGRESS_BAR_VERTICAL) {
			/* Draw the top section of the bar. */
			gfx_draw_filled_rect(clip->origin.x + 1,
					clip->origin.y + 1,
					area->size.x - 2,
					position, bar->fill_color);
			/* Draw the bottom section of the bar. */
			gfx_draw_filled_rect(clip->origin.x + 1,
					clip->origin.y + 1 + position,
					area->size.x - 2,
					area->size.y - 2 - position,
					bar->background_color);
		} else {
			/* Draw the left section of the bar. */
			gfx_draw_filled_rect(clip->origin.x + 1,
					clip->origin.y + 1,
					bar->position,
					area->size.y - 2, bar->fill_color);
			/* Draw the right section of the bar. */
			gfx_draw_filled_rect(clip->origin.x + 1 + position,
					clip->origin.y + 1,
					area->size.x - 2 - position,
					area->size.y - 2,
					bar->background_color);
		}

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

	case WIN_EVENT_DESTROY:

		/* Free up all memory allocated by widget.
		 * The window is freed by the window system
		 */
		membag_free(bar);
		return true;

	default:
		return false;
	}
}
Exemple #10
0
/**
 * This function creates a new frame widget. It allocates required memory and
 * intializes necessary windows to create the widget. If there is not enough
 * memory, the function returns NULL.
 *
 * To destroy the widget and all its contents, and free its memory, call
 * win_destroy() on the frame's child reference, given by wtk_frame_as_child(),
 * like this: "win_destroy(wtk_frame_as_child(my_frame_ptr));".
 * The frame's internal area will equal the area parameter, but the total
 * extents will be slightly larger, to accommodate for titlebar, borders etc.
 *
 * \param parent Parent window.
 * \param area Area of the internal contents.
 * \param caption Pointer to caption string. Will be copied into widget.
 * \param allow_resize True if resize handle should be included on the frame.
 * \param frame_handler Optional command event handler, for applications.
 * \param custom_data Optional custom data link, for applications.
 *
 * \return Pointer to frame, or NULL if failed.
 */
struct wtk_frame *wtk_frame_create(struct win_window *parent,
		struct win_area const *area,
		char const *caption,
		bool allow_resize,
		wtk_frame_handler_t frame_handler, void *custom_data)
{
	struct win_attributes attr;
	struct wtk_frame *frame;

	Assert(area);
	Assert(caption);
	Assert(parent);

	/* Allocate memory for frame control data. */
	frame = membag_alloc(sizeof(struct wtk_frame));
	if (!frame) {
		goto outofmem_frame;
	}

	frame->state = WTK_FRAME_NORMAL;
	frame->frame_handler = frame_handler;
	frame->custom_data = custom_data;

	/* Allocate memory for caption string, and copy text. */
	frame->caption = membag_alloc((strlen(caption) + 1) * sizeof(char));
	if (!frame->caption) {
		goto outofmem_caption;
	}

	wtk_copy_string(frame->caption, caption);

	/* Start with valid area info, but only contents frame will keep the
	 * original area. The other frames will be resized properly at the end.
	 * All windows have the same event handler, and the same link back to
	 * the widget object.
	 */
	attr.area = *area;
	attr.event_handler = wtk_frame_handler;
	attr.custom = frame;

	/* Prepare container frame, which will contain title bar, border, size,
	 * handle etc.
	 */
	attr.background = NULL;
	attr.behavior = WIN_BEHAVIOR_RAISE_ON_PRESS;

	/* Create the container window, the proper size will be set later. */
	frame->container = win_create(parent, &attr);
	if (!frame->container) {
		goto outofmem_container;
	}

	/* Prepare the contents frame, which will contain whatever controls
	 * owned by the frame. Size will be equal to the given area parameter.
	 */
	attr.area.pos.x = WTK_FRAME_LEFTBORDER;
	attr.area.pos.y = WTK_FRAME_TOPBORDER + WTK_FRAME_TITLEBAR_HEIGHT;
	attr.background = &wtk_frame_background;
	attr.behavior = 0;

	frame->contents = win_create(frame->container, &attr);
	if (!frame->contents) {
		goto outofmem_contents;
	}

	/* Only create resize handle window if resize is allowed. */
	if (allow_resize) {
		/* Prepare resize handle. Proper position will be set later.
		 * Size is set here, though.
		 */
		attr.area.size.x = WTK_FRAME_RESIZE_WIDTH;
		attr.area.size.y = WTK_FRAME_RESIZE_HEIGHT;
		attr.background = NULL;
		attr.behavior = 0;

		frame->resize = win_create(frame->container, &attr);
		if (!frame->resize) {
			goto outofmem_resize;
		}

		win_show(frame->resize);
	} else {
		frame->resize = NULL;
	}

	/* Now, resize and rearrange according to size of contents frame, which
	 * is equal to the given area parameter.
	 */
	wtk_resize_frame(frame, area);

	/* Make sure internals are visible when frame is mapped. */
	win_show(frame->contents);

	return frame;

outofmem_resize:
	win_destroy(frame->contents);

outofmem_contents:
	win_destroy(frame->container);

outofmem_container:
	membag_free(frame->caption);

outofmem_caption:
	membag_free(frame);

outofmem_frame:
	return NULL;
}
Exemple #11
0
/**
 * This function is the window event handler for frame 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_frame_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_frame *frame = (struct wtk_frame *)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);

		/* Draw frame decorations if this is the container window. */
		if (win == frame->container) {
			/* Draw left border. */
			gfx_draw_filled_rect(clip->origin.x,
					clip->origin.y,
					WTK_FRAME_LEFTBORDER,
					area->size.y,
					WTK_FRAME_BORDER_COLOR);

			/* Draw right border. */
			gfx_draw_filled_rect(clip->origin.x +
					area->size.x -
					WTK_FRAME_RIGHTBORDER,
					clip->origin.y,
					WTK_FRAME_RIGHTBORDER,
					area->size.y,
					WTK_FRAME_BORDER_COLOR);

			/* Draw top border. */
			gfx_draw_filled_rect(clip->origin.x +
					WTK_FRAME_LEFTBORDER,
					clip->origin.y,
					area->size.x -
					WTK_FRAME_LEFTBORDER -
					WTK_FRAME_RIGHTBORDER,
					WTK_FRAME_TOPBORDER,
					WTK_FRAME_BORDER_COLOR);

			/* Draw bottom border. */
			gfx_draw_filled_rect(clip->origin.x +
					WTK_FRAME_LEFTBORDER,
					clip->origin.y + area->size.y -
					WTK_FRAME_BOTTOMBORDER,
					area->size.x -
					WTK_FRAME_LEFTBORDER -
					WTK_FRAME_RIGHTBORDER,
					WTK_FRAME_BOTTOMBORDER,
					WTK_FRAME_BORDER_COLOR);

			/* Draw title bar background. */
			gfx_draw_filled_rect(clip->origin.x +
					WTK_FRAME_LEFTBORDER,
					clip->origin.y +
					WTK_FRAME_TOPBORDER,
					area->size.x -
					WTK_FRAME_LEFTBORDER -
					WTK_FRAME_RIGHTBORDER,
					WTK_FRAME_TITLEBAR_HEIGHT,
					WTK_FRAME_TITLEBAR_COLOR);

			/* Draw caption string. */
			gfx_draw_string(frame->caption,
					clip->origin.x +
					WTK_FRAME_LEFTBORDER +
					WTK_FRAME_CAPTION_X,
					clip->origin.y +
					WTK_FRAME_TOPBORDER +
					WTK_FRAME_CAPTION_Y, &sysfont,
					GFX_COLOR_TRANSPARENT,
					WTK_FRAME_CAPTION_COLOR);
		}
		/* Draw resize handle if this is the resize window. */
		else if (win == frame->resize) {
			gfx_draw_filled_circle(clip->origin.x +
					area->size.x - 1,
					clip->origin.y + area->size.y -
					1, WTK_FRAME_RESIZE_RADIUS,
					WTK_FRAME_RESIZE_COLOR,
					GFX_QUADRANT1);
		}

		/* 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.
		 */
		struct win_pointer_event const *event
			= (struct win_pointer_event const *)data;

		/* Handle move if this is the container window. */
		if (win == frame->container) {
			switch (event->type) {
			case WIN_POINTER_PRESS:
				wtk_handle_frame_press(frame, event);
				break;

			case WIN_POINTER_MOVE:
				wtk_handle_frame_move(frame, event);
				break;

			case WIN_POINTER_RELEASE:
				wtk_handle_frame_release(frame, event);
				break;

			default:
				break;
			}
		}
		/* Handle resize if this is the resize handle. */
		else if (win == frame->resize) {
			switch (event->type) {
			case WIN_POINTER_PRESS:
				wtk_handle_resize_press(frame, event);
				break;

			case WIN_POINTER_MOVE:
				wtk_handle_resize_move(frame, event);
				break;

			case WIN_POINTER_RELEASE:
				wtk_handle_resize_release(frame, event);
				break;

			default:
				break;
			}
		}

		/* Accept all POINTER events so that it does not
		 * propagate up the window tree to our parent in case
		 * we did not click anything useful inside the frame.
		 */
		return true;
	}

	case WIN_EVENT_DESTROY:
	{
		/* When the container window is destroyed, also destroy
		 * the rest of the non-window frame allocations.
		 */
		if (win == frame->container) {
			/* Memory allocated for windows will be
			 * automatically destroyed by the window
			 * system. We must destroy other allocations.
			 */
			membag_free(frame->caption);
			membag_free(frame);
		}

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

	case WIN_EVENT_COMMAND:
	{
		/* When commands are received either directly or
		 * propagated from child widgets and windows, send it
		 * to the frame handler.
		 */
		if (win == frame->container) {
			if (frame->frame_handler) {
				/* If the frame handler returns true,
				 * it wants us to destroy the frame.
				 * This is normally used by CLOSE
				 * buttons.
				 */
				bool shouldDestroy
					= frame->frame_handler(frame,
						(win_command_t)
						data);

				/* It is safe to destroy it here, since
				 * the event handling finished right
				 * after this handler returns, and no
				 * other references to this frame or
				 * its contents will be done.
				 */
				if (shouldDestroy) {
					win_destroy(frame->container);
				}

				/* Accept the event if there was a
				 * handler installed.
				 */
				return true;
			}
		}

		/* Reject the event if there was no handler, or this
		 * was not the container window at all.
		 */
		return false;
	}

	default:
		/* Reject unknown event types. */
		return false;
	}
}
Exemple #12
0
/**
 * \brief Setup widget demo
 *
 * Allocates memory for the application context, and creates all widgets that
 * make up its interface. If memory allocation or widget creation fails, the
 * application exits immediately.
 *
 * \return Boolean true if the application was launched successfully, false if
 *         a memory allocation occurred.
 */
bool app_widget_launch(void)
{
	struct win_window *parent;
	struct win_area area;
	struct wtk_check_box *cb;
	struct wtk_radio_group *rg;
	struct wtk_radio_button *rb;
	struct wtk_button *btn;

	/* Create a new context for the GUI */
	widget_ctx = membag_alloc(sizeof(struct widget_context));
	if (!widget_ctx) {
		return false;
	}

	/* Initialize context data. */
	widget_ctx->color_scheme = 0;
	widget_ctx->color_invert = 0;

	/* Set the background information for the GUI window */
	widget_ctx->frame_bg.type = GFX_BITMAP_SOLID;
	widget_ctx->frame_bg.data.color = APP_BACKGROUND_COLOR;

	/* Set the area for the GUI window */
	area = win_get_attributes(win_get_root())->area;
	win_inflate_area(&area, -20);

	/* Create and show the main GUI frame */
	widget_ctx->frame = wtk_basic_frame_create(
			win_get_root(), &area, &widget_ctx->frame_bg, NULL,
			widget_frame_command_handler, widget_ctx);

	if (!widget_ctx->frame) {
		goto error_frame;
	}
	parent = wtk_basic_frame_as_child(widget_ctx->frame);
	win_show(parent);

	/* Update area for the slider widget */
	area.pos.x = WIDGET_POS_X;
	area.pos.y = WIDGET_POS_Y + SLIDER_POS_Y;
	area.size.x = SLIDER_SIZE_X;
	area.size.y = SLIDER_SIZE_Y;

	/* Create slider inside frame */
	widget_ctx->slider = wtk_slider_create(parent, &area, 100, 50,
			WTK_SLIDER_HORIZONTAL | WTK_SLIDER_CMD_MOVE | WTK_SLIDER_CMD_RELEASE,
			(win_command_t)SLIDER_ID);

	if (!widget_ctx->slider) {
		goto error_widget;
	}
	win_show(wtk_slider_as_child(widget_ctx->slider));

	/* Update area for the progress bar widget */
	area.pos.x += area.size.x + SLIDER_PB_SPACING_X;
	area.size.x = PB_SIZE_X;
	area.size.y = PB_SIZE_Y;

	/* Create progress bar to the right of the slider */
	widget_ctx->pb = wtk_progress_bar_create(parent, &area, 100,
			50, GFX_COLOR_BLACK, GFX_COLOR_BLACK, WTK_PROGRESS_BAR_HORIZONTAL);

	if (!widget_ctx->pb) {
		goto error_widget;
	}
	win_show(wtk_progress_bar_as_child(widget_ctx->pb));
	app_widget_update_colors(widget_ctx);

	/* Update area for the checkbox widget */
	area.pos.x = WIDGET_POS_X;
	area.pos.y += area.size.y + CHECK_BOX_SPACING_Y;
	wtk_check_box_size_hint(&area.size, checkbox_string);

	/* Create check box below slider and progress bar */
	cb = wtk_check_box_create(parent, &area, checkbox_string,
			false, (win_command_t)CHECK_BOX_ID);

	if (!cb) {
		goto error_widget;
	}
	win_show(wtk_check_box_as_child(cb));

	/* Create a logical group for the radio buttons */
	rg = wtk_radio_group_create();
	if (!rg) {
		goto error_widget;
	}

	/* Update area for the first radio button widget */
	area.pos.y += area.size.y + RADIO_BUTTON_SPACING_Y;
	wtk_radio_button_size_hint(&area.size, rb1_string);

	/* Create first radio button widget */
	rb = wtk_radio_button_create(parent, &area, rb1_string,
			true, rg, (win_command_t)RADIO_BUTTON_1_ID);

	if (!rb) {
		goto error_widget;
	}
	win_show(wtk_radio_button_as_child(rb));

	/* Update area for the second radio button widget */
	area.pos.y += area.size.y + RADIO_BUTTON_SPACING_Y;
	wtk_radio_button_size_hint(&area.size, rb2_string);

	/* Create second radio button widget */
	rb = wtk_radio_button_create(parent, &area, rb2_string,
			false, rg, (win_command_t)RADIO_BUTTON_2_ID);

	if (!rb) {
		goto error_widget;
	}
	win_show(wtk_radio_button_as_child(rb));

	/* Update area for the button widget */
	area.pos.y += area.size.y + BUTTON_SPACING_Y;
	area.size.x = SLIDER_SIZE_X + SLIDER_PB_SPACING_X + PB_SIZE_X;
	area.size.y = BUTTON_SIZE_Y;

	/* Create button widget */
	btn = wtk_button_create(parent, &area, btn_string, (win_command_t)BUTTON_ID);
	wtk_button_size_hint(&area.size, btn_string);

	if (!btn) {
		goto error_widget;
	}
	win_show(wtk_button_as_child(btn));

	return true;

	/* Error handling to clean up allocations after an error */
error_widget:
	win_destroy(wtk_basic_frame_as_child(widget_ctx->frame));
error_frame:
	membag_free(widget_ctx);
	
	return false;
}
Exemple #13
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 Application loader.
 *
 * This worker function loads the alarm light bitmaps, then loads the background
 * image before showing all the widgets and starting the process simulation.
 *
 * If memory for bitmaps cannot be allocated, or the background image cannot be
 * loaded, the application will exit immediately.
 *
 * \param task Workqueue task for this worker function.
 */
static void tank_loader(struct workqueue_task *task)
{
	enum status_code    result;
	hugemem_ptr_t       bitmap_data;

	/* Handle the individual bitmap load states.
	 *
	 * All states, except LOAD_FINISHED, will cause the current workqueue
	 * task to be re-enqueued after loading of the corresponding bitmap has
	 * completed. This task worker will thus go through the states in
	 * sequence.
	 */
	switch (tank_ctx->loader_state) {
	case LOAD_RED_LIGHT:
		// Enqueue loading of the red alarm light bitmap.
		bitmap_data = load_file_to_hugemem(BITMAP_RED_LIGHT_FILENAME,
				task);

		/* If memory could be allocated for the bitmap, update the
		 * pointer in the bitmap metadata and set next load state.
		 * Otherwise, exit the application load error.
		 */
		if (bitmap_data != HUGEMEM_NULL) {
			tank_bitmap_data[BITMAP_RED_LIGHT] = bitmap_data;
			tank_ctx->bitmaps[BITMAP_RED_LIGHT].data.hugemem =
					bitmap_data;

			tank_ctx->loader_state = LOAD_GREEN_LIGHT;
		} else {
			goto exit_load_error;
		}
		break;

	case LOAD_GREEN_LIGHT:
		bitmap_data = load_file_to_hugemem(BITMAP_GREEN_LIGHT_FILENAME,
				task);

		if (bitmap_data != HUGEMEM_NULL) {
			tank_bitmap_data[BITMAP_GREEN_LIGHT] = bitmap_data;
			tank_ctx->bitmaps[BITMAP_GREEN_LIGHT].data.hugemem
					= bitmap_data;

			tank_ctx->loader_state = LOAD_BACKGROUND;
		} else {
			goto exit_load_error;
		}
		break;

	case LOAD_BACKGROUND:
		// Now load the background image.
		result = load_file_to_screen(BITMAP_BACKGROUND_FILENAME,
				BITMAP_BACKGROUND_POSITION_X,
				BITMAP_BACKGROUND_POSITION_Y,
				BITMAP_BACKGROUND_SIZE_X,
				BITMAP_BACKGROUND_SIZE_Y, task);

		if (result == STATUS_OK) {
			tank_ctx->loader_state = LOAD_FINISHED;
		} else {
			goto exit_load_error;
		}
		break;

	case LOAD_FINISHED:
		// Now show the application's frame. This will draw all widgets.
		win_show(wtk_basic_frame_as_child(tank_ctx->frame));

		// Set the worker function that updates the application.
		workqueue_task_set_work_func(task, tank_worker);

		// Set the timer alarm to trigger application updates.
		timer_start(CONFIG_TIMER_ID, &tank_ctx->timer);
		timer_set_alarm(CONFIG_TIMER_ID, &tank_ctx->timer,
				tank_ctx->timer_delay);
		break;

	default:
		// Should not end up here.
		unhandled_case(tank_ctx->loader_state);
		break;
	}

	return;

	// If a load error occurred, go back to the desktop.
exit_load_error:
	win_destroy(wtk_basic_frame_as_child(tank_ctx->frame));
	memcpy(&sysfont, &tank_ctx->old_sysfont, sizeof(struct font));
	membag_free(tank_ctx);
	tank_ctx = NULL;
	app_desktop_restart();
}
/**
 * This function is the window event handler for label 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_label_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_label *label = (struct wtk_label *)win_get_custom_data(win);

	switch (type) {
	case WIN_EVENT_DRAW:
	{
		/* There should not be other windows in this widget. */
		Assert(win == label->container);

		/* 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);

		if (label->align_right == false) {
			/* Draw caption string. */
			gfx_draw_string(label->caption,
					clip->origin.x,
					clip->origin.y,
					&sysfont,
					GFX_COLOR_TRANSPARENT,
					label->text_color);
		} else {
			/* Get string size and draw the caption text right
			 * aligned. */
			gfx_coord_t width;
			gfx_coord_t height;

			gfx_get_string_bounding_box(label->caption,
					&sysfont, &width, &height);

			gfx_draw_string(label->caption,
					clip->origin.x + area->size.x -
					width, clip->origin.y, &sysfont,
					GFX_COLOR_TRANSPARENT,
					label->text_color);
		}

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

	case WIN_EVENT_DESTROY:
		/* There should not be other windows in this widget. */
		Assert(win == label->container);

		/* Memory allocated for windows will be automatically destroyed
		 * by the window system. We must destroy other allocations.
		 */
		membag_free(label->caption);
		membag_free(label);

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

	default:
		/* Reject unknown event types. */
		return false;
	}
}
Exemple #16
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;
	}
}
/**
 * This function creates a new label widget. It allocates required memory
 * and intializes necessary windows to create the widget. If there is not enough
 * memory, the function returns NULL.
 *
 * To destroy the widget and all its contents, and free its memory, call
 * win_destroy() on the label's child reference, given by
 * wtk_label_as_child(),
 * like this: "win_destroy(wtk_label_as_child(myStaticTextPtr));".
 * Usually it will be destroyed automatically when it's parent is destroyed.
 *
 * \param parent Parent window, possibly wtk_frame_as_parent(myFramePtr).
 * \param area Area of the internal contents.
 * \param caption Pointer to caption string. Will be copied into widget.
 * \param text_color Foreground color of the text when drawn.
 * \param background Background of the label.
 * \param align_right True if caption is to be aligned to the right,
 *                    false otherwise.
 * \return Pointer to label, or NULL if failed.
 */
struct wtk_label *wtk_label_create(struct win_window *parent,
		struct win_area const *area, char const *caption,
		gfx_color_t text_color, struct gfx_bitmap *background,
		bool align_right)
{
	struct win_attributes attr;
	struct wtk_label *label;

	Assert(area);
	Assert(caption);
	Assert(parent);

	/* Allocate memory for label control data. */
	label = membag_alloc(sizeof(struct wtk_label));
	if (!label) {
		goto outofmem_label;
	}

	label->text_color = text_color;
	label->align_right = align_right;

	/* Allocate memory for caption string, and copy text. */
	label->caption = membag_alloc((strlen(caption) + 1) * sizeof(char));
	if (!label->caption) {
		goto outofmem_caption;
	}

	wtk_copy_string(label->caption, caption);
	
	/* Handling information. */
	attr.event_handler = wtk_label_handler;
	attr.custom = label;

	/* Prepare container frame. */
	attr.area = *area;
	
	/* Set background for label. */
	if (background) {
		attr.background = background;
		attr.behavior = 0;
	} else {
		attr.background = NULL;
		attr.behavior = WIN_BEHAVIOR_REDRAW_PARENT;
	}
	
	label->container = win_create(parent, &attr);
	if (!label->container) {
		goto outofmem_container;
	}

	return label;

outofmem_container:
	membag_free(label->caption);

outofmem_caption:
	membag_free(label);

outofmem_label:
	return NULL;
}
Exemple #18
0
void core_process_wifi_data(void){
  int BUF_SIZE=XL_BUF_SIZE;
  char *buf;
  int chan_num, data_size, r;
  unsigned int red,green,blue, blink;
  unsigned int yr,mo,dt,dw,hr,mn,sc;
  int time_buf_size =  MD_BUF_SIZE;
  char *time_buf;

  //match against the data
  if(strlen(wifi_rx_buf)>BUF_SIZE){
    printf("can't process rx'd packet, too large\n");
    core_log("can't process rx'd packet, too large");
    return;
  }
  //allocate memory
  buf = core_malloc(BUF_SIZE);
  r=sscanf(wifi_rx_buf,"\r\n+IPD,%d,%d:%s", &chan_num, &data_size, buf);
  if(r!=3){
    printf("rx'd corrupt data, ignoring\n");
    core_log("rx'd corrupt data, ignoring\n");
    //free memory
    core_free(buf);
    return;
  }

  if(wemo_config.debug_level>DEBUG_INFO)
    printf("Got [%d] bytes on channel [%d]\n",
	   data_size, chan_num);
  //discard responses from the NILM to power logging packets, but keep the response
  //if another core function has requested some data, this is done with the callback 
  //function. The requesting core function registers a callback and this function calls
  //it and then resets the callback to NULL
  if(chan_num==4){
    //close the socket
    wifi_send_cmd("AT+CIPCLOSE=4","Unlink",buf,BUF_SIZE,1);
    //execute the callback
    if(tx_callback!=NULL){
      (*tx_callback)(wifi_rx_buf);
      tx_callback=NULL;
    }
    //clear the server buffer
    memset(wifi_rx_buf,0x0,WIFI_RX_BUF_SIZE);
    //free memory
    core_free(buf);
    return;
  }
  ///////////////////
  //this data must be inbound to the server port, process the command
  //
  //     RELAY ON
  if(strcmp(buf,"relay_on")==0){
    gpio_set_pin_high(RELAY_PIN);
    printf("relay ON\n");
    //return "OK" to indicate success
    wifi_send_txt(0,"OK");
  }
  //     RELAY OFF
  else if(strcmp(buf,"relay_off")==0){
    gpio_set_pin_low(RELAY_PIN);
    printf("relay OFF\n");
    //return "OK" to indicate success
    wifi_send_txt(0,"OK");
  }
  //     LED SET
  else if(strstr(buf,"set_led")==buf){
    if(sscanf(buf,"set_led_%u_%u_%u_%u.",&red,&green,&blue,&blink)!=4){
      core_log("corrupt led_set request");
    } else {
      rgb_led_set(red,green,blue,blink);
      if(wemo_config.echo)
	printf("set led: [%u, %u, %u, %u]\n",red,green,blue,blink);
      wifi_send_txt(0,"OK");
    }
  }
  //     RTC SET
  else if(strstr(buf,"set_rtc")==buf){
    if(sscanf(buf,"set_rtc_%u_%u_%u_%u_%u_%u_%u.",
	      &yr,&mo,&dt,&dw,&hr,&mn,&sc)!=7){
      core_log("corrupt rtc_set request");
    } else {
      if(i2c_rtc_set_time(sc,mn,hr,dw,dt,mo,yr)!=0)
	printf("error setting RTC\n");
      else{
	time_buf = membag_alloc(time_buf_size);
	if(time_buf==NULL)
	  core_panic();
	rtc_get_time_str(time_buf,time_buf_size);
	if(wemo_config.echo)
	  printf("wifi set rtc to: %s\n",time_buf);
	core_log("wifi set rtc");
	membag_free(time_buf);
	wifi_send_txt(0,"OK");
      }
    }
  }
  //     SEND DATA
  else if(strcmp(buf,"send_data")==0){
    if(tx_pkt->status!=POWER_PKT_READY){
      r = wifi_send_txt(chan_num,"error: no data");
      if(r==TX_ERR_MODULE_RESET)
	while(wifi_init()!=0); //fail!!! anger!!!! reset the module
    } else {
      //send the data
      r=wifi_send_raw(chan_num,(uint8_t*)tx_pkt,sizeof(*tx_pkt));
      if(r==TX_ERR_MODULE_RESET){
	while(wifi_init()!=0); //fail!! anger!!! reset the module
      } else {
	//clear out the packet so we can start again
	memset(tx_pkt,0,sizeof(*tx_pkt));
	tx_pkt->status=POWER_PKT_EMPTY;
	if(wemo_config.debug_level>=DEBUG_INFO)
	  printf("sent data\n");
      }
    }
  }
  else{
    printf("unknown command: %s\n",buf);
    wifi_send_txt(chan_num,"error: unknown command");
    //free memory
    core_free(buf);
    return;
  }
  //clear the server buffer
  memset(wifi_rx_buf,0x0,WIFI_RX_BUF_SIZE);
  //free the memory
  core_free(buf);
  return;
}
Exemple #19
0
void
core_free(void *ptr){
  membag_free(ptr);
}
/**
 * \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;
}
/**
 * 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;
	}
}
Exemple #22
0
/**
 * \brief Create a new plot widget.
 *
 * Allocates the necessary memory and intializes the window and data for
 * plot widgets. If there is not enough memory, the function returns
 * NULL.\n To destroy a plot widget and all its contents, and free its
 * memory, call \ref win_destroy() on the plot's child reference, given
 * by \ref wtk_plot_as_child(), similar to:
 * \code
	win_destroy(wtk_plot_as_child(my_plot_ptr));
\endcode
 *
 * The plotted graph will shift from right to left as new data values are added.
 * Data values will be overwritten in the ring buffer as they shift out of
 * the plot window.
 * The maximum parameter scales the input value to fit the plot dimensions.
 *
 * The num_datapoints parameter must not exceed the maximum membag size,
 * and never over 255.
 *
 *
 * 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
 *        plot. Minimum size in both x and y direction is 4 pixels.
 * \param maximum Maximum value of the plot.
 * \param num_datapoints Number of datapoints of the plot.
 * \param draw_color Plot drawing color.
 * \param background Pointer to background bitmap for frame. NULL for
 *        transparent background. When background is transparent
 *        the parent window will automatically be redrawn
 *        when the basic frame is drawn.
 * \param option Configuration options for plot.
 *
 * \return Pointer to new plot, if memory allocation was successful.
 */
struct wtk_plot *wtk_plot_create(struct win_window *parent,
		struct win_area const *area, uint8_t maximum,
		uint8_t num_datapoints, gfx_color_t draw_color,
		struct gfx_bitmap *background, uint8_t option)
{
	uint16_t length;

	/* Do sanity check on parameters. */
	Assert(maximum > 0);
	Assert(area);
	Assert(parent);
	Assert(num_datapoints > 1);

	/* Attributes scratchpad. */
	struct win_attributes attr;

	/* Allocate memory for the control data. */
	struct wtk_plot *plot = membag_alloc(sizeof(struct wtk_plot));
	if (!plot) {
		goto outofmem_plot;
	}

	/* Allocate memory for the control data. */
	plot->plot_buffer = membag_alloc(num_datapoints);
	if (!plot->plot_buffer) {
		goto outofmem_plot_buffer;
	}

	/* Initialize the plot data. */
	plot->maximum = maximum;
	plot->num_datapoints = num_datapoints;
	plot->buffer_start = 0;
	plot->option = option;
	plot->draw_color = draw_color;
	plot->background = background;

	plot->axis_option = 0;
	plot->axis_spacing_x = 0;
	plot->axis_offset_x = 0;
	plot->axis_spacing_y = 0;
	plot->axis_offset_y = 0;
	plot->axis_color = 0;
	plot->axis_zero_color = 0;

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

	/* Makes the plot fit inside the window border. */
	length = attr.area.size.x;
	length -= 2;

	/* Calculate the spacing between datapoints. */
	plot->spacing = length / (num_datapoints - 1);

	/* Calculate the fixed-point remainder of the above operation. */
	plot->spacing_error = (uint8_t)(
		(((uint16_t)(length - plot->spacing * (num_datapoints - 1)))
		* WTK_PLOT_SCALE_FACTOR) / ((uint16_t)(num_datapoints - 1)));

	/* Set up handling information. */
	attr.event_handler = wtk_plot_handler;
	attr.custom = plot;

	/* Set background for window */
	if (background) {
		attr.background = background;
		attr.behavior = 0;
	} else {
		attr.background = NULL;
		if (option & WTK_PLOT_DONT_REDRAW_PARENT) {
			attr.behavior = 0;
		} else {
			attr.behavior = WIN_BEHAVIOR_REDRAW_PARENT;
		}
	}

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

	return plot;

outofmem_container:
	membag_free(plot->plot_buffer);

outofmem_plot_buffer:
	membag_free(plot);

outofmem_plot:
	return NULL;
}
/**
 * \brief Launch the water tank application.
 *
 * This function allocates memory, creates the application frame and widgets,
 * initializes the timer and initiates loading of the required bitmaps.
 *
 * One basic frame is created, along with four widgets: one slider, two progress
 * bars and a command button. These are not shown until the background image has
 * been loaded.
 *
 * If the alarm light bitmaps have already been loaded, i.e., the application
 * has already been run, the application will skip directly to loading of the
 * background image.
 *
 * If memory for the application context cannot be allocated or the frame or
 * widgets cannot be created, the application will exit immediately.
 *
 * \param task Workqueue task to use for the application's worker functions.
 */
void app_tank_launch(struct workqueue_task *task)
{
	struct win_attributes    attr;
	struct win_window        *win;
	struct gfx_bitmap        bitmap;
	struct wtk_basic_frame   *frame;
	struct wtk_slider        *slider;
	struct wtk_button        *button;
	struct wtk_progress_bar  *pbar;
	struct timer             *timer;
	timer_res_t              timer_res;
	uint32_t                 timer_clk;

	assert(task);

	// Clear the screen right away.
#ifdef CONFIG_GFX_USE_CLIPPING
	gfx_set_clipping(0, 0, gfx_get_width(), gfx_get_height());
#endif /* CONFIG_GFX_USE_CLIPPING */
	gfx_draw_filled_rect(0, 0, gfx_get_width(), gfx_get_height(),
			COLOR_WIN_BACKGROUND);

	// Allocate the application context first.
	tank_ctx = membag_alloc(sizeof(struct tank_context));
	if (!tank_ctx)
		goto exit_no_context;

	// Use larger sysfont for this app.
	memcpy(&tank_ctx->old_sysfont, &sysfont, sizeof(struct font));
	sysfont.scale = 2;

	// Create a basic frame to contain the widgets.
	attr.area.pos.x = 0;
	attr.area.pos.y = 0;
	attr.area.size.x = gfx_get_width();
	attr.area.size.y = gfx_get_height();

	frame = wtk_basic_frame_create(win_get_root(), &attr.area, NULL,
			NULL, tank_frame_handler, NULL);
	if (!frame) {
		goto exit_no_frame;
	}
	tank_ctx->frame = frame;

	// Get the frame's window to use as parent for widgets.
	win = wtk_basic_frame_as_child(frame);

	// Initialize the application timer.
	timer = &tank_ctx->timer;
	timer_init(CONFIG_TIMER_ID, timer, tank_timer_callback);
	timer_res = timer_set_resolution(CONFIG_TIMER_ID, timer,
			TICK_RATE);
	timer_write_resolution(CONFIG_TIMER_ID, timer, timer_res);

	// Get the timer alarm delay to use for the configured tick rate.
	timer_clk = timer_get_resolution(CONFIG_TIMER_ID, timer, timer_res);
	tank_ctx->timer_delay = timer_clk / TICK_RATE;

	// Initialize random variable and tick count.
	tank_ctx->rand = 1;
	tank_ctx->rand_ticks = TICKS_PER_RANDOM_UPDATE;

	// Create the supply slider.
	attr.area.pos.x = WIDGET_SUPPLY_POSITION_X;
	attr.area.pos.y = WIDGET_SUPPLY_POSITION_Y;
	attr.area.size.x = WIDGET_SUPPLY_SIZE_X;
	attr.area.size.y = WIDGET_SUPPLY_SIZE_Y;

	slider = wtk_slider_create(win, &attr.area, VALUE_SUPPLY_MAXIMUM,
			VALUE_SUPPLY_INITIAL, WTK_SLIDER_VERTICAL |
					WTK_SLIDER_INVERT, CMD_NONE);
	if (!slider) {
		goto exit_no_widget;
	}
	tank_ctx->supply = slider;
	win_show(wtk_slider_as_child(slider));

	// Create the tank level progress bar.
	attr.area.pos.x = WIDGET_LEVEL_POSITION_X;
	attr.area.pos.y = WIDGET_LEVEL_POSITION_Y;
	attr.area.size.x = WIDGET_LEVEL_SIZE_X;
	attr.area.size.y = WIDGET_LEVEL_SIZE_Y;

	pbar = wtk_progress_bar_create(win, &attr.area, VALUE_LEVEL_MAXIMUM,
			VALUE_LEVEL_INITIAL, COLOR_LEVEL_FILL,
			COLOR_LEVEL_BACKGROUND, WTK_PROGRESS_BAR_VERTICAL |
					WTK_PROGRESS_BAR_INVERT);
	if (!pbar) {
		goto exit_no_widget;
	}
	tank_ctx->level = pbar;
	win_show(wtk_progress_bar_as_child(pbar));

	// Create the demand progress bar.
	attr.area.pos.x = WIDGET_DEMAND_POSITION_X;
	attr.area.pos.y = WIDGET_DEMAND_POSITION_Y;
	attr.area.size.x = WIDGET_DEMAND_SIZE_X;
	attr.area.size.y = WIDGET_DEMAND_SIZE_Y;

	pbar = wtk_progress_bar_create(win, &attr.area, VALUE_DEMAND_MAXIMUM,
			VALUE_DEMAND_INITIAL, COLOR_DEMAND_NORMAL,
			COLOR_DEMAND_BACKGROUND, WTK_PROGRESS_BAR_VERTICAL |
					WTK_PROGRESS_BAR_INVERT);
	if (!pbar) {
		goto exit_no_widget;
	}
	tank_ctx->demand = pbar;
	win_show(wtk_progress_bar_as_child(pbar));

	// Create the exit button with the standard settings.
	attr.area.pos.x = APP_EXIT_BUTTON_POS_X;
	attr.area.pos.y = APP_EXIT_BUTTON_POS_Y;
	attr.area.size.x = APP_EXIT_BUTTON_SIZE_X;
	attr.area.size.y = APP_EXIT_BUTTON_SIZE_Y;

	button = wtk_button_create(win, &attr.area, APP_EXIT_BUTTON_TEXT,
			(win_command_t)CMD_EXIT);
	if (!button) {
		goto exit_no_widget;
	}
	win_show(wtk_button_as_child(button));

	// Set the tank alarm to trigger initial drawing of alarm light.
	tank_ctx->level_alarm = true;
	tank_ctx->flow_alarm = false;
	tank_ctx->task = task;

	/* Initialize bitmap data and set initial application loader state:
	 * If the alarm light bitmaps have already been loaded, skip right to
	 * loading of the application background bitmap.
	 */
	bitmap.width = BITMAP_LIGHT_SIZE_X;
	bitmap.height = BITMAP_LIGHT_SIZE_Y;
	bitmap.type = BITMAP_HUGEMEM;
	tank_ctx->bitmaps[BITMAP_RED_LIGHT] = bitmap;
	tank_ctx->bitmaps[BITMAP_GREEN_LIGHT] = bitmap;

	if (tank_bitmap_data[BITMAP_GREEN_LIGHT]) {
		tank_ctx->loader_state = LOAD_BACKGROUND;
		tank_ctx->bitmaps[BITMAP_RED_LIGHT].data.hugemem =
				tank_bitmap_data[BITMAP_RED_LIGHT];
		tank_ctx->bitmaps[BITMAP_GREEN_LIGHT].data.hugemem =
				tank_bitmap_data[BITMAP_GREEN_LIGHT];
	} else {
		tank_ctx->loader_state = LOAD_RED_LIGHT;
	}
	workqueue_task_set_work_func(task, tank_loader);
	workqueue_add_task(&main_workqueue, task);
	return;

	// Handle allocation errors.
exit_no_widget:
	win_destroy(wtk_basic_frame_as_child(tank_ctx->frame));
exit_no_frame:
	memcpy(&sysfont, &tank_ctx->old_sysfont, sizeof(struct font));
	membag_free(tank_ctx);
exit_no_context:
	app_desktop_restart();
	return;
}
/**
 * This function creates a new radio button widget. It allocates required memory
 * and intializes necessary windows to create the widget. If there is not enough
 * memory, the function returns NULL.
 * To destroy the widget and all its contents, and free its memory, call
 * win_destroy() on the radio button's child reference, given by
 * wtk_radio_button_as_child(), like this:
 * "win_destroy(wtk_radio_button_as_child(myButtonPtr));".
 * Usually it will be destroyed automatically when it's parent is destroyed.
 *
 * \param parent Parent window, possibly wtk_frame_as_parent(myFramePtr).
 * \param area Area of the internal contents.
 * \param caption Pointer to caption string. Will be copied into widget.
 * \param selected Initial state of radio button, true if checked/selected.
 * \param group Radio button group to be a member of.
 * \param command Command to send to parent window. Must be non-zero to be
 *                enabled.
 *
 * \return Pointer to radio button, or NULL if failed.
 */
struct wtk_radio_button *wtk_radio_button_create(struct win_window *parent,
		struct win_area const *area,
		char const *caption,
		bool selected,
		struct wtk_radio_group *group, win_command_t command)
{
	struct wtk_radio_button *radio_button;
	struct win_attributes attr;

	Assert(group);
	Assert(area);
	Assert(caption);
	Assert(parent);

	/* Allocate memory for check box control data. */
	radio_button = membag_alloc(sizeof(struct wtk_radio_button));
	if (!radio_button) {
		goto outofmem_radio_button;
	}

	radio_button->state = WTK_RADIOBUTTON_NORMAL;
	radio_button->group = group;
	radio_button->command = command;

	/* Allocate memory for caption string, and copy text. */
	radio_button->caption = membag_alloc(
			(strlen(caption) + 1) * sizeof(char));
	if (!radio_button->caption) {
		goto outofmem_caption;
	}

	wtk_copy_string(radio_button->caption, caption);

	/* Handling information. */
	attr.event_handler = wtk_radio_button_handler;
	attr.custom = radio_button;

	/* Prepare container frame. */
	attr.area = *area;
	attr.background = NULL;
	attr.behavior = WIN_BEHAVIOR_REDRAW_PARENT;

	radio_button->container = win_create(parent, &attr);
	if (!radio_button->container) {
		goto outofmem_container;
	}

	/* Select the radio button in the group if either no radio button is
	 * currently selected (empty group), or the user has requested it takes
	 * over the selection */
	if (selected || (group->selected == NULL)) {
		wtk_radio_button_select(radio_button);
	}

	/* Make sure we haven't filled up the group reference count, and
	 * increment. */
	Assert(group->num_references < (wtk_radio_group_size_t)-1L);
	++(group->num_references);

	return radio_button;

outofmem_container:
	membag_free(radio_button->caption);

outofmem_caption:
	membag_free(radio_button);

outofmem_radio_button:
	return NULL;
}
/**
 * \brief Application task worker
 *
 * Waits for the touch release events generated after the user has touched a
 * calibration circle drawn on screen, then stores the calibration data and
 * draws the circle for the next calibration point.
 *
 * Three such calibration points are stored before the calibration matrix for
 * the touch driver is computed and assigned to it.
 *
 * \sa touch_driver_group
 *
 * \note If the raw samples of a calibration point do not differ by at least
 * \ref CAL_TRESHOLD from the previous calibration point, it is interpreted as
 * an unintended touch and ignored.
 *
 * \param task Workqueue task for this worker function
 */
static void touch_calibrate_task_handler(struct workqueue_task *task)
{
	int16_t                         dx;
	int16_t                         dy;
	struct touch_calibrate_context  *cal_ctx;

	cal_ctx = container_of(task, struct touch_calibrate_context, task);

	switch (cal_ctx->state) {
	case 0:	/* Fall through */
	case 1:
	case 2:
		// Schedule task to run once more
		workqueue_add_task(&main_workqueue, &cal_ctx->task);

		// Run until touch is released
		if (cal_ctx->event.type != TOUCH_RELEASE)
			break;

		// Store calibration values
		cal_ctx->event.type = TOUCH_NO_EVENT;
		cal_ctx->cal_points[cal_ctx->state].raw_x =
				cal_ctx->event.point.raw_x;
		cal_ctx->cal_points[cal_ctx->state].raw_y =
				cal_ctx->event.point.raw_y;

		dx = cal_ctx->cal_points[cal_ctx->state - 1].raw_x -
				cal_ctx->cal_points[cal_ctx->state].raw_x;
		dy = cal_ctx->cal_points[cal_ctx->state - 1].raw_y -
				cal_ctx->cal_points[cal_ctx->state].raw_y;
		dx = abs(dx);
		dy = abs(dy);

		// If point is too close to the last one, wait for another touch
		if ((dx < CAL_TRESHOLD) && (dy < CAL_TRESHOLD))
			break;

		// Clear old circle before moving on.
		gfx_draw_circle(cal_ctx->cal_points[cal_ctx->state].panel_x,
				cal_ctx->cal_points[cal_ctx->state].panel_y,
				CAL_RADIUS, CAL_BG_COLOR, GFX_WHOLE);

		// Move to next point
		cal_ctx->state++;

		/* Skip drawing last circles if we're done. */
		if (cal_ctx->state >= 3)
			break;

		// Draw next circle.
		gfx_draw_circle(cal_ctx->cal_points[cal_ctx->state].panel_x,
				cal_ctx->cal_points[cal_ctx->state].panel_y,
				CAL_RADIUS, CAL_FG_COLOR, GFX_WHOLE);
		break;

	case 3:
		// Calibration completed

		// Clear circle before moving on.
		gfx_draw_circle(cal_ctx->cal_points[2].panel_x,
				cal_ctx->cal_points[2].panel_y,
				CAL_RADIUS, CAL_BG_COLOR, GFX_WHOLE);

		// Compute and assign the calibration matrix to the driver.
		touch_compute_calibration_matrix(cal_ctx->cal_points,
				&cal_ctx->cal_matrix);

		touch_set_calibration_matrix(&cal_ctx->cal_matrix);

		// Restore handler
		touch_set_event_handler(cal_ctx->old_handler);

		// Can now free memory
		membag_free(calibrate_context);

		// Schedule task if available
		if (calibrate_context->completed_task) {
			workqueue_add_task(&main_workqueue,
					calibrate_context->completed_task);
		}

		break;
	}
}
Exemple #26
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;
	}
}