LVGL 库提交
This commit is contained in:
@@ -0,0 +1,767 @@
|
||||
/**
|
||||
* @file lv_file_explorer.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_file_explorer_private.h"
|
||||
#include "../../misc/lv_fs_private.h"
|
||||
#include "../../core/lv_obj_class_private.h"
|
||||
#if LV_USE_FILE_EXPLORER != 0
|
||||
|
||||
#include "../../lvgl.h"
|
||||
#include "../../core/lv_global.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define MY_CLASS (&lv_file_explorer_class)
|
||||
|
||||
#define FILE_EXPLORER_QUICK_ACCESS_AREA_WIDTH (22)
|
||||
#define FILE_EXPLORER_BROWSER_AREA_WIDTH (100 - FILE_EXPLORER_QUICK_ACCESS_AREA_WIDTH)
|
||||
|
||||
#define quick_access_list_button_style (LV_GLOBAL_DEFAULT()->fe_list_button_style)
|
||||
|
||||
#define LV_FILE_NAVIGATION_CURRENT_DIR "."
|
||||
#define LV_FILE_NAVIGATION_PARENT_DIR "Back"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void lv_file_explorer_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
||||
static void init_style(lv_obj_t * obj);
|
||||
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
static void quick_access_event_handler(lv_event_t * e);
|
||||
static void quick_access_area_event_handler(lv_event_t * e);
|
||||
#endif
|
||||
|
||||
static void browser_file_event_handler(lv_event_t * e);
|
||||
static void show_dir(lv_obj_t * obj, const char * path);
|
||||
static void strip_ext(char * dir);
|
||||
static void exch_table_item(lv_obj_t * tb, int16_t i, int16_t j);
|
||||
static void file_explorer_sort(lv_obj_t * obj);
|
||||
static void sort_by_file_kind(lv_obj_t * tb, int16_t lo, int16_t hi);
|
||||
static bool is_end_with(const char * str1, const char * str2);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
const lv_obj_class_t lv_file_explorer_class = {
|
||||
.constructor_cb = lv_file_explorer_constructor,
|
||||
.width_def = LV_SIZE_CONTENT,
|
||||
.height_def = LV_SIZE_CONTENT,
|
||||
.instance_size = sizeof(lv_file_explorer_t),
|
||||
.base_class = &lv_obj_class,
|
||||
.name = "lv_file_explorer",
|
||||
};
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_obj_t * lv_file_explorer_create(lv_obj_t * parent)
|
||||
{
|
||||
LV_LOG_INFO("begin");
|
||||
lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
|
||||
lv_obj_class_init_obj(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
void lv_file_explorer_set_quick_access_path(lv_obj_t * obj, lv_file_explorer_dir_t dir, const char * path)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
/*If path is unavailable */
|
||||
if((path == NULL) || (lv_strlen(path) <= 0)) return;
|
||||
|
||||
char ** dir_str = NULL;
|
||||
switch(dir) {
|
||||
case LV_EXPLORER_HOME_DIR:
|
||||
dir_str = &(explorer->home_dir);
|
||||
break;
|
||||
case LV_EXPLORER_MUSIC_DIR:
|
||||
dir_str = &(explorer->music_dir);
|
||||
break;
|
||||
case LV_EXPLORER_PICTURES_DIR:
|
||||
dir_str = &(explorer->pictures_dir);
|
||||
break;
|
||||
case LV_EXPLORER_VIDEO_DIR:
|
||||
dir_str = &(explorer->video_dir);
|
||||
break;
|
||||
case LV_EXPLORER_DOCS_DIR:
|
||||
dir_str = &(explorer->docs_dir);
|
||||
break;
|
||||
case LV_EXPLORER_FS_DIR:
|
||||
dir_str = &(explorer->fs_dir);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
/*Free the old text*/
|
||||
if(*dir_str != NULL) {
|
||||
lv_free(*dir_str);
|
||||
*dir_str = NULL;
|
||||
}
|
||||
|
||||
/*Allocate space for the new text*/
|
||||
*dir_str = lv_strdup(path);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void lv_file_explorer_set_sort(lv_obj_t * obj, lv_file_explorer_sort_t sort)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
explorer->sort = sort;
|
||||
|
||||
file_explorer_sort(obj);
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
const char * lv_file_explorer_get_selected_file_name(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
return explorer->sel_fn;
|
||||
}
|
||||
|
||||
const char * lv_file_explorer_get_current_path(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
return explorer->current_path;
|
||||
}
|
||||
|
||||
lv_obj_t * lv_file_explorer_get_file_table(lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
return explorer->file_table;
|
||||
}
|
||||
|
||||
lv_obj_t * lv_file_explorer_get_header(lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
return explorer->head_area;
|
||||
}
|
||||
|
||||
lv_obj_t * lv_file_explorer_get_path_label(lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
return explorer->path_label;
|
||||
}
|
||||
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
lv_obj_t * lv_file_explorer_get_quick_access_area(lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
return explorer->quick_access_area;
|
||||
}
|
||||
|
||||
lv_obj_t * lv_file_explorer_get_places_list(lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
return explorer->list_places;
|
||||
}
|
||||
|
||||
lv_obj_t * lv_file_explorer_get_device_list(lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
return explorer->list_device;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
lv_file_explorer_sort_t lv_file_explorer_get_sort(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
return explorer->sort;
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
void lv_file_explorer_open_dir(lv_obj_t * obj, const char * dir)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
show_dir(obj, dir);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
static void lv_file_explorer_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
{
|
||||
LV_UNUSED(class_p);
|
||||
LV_TRACE_OBJ_CREATE("begin");
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
explorer->home_dir = NULL;
|
||||
explorer->video_dir = NULL;
|
||||
explorer->pictures_dir = NULL;
|
||||
explorer->music_dir = NULL;
|
||||
explorer->docs_dir = NULL;
|
||||
explorer->fs_dir = NULL;
|
||||
#endif
|
||||
|
||||
explorer->sort = LV_EXPLORER_SORT_NONE;
|
||||
|
||||
lv_memzero(explorer->current_path, sizeof(explorer->current_path));
|
||||
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN);
|
||||
|
||||
explorer->cont = lv_obj_create(obj);
|
||||
lv_obj_set_width(explorer->cont, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(explorer->cont, 1);
|
||||
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
/*Quick access bar area on the left*/
|
||||
explorer->quick_access_area = lv_obj_create(explorer->cont);
|
||||
lv_obj_set_size(explorer->quick_access_area, LV_PCT(FILE_EXPLORER_QUICK_ACCESS_AREA_WIDTH), LV_PCT(100));
|
||||
lv_obj_set_flex_flow(explorer->quick_access_area, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_add_event_cb(explorer->quick_access_area, quick_access_area_event_handler, LV_EVENT_ALL,
|
||||
explorer);
|
||||
#endif
|
||||
|
||||
/*File table area on the right*/
|
||||
explorer->browser_area = lv_obj_create(explorer->cont);
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
lv_obj_set_size(explorer->browser_area, LV_PCT(FILE_EXPLORER_BROWSER_AREA_WIDTH), LV_PCT(100));
|
||||
#else
|
||||
lv_obj_set_size(explorer->browser_area, LV_PCT(100), LV_PCT(100));
|
||||
#endif
|
||||
lv_obj_set_flex_flow(explorer->browser_area, LV_FLEX_FLOW_COLUMN);
|
||||
|
||||
/*The area displayed above the file browse list(head)*/
|
||||
explorer->head_area = lv_obj_create(explorer->browser_area);
|
||||
lv_obj_set_size(explorer->head_area, LV_PCT(100), LV_PCT(14));
|
||||
lv_obj_remove_flag(explorer->head_area, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
/*Two lists of quick access bar*/
|
||||
lv_obj_t * btn;
|
||||
/*list 1*/
|
||||
explorer->list_device = lv_list_create(explorer->quick_access_area);
|
||||
lv_obj_set_size(explorer->list_device, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_bg_color(lv_list_add_text(explorer->list_device, "DEVICE"), lv_palette_main(LV_PALETTE_ORANGE), 0);
|
||||
|
||||
btn = lv_list_add_button(explorer->list_device, NULL, LV_SYMBOL_DRIVE " File System");
|
||||
lv_obj_add_event_cb(btn, quick_access_event_handler, LV_EVENT_CLICKED, obj);
|
||||
|
||||
/*list 2*/
|
||||
explorer->list_places = lv_list_create(explorer->quick_access_area);
|
||||
lv_obj_set_size(explorer->list_places, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_bg_color(lv_list_add_text(explorer->list_places, "PLACES"), lv_palette_main(LV_PALETTE_LIME), 0);
|
||||
|
||||
btn = lv_list_add_button(explorer->list_places, NULL, LV_SYMBOL_HOME " HOME");
|
||||
lv_obj_add_event_cb(btn, quick_access_event_handler, LV_EVENT_CLICKED, obj);
|
||||
btn = lv_list_add_button(explorer->list_places, NULL, LV_SYMBOL_VIDEO " Video");
|
||||
lv_obj_add_event_cb(btn, quick_access_event_handler, LV_EVENT_CLICKED, obj);
|
||||
btn = lv_list_add_button(explorer->list_places, NULL, LV_SYMBOL_IMAGE " Pictures");
|
||||
lv_obj_add_event_cb(btn, quick_access_event_handler, LV_EVENT_CLICKED, obj);
|
||||
btn = lv_list_add_button(explorer->list_places, NULL, LV_SYMBOL_AUDIO " Music");
|
||||
lv_obj_add_event_cb(btn, quick_access_event_handler, LV_EVENT_CLICKED, obj);
|
||||
btn = lv_list_add_button(explorer->list_places, NULL, LV_SYMBOL_FILE " Documents");
|
||||
lv_obj_add_event_cb(btn, quick_access_event_handler, LV_EVENT_CLICKED, obj);
|
||||
#endif
|
||||
|
||||
/*Show current path*/
|
||||
explorer->path_label = lv_label_create(explorer->head_area);
|
||||
lv_label_set_text(explorer->path_label, LV_SYMBOL_EYE_OPEN"https://lvgl.io");
|
||||
lv_obj_center(explorer->path_label);
|
||||
|
||||
/*Table showing the contents of the table of contents*/
|
||||
explorer->file_table = lv_table_create(explorer->browser_area);
|
||||
lv_obj_set_size(explorer->file_table, LV_PCT(100), LV_PCT(86));
|
||||
lv_table_set_column_width(explorer->file_table, 0, LV_PCT(100));
|
||||
lv_table_set_column_count(explorer->file_table, 1);
|
||||
lv_obj_add_event_cb(explorer->file_table, browser_file_event_handler, LV_EVENT_ALL, obj);
|
||||
|
||||
/*only scroll up and down*/
|
||||
lv_obj_set_scroll_dir(explorer->file_table, LV_DIR_TOP | LV_DIR_BOTTOM);
|
||||
|
||||
/*Initialize style*/
|
||||
init_style(obj);
|
||||
|
||||
LV_TRACE_OBJ_CREATE("finished");
|
||||
}
|
||||
|
||||
static void init_style(lv_obj_t * obj)
|
||||
{
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
/*lv_file_explorer obj style*/
|
||||
lv_obj_set_style_radius(obj, 0, 0);
|
||||
lv_obj_set_style_bg_color(obj, lv_color_hex(0xf2f1f6), 0);
|
||||
|
||||
/*main container style*/
|
||||
lv_obj_set_style_radius(explorer->cont, 0, 0);
|
||||
lv_obj_set_style_bg_opa(explorer->cont, LV_OPA_0, 0);
|
||||
lv_obj_set_style_border_width(explorer->cont, 0, 0);
|
||||
lv_obj_set_style_outline_width(explorer->cont, 0, 0);
|
||||
lv_obj_set_style_pad_column(explorer->cont, 0, 0);
|
||||
lv_obj_set_style_pad_row(explorer->cont, 0, 0);
|
||||
lv_obj_set_style_flex_flow(explorer->cont, LV_FLEX_FLOW_ROW, 0);
|
||||
lv_obj_set_style_pad_all(explorer->cont, 0, 0);
|
||||
lv_obj_set_style_layout(explorer->cont, LV_LAYOUT_FLEX, 0);
|
||||
|
||||
/*head cont style*/
|
||||
lv_obj_set_style_radius(explorer->head_area, 0, 0);
|
||||
lv_obj_set_style_border_width(explorer->head_area, 0, 0);
|
||||
lv_obj_set_style_pad_top(explorer->head_area, 0, 0);
|
||||
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
/*Quick access bar container style*/
|
||||
lv_obj_set_style_pad_all(explorer->quick_access_area, 0, 0);
|
||||
lv_obj_set_style_pad_row(explorer->quick_access_area, 20, 0);
|
||||
lv_obj_set_style_radius(explorer->quick_access_area, 0, 0);
|
||||
lv_obj_set_style_border_width(explorer->quick_access_area, 1, 0);
|
||||
lv_obj_set_style_outline_width(explorer->quick_access_area, 0, 0);
|
||||
lv_obj_set_style_bg_color(explorer->quick_access_area, lv_color_hex(0xf2f1f6), 0);
|
||||
#endif
|
||||
|
||||
/*File browser container style*/
|
||||
lv_obj_set_style_pad_all(explorer->browser_area, 0, 0);
|
||||
lv_obj_set_style_pad_row(explorer->browser_area, 0, 0);
|
||||
lv_obj_set_style_radius(explorer->browser_area, 0, 0);
|
||||
lv_obj_set_style_border_width(explorer->browser_area, 0, 0);
|
||||
lv_obj_set_style_outline_width(explorer->browser_area, 0, 0);
|
||||
lv_obj_set_style_bg_color(explorer->browser_area, lv_color_hex(0xffffff), 0);
|
||||
|
||||
/*Style of the table in the browser container*/
|
||||
lv_obj_set_style_bg_color(explorer->file_table, lv_color_hex(0xffffff), 0);
|
||||
lv_obj_set_style_pad_all(explorer->file_table, 0, 0);
|
||||
lv_obj_set_style_radius(explorer->file_table, 0, 0);
|
||||
lv_obj_set_style_border_width(explorer->file_table, 0, 0);
|
||||
lv_obj_set_style_outline_width(explorer->file_table, 0, 0);
|
||||
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
/*Style of the list in the quick access bar*/
|
||||
lv_obj_set_style_border_width(explorer->list_device, 0, 0);
|
||||
lv_obj_set_style_outline_width(explorer->list_device, 0, 0);
|
||||
lv_obj_set_style_radius(explorer->list_device, 0, 0);
|
||||
lv_obj_set_style_pad_all(explorer->list_device, 0, 0);
|
||||
|
||||
lv_obj_set_style_border_width(explorer->list_places, 0, 0);
|
||||
lv_obj_set_style_outline_width(explorer->list_places, 0, 0);
|
||||
lv_obj_set_style_radius(explorer->list_places, 0, 0);
|
||||
lv_obj_set_style_pad_all(explorer->list_places, 0, 0);
|
||||
|
||||
/*Style of the quick access list btn in the quick access bar*/
|
||||
lv_style_init(&quick_access_list_button_style);
|
||||
lv_style_set_border_width(&quick_access_list_button_style, 0);
|
||||
lv_style_set_bg_color(&quick_access_list_button_style, lv_color_hex(0xf2f1f6));
|
||||
|
||||
uint32_t ch_cnt = lv_obj_get_child_count(explorer->quick_access_area);
|
||||
|
||||
for(uint32_t i = 0; i < ch_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(explorer->quick_access_area, i);
|
||||
|
||||
if(lv_obj_check_type(child, &lv_list_class)) {
|
||||
uint32_t list_ch_cnt = lv_obj_get_child_count(child);
|
||||
|
||||
for(uint32_t j = 0; j < list_ch_cnt; j++) {
|
||||
lv_obj_t * list_child = lv_obj_get_child(child, j);
|
||||
if(lv_obj_check_type(list_child, &lv_list_button_class)) {
|
||||
lv_obj_add_style(list_child, &quick_access_list_button_style, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
static void quick_access_event_handler(lv_event_t * e)
|
||||
{
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
lv_obj_t * btn = lv_event_get_current_target(e);
|
||||
lv_obj_t * obj = lv_event_get_user_data(e);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
if(code == LV_EVENT_CLICKED) {
|
||||
char ** path = NULL;
|
||||
lv_obj_t * label = lv_obj_get_child(btn, -1);
|
||||
char * label_text = lv_label_get_text(label);
|
||||
|
||||
if((lv_strcmp(label_text, LV_SYMBOL_HOME " HOME") == 0)) {
|
||||
path = &(explorer->home_dir);
|
||||
}
|
||||
else if((lv_strcmp(label_text, LV_SYMBOL_VIDEO " Video") == 0)) {
|
||||
path = &(explorer->video_dir);
|
||||
}
|
||||
else if((lv_strcmp(label_text, LV_SYMBOL_IMAGE " Pictures") == 0)) {
|
||||
path = &(explorer->pictures_dir);
|
||||
}
|
||||
else if((lv_strcmp(label_text, LV_SYMBOL_AUDIO " Music") == 0)) {
|
||||
path = &(explorer->music_dir);
|
||||
}
|
||||
else if((lv_strcmp(label_text, LV_SYMBOL_FILE " Documents") == 0)) {
|
||||
path = &(explorer->docs_dir);
|
||||
}
|
||||
else if((lv_strcmp(label_text, LV_SYMBOL_DRIVE " File System") == 0)) {
|
||||
path = &(explorer->fs_dir);
|
||||
}
|
||||
|
||||
if(path != NULL)
|
||||
show_dir(obj, *path);
|
||||
}
|
||||
}
|
||||
|
||||
static void quick_access_area_event_handler(lv_event_t * e)
|
||||
{
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
lv_obj_t * area = lv_event_get_current_target(e);
|
||||
lv_obj_t * obj = lv_event_get_user_data(e);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
if(code == LV_EVENT_LAYOUT_CHANGED) {
|
||||
if(lv_obj_has_flag(area, LV_OBJ_FLAG_HIDDEN))
|
||||
lv_obj_set_size(explorer->browser_area, LV_PCT(100), LV_PCT(100));
|
||||
else
|
||||
lv_obj_set_size(explorer->browser_area, LV_PCT(FILE_EXPLORER_BROWSER_AREA_WIDTH), LV_PCT(100));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void browser_file_event_handler(lv_event_t * e)
|
||||
{
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
lv_obj_t * obj = lv_event_get_user_data(e);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
lv_indev_type_t type = lv_indev_get_type(lv_indev_active());
|
||||
lv_event_code_t active_code = type == LV_INDEV_TYPE_POINTER ||
|
||||
type == LV_INDEV_TYPE_BUTTON ? LV_EVENT_VALUE_CHANGED : LV_EVENT_CLICKED;
|
||||
|
||||
if(code == active_code) {
|
||||
char file_name[LV_FILE_EXPLORER_PATH_MAX_LEN];
|
||||
const char * selected_text = NULL;
|
||||
const lv_file_explorer_file_table_entry_data_t * file_entry_user_data = NULL;
|
||||
uint32_t row;
|
||||
uint32_t col;
|
||||
uint8_t navigate_to_parent_dir = 0;
|
||||
uint8_t navigate_to_child = 0;
|
||||
|
||||
lv_memzero(file_name, sizeof(file_name));
|
||||
lv_table_get_selected_cell(explorer->file_table, &row, &col);
|
||||
selected_text = lv_table_get_cell_value(explorer->file_table, row, col);
|
||||
file_entry_user_data = lv_table_get_cell_user_data(explorer->file_table, row, col);
|
||||
|
||||
selected_text = selected_text + 5; /* skip table cell format */
|
||||
|
||||
/* Three navigation modes are supported:
|
||||
* - Navigate to current directory
|
||||
* - Navigate to parent directory
|
||||
* - Navigate to (current directory) child */
|
||||
navigate_to_parent_dir = (lv_strcmp(selected_text, LV_FILE_NAVIGATION_PARENT_DIR) == 0);
|
||||
navigate_to_child = !navigate_to_parent_dir;
|
||||
|
||||
|
||||
if((navigate_to_parent_dir) && (lv_strlen(explorer->current_path) > 3)) {
|
||||
lv_strlcpy(file_name, explorer->current_path, sizeof(file_name));
|
||||
strip_ext(file_name);
|
||||
/*Remove the last '/' character*/
|
||||
strip_ext(file_name);
|
||||
|
||||
/* Append / at the end */
|
||||
size_t stripped_file_name_length = lv_strlen(file_name);
|
||||
*(file_name + stripped_file_name_length) = '/';
|
||||
if(stripped_file_name_length + 1 < LV_FILE_EXPLORER_PATH_MAX_LEN) {
|
||||
*(file_name + stripped_file_name_length + 1) = '\0';
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(navigate_to_child) {
|
||||
lv_snprintf((char *)file_name, sizeof(file_name), "%s%s", explorer->current_path, selected_text);
|
||||
}
|
||||
else if(navigate_to_parent_dir) { /* We are most likely in the drive letter directory, doesn't have parent directory */
|
||||
return;
|
||||
}
|
||||
else { /* Nothing to do*/ }
|
||||
}
|
||||
|
||||
/* Navigate to the file path if this is a directory */
|
||||
if(file_entry_user_data->file_kind == LV_FILE_EXPLORER_FILE_KIND_DIR) {
|
||||
lv_fs_dir_t dir;
|
||||
lv_fs_res_t res = lv_fs_dir_open(&dir, file_name);
|
||||
if(res == LV_FS_RES_OK) {
|
||||
lv_fs_dir_close(&dir);
|
||||
show_dir(obj, (char *)file_name);
|
||||
}
|
||||
else {
|
||||
LV_LOG_USER("Could not navigate to %s (error: %d)", file_name, res);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(navigate_to_child) {
|
||||
explorer->sel_fn = selected_text;
|
||||
lv_obj_send_event(obj, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(code == LV_EVENT_SIZE_CHANGED) {
|
||||
lv_table_set_column_width(explorer->file_table, 0, lv_obj_get_width(explorer->file_table));
|
||||
}
|
||||
}
|
||||
|
||||
static void show_dir(lv_obj_t * obj, const char * path)
|
||||
{
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
char fn[LV_FILE_EXPLORER_PATH_MAX_LEN];
|
||||
uint16_t index = 0;
|
||||
lv_fs_dir_t dir;
|
||||
lv_fs_res_t res;
|
||||
lv_file_explorer_file_table_entry_data_t * file_entry_user_data;
|
||||
|
||||
res = lv_fs_dir_open(&dir, path);
|
||||
if(res != LV_FS_RES_OK) {
|
||||
LV_LOG_USER("Open dir error %d!", res);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_table_set_cell_value(explorer->file_table, index++, 0, LV_SYMBOL_LEFT " " LV_FILE_NAVIGATION_PARENT_DIR);
|
||||
file_entry_user_data = lv_malloc(sizeof(lv_file_explorer_file_table_entry_data_t));
|
||||
LV_ASSERT_MALLOC(file_entry_user_data);
|
||||
file_entry_user_data->file_kind = LV_FILE_EXPLORER_FILE_KIND_DIR;
|
||||
lv_table_set_cell_user_data(explorer->file_table, 0, 0, file_entry_user_data);
|
||||
|
||||
while(1) {
|
||||
res = lv_fs_dir_read(&dir, fn, sizeof(fn));
|
||||
if(res != LV_FS_RES_OK) {
|
||||
LV_LOG_USER("Driver, file or directory does not exist %d!", res);
|
||||
break;
|
||||
}
|
||||
|
||||
/*fn is empty, if not more files to read*/
|
||||
if(lv_strlen(fn) == 0) {
|
||||
LV_LOG_USER("No more files to read!");
|
||||
break;
|
||||
}
|
||||
|
||||
file_entry_user_data = lv_malloc(sizeof(lv_file_explorer_file_table_entry_data_t));
|
||||
LV_ASSERT_MALLOC(file_entry_user_data);
|
||||
|
||||
if((is_end_with(fn, ".png") == true) || (is_end_with(fn, ".PNG") == true) || \
|
||||
(is_end_with(fn, ".jpg") == true) || (is_end_with(fn, ".JPG") == true) || \
|
||||
(is_end_with(fn, ".bmp") == true) || (is_end_with(fn, ".BMP") == true) || \
|
||||
(is_end_with(fn, ".gif") == true) || (is_end_with(fn, ".GIF") == true)) {
|
||||
lv_table_set_cell_value_fmt(explorer->file_table, index, 0, LV_SYMBOL_IMAGE " %s", fn);
|
||||
file_entry_user_data->file_kind = LV_FILE_EXPLORER_FILE_KIND_IMAGE;
|
||||
}
|
||||
else if((is_end_with(fn, ".mp3") == true) || (is_end_with(fn, ".MP3") == true) || \
|
||||
(is_end_with(fn, ".wav") == true) || (is_end_with(fn, ".WAV") == true)) {
|
||||
lv_table_set_cell_value_fmt(explorer->file_table, index, 0, LV_SYMBOL_AUDIO " %s", fn);
|
||||
file_entry_user_data->file_kind = LV_FILE_EXPLORER_FILE_KIND_AUDIO;
|
||||
}
|
||||
else if((is_end_with(fn, ".mp4") == true) || (is_end_with(fn, ".MP4") == true)) {
|
||||
lv_table_set_cell_value_fmt(explorer->file_table, index, 0, LV_SYMBOL_VIDEO " %s", fn);
|
||||
file_entry_user_data->file_kind = LV_FILE_EXPLORER_FILE_KIND_VIDEO;
|
||||
}
|
||||
else if((is_end_with(fn, ".") == true) || (is_end_with(fn, "..") == true)) {
|
||||
/*is dir*/
|
||||
continue;
|
||||
}
|
||||
else if(fn[0] == '/') {/*is dir*/
|
||||
lv_table_set_cell_value_fmt(explorer->file_table, index, 0, LV_SYMBOL_DIRECTORY " %s", fn + 1);
|
||||
file_entry_user_data->file_kind = LV_FILE_EXPLORER_FILE_KIND_DIR;
|
||||
}
|
||||
else {
|
||||
lv_table_set_cell_value_fmt(explorer->file_table, index, 0, LV_SYMBOL_FILE " %s", fn);
|
||||
file_entry_user_data->file_kind = LV_FILE_EXPLORER_FILE_KIND_FILE;
|
||||
}
|
||||
|
||||
lv_table_set_cell_user_data(explorer->file_table, index, 0, file_entry_user_data);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
lv_fs_dir_close(&dir);
|
||||
|
||||
lv_table_set_row_count(explorer->file_table, index);
|
||||
file_explorer_sort(obj);
|
||||
lv_obj_send_event(obj, LV_EVENT_READY, NULL);
|
||||
|
||||
/*Move the table to the top*/
|
||||
lv_obj_scroll_to_y(explorer->file_table, 0, LV_ANIM_OFF);
|
||||
|
||||
lv_strncpy(explorer->current_path, path, sizeof(explorer->current_path));
|
||||
lv_label_set_text_fmt(explorer->path_label, LV_SYMBOL_EYE_OPEN" %s", path);
|
||||
|
||||
size_t current_path_len = lv_strlen(explorer->current_path);
|
||||
if((explorer->current_path[current_path_len - 1] != '/') && (current_path_len < LV_FILE_EXPLORER_PATH_MAX_LEN)) {
|
||||
*((explorer->current_path) + current_path_len) = '/';
|
||||
}
|
||||
}
|
||||
|
||||
/*Remove the specified suffix*/
|
||||
static void strip_ext(char * dir)
|
||||
{
|
||||
char * end = dir + lv_strlen(dir);
|
||||
|
||||
while(end >= dir && *end != '/') {
|
||||
--end;
|
||||
}
|
||||
|
||||
if(end > dir) {
|
||||
*end = '\0';
|
||||
}
|
||||
else if(end == dir) {
|
||||
*(end + 1) = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static void exch_table_item(lv_obj_t * tb, int16_t i, int16_t j)
|
||||
{
|
||||
if(i == j) return;
|
||||
const char * i_value = lv_table_get_cell_value(tb, i, 0);
|
||||
|
||||
char * tmp_i_value = lv_malloc(lv_strlen(i_value) + 1);
|
||||
LV_ASSERT_MALLOC(tmp_i_value);
|
||||
lv_strcpy(tmp_i_value, i_value);
|
||||
|
||||
//*Will be freed when the table is freed. The previous user data is freed when the new one is set*/
|
||||
lv_file_explorer_file_table_entry_data_t * tmp_i_user_data = lv_malloc(sizeof(
|
||||
lv_file_explorer_file_table_entry_data_t));
|
||||
LV_ASSERT_MALLOC(tmp_i_user_data);
|
||||
lv_memcpy(tmp_i_user_data, lv_table_get_cell_user_data(tb, i, 0), sizeof(lv_file_explorer_file_table_entry_data_t));
|
||||
|
||||
lv_file_explorer_file_table_entry_data_t * tmp_j_user_data = lv_malloc(sizeof(
|
||||
lv_file_explorer_file_table_entry_data_t));
|
||||
LV_ASSERT_MALLOC(tmp_j_user_data);
|
||||
lv_memcpy(tmp_j_user_data, lv_table_get_cell_user_data(tb, j, 0), sizeof(lv_file_explorer_file_table_entry_data_t));
|
||||
|
||||
lv_table_set_cell_value(tb, i, 0, lv_table_get_cell_value(tb, j, 0));
|
||||
lv_table_set_cell_user_data(tb, i, 0, tmp_j_user_data);
|
||||
|
||||
lv_table_set_cell_value(tb, j, 0, tmp_i_value);
|
||||
lv_table_set_cell_user_data(tb, j, 0, tmp_i_user_data);
|
||||
|
||||
lv_free(tmp_i_value);
|
||||
}
|
||||
|
||||
static void file_explorer_sort(lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_file_explorer_t * explorer = (lv_file_explorer_t *)obj;
|
||||
|
||||
uint16_t sum = lv_table_get_row_count(explorer->file_table);
|
||||
|
||||
if(sum > 1) {
|
||||
switch(explorer->sort) {
|
||||
case LV_EXPLORER_SORT_NONE:
|
||||
break;
|
||||
case LV_EXPLORER_SORT_KIND:
|
||||
sort_by_file_kind(explorer->file_table, 0, (sum - 1));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Quick sort 3 way*/
|
||||
static void sort_by_file_kind(lv_obj_t * tb, int16_t lo, int16_t hi)
|
||||
{
|
||||
if(lo >= hi) return;
|
||||
|
||||
int16_t lt = lo;
|
||||
int16_t i = lo + 1;
|
||||
int16_t gt = hi;
|
||||
lv_file_explorer_file_table_entry_data_t * v = lv_table_get_cell_user_data(tb, lo, 0);
|
||||
while(i <= gt) {
|
||||
lv_file_explorer_file_table_entry_data_t * x = lv_table_get_cell_user_data(tb, i, 0);
|
||||
if(x->file_kind < v->file_kind)
|
||||
exch_table_item(tb, lt++, i++);
|
||||
else if(x->file_kind > v->file_kind)
|
||||
exch_table_item(tb, i, gt--);
|
||||
else
|
||||
i++;
|
||||
}
|
||||
|
||||
sort_by_file_kind(tb, lo, lt - 1);
|
||||
sort_by_file_kind(tb, gt + 1, hi);
|
||||
}
|
||||
|
||||
static bool is_end_with(const char * str1, const char * str2)
|
||||
{
|
||||
if(str1 == NULL || str2 == NULL)
|
||||
return false;
|
||||
|
||||
size_t len1 = lv_strlen(str1);
|
||||
size_t len2 = lv_strlen(str2);
|
||||
if((len1 < len2) || (len1 == 0 || len2 == 0))
|
||||
return false;
|
||||
|
||||
while(len2 >= 1) {
|
||||
if(str2[len2 - 1] != str1[len1 - 1])
|
||||
return false;
|
||||
|
||||
len2--;
|
||||
len1--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_FILE_EXPLORER*/
|
||||
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* @file lv_file_explorer.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_FILE_EXPLORER_H
|
||||
#define LV_FILE_EXPLORER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../lv_conf_internal.h"
|
||||
#include "../../core/lv_obj.h"
|
||||
|
||||
#if LV_USE_FILE_EXPLORER != 0
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
LV_EXPLORER_SORT_NONE,
|
||||
LV_EXPLORER_SORT_KIND,
|
||||
} lv_file_explorer_sort_t;
|
||||
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
typedef enum {
|
||||
LV_EXPLORER_HOME_DIR,
|
||||
LV_EXPLORER_MUSIC_DIR,
|
||||
LV_EXPLORER_PICTURES_DIR,
|
||||
LV_EXPLORER_VIDEO_DIR,
|
||||
LV_EXPLORER_DOCS_DIR,
|
||||
LV_EXPLORER_FS_DIR,
|
||||
} lv_file_explorer_dir_t;
|
||||
#endif
|
||||
|
||||
extern const lv_obj_class_t lv_file_explorer_class;
|
||||
|
||||
/***********************
|
||||
* GLOBAL VARIABLES
|
||||
***********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
lv_obj_t * lv_file_explorer_create(lv_obj_t * parent);
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
/**
|
||||
* Set file_explorer
|
||||
* @param obj pointer to a label object
|
||||
* @param dir the dir from 'lv_file_explorer_dir_t' enum.
|
||||
* @param path path
|
||||
|
||||
*/
|
||||
void lv_file_explorer_set_quick_access_path(lv_obj_t * obj, lv_file_explorer_dir_t dir, const char * path);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set file_explorer sort
|
||||
* @param obj pointer to a file explorer object
|
||||
* @param sort the sort from 'lv_file_explorer_sort_t' enum.
|
||||
*/
|
||||
void lv_file_explorer_set_sort(lv_obj_t * obj, lv_file_explorer_sort_t sort);
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Get file explorer Selected file
|
||||
* @param obj pointer to a file explorer object
|
||||
* @return pointer to the file explorer selected file name
|
||||
*/
|
||||
const char * lv_file_explorer_get_selected_file_name(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get file explorer cur path
|
||||
* @param obj pointer to a file explorer object
|
||||
* @return pointer to the file explorer cur path
|
||||
*/
|
||||
const char * lv_file_explorer_get_current_path(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get file explorer file list obj(lv_table)
|
||||
* @param obj pointer to a file explorer object
|
||||
* @return pointer to the file explorer file table obj(lv_table)
|
||||
*/
|
||||
lv_obj_t * lv_file_explorer_get_file_table(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get file explorer head area obj
|
||||
* @param obj pointer to a file explorer object
|
||||
* @return pointer to the file explorer head area obj(lv_obj)
|
||||
*/
|
||||
lv_obj_t * lv_file_explorer_get_header(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get file explorer path obj(label)
|
||||
* @param obj pointer to a file explorer object
|
||||
* @return pointer to the file explorer path obj(lv_label)
|
||||
*/
|
||||
lv_obj_t * lv_file_explorer_get_path_label(lv_obj_t * obj);
|
||||
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
/**
|
||||
* Get file explorer head area obj
|
||||
* @param obj pointer to a file explorer object
|
||||
* @return pointer to the file explorer quick access area obj(lv_obj)
|
||||
*/
|
||||
lv_obj_t * lv_file_explorer_get_quick_access_area(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get file explorer places list obj(lv_list)
|
||||
* @param obj pointer to a file explorer object
|
||||
* @return pointer to the file explorer places list obj(lv_list)
|
||||
*/
|
||||
lv_obj_t * lv_file_explorer_get_places_list(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get file explorer device list obj(lv_list)
|
||||
* @param obj pointer to a file explorer object
|
||||
* @return pointer to the file explorer device list obj(lv_list)
|
||||
*/
|
||||
lv_obj_t * lv_file_explorer_get_device_list(lv_obj_t * obj);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set file_explorer sort
|
||||
* @param obj pointer to a file explorer object
|
||||
* @return the current mode from 'lv_file_explorer_sort_t'
|
||||
*/
|
||||
lv_file_explorer_sort_t lv_file_explorer_get_sort(const lv_obj_t * obj);
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Open a specified path
|
||||
* @param obj pointer to a file explorer object
|
||||
* @param dir pointer to the path
|
||||
*/
|
||||
void lv_file_explorer_open_dir(lv_obj_t * obj, const char * dir);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_FILE_EXPLORER*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_FILE_EXPLORER_H*/
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* @file lv_file_explorer_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_FILE_EXPLORER_PRIVATE_H
|
||||
#define LV_FILE_EXPLORER_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../core/lv_obj_private.h"
|
||||
#include "lv_file_explorer.h"
|
||||
|
||||
#if LV_USE_FILE_EXPLORER != 0
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/*Data of canvas*/
|
||||
struct _lv_file_explorer_t {
|
||||
lv_obj_t obj;
|
||||
lv_obj_t * cont;
|
||||
lv_obj_t * head_area;
|
||||
lv_obj_t * browser_area;
|
||||
lv_obj_t * file_table;
|
||||
lv_obj_t * path_label;
|
||||
#if LV_FILE_EXPLORER_QUICK_ACCESS
|
||||
lv_obj_t * quick_access_area;
|
||||
lv_obj_t * list_device;
|
||||
lv_obj_t * list_places;
|
||||
char * home_dir;
|
||||
char * music_dir;
|
||||
char * pictures_dir;
|
||||
char * video_dir;
|
||||
char * docs_dir;
|
||||
char * fs_dir;
|
||||
#endif
|
||||
const char * sel_fn;
|
||||
char current_path[LV_FILE_EXPLORER_PATH_MAX_LEN];
|
||||
lv_file_explorer_sort_t sort;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
LV_FILE_EXPLORER_FILE_KIND_DIR,
|
||||
LV_FILE_EXPLORER_FILE_KIND_IMAGE,
|
||||
LV_FILE_EXPLORER_FILE_KIND_AUDIO,
|
||||
LV_FILE_EXPLORER_FILE_KIND_VIDEO,
|
||||
LV_FILE_EXPLORER_FILE_KIND_FILE
|
||||
} lv_file_explorer_file_kind_t;
|
||||
|
||||
typedef struct {
|
||||
lv_file_explorer_file_kind_t file_kind;
|
||||
} lv_file_explorer_file_table_entry_data_t;
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /* LV_USE_FILE_EXPLORER != 0 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_FILE_EXPLORER_PRIVATE_H*/
|
||||
Reference in New Issue
Block a user