/** * \brief Draws a character to the display * * \param c Character to be drawn * \param x X coordinate on screen. * \param y Y coordinate on screen. * \param font Font to draw character in * \param bg_color Background color to draw behind the text string * \param text_color Foreground color to draw the text string in */ void gfx_draw_char(const char c, const gfx_coord_t x, const gfx_coord_t y, const struct font *font, const gfx_color_t bg_color, const gfx_color_t text_color) { if (bg_color != GFX_COLOR_TRANSPARENT) { gfx_draw_filled_rect(x, y, font->width, font->height, bg_color); } switch (font->type) { case FONT_LOC_PROGMEM: if (font->inverted) { gfx_draw_inverted_char_progmem(c, x, y, font, text_color); } else { gfx_draw_char_progmem(c, x, y, font, text_color); } break; #ifdef CONFIG_HUGEMEM case FONT_LOC_HUGEMEM: gfx_draw_char_hugemem(c, x, y, font, text_color); break; #endif default: /* Unsupported mode, call assert */ Assert(false); break; } }
/** * \brief Clears a calibration point from the given buffer. * * \param p_point Calibration point to clear. */ static void clear_calibration_point(const rtouch_point_t *p_point) { gfx_draw_filled_rect(p_point->x - POINTS_SIZE / 2, p_point->y - POINTS_SIZE / 2, POINTS_SIZE, POINTS_SIZE, BGCOLOR ); }
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); }
/** * \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 network_application() { draw_background(); gfx_draw_filled_rect(5, 26, 310, 182, GFX_COLOR(20, 20, 20)); if(!wifi_ready && wifi_error) { gfx_draw_string_aligned(SYMFONT_WIFI, gfx_get_width() / 2, 120, &symbol_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_RED, TEXT_POS_CENTER_X, TEXT_ALIGN_CENTER); gfx_draw_string_aligned("Not Connected", gfx_get_width() / 2, 155, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_RED, TEXT_POS_CENTER_X, TEXT_ALIGN_CENTER); } else { gfx_draw_string_aligned(SYMFONT_WIFI, gfx_get_width() / 2, 120, &symbol_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_GREEN, TEXT_POS_CENTER_X, TEXT_ALIGN_CENTER); gfx_draw_string_aligned("Connected", gfx_get_width() / 2, 155, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_GREEN, TEXT_POS_CENTER_X, TEXT_ALIGN_CENTER); } uint8_t ram_buf[AT45DBX_SECTOR_SIZE]; at45dbx_read_sector_open(0x0007); at45dbx_read_sector_to_ram(ram_buf); at45dbx_read_close(); char mac_string[128]; snprintf(mac_string, sizeof(mac_string), "MAC: %s", ram_buf); gfx_draw_string_aligned(mac_string, 11, 27, &small_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); if (wifi_error) { gfx_draw_string_aligned(esp_error, 11, 47, &small_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); } struct keyboard_event input; while(mma8451_orientation() != 6) { esp8266_check_buffer(); keyboard_get_key_state(&input); if (input.type == KEYBOARD_RELEASE) { if (input.keycode == KEYBOARD_B) { break; } } if(mma8451_clear_interrupt() && is_low_power()) { exit_low_power(); } } }
/** * \brief Main application loop * * This is the main application function, which runs all the initialization * code, clears the display and enters a loop in which it continuously polls for * new messages from the maXTouch device. If one or more messages are pending, * the maXTouch message handler is invoked. */ int main(void) { /* maXTouch data structure */ static struct mxt_device device; /* Basic init routines */ board_init(); sysclk_init(); gfx_init(); mxt_init(&device); /* Clear the display */ gfx_draw_filled_rect(0, 0, gfx_get_width(), gfx_get_height(), DISPLAY_COLOR); while (true) { /* Check for any pending messages and run message handler if any * message is found in the queue */ if (mxt_is_message_pending(&device)) { mxt_handler(&device); } } }
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 Draws the color pallet to the display * * This function draws the paint pallet to the display, including the special * function entries (such as display clear) and the selection box. */ static void draw_paint_pallet(void) { /* Draw each color in the pallet to the display at the correct * location */ for (uint8_t i = 0; i < NUM_PALLET_COLORS; i++) { gfx_draw_filled_rect( PALLET_COLOR_WIDTH * i, gfx_get_height() - PALLET_HEIGHT, PALLET_COLOR_WIDTH, PALLET_HEIGHT, pallet_colors[i]); } /* Draw a dark gray line to separate the drawing area from the pallet */ gfx_draw_horizontal_line(0, (gfx_get_height() - PALLET_HEIGHT - 1), gfx_get_width(), GFX_COLOR_GRAY); /* Draw special function labels */ draw_pallet_labels(false); /* Draw selection box */ update_pallet_selection(); }
/** * 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; } }
/** * \brief Starts the calibration routines and displays user instructions on screen. * * \return 0 if calibration is successful, else 1. */ uint32_t rtouch_calibrate(void) { uint32_t i; uint32_t x, y; /* Fill the whole screen with the background color */ gfx_draw_filled_rect(0, 0, gfx_get_width(), gfx_get_height(), BGCOLOR); /* Print user instructions */ /* Write center-aligned text string to the top of the display */ gfx_draw_string_aligned(string_calib_name, gfx_get_width() / 2, 60, &sysfont, GFX_COLOR_WHITE, TXTCOLOR, TEXT_POS_CENTER, TEXT_ALIGN_LEFT); gfx_draw_string_aligned(string_calib_instruction, gfx_get_width() / 2, 190, &sysfont, GFX_COLOR_WHITE, TXTCOLOR, TEXT_POS_CENTER, TEXT_ALIGN_LEFT); /* Calibration points */ for (i = 0; i < NUM_TOUCH_POINTS; i++) { draw_calibration_point(&gs_calibration_points[i].panel); /* Wait for touch & end of conversion */ rtouch_wait_pressed(); rtouch_get_raw_point(&x, &y); gs_calibration_points[i].raw.x = x; gs_calibration_points[i].raw.y = y; clear_calibration_point(&gs_calibration_points[i].panel); /* Wait for contact loss */ rtouch_wait_released(); } /* Check if the points acceptable */ if (rtouch_compute_calibration((rtouch_calibration_point_t *) &gs_calibration_points) == 0) { for (i=0;i<NUM_TOUCH_POINTS;i++) { g_demo_parameters.calib_points[i].raw.x = gs_calibration_points[i].raw.x; g_demo_parameters.calib_points[i].raw.y = gs_calibration_points[i].raw.y; } /* Commit changes to the parameter area */ demo_parameters_commit_changes(); /* Display calibration done string */ gfx_draw_string_aligned(string_calib_done, gfx_get_width() / 2, 130, &sysfont, GFX_COLOR_WHITE, TXTCOLOR, TEXT_POS_CENTER, TEXT_ALIGN_LEFT); return 0; } else { /* Clear instruction string first */ gfx_draw_string_aligned(string_calib_instruction, gfx_get_width() / 2, 190, &sysfont, GFX_COLOR_WHITE, GFX_COLOR_WHITE, TEXT_POS_CENTER, TEXT_ALIGN_LEFT); /* Show up failed string */ gfx_draw_string_aligned(string_calib_failed, gfx_get_width() / 2, 100, &sysfont, GFX_COLOR_WHITE, TXTCOLOR, TEXT_POS_CENTER, TEXT_ALIGN_LEFT); /* Display retry string */ gfx_draw_string_aligned(string_calib_retry, gfx_get_width() / 2, 190, &sysfont, GFX_COLOR_WHITE, TXTCOLOR, TEXT_POS_CENTER, TEXT_ALIGN_LEFT); /* Wait for contact loss */ rtouch_wait_released(); return 1; } }
void battery_application() { draw_background(); gfx_draw_string_aligned("Power Info", gfx_get_width() / 2, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_CENTER_X, TEXT_ALIGN_LEFT); uint8_t battery = max1704x_bat(); char batlvl[5]; if (battery > 100) { battery = 100; } //battery = 19; uint16_t x = 75; uint16_t y = 40; gfx_draw_rect(x, y, 164, 54, GFX_COLOR_WHITE); gfx_draw_filled_rect(x+164, y+15, 3, 20, GFX_COLOR_WHITE); if (battery < 20) { gfx_draw_filled_rect(x+2, y+2, battery/6 * 10, 50, GFX_COLOR_RED); } else { gfx_draw_filled_rect(x+2, y+2, battery/6 * 10, 50, GFX_COLOR_GREEN); } snprintf(batlvl, sizeof(batlvl), "%d%%", battery); if (battery > 20) { gfx_draw_string_aligned(batlvl, gfx_get_width() /2, 50, &large_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_CENTER_X, TEXT_ALIGN_LEFT); } else { gfx_draw_string_aligned(batlvl, gfx_get_width() /2, 50, &large_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_CENTER_X, TEXT_ALIGN_LEFT); } char atime[32]; snprintf(atime, sizeof(atime), "Seconds Awake: %lu", get_time_awake()); gfx_draw_string_aligned(atime, 70, 100, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); char stime[32]; snprintf(stime, sizeof(stime), "Seconds Sleeping: %lu", get_time_sleep()); gfx_draw_string_aligned(stime, 70, 120, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); gfx_draw_filled_circle(gfx_get_width() /2, 80+80+10+10, 25, GFX_COLOR_WHITE, GFX_WHOLE); gfx_draw_string_aligned(SYMFONT_MOON, gfx_get_width() /2, 152+10, &symbol_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR(200, 101, 18), TEXT_POS_CENTER_X, TEXT_ALIGN_CENTER); gfx_draw_string_aligned("Enter Sleep Mode", gfx_get_width() / 2, 152+15+30+15, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_CENTER_X, TEXT_ALIGN_LEFT); struct keyboard_event input; while(mma8451_orientation() != 6) { esp8266_check_buffer(); if(mma8451_clear_interrupt() && is_low_power()) { exit_low_power(); } keyboard_get_key_state(&input); if (input.type == KEYBOARD_RELEASE) { if (input.keycode == KEYBOARD_B) { break; } else if (input.keycode == KEYBOARD_A) { esp8266_enter_standby(); enter_low_power(); break; } } } }
/** * 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 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 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)); }
void draw_event() { draw_background(); draw_time(); gfx_draw_filled_rect(5, 26, 310, 182, GFX_COLOR(8, 8, 8)); draw_button_hints(); switch(event_track) { case 0: gfx_draw_string_aligned("Schedule - KEYNOTES", 11, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); break; case 1: gfx_draw_string_aligned("Schedule - TRACK 1", 11, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); break; case 2: gfx_draw_string_aligned("Schedule - TRACK 2", 11, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); break; case 3: gfx_draw_string_aligned("Schedule - TRACK 3", 11, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); break; case 4: gfx_draw_string_aligned("Schedule - TRACK 4", 11, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); break; case 5: gfx_draw_string_aligned("Schedule - TRACK 5", 11, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); break; } uint16_t keynote = 0x0100; uint16_t track1 = 0x0200; uint16_t track2 = 0x0300; uint16_t track3 = 0x0400; uint16_t track4 = 0x0500; uint16_t track5 = 0x0600; uint16_t addresses[] = {keynote, track1, track2, track3, track4, track5}; //uint16_t max_event[] = {5, 22, 22, 15, 23}; uint8_t ram_buf[AT45DBX_SECTOR_SIZE]; at45dbx_read_sector_open(addresses[event_track] + event_index); at45dbx_read_sector_to_ram(ram_buf); at45dbx_read_close(); char *array[6]; uint8_t i = 0; array[i] = strtok(ram_buf,";"); while(array[i] != NULL) { array[++i] = strtok(NULL, ";"); } char *title[256]; uint8_t a = word_wrap(&title, array[0], 30); gfx_draw_string_aligned(title, 11, 27, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); char event_time[36]; snprintf(event_time, sizeof(event_time),"%s - %s", array[1], array[2]); char *names[256]; uint8_t n = word_wrap(&names, array[3], 33); gfx_draw_string_aligned(names, 11, 60+(a*20), &small_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_RED, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); gfx_draw_string_aligned(array[4], 11, 85+(a*20)+(n*20), &tiny_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); gfx_draw_string_aligned(event_time, 11, 100+(a*20)+(n*20), &tiny_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_LEFT, TEXT_ALIGN_LEFT); // } }
/** * \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; } }
/** * \brief Main application function * * This function ensures that the hardware and drivers are initialized before * entering an infinite work loop. * * In the work loop, the maXTouch device is polled for new touch events and any * new event is passed on to the user interface implementation for processing. * The loop then attempts to enter sleep. * * The user interface processing itself is not started by the work loop, but by * the USB callback function for start of frame. */ int main(void) { #ifdef USB_DEVICE_LOW_SPEED uint16_t virtual_sof_sub; uint16_t virtual_sof; #endif /* maXTouch data structure */ static struct mxt_device device; /* Initialize system clocks */ sysclk_init(); /* Initialize interrupt vectors */ irq_initialize_vectors(); /* Enable interrupts */ cpu_irq_enable(); /* Initialize the sleep manager */ sleepmgr_init(); /* Initialize the board */ board_init(); /* Initialize the mXT touch device */ mxt_init(&device); /* Initialize the graphical library */ gfx_init(); /* Set correct landscape orientation */ gfx_set_orientation(GFX_SWITCH_XY | GFX_FLIP_Y); /* Set background color */ gfx_draw_filled_rect(0, 0, gfx_get_width(), gfx_get_height(), COLOR_BACKGROUND); /* Draw the help text */ gfx_draw_string_aligned( "Middle finger to move cursor\n" "Index finger to left click\n" "Ring finger to right click", gfx_get_width() / 2, gfx_get_height() / 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_CENTER, TEXT_ALIGN_CENTER); /* Initialize the user interface */ ui_init(); ui_powerdown(); /* Start USB stack to authorize VBus monitoring */ udc_start(); /* Check if there are any new touch data pending */ while (true) { if (mxt_is_message_pending(&device)) { if (mxt_read_touch_event(&device, &ui_touch_event) == STATUS_OK) { ui_flag_new_touch_event(); } } /* Try to sleep */ sleepmgr_enter_sleep(); #ifdef USB_DEVICE_LOW_SPEED /* No USB "Keep alive" interrupt available in low speed * to scan mouse interface then use main loop */ if (main_b_mouse_enable) { virtual_sof_sub = 0; virtual_sof = 0; if (virtual_sof_sub++ == 700) { virtual_sof_sub = 0; ui_process(virtual_sof++); } } #endif } }
/** * 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; } }
/** * \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; } }