/** * \brief Frame command events handler * * This function handles the command events generated by the widgets. * * \sa wtk_basic_frame_command_handler_t */ static bool widget_frame_command_handler(struct wtk_basic_frame *frame, win_command_t command_data) { char command = (uintptr_t)command_data; switch (command) { case SLIDER_ID: wtk_progress_bar_set_value(progress_bar, wtk_slider_get_value(slider)); break; case BUTTON_ID: /** \todo Add code here to handle button press. */ counter++; win_redraw(wtk_basic_frame_as_child(sub_frame)); break; } return false; }
/** * \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; }
/** * \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(); }
/** * \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; }
/** * \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; }
/** * \brief Setup widget demo * * This function launches the widget demo. */ void app_widget_launch() { struct win_window *win_root; struct win_window *parent; struct win_area area; struct wtk_label *lbl; struct wtk_button *btn; /* Get pointer to root window */ win_root = win_get_root(); /* Application frame */ /* Create a background bitmap using a solid color. */ frame_background.type = GFX_BITMAP_SOLID; frame_background.data.color = APP_BACKGROUND_COLOR; /* Set the area to fill the entire screen */ area.pos.x = 0; area.pos.y = 0; area.size.x = gfx_get_width(); area.size.y = gfx_get_height(); /* * Create a basic frame with a specified background and command event * handler. Check the return value if an error occurred while creating * the widget. */ main_frame = wtk_basic_frame_create(win_root, &area, &frame_background, NULL, widget_frame_command_handler, NULL); if (!main_frame) { goto error_frame; } /* Get a pointer to the widget's window for adding sub-widgets. */ parent = wtk_basic_frame_as_child(main_frame); /* * Draw the frame by showing the frame widget's window. Any * child-widgets and windows will not be shown before the parent * widget/window is shown. */ win_show(parent); /* Application label */ area.pos.x = LABEL_POS_X; area.pos.y = LABEL_POS_Y; /* Find an optimal size for the widget. */ wtk_label_size_hint(&area.size, demo_string); /* * Create the label and check the return value if an error occurred * while creating the label. */ lbl = wtk_label_create(parent, &area, demo_string, GFX_COLOR(255, 255, 255), NULL, false); if (!lbl) { goto error_widget; } /* Draw the label by showing the label widget's window. */ win_show(wtk_label_as_child(lbl)); /* Application slider */ area.pos.x = SLIDER_POS_X; area.pos.y = SLIDER_POS_Y; area.size.x = SLIDER_SIZE_X; area.size.y = SLIDER_SIZE_Y; /* * Create the slider and check the return value if an error occurred * while creating the slider. */ slider = wtk_slider_create(parent, &area, SLIDER_MAX_VALUE, SLIDER_MAX_VALUE / 2, WTK_SLIDER_HORIZONTAL | WTK_SLIDER_CMD_RELEASE, (win_command_t)SLIDER_ID); if (!slider) { goto error_widget; } /* Draw the slider by showing the slider widget's window. */ win_show(wtk_slider_as_child(slider)); /* Application progress bar, placed right of the slider. */ area.pos.x += area.size.x + SLIDER_PB_SPACING_X; area.size.x = PB_SIZE_X; area.size.y = PB_SIZE_Y; /* * Create the progress bar and check the return value if an error * occurred while creating the progress bar. */ progress_bar = wtk_progress_bar_create(parent, &area, SLIDER_MAX_VALUE, SLIDER_MAX_VALUE / 2, GFX_COLOR(255, 255, 0), GFX_COLOR(90, 90, 90), WTK_PROGRESS_BAR_HORIZONTAL); if (!progress_bar) { goto error_widget; } /* Draw the progress bar by showing the progress bar widget's window. */ win_show(wtk_progress_bar_as_child(progress_bar)); /** \todo Add code to set up button here. */ /** \todo Add code to set up basic frame here. */ return; error_widget: /* Destroy widget and all sub-widgets. */ win_destroy(wtk_basic_frame_as_child(main_frame)); error_frame: /* Wait forever if an error occurred during setup. */ while (1) { } }