/** * This function stops an ongoing drag operation. Do not call this unless * dragging has been started with wtk_start_drag() first. This function erases * the drag handles and frees any allocated memory. * * \param last_pos Last position, as for wtk_continue_drag(). */ static void wtk_stop_drag(struct win_point const *last_pos) { /* Don't do any graphics if we did not get memory when drag started. */ if (!wtk_drag_origin_pixmap || !wtk_drag_target_pixmap) { return; } /* 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); /* Restore screen underneath drag origin symbol. */ gfx_put_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); /* Restore screen underneath drag target symbol. */ gfx_put_pixmap(wtk_drag_target_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0, last_pos->x - WTK_DRAG_HANDLE_RADIUS, last_pos->y - WTK_DRAG_HANDLE_RADIUS, WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE); /* Free memory when not dragging. */ membag_free(wtk_drag_origin_pixmap); membag_free(wtk_drag_target_pixmap); }
/** * This function updated the drag target handle graphics. Call this function * from the MOVE event handler of the dragging widget. This function needs * both the current position and the last used position. The last position will * be either the position handed to wtk_start_drag() or the "pos" parameter of * the last call to wtk_continue_drag(). The pointer event struct will keep this * value for you. No need to store it yourself. * * \param last_pos Last position. * \param pos Current position. */ static void wtk_continue_drag(struct win_point const *last_pos, struct win_point const *pos) { /* Don't do any graphics if we did not get memory when drag started. */ if (!wtk_drag_origin_pixmap || !wtk_drag_target_pixmap) { return; } /* 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); /* Restore screen underneath drag target symbol. */ gfx_put_pixmap(wtk_drag_target_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0, last_pos->x - WTK_DRAG_HANDLE_RADIUS, last_pos->y - WTK_DRAG_HANDLE_RADIUS, WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE); /* Store screen underneath and draw new 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); }
/** * 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; }
void gfx_ili9325_init(void) { struct ili9325_opt_t g_ili9325_display_opt; /* initialize globals */ gfx_width = ILI9325_LCD_WIDTH; gfx_height = ILI9325_LCD_HEIGHT; /* Enable peripheral clock */ pmc_enable_periph_clk(ID_SMC); /* Configure SMC interface for Lcd */ smc_set_setup_timing(SMC,ILI9325_LCD_CS,SMC_SETUP_NWE_SETUP(2) | SMC_SETUP_NCS_WR_SETUP(2) | SMC_SETUP_NRD_SETUP(2) | SMC_SETUP_NCS_RD_SETUP(2)); smc_set_pulse_timing(SMC, ILI9325_LCD_CS , SMC_PULSE_NWE_PULSE(4) | SMC_PULSE_NCS_WR_PULSE(4) | SMC_PULSE_NRD_PULSE(10) | SMC_PULSE_NCS_RD_PULSE(10)); smc_set_cycle_timing(SMC, ILI9325_LCD_CS, SMC_CYCLE_NWE_CYCLE(10) | SMC_CYCLE_NRD_CYCLE(22)); #if !defined(SAM4S) smc_set_mode(SMC, ILI9325_LCD_CS, SMC_MODE_READ_MODE | SMC_MODE_WRITE_MODE | SMC_MODE_DBW_8_BIT); #else smc_set_mode(SMC, ILI9325_LCD_CS, SMC_MODE_READ_MODE | SMC_MODE_WRITE_MODE); #endif /* Initialize display parameter */ g_ili9325_display_opt.ul_width= ILI9325_LCD_WIDTH; g_ili9325_display_opt.ul_height = ILI9325_LCD_HEIGHT; g_ili9325_display_opt.foreground_color= COLOR_BLACK; g_ili9325_display_opt.background_color = COLOR_WHITE; /* Switch off backlight */ aat31xx_disable_backlight(); /* Initialize LCD */ ili9325_init(&g_ili9325_display_opt); ili9325_display_on(); /* Set backlight level */ aat31xx_set_backlight(AAT31XX_AVG_BACKLIGHT_LEVEL); /* Set clipping area to whole screen initially */ gfx_set_clipping(0, 0, gfx_width, gfx_height); gfx_draw_filled_rect(0, 0, gfx_width, gfx_height, GFX_COLOR(0xFF, 0xFF, 0xFF)); }
void gfx_ili9341_init(void) { /* initialize globals */ gfx_width = ILI9341_DEFAULT_WIDTH; gfx_height = ILI9341_DEFAULT_HEIGHT; ili9341_init(); ili9341_backlight_on(); /* Set clipping area to whole screen initially */ gfx_set_clipping(0, 0, gfx_width, gfx_height); gfx_draw_filled_rect(0, 0, gfx_width, gfx_height, GFX_COLOR_BLACK); }
/** * \brief Set up calibration * * Allocates and initializes the application context; sets up the font, touch * event handler and calibration data; updates the display and then schedules * the calibration task. * * \param completed_task Task to schedule when calibration is complete */ void app_touch_calibrate_setup(struct workqueue_task *completed_task) { calibrate_context = membag_alloc(sizeof(struct touch_calibrate_context)); assert(calibrate_context != NULL); // Use twice as large font for this application. memcpy(&sysfont2x, &sysfont, sizeof(sysfont)); sysfont2x.scale = 2; // Temporarily replace touch event handler. calibrate_context->old_handler = touch_get_event_handler(); touch_set_event_handler(touch_calibrate_event_handler); // Clear the screen and draw the calibration guide text. gfx_set_clipping(0, 0, gfx_get_width(), gfx_get_height()); gfx_draw_filled_rect(0, 0, gfx_get_width(), gfx_get_height(), CAL_BG_COLOR); gfx_draw_progmem_string((const char __progmem_arg *) &calibrate_help_text, 10, 80, &sysfont2x, CAL_FG_COLOR, GFX_COLOR_TRANSPARENT); // Set panel coordinates for all calibration points. calibrate_context->cal_points[0].panel_x = (gfx_get_width() - CAL_OFFSET - 1); calibrate_context->cal_points[0].panel_y = (gfx_get_height() - CAL_OFFSET - 1); calibrate_context->cal_points[1].panel_x = (CAL_OFFSET); calibrate_context->cal_points[1].panel_y = (gfx_get_height() - CAL_OFFSET - 1); calibrate_context->cal_points[2].panel_x = (CAL_OFFSET); calibrate_context->cal_points[2].panel_y = (CAL_OFFSET); // Draw circle for first calibration point. gfx_draw_circle(calibrate_context->cal_points[0].panel_x, calibrate_context->cal_points[0].panel_y, CAL_RADIUS, CAL_FG_COLOR, GFX_WHOLE); // Initialize the calibration state and tasks before scheduling it. calibrate_context->state = 0; calibrate_context->completed_task = completed_task; workqueue_task_init(&calibrate_context->task, touch_calibrate_task_handler); workqueue_add_task(&main_workqueue, &calibrate_context->task); }
void gfx_ili9488_set_orientation(uint8_t flags) { ili9488_set_orientation(flags); /* Switch width and height if XY is switched. */ if ((flags & GFX_SWITCH_XY) != 0x00) { gfx_width = ILI9488_SWITCH_XY_WIDTH; gfx_height = ILI9488_SWITCH_XY_HEIGHT; } else { gfx_width = ILI9488_LCD_WIDTH; gfx_height = ILI9488_LCD_HEIGHT; } #ifdef CONF_GFX_USE_CLIPPING /* Reset clipping region. */ gfx_set_clipping(0, 0, gfx_width - 1, gfx_height - 1); #endif }
void gfx_hx8347a_set_orientation(uint8_t flags) { hx8347a_set_orientation(flags); /* Switch width and height if XY is switched. */ if ((flags & GFX_SWITCH_XY) != 0x00) { gfx_width = HX8347A_SWITCH_XY_WIDTH; gfx_height = HX8347A_SWITCH_XY_HEIGHT; } else { gfx_width = HX8347A_DEFAULT_WIDTH; gfx_height = HX8347A_DEFAULT_HEIGHT; } #ifdef CONF_GFX_USE_CLIPPING /* Reset clipping region. */ gfx_set_clipping(0, 0, gfx_width, gfx_height); #endif }
/** * \brief Show an out of memory error on the display * * Shows a full screen error when called, signaling that the system * ran out of memory when initializing a WTK application. */ static void show_out_of_memory_error(void) { const char memory_string[] = "OUT OF MEMORY"; gfx_coord_t disp_width, disp_height; /* Get the display width and height */ disp_width = gfx_get_width(); disp_height = gfx_get_height(); /* Blank display */ gfx_set_clipping(0, 0, disp_width, disp_height); gfx_draw_filled_rect(0, 0, disp_width, disp_height, GFX_COLOR_BLACK); /* Show centered out of memory error text */ gfx_draw_string_aligned(memory_string, disp_width / 2, disp_height / 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_RED, TEXT_POS_CENTER, TEXT_ALIGN_CENTER); }
void gfx_ili9488_init(void) { struct ili9488_opt_t g_ili9488_display_opt; /* initialize globals */ gfx_width = ILI9488_LCD_WIDTH; gfx_height = ILI9488_LCD_HEIGHT; /* Initialize display parameter */ g_ili9488_display_opt.ul_width= ILI9488_LCD_WIDTH; g_ili9488_display_opt.ul_height = ILI9488_LCD_HEIGHT; g_ili9488_display_opt.foreground_color= COLOR_BLACK; g_ili9488_display_opt.background_color = COLOR_WHITE; ili9488_init(&g_ili9488_display_opt); ili9488_display_on(); /* Set clipping area to whole screen initially */ gfx_set_clipping(0, 0, gfx_width, gfx_height); gfx_draw_filled_rect(0, 0, gfx_width, gfx_height, GFX_COLOR_BLACK); }
/** * \brief Load file data directly to screen worker * * This worker function puts the data fetched from the file system directly to * the screen. * * \param task Pointer to the current work queue task */ static void load_to_screen_worker(struct workqueue_task *task) { struct file_loader *floader = &the_file_loader; enum status_code result; gfx_set_clipping(0, 0, gfx_get_width(), gfx_get_height()); gfx_put_pixmap((gfx_color_t *)floader->buffer, floader->load_size, 0, 0, floader->current_x + floader->offset_x, floader->current_y + floader->offset_y, floader->load_size, 1); floader->current_x += floader->load_size; if (floader->current_x >= floader->width) { floader->current_y++; floader->current_x = 0; } floader->load_size = min_u((floader->width - floader->current_x), MAX_LOAD_PIXELS); result = tsfs_read(&myfs, &floader->file, &floader->buffer, floader->load_size * sizeof(gfx_color_t), &floader->task); // If file we are done, run the image done task if ((result != STATUS_OK) || (floader->current_y > floader->height)) { floader->busy = false; if (floader->done_task) workqueue_add_task(&main_workqueue, floader->done_task); } }
/** * \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 worker function. * * This task worker updates the parameters of the simulated process and the * display unless the application context has been cleared, in which case the * function returns immediately. * * Refer to the detailed description of \ref apps_tank_group for information on * the simulated process. * * If the tank level reaches 0, the indicator for demand will change color to * indicate that the supply is insufficient. If, on the other hand, it reaches * \ref VALUE_LEVEL_MAXIMUM, the alarm light changes color to indicate that the * supply is too great. * * \note The task for this worker function is enqueued by the timer callback * function. * * \param task Workqueue task for this worker function. */ static void tank_worker(struct workqueue_task *task) { struct gfx_bitmap *alarm_bitmap = NULL; bool alarm_update = false; int32_t rand; uint8_t supply; uint16_t demand; int16_t flow; int16_t level; // Quit immediately if application context has been cleared. if (!tank_ctx) { return; } // Get current values of the process parameters. level = wtk_progress_bar_get_value(tank_ctx->level); supply = wtk_slider_get_value(tank_ctx->supply); demand = wtk_progress_bar_get_value(tank_ctx->demand); rand = tank_ctx->rand; // Update the random variable if enough ticks have passed. if (--(tank_ctx->rand_ticks) == 0) { tank_ctx->rand_ticks = TICKS_PER_RANDOM_UPDATE; // Flip some LSBs to help avoid a stuck process. rand ^= demand & 0x03; // Compute new random value and store it for next iteration. rand = tank_logistic_map(rand); tank_ctx->rand = rand; } // Now, compute the new demand from a weighted scheme. demand = rand + (2 * demand) + level; demand /= 4; demand = min_u(demand, VALUE_DEMAND_MAXIMUM); /* Compute the total flow and scale it down for a smoother * simulation. */ flow = supply; flow -= demand; flow /= 4; // Compute new level for the tank. level += flow; /* Update the demand indicator. Change its color if the demand * exceeds the supply and available water in the tank. */ if (level <= 0) { if (!tank_ctx->flow_alarm) { tank_ctx->flow_alarm = true; wtk_progress_bar_set_colors(tank_ctx->demand, COLOR_DEMAND_CRITICAL, COLOR_DEMAND_BACKGROUND); } level = 0; } else { if (tank_ctx->flow_alarm) { tank_ctx->flow_alarm = false; wtk_progress_bar_set_colors(tank_ctx->demand, COLOR_DEMAND_NORMAL, COLOR_DEMAND_BACKGROUND); } } wtk_progress_bar_set_value(tank_ctx->demand, demand); /* Update the tank level indicator. * The level of the tank cannot exceed the defined maximum, * and its alarm light must be updated whenever this level * is crossed. */ if (level >= VALUE_LEVEL_MAXIMUM) { if (!tank_ctx->level_alarm) { tank_ctx->level_alarm = true; alarm_update = true; alarm_bitmap = &tank_ctx->bitmaps[BITMAP_RED_LIGHT]; } level = VALUE_LEVEL_MAXIMUM; } else { if (tank_ctx->level_alarm) { tank_ctx->level_alarm = false; alarm_update = true; alarm_bitmap = &tank_ctx->bitmaps[BITMAP_GREEN_LIGHT]; } } wtk_progress_bar_set_value(tank_ctx->level, level); /* If a level alarm update occurred, set up clipping area and draw * the new alarm light bitmap. */ if (alarm_update) { #ifdef CONFIG_GFX_USE_CLIPPING gfx_set_clipping(BITMAP_LIGHT_POSITION_X, BITMAP_LIGHT_POSITION_Y, BITMAP_LIGHT_POSITION_X + BITMAP_LIGHT_SIZE_X - 1, BITMAP_LIGHT_POSITION_Y + BITMAP_LIGHT_SIZE_Y - 1 ); #endif /* CONFIG_GFX_USE_CLIPPING */ gfx_draw_bitmap(alarm_bitmap, BITMAP_LIGHT_POSITION_X, BITMAP_LIGHT_POSITION_Y); } }
/** * \brief Handle maXTouch messages * * This function handles the maXTouch messages, triggering the drawing of * squares around new or moved touches, and removing the squares around * released touches. * * \param device Pointer to mxt_device struct */ static void mxt_handler(struct mxt_device *device) { struct mxt_touch_event touch_event; gfx_coord_t screen_touch_x, screen_touch_y, screen_touch_size; do { /* Get the first touch event in queue */ if (mxt_read_touch_event(device, &touch_event) != STATUS_OK) { continue; } /* Discard non press, movement or release events */ if (!(touch_event.status & (MXT_PRESS_EVENT | MXT_MOVE_EVENT | MXT_RELEASE_EVENT))) { continue; } /* Rescale from 4k touch X-coordinate to the display width */ screen_touch_x = ((uint32_t)(4096 - touch_event.x) * gfx_get_width()) / 4096; /* Rescale from 4k touch Y-coordinate to the display height */ screen_touch_y = ((uint32_t)(4096 - touch_event.y) * gfx_get_height()) / 4096; /* Scale the touch size to a value suitable for the target display */ screen_touch_size = touch_event.size; /* Check if the touch is within the drawing area */ if (screen_touch_y < (gfx_get_height() - PALLET_HEIGHT)) { /* Obtain the color to draw from the pallet colors */ gfx_color_t draw_color = pallet_colors[selected_pallet_color]; /* Color pallet index 0 selects multi-color mode */ if (selected_pallet_color == 0) { draw_color = get_next_rainbow_color(); } /* Set clipping area */ gfx_set_clipping(0, 0, gfx_get_width(), (gfx_get_height() - PALLET_HEIGHT - 2)); /* Draw touch point on the screen in the selected color */ gfx_draw_filled_circle(screen_touch_x, screen_touch_y, screen_touch_size, draw_color, GFX_WHOLE); /* Reset clipping area */ gfx_set_clipping(0, 0, gfx_get_width(), gfx_get_height()); } else if (touch_event.status & MXT_PRESS_EVENT) { /* Calculate the pressed pallet entry */ uint8_t pallete_index = (screen_touch_x / PALLET_COLOR_WIDTH); /* The last entry in the pallet clears the screen */ if (pallete_index == (NUM_PALLET_COLORS - 1)) { /* Indicate display is being cleared */ draw_pallet_labels(true); /* Clear the display */ gfx_draw_filled_rect(0, 0, gfx_get_width(), (gfx_get_height() - PALLET_HEIGHT - 1), GFX_COLOR_BLACK); /* Indicate display has been cleared */ draw_pallet_labels(false); } else { /* Change color selection based on the color chosen */ selected_pallet_color = pallete_index; /* Draw new selection box around chosen color */ update_pallet_selection(); } } } while (mxt_is_message_pending(device)); }