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