Skip to content

Instantly share code, notes, and snippets.

@embeddedt
Created July 6, 2020 12:03
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save embeddedt/be0adf541e65a2fbbf3c5e2e4efd85e1 to your computer and use it in GitHub Desktop.
Save embeddedt/be0adf541e65a2fbbf3c5e2e4efd85e1 to your computer and use it in GitHub Desktop.
Incomplete file browser implementation for LVGL
#include <lvgl/lvgl.h>
#define BROWSE_DRV_LETTER "C"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void file_list_button_event(lv_obj_t * list_btn, lv_event_t event);
static void populate_list(void);
static void go_up(lv_obj_t * up_btn, lv_event_t event);
static void stop_selecting(lv_obj_t * btn, lv_event_t event);
static void set_selecting_mode(bool mode);
/**********************
* STATIC VARIABLES
**********************/
static bool selecting_mode;
static lv_obj_t * main_list, * win;
static lv_obj_t * select_stop_btn = NULL;
static char current_dir[LV_FS_MAX_PATH_LENGTH] = BROWSE_DRV_LETTER ":";
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_file_browser(void)
{
static lv_style_t header_style, page_style;
/* Create a window to use as the action bar */
win = lv_win_create(lv_scr_act(), NULL);
lv_obj_set_size(win, LV_HOR_RES, LV_VER_RES);
/* Override some properties of the style */
lv_style_copy(&header_style, lv_win_get_style(win, LV_WIN_STYLE_HEADER));
lv_style_copy(&page_style, &lv_style_transp);
header_style.body.shadow.color = lv_color_hex3(0xaaa);
header_style.body.shadow.width = 4;
header_style.body.shadow.type = LV_SHADOW_BOTTOM;
page_style.body.padding.left = page_style.body.padding.right = 0;
page_style.body.padding.top = page_style.body.padding.bottom = 0;
page_style.body.padding.inner = 0;
lv_win_set_style(win, LV_WIN_STYLE_HEADER, &header_style);
lv_win_set_style(win, LV_WIN_STYLE_CONTENT, &page_style);
lv_win_set_title(win, "File Manager");
lv_obj_t * up_btn = lv_win_add_btn(win, LV_SYMBOL_UP);
lv_obj_set_event_cb(up_btn, go_up);
lv_win_add_btn(win, LV_SYMBOL_HOME);
lv_win_add_btn(win, LV_SYMBOL_TRASH);
lv_obj_t * win_content = lv_win_get_content(win);
lv_cont_set_fit(lv_page_get_scrl(win_content), LV_FIT_FLOOD);
/* Create the list */
main_list = lv_list_create(win, NULL);
lv_list_set_style(main_list, LV_LIST_STYLE_BG, &page_style);
/* Fit the list inside the page, taking into account any borders. */
lv_area_t page_area;
lv_obj_get_coords(win_content, &page_area);
lv_obj_get_inner_coords(win_content, &page_area);
lv_obj_set_size(main_list, lv_area_get_width(&page_area), lv_area_get_height(&page_area));
populate_list();
}
/**********************
* STATIC FUNCTIONS
**********************/
static void stop_selecting(lv_obj_t * btn, lv_event_t event)
{
if(event == LV_EVENT_CLICKED) {
set_selecting_mode(false);
}
}
static void set_selecting_mode(bool mode)
{
if(selecting_mode != mode) {
if(mode) {
select_stop_btn = lv_win_add_btn(win, LV_SYMBOL_OK);
lv_obj_set_event_cb(select_stop_btn, stop_selecting);
} else {
if(select_stop_btn) {
lv_obj_del(select_stop_btn);
select_stop_btn = NULL;
}
lv_obj_t * btn = NULL;
do {
btn = lv_list_get_next_btn(main_list, btn);
if(btn != NULL) {
lv_btn_set_state(btn, LV_BTN_STATE_REL);
}
} while(btn != NULL);
}
}
selecting_mode = mode;
}
static void go_up(lv_obj_t * up_btn, lv_event_t event)
{
if(event == LV_EVENT_CLICKED) {
if(strlen(current_dir) == 2) { /* drive letter plus : */
/* We cannot go up further */
return;
}
printf("Current directory: %s\n", current_dir);
char *last_slash = strrchr(current_dir, '/');
assert(last_slash != NULL);
*last_slash = 0;
populate_list();
}
}
static void file_list_button_event(lv_obj_t * list_btn, lv_event_t event)
{
if(event == LV_EVENT_SHORT_CLICKED) {
if(selecting_mode) {
if(lv_btn_get_state(list_btn) == LV_BTN_STATE_TGL_REL) {
lv_btn_set_state(list_btn, LV_BTN_STATE_REL);
} else
lv_btn_set_state(list_btn, LV_BTN_STATE_TGL_REL);
return;
}
/* Get some basic information about the file */
char *filename = lv_list_get_btn_text(list_btn);
lv_obj_t * img = lv_list_get_btn_img(list_btn);
/* This assumes that the button's image is always a symbol */
bool is_dir = (!strcmp(lv_img_get_src(img), LV_SYMBOL_DIRECTORY));
/* Only change to new directories */
if(!is_dir)
return;
uint32_t len = strnlen(current_dir, LV_FS_MAX_PATH_LENGTH);
strncat(current_dir, "/", LV_FS_MAX_PATH_LENGTH - len - 1);
len++;
strncat(current_dir, filename, LV_FS_MAX_PATH_LENGTH - len - 1);
populate_list();
/* The list button is deleted now */
} else if(event == LV_EVENT_LONG_PRESSED) {
set_selecting_mode(true);
lv_btn_set_state(list_btn, LV_BTN_STATE_TGL_PR);
}
}
static void populate_list(void)
{
static char fn[LV_FS_MAX_FN_LENGTH];
lv_fs_res_t err;
lv_fs_dir_t dir;
bool is_dir;
err = lv_fs_dir_open(&dir, current_dir);
if(err != LV_FS_RES_OK) {
printf("Error: %d\n", err);
return;
}
/* Once the list changes we are no longer selecting */
set_selecting_mode(false);
lv_list_clean(main_list);
fn[0] = 0;
do {
lv_fs_dir_read(&dir, fn);
if(fn[0] != 0) {
is_dir = (fn[0] == '/');
lv_obj_t * list_btn = lv_list_add_btn(main_list, (is_dir ? LV_SYMBOL_DIRECTORY : LV_SYMBOL_FILE), &fn[is_dir]);
lv_obj_set_event_cb(list_btn, file_list_button_event);
} else
break;
} while(1);
lv_fs_dir_close(&dir);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment