#include #include #include "lvgl.h" #include "compass_screen.h" #include "menu_screen.h" static const char *cardinals[] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW" }; static void gesture_event_cb(lv_event_t * e) { CompassScreen_t *compassScreen = e->user_data; lv_dir_t gesture; switch(gesture = lv_indev_get_gesture_dir(lv_indev_get_act())) { case LV_DIR_LEFT: LV_LOG_USER("GESTURE : LEFT"); break; case LV_DIR_RIGHT: LV_LOG_USER("GESTURE : RIGHT"); // We create the menu screen and switch to it extern MenuScreen_t menuScreen; menu_screen_create(&menuScreen); lv_scr_load_anim(menuScreen.display, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 400, 0, true); break; case LV_DIR_TOP: LV_LOG_USER("GESTURE : TOP"); break; case LV_DIR_BOTTOM: LV_LOG_USER("GESTURE : BOTTOM"); break; default: LV_LOG_USER("GESTURE : %u", gesture); } } static void cleanup_event_cb(lv_event_t * e) { CompassScreen_t *compassScreen = e->user_data; compass_screen_destroy(compassScreen); LV_LOG_USER("cleanup"); } static void create_cardinal(CompassCardinal_t *cardidanl, const char *cardinalText, lv_color_t textColor, lv_coord_t x, lv_coord_t y, lv_obj_t *parent) { cardidanl->label = lv_label_create(parent); lv_label_set_text_static(cardidanl->label, cardinalText); lv_obj_set_style_text_font(cardidanl->label, &lv_font_montserrat_24, LV_PART_MAIN); lv_obj_set_style_text_color(cardidanl->label, textColor, LV_PART_MAIN); lv_obj_update_layout(cardidanl->label); //Needed to compute the height and width of the label, if not called, lv_obj_get_width and height return 0. //Let's compute the offset to move the origin of the letter to it's center : cardidanl->offset.x = lv_obj_get_width(cardidanl->label)/2; cardidanl->offset.y = lv_obj_get_height(cardidanl->label)/2; cardidanl->position.x = x - cardidanl->offset.x; cardidanl->position.y = y - cardidanl->offset.y; lv_obj_set_pos(cardidanl->label, cardidanl->position.x, cardidanl->position.y); } static void rotate_cardinal(CompassCardinal_t *cardinal, uint16_t azimuth) { lv_coord_t rotated_x, rotated_y; float azimuth_in_rads = (float)azimuth*M_PI/180.0; rotated_x = (float)(cardinal->position.x-120+cardinal->offset.x)*cos(azimuth_in_rads) - (float)(cardinal->position.y-120+cardinal->offset.y)*sin(azimuth_in_rads) + 120-cardinal->offset.x; rotated_y = (float)(cardinal->position.y-120+cardinal->offset.y)*cos(azimuth_in_rads) + (float)(cardinal->position.x-120+cardinal->offset.x)*sin(azimuth_in_rads) + 120-cardinal->offset.y; lv_obj_set_pos(cardinal->label, rotated_x, rotated_y); } void compass_screen_init(CompassScreen_t * const compassScreen) { if(!compassScreen) { LV_LOG_ERROR("NULL pointer given !"); return; } memset(compassScreen, 0, sizeof(CompassScreen_t)); strcpy(compassScreen->compassAzimuth.text, "0° N"); } void compass_screen_set_azimuth(CompassScreen_t * const compassScreen, uint16_t azimuth) { if(!compassScreen) { LV_LOG_ERROR("NULL pointer given !"); return; } //Mandatory, if the screen is not displayed anymore, we should still be able to call this function ! if(!compassScreen->display) return; //We make sure the azimuth is in the right range ie 0 to 359 azimuth %= 360; uint16_t azimuthAdjusted = 359 - azimuth; uint8_t index; if(azimuthAdjusted >= 23 && azimuthAdjusted <= 67) index = 1;//NE else if(azimuthAdjusted >= 68 && azimuthAdjusted <= 112) index = 2;//E else if(azimuthAdjusted >= 113 && azimuthAdjusted <= 157) index = 3;//SE else if(azimuthAdjusted >= 158 && azimuthAdjusted <= 202) index = 4;//S else if(azimuthAdjusted >= 203 && azimuthAdjusted <= 247) index = 5;//SW else if(azimuthAdjusted >= 248 && azimuthAdjusted <= 292) index = 6;//W else if(azimuthAdjusted >= 293 && azimuthAdjusted <= 337) index = 7;//NW else index = 0;//N //Update the center label sprintf(compassScreen->compassAzimuth.text, "%u° %s", azimuthAdjusted, cardinals[index]); lv_label_set_text_static(compassScreen->compassAzimuth.label, compassScreen->compassAzimuth.text); //Rotate each cardinal with the current azimuth rotate_cardinal(&compassScreen->northCardinal, azimuth); lv_img_set_angle(compassScreen->northMarker, azimuth*10); //lv_meter_set_scale_range(compassScreen->compassGraduation.meter, compassScreen->compassGraduation.scale, 0, 330, 330, azimuth-90); rotate_cardinal(&compassScreen->eastCardinal, azimuth); rotate_cardinal(&compassScreen->southCardinal, azimuth); rotate_cardinal(&compassScreen->westCardinal, azimuth); } bool compass_screen_is_in_use(CompassScreen_t *const compassScreen) { if(!compassScreen) { LV_LOG_ERROR("NULL pointer given !"); return; } return compassScreen->display != NULL; } void compass_screen_create(CompassScreen_t * const compassScreen) { if(!compassScreen) { LV_LOG_ERROR("NULL pointer given !"); return; } //We declare all the needed assets by the compass screen: LV_IMG_DECLARE(compass_marker) LV_IMG_DECLARE(compass_marker_north) //We create our parent screen : if(compassScreen->display) { LV_LOG_ERROR("display should be NULL here !"); lv_obj_del(compassScreen->display); compassScreen->display = NULL; } compassScreen->display = lv_obj_create(NULL); lv_obj_set_style_bg_color(compassScreen->display, lv_color_white(), LV_PART_MAIN); //Let's add some arcs lv_obj_t *arc = lv_arc_create(compassScreen->display); lv_arc_set_angles(arc, 0, 360); lv_obj_set_style_arc_width(arc, 2, LV_PART_INDICATOR); lv_obj_remove_style(arc, NULL, LV_PART_KNOB); lv_obj_set_style_arc_width(arc, 0, LV_PART_MAIN); lv_obj_clear_flag(arc, LV_OBJ_FLAG_CLICKABLE); lv_obj_set_size(arc, 168, 168); lv_obj_center(arc); arc = lv_arc_create(compassScreen->display); lv_arc_set_angles(arc, 0, 360); lv_obj_set_style_arc_width(arc, 2, LV_PART_INDICATOR); lv_obj_remove_style(arc, NULL, LV_PART_KNOB); lv_obj_set_style_arc_width(arc, 0, LV_PART_MAIN); lv_obj_clear_flag(arc, LV_OBJ_FLAG_CLICKABLE); lv_obj_set_size(arc, 210, 210); lv_obj_center(arc); //Marker images are created here lv_obj_t *compassMarker = lv_img_create(compassScreen->display); lv_img_set_src(compassMarker, &compass_marker); lv_obj_set_pos(compassMarker, 113, 0); //Azimuth label is created here if(compassScreen->compassAzimuth.label) { LV_LOG_ERROR("label should be NULL here !"); lv_obj_del(compassScreen->compassAzimuth.label); compassScreen->compassAzimuth.label = NULL; } compassScreen->compassAzimuth.label = lv_label_create(compassScreen->display); lv_label_set_text_static(compassScreen->compassAzimuth.label, compassScreen->compassAzimuth.text); lv_obj_set_style_text_font(compassScreen->compassAzimuth.label, &lv_font_montserrat_28, LV_PART_MAIN); lv_obj_center(compassScreen->compassAzimuth.label); //Add some graduation : ( was nice but is too CPU intensive :( ) /*if(compassScreen->compassGraduation.meter) { LV_LOG_ERROR("meter should be NULL here !"); lv_obj_del(compassScreen->compassGraduation.meter); compassScreen->compassGraduation.meter = NULL; } compassScreen->compassGraduation.meter = lv_meter_create(compassScreen->display); lv_obj_remove_style(compassScreen->compassGraduation.meter, NULL, LV_PART_INDICATOR); lv_obj_remove_style(compassScreen->compassGraduation.meter, NULL, LV_PART_MAIN); lv_obj_set_size(compassScreen->compassGraduation.meter, 204, 204); lv_obj_center(compassScreen->compassGraduation.meter); compassScreen->compassGraduation.scale = lv_meter_add_scale(compassScreen->compassGraduation.meter); lv_meter_set_scale_ticks(compassScreen->compassGraduation.meter, compassScreen->compassGraduation.scale, 12, 1, 0, lv_color_black()); lv_meter_set_scale_major_ticks(compassScreen->compassGraduation.meter, compassScreen->compassGraduation.scale, 1, 1, 0, lv_color_black(), 11); lv_meter_set_scale_range(compassScreen->compassGraduation.meter, compassScreen->compassGraduation.scale, 0, 330, 330, -90);*/ if(compassScreen->northMarker) { LV_LOG_ERROR("img should be NULL here !"); lv_obj_del(compassScreen->northMarker); compassScreen->northMarker = NULL; } compassScreen->northMarker = lv_img_create(compassScreen->display); lv_img_set_src(compassScreen->northMarker, &compass_marker_north); lv_obj_set_pos(compassScreen->northMarker, 113, 18); lv_img_set_pivot(compassScreen->northMarker, 7, 101); //Cardinal labels are created here if(compassScreen->northCardinal.label) { LV_LOG_ERROR("label should be NULL here !"); lv_obj_del(compassScreen->northCardinal.label); compassScreen->northCardinal.label = NULL; } create_cardinal(&compassScreen->northCardinal, cardinals[0], lv_palette_main(LV_PALETTE_RED), 120, 53, compassScreen->display); if(compassScreen->eastCardinal.label) { LV_LOG_ERROR("label should be NULL here !"); lv_obj_del(compassScreen->eastCardinal.label); compassScreen->eastCardinal.label = NULL; } create_cardinal(&compassScreen->eastCardinal, cardinals[2], lv_color_black(), 187, 120, compassScreen->display); if(compassScreen->southCardinal.label) { LV_LOG_ERROR("label should be NULL here !"); lv_obj_del(compassScreen->southCardinal.label); compassScreen->southCardinal.label = NULL; } create_cardinal(&compassScreen->southCardinal, cardinals[4], lv_color_black(), 120, 187, compassScreen->display); if(compassScreen->westCardinal.label) { LV_LOG_ERROR("label should be NULL here !"); lv_obj_del(compassScreen->westCardinal.label); compassScreen->westCardinal.label = NULL; } create_cardinal(&compassScreen->westCardinal, cardinals[6], lv_color_black(), 53, 120, compassScreen->display); //We register the event callback to handle gestures lv_obj_add_event_cb(compassScreen->display, &(gesture_event_cb), LV_EVENT_GESTURE, compassScreen); //We register the event callback to handle the cleanup lv_obj_add_event_cb(compassScreen->display, &(cleanup_event_cb), LV_EVENT_DELETE, compassScreen); } void compass_screen_destroy(CompassScreen_t * const compassScreen) { if(!compassScreen) { LV_LOG_ERROR("NULL pointer given !"); return; } compassScreen->display = NULL; compassScreen->compassAzimuth.label = NULL; compassScreen->northCardinal.label = NULL; compassScreen->eastCardinal.label = NULL; compassScreen->southCardinal.label = NULL; compassScreen->westCardinal.label = NULL; compassScreen->northMarker = NULL; //compassScreen->compassGraduation.meter = NULL; //compassScreen->compassGraduation.scale = NULL; }