/** * Signal function of the roller * @param roller pointer to a roller object * @param sign a signal type from lv_signal_t enum * @param param pointer to a signal specific variable * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted */ static lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * param) { lv_res_t res = LV_RES_OK; /*Don't let the drop down list to handle the control signals. It works differently*/ if(sign != LV_SIGNAL_CONTROLL && sign != LV_SIGNAL_FOCUS && sign != LV_SIGNAL_DEFOCUS) { /* Include the ancient signal function */ res = ancestor_signal(roller, sign, param); if(res != LV_RES_OK) return res; } lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); if(sign == LV_SIGNAL_STYLE_CHG) { lv_obj_set_height(lv_page_get_scrl(roller), lv_obj_get_height(ext->ddlist.label) + lv_obj_get_height(roller)); lv_obj_align(ext->ddlist.label, NULL, LV_ALIGN_CENTER, 0, 0); lv_ddlist_set_selected(roller, ext->ddlist.sel_opt_id); refr_position(roller, false); } else if(sign == LV_SIGNAL_CORD_CHG) { if(lv_obj_get_width(roller) != lv_area_get_width(param) || lv_obj_get_height(roller) != lv_area_get_height(param)) { lv_ddlist_set_fix_height(roller, lv_obj_get_height(roller)); lv_obj_set_height(lv_page_get_scrl(roller), lv_obj_get_height(ext->ddlist.label) + lv_obj_get_height(roller)); lv_obj_align(ext->ddlist.label, NULL, LV_ALIGN_CENTER, 0, 0); lv_ddlist_set_selected(roller, ext->ddlist.sel_opt_id); refr_position(roller, false); } } else if(sign == LV_SIGNAL_CONTROLL) { char c = *((char*)param); if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN) { if(ext->ddlist.sel_opt_id +1 < ext->ddlist.option_cnt) { lv_roller_set_selected(roller, ext->ddlist.sel_opt_id + 1, true); if(ext->ddlist.action != NULL) { ext->ddlist.action(roller); } } } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP) { if(ext->ddlist.sel_opt_id > 0) { lv_roller_set_selected(roller, ext->ddlist.sel_opt_id - 1, true); if(ext->ddlist.action != NULL) { ext->ddlist.action(roller); } } } } return res; }
/** * Create a roller object * @param par pointer to an object, it will be the parent of the new roller * @param copy pointer to a roller object, if not NULL then the new object will be copied from it * @return pointer to the created roller */ lv_obj_t * lv_roller_create(lv_obj_t * par, lv_obj_t * copy) { /*Create the ancestor of roller*/ lv_obj_t * new_roller = lv_ddlist_create(par, copy); lv_mem_assert(new_roller); if(ancestor_scrl_signal == NULL) ancestor_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_roller)); if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_roller); /*Allocate the roller type specific extended data*/ lv_roller_ext_t * ext = lv_obj_allocate_ext_attr(new_roller, sizeof(lv_roller_ext_t)); lv_mem_assert(ext); /*The signal and design functions are not copied so set them here*/ lv_obj_set_signal_func(new_roller, lv_roller_signal); lv_obj_set_design_func(new_roller, lv_roller_design); /*Init the new roller roller*/ if(copy == NULL) { lv_obj_t * scrl = lv_page_get_scrl(new_roller); lv_obj_set_drag(scrl, true); /*In ddlist is might be disabled*/ lv_page_set_rel_action(new_roller, NULL); /*Roller don't uses it (like ddlist)*/ lv_page_set_scrl_fit(new_roller, true, false); /*Height is specified directly*/ lv_ddlist_open(new_roller, false); lv_ddlist_set_anim_time(new_roller, LV_ROLLER_ANIM_TIME); lv_roller_set_visible_row_count(new_roller, 3); lv_label_set_align(ext->ddlist.label, LV_LABEL_ALIGN_CENTER); lv_obj_set_signal_func(scrl, lv_roller_scrl_signal); /*Set the default styles*/ lv_theme_t *th = lv_theme_get_current(); if(th) { lv_roller_set_style(new_roller, LV_ROLLER_STYLE_BG, th->roller.bg); lv_roller_set_style(new_roller, LV_ROLLER_STYLE_SEL, th->roller.sel); } else { /*Let the ddlist's style*/ lv_obj_refresh_style(new_roller); /*To set scrollable size automatically*/ } } /*Copy an existing roller*/ else { lv_obj_t * scrl = lv_page_get_scrl(new_roller); lv_ddlist_open(new_roller, false); lv_obj_set_signal_func(scrl, lv_roller_scrl_signal); lv_obj_refresh_style(new_roller); /*Refresh the style with new signal function*/ } return new_roller; }
/** * Refresh the position of the roller. It uses the id stored in: ext->ddlist.selected_option_id * @param roller pointer to a roller object * @param anim_en true: refresh with animation; false: without animation */ static void refr_position(lv_obj_t *roller, bool anim_en) { lv_obj_t *roller_scrl = lv_page_get_scrl(roller); lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); lv_style_t * style_label = lv_obj_get_style(ext->ddlist.label); const lv_font_t * font = style_label->text.font; lv_coord_t font_h = lv_font_get_height_scale(font); lv_coord_t h = lv_obj_get_height(roller); int32_t id = ext->ddlist.sel_opt_id; lv_coord_t line_y1 = id * (font_h + style_label->text.line_space) + ext->ddlist.label->coords.y1 - roller_scrl->coords.y1; lv_coord_t new_y = - line_y1 + (h - font_h) / 2; if(ext->ddlist.anim_time == 0 || anim_en == false) { lv_obj_set_y(roller_scrl, new_y); } else { #if USE_LV_ANIMATION lv_anim_t a; a.var = roller_scrl; a.start = lv_obj_get_y(roller_scrl); a.end = new_y; a.fp = (lv_anim_fp_t)lv_obj_set_y; a.path = lv_anim_path_linear; a.end_cb = NULL; a.act_time = 0; a.time = ext->ddlist.anim_time; a.playback = 0; a.playback_pause = 0; a.repeat = 0; a.repeat_pause = 0; lv_anim_create(&a); #endif } }
/** * Close (Collapse) the drop down list * @param ddlist pointer to drop down list object * @param anim_en true: use animation; false: not use animations */ void lv_ddlist_close(lv_obj_t * ddlist, bool anim_en) { #if USE_LV_ANIMATION == 0 anim_en = false; #endif lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); ext->opened = 0; lv_obj_set_drag(lv_page_get_scrl(ddlist), false); lv_ddlist_refr_size(ddlist, anim_en); }
/** * Create an mpty list on the window. 'win_load_file_list' will fill it. * @param app pointer to a Files application */ static void win_create_list(lv_app_inst_t * app) { my_win_data_t * win_data = app->win_data; /*Delete the previous list*/ if(win_data->file_list != NULL) { lv_obj_del(win_data->file_list); } /*Create a new list*/ win_data->file_list = lv_list_create(app->win, NULL); lv_obj_set_width(win_data->file_list, lv_win_get_width(app->win)); lv_list_set_style_img(win_data->file_list, &style_btn_symbol); lv_obj_set_style(lv_page_get_scrl(win_data->file_list), lv_style_get(LV_STYLE_TRANSP_TIGHT, NULL)); lv_obj_set_drag_parent(win_data->file_list, true); lv_obj_set_drag_parent(lv_page_get_scrl(win_data->file_list), true); lv_cont_set_fit(win_data->file_list, false, true); lv_cont_set_layout(lv_page_get_scrl(win_data->file_list), LV_CONT_LAYOUT_COL_L); }
/** * Called when a drop down list is released to open it or set new option * @param ddlist pointer to a drop down list object * @return LV_ACTION_RES_INV if the ddlist it deleted in the user callback else LV_ACTION_RES_OK */ static lv_res_t lv_ddlist_release_action(lv_obj_t * ddlist) { lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); if(ext->opened == 0) { /*Open the list*/ ext->opened = 1; lv_obj_set_drag(lv_page_get_scrl(ddlist), true); } else { ext->opened = 0; lv_obj_set_drag(lv_page_get_scrl(ddlist), false); /*Search the clicked option*/ lv_indev_t *indev = lv_indev_get_act(); lv_point_t p; lv_indev_get_point(indev, &p); p.x -= ext->label->coords.x1; p.y -= ext->label->coords.y1; uint16_t letter_i; letter_i = lv_label_get_letter_on(ext->label, &p); uint16_t new_opt = 0; const char * txt = lv_label_get_text(ext->label); uint16_t i; for(i = 0; i < letter_i; i++) { if(txt[i] == '\n') new_opt ++; } ext->sel_opt_id = new_opt; if(ext->action != NULL) { ext->action(ddlist); } } lv_ddlist_refr_size(ddlist, true); return LV_RES_OK; }
/** * Set the position of list when it is closed to show the selected item * @param ddlist pointer to a drop down list */ static void lv_ddlist_pos_current_option(lv_obj_t * ddlist) { lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); lv_style_t * style = lv_obj_get_style(ddlist); const lv_font_t * font = style->text.font; lv_coord_t font_h = lv_font_get_height(font); lv_style_t * label_style = lv_obj_get_style(ext->label); lv_obj_t * scrl = lv_page_get_scrl(ddlist); lv_coord_t h = lv_obj_get_height(ddlist); lv_coord_t line_y1 = ext->sel_opt_id * (font_h + label_style->text.line_space) + ext->label->coords.y1 - scrl->coords.y1; lv_obj_set_y(scrl, - line_y1 + (h - font_h) / 2); }
/** * Set a style of a drop down list * @param ddlist pointer to a drop down list object * @param type which style should be set * @param style pointer to a style */ void lv_ddlist_set_style(lv_obj_t *ddlist, lv_ddlist_style_t type, lv_style_t *style) { lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); switch (type) { case LV_DDLIST_STYLE_BG: lv_page_set_style(ddlist, LV_PAGE_STYLE_BG, style); break; case LV_DDLIST_STYLE_SB: lv_page_set_style(ddlist, LV_PAGE_STYLE_SB, style); break; case LV_DDLIST_STYLE_SEL: ext->sel_style = style; lv_obj_t *scrl = lv_page_get_scrl(ddlist); lv_obj_refresh_ext_size(scrl); /*Because of the wider selected rectangle*/ break; } }
/** * Refresh the size of drop down list according to its status (open or closed) * @param ddlist pointer to a drop down list object * @param anim_en Change the size (open/close) with or without animation (true/false) */ static void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en) { #if USE_LV_ANIMATION == 0 anim_en = false; #endif lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); lv_style_t * style = lv_obj_get_style(ddlist); lv_coord_t new_height; if(ext->opened) { /*Open the list*/ if(ext->fix_height == 0) new_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) + 2 * style->body.padding.ver; else new_height = ext->fix_height; } else { /*Close the list*/ const lv_font_t * font = style->text.font; lv_style_t * label_style = lv_obj_get_style(ext->label); lv_coord_t font_h = lv_font_get_height(font); new_height = font_h + 2 * label_style->text.line_space; } if(anim_en == 0) { lv_obj_set_height(ddlist, new_height); lv_ddlist_pos_current_option(ddlist); } else { #if USE_LV_ANIMATION lv_anim_t a; a.var = ddlist; a.start = lv_obj_get_height(ddlist); a.end = new_height; a.fp = (lv_anim_fp_t)lv_obj_set_height; a.path = lv_anim_path_linear; a.end_cb = (lv_anim_cb_t)lv_ddlist_pos_current_option; a.act_time = 0; a.time = ext->anim_time; a.playback = 0; a.playback_pause = 0; a.repeat = 0; a.repeat_pause = 0; lv_anim_create(&a); #endif } }
/** * Create a drop down list objects * @param par pointer to an object, it will be the parent of the new drop down list * @param copy pointer to a drop down list object, if not NULL then the new object will be copied from it * @return pointer to the created drop down list */ lv_obj_t * lv_ddlist_create(lv_obj_t * par, lv_obj_t * copy) { /*Create the ancestor drop down list*/ lv_obj_t * new_ddlist = lv_page_create(par, copy); lv_mem_assert(new_ddlist); if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_ddlist); if(ancestor_scrl_signal == NULL) ancestor_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_ddlist)); if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_ddlist); /*Allocate the drop down list type specific extended data*/ lv_ddlist_ext_t * ext = lv_obj_allocate_ext_attr(new_ddlist, sizeof(lv_ddlist_ext_t)); lv_mem_assert(ext); /*Initialize the allocated 'ext' */ ext->label = NULL; ext->action = NULL; ext->opened = 0; ext->fix_height = 0; ext->sel_opt_id = 0; ext->sel_opt_id_ori = 0; ext->option_cnt = 0; ext->anim_time = LV_DDLIST_ANIM_TIME; ext->sel_style = &lv_style_plain_color; /*The signal and design functions are not copied so set them here*/ lv_obj_set_signal_func(new_ddlist, lv_ddlist_signal); lv_obj_set_signal_func(lv_page_get_scrl(new_ddlist), lv_ddlist_scrl_signal); lv_obj_set_design_func(new_ddlist, lv_ddlist_design); /*Init the new drop down list drop down list*/ if(copy == NULL) { lv_obj_t * scrl = lv_page_get_scrl(new_ddlist); lv_obj_set_drag(scrl, false); lv_page_set_scrl_fit(new_ddlist, true, true); ext->label = lv_label_create(new_ddlist, NULL); lv_cont_set_fit(new_ddlist, true, false); lv_page_set_rel_action(new_ddlist, lv_ddlist_release_action); lv_page_set_sb_mode(new_ddlist, LV_SB_MODE_DRAG); lv_page_set_style(new_ddlist, LV_PAGE_STYLE_SCRL, &lv_style_transp_tight); lv_ddlist_set_options(new_ddlist, "Option 1\nOption 2\nOption 3"); /*Set the default styles*/ lv_theme_t *th = lv_theme_get_current(); if(th) { lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BG, th->ddlist.bg); lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL,th->ddlist.sel); lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, th->ddlist.sb); } else { lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BG, &lv_style_pretty); lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, &lv_style_plain_color); lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, &lv_style_pretty_color); } } /*Copy an existing drop down list*/ else { lv_ddlist_ext_t * copy_ext = lv_obj_get_ext_attr(copy); ext->label = lv_label_create(new_ddlist, copy_ext->label); lv_label_set_text(ext->label, lv_label_get_text(copy_ext->label)); ext->sel_opt_id = copy_ext->sel_opt_id; ext->fix_height = copy_ext->fix_height; ext->action = copy_ext->action; ext->option_cnt = copy_ext->option_cnt; ext->sel_style = copy_ext->sel_style; ext->anim_time = copy_ext->anim_time; /*Refresh the style with new signal function*/ lv_obj_refresh_style(new_ddlist); } return new_ddlist; }
/** * Load the file list from the current path on the window * @param app pointer to a Files application */ static void win_load_file_list(lv_app_inst_t * app) { my_app_data_t * app_data = app->app_data; my_win_data_t * win_data = app->win_data; /*Create a new list*/ win_create_list(app); fs_res_t res = FS_RES_OK; /*At empty path show the drivers */ lv_obj_t * liste; if(app_data->path[0] == '\0') { char drv[16]; char buf[2]; fs_get_letters(drv); uint8_t i; for(i = 0; drv[i] != '\0'; i++) { buf[0] = drv[i]; buf[1] = '\0'; liste = lv_list_add(win_data->file_list, SYMBOL_DRIVE, buf, win_drv_action); lv_obj_set_free_p(liste, app); } } /*List the files/folders with fs interface*/ else { liste = lv_list_add(win_data->file_list, SYMBOL_UP, "Up", win_up_action); lv_obj_set_free_p(liste, app); fs_readdir_t rd; res = fs_readdir_init(&rd, app_data->path); if(res != FS_RES_OK) { lv_app_notice_add("Can not read the\npath in Files"); return; } /*At not first page add prev. page button */ if(app_data->file_cnt != 0) { liste = lv_list_add(win_data->file_list, SYMBOL_LEFT, "Previous page", win_prev_action); lv_obj_set_free_p(liste, app); } char fn[LV_APP_FILES_FN_MAX_LEN]; /*Read the files from the previous pages*/ uint16_t file_cnt = 0; while(file_cnt <= app_data->file_cnt) { res = fs_readdir(&rd, fn); if(res != FS_RES_OK ){ lv_app_notice_add("Can not read\nthe path in Files"); return; } file_cnt ++; } /*Add list elements from the files and folders*/ while(res == FS_RES_OK && fn[0] != '\0') { if(fn[0] == '/') { /*Add a folder*/ lv_obj_t * liste; liste = lv_list_add(win_data->file_list, SYMBOL_FOLDER, &fn[1], win_folder_action); lv_obj_set_free_p(liste, app); app_data->file_cnt ++; } /*Add a file*/ else { liste = lv_list_add(win_data->file_list, SYMBOL_FILE, fn, win_file_action); lv_obj_set_free_p(liste, app); app_data->file_cnt ++; } /*Get the next element*/ res = fs_readdir(&rd, fn); /*Show only LV_APP_FSEL_MAX_FILE elements and add a Next page button*/ if(app_data->file_cnt != 0 && app_data->file_cnt % LV_APP_FILES_PAGE_SIZE == 0) { liste = lv_list_add(win_data->file_list, SYMBOL_RIGHT, "Next page", win_next_action); lv_obj_set_free_p(liste, app); break; } } /*Close the read directory*/ fs_readdir_close(&rd); } if(res != FS_RES_OK) { lv_app_notice_add("Can not read\nthe path in Files"); } /*Focus to the top of the list*/ lv_obj_set_y(lv_page_get_scrl(win_data->file_list), 0); return; }