├── lv_apps.h ├── src ├── lv_menu │ ├── lv_menu.c │ ├── lv_menu.h │ └── lv_menu.mk ├── lv_wifi │ ├── lv_wifi.c │ ├── lv_wifi.h │ └── lv_wifi.mk ├── lv_demo │ ├── bubble_pattern.png │ ├── lv_demo.mk │ ├── lv_demo.h │ └── lv_demo.c ├── lv_benchmark │ ├── benchmark_bg.png │ ├── lv_benchmark.mk │ ├── lv_benchmark.h │ └── lv_benchmark.c ├── lv_tpcal │ ├── lv_tpcal.mk │ ├── lv_tpcal.h │ └── lv_tpcal.c ├── lv_sysmon │ ├── lv_sysmon.mk │ ├── lv_sysmon.h │ └── lv_sysmon.c ├── lv_settings │ ├── lv_settings.mk │ ├── lv_settings.h │ ├── README.md │ └── lv_settings.c ├── lv_terminal │ ├── lv_terminal.mk │ ├── lv_terminal.h │ └── lv_terminal.c └── lv_apps.mk ├── misc ├── lv_settings_btn.gif ├── lv_settings_sw.gif ├── lv_settings_ddlist.gif ├── lv_settings_numset.gif ├── lv_settings_slider.gif └── lv_settings_list_btn.png ├── README.md ├── examples └── lv_ex_settings │ ├── lv_ex_settings_2.gif │ ├── lv_ex_settings_1.c │ └── lv_ex_settings_2.c ├── .gitignore └── LICENSE /lv_apps.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/lv_menu/lv_menu.c: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/lv_menu/lv_menu.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/lv_wifi/lv_wifi.c: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/lv_wifi/lv_wifi.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /misc/lv_settings_btn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgl/lv_apps/HEAD/misc/lv_settings_btn.gif -------------------------------------------------------------------------------- /misc/lv_settings_sw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgl/lv_apps/HEAD/misc/lv_settings_sw.gif -------------------------------------------------------------------------------- /misc/lv_settings_ddlist.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgl/lv_apps/HEAD/misc/lv_settings_ddlist.gif -------------------------------------------------------------------------------- /misc/lv_settings_numset.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgl/lv_apps/HEAD/misc/lv_settings_numset.gif -------------------------------------------------------------------------------- /misc/lv_settings_slider.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgl/lv_apps/HEAD/misc/lv_settings_slider.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Application UIs with LVGL 2 | 3 | > This repository will be archived on 1st August 2020. 4 | -------------------------------------------------------------------------------- /misc/lv_settings_list_btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgl/lv_apps/HEAD/misc/lv_settings_list_btn.png -------------------------------------------------------------------------------- /src/lv_demo/bubble_pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgl/lv_apps/HEAD/src/lv_demo/bubble_pattern.png -------------------------------------------------------------------------------- /src/lv_benchmark/benchmark_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgl/lv_apps/HEAD/src/lv_benchmark/benchmark_bg.png -------------------------------------------------------------------------------- /examples/lv_ex_settings/lv_ex_settings_2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgl/lv_apps/HEAD/examples/lv_ex_settings/lv_ex_settings_2.gif -------------------------------------------------------------------------------- /src/lv_menu/lv_menu.mk: -------------------------------------------------------------------------------- 1 | CSRCS += lv_menu.c 2 | 3 | DEPPATH += --dep-path $(LVGL_DIR)/lv_apps/lv_menu 4 | VPATH += :$(LVGL_DIR)/lv_apps/lv_menu 5 | 6 | CFLAGS += "-I$(LVGL_DIR)/lv_apps/lv_menu" 7 | -------------------------------------------------------------------------------- /src/lv_wifi/lv_wifi.mk: -------------------------------------------------------------------------------- 1 | CSRCS += lv_wifi.c 2 | 3 | DEPPATH += --dep-path $(LVGL_DIR)/lv_apps/lv_wifi 4 | VPATH += :$(LVGL_DIR)/lv_apps/lv_wifi 5 | 6 | CFLAGS += "-I$(LVGL_DIR)/lv_apps/lv_wifi" 7 | -------------------------------------------------------------------------------- /src/lv_tpcal/lv_tpcal.mk: -------------------------------------------------------------------------------- 1 | CSRCS += lv_tpcal.c 2 | 3 | DEPPATH += --dep-path $(LVGL_DIR)/lv_apps/lv_tpcal 4 | VPATH += :$(LVGL_DIR)/lv_apps/lv_tpcal 5 | 6 | CFLAGS += "-I$(LVGL_DIR)/lv_apps/lv_tpcal" 7 | -------------------------------------------------------------------------------- /src/lv_sysmon/lv_sysmon.mk: -------------------------------------------------------------------------------- 1 | CSRCS += lv_sysmon.c 2 | 3 | DEPPATH += --dep-path $(LVGL_DIR)/lv_apps/lv_sysmon 4 | VPATH += :$(LVGL_DIR)/lv_apps/lv_sysmon 5 | 6 | CFLAGS += "-I$(LVGL_DIR)/lv_apps/lv_sysmon" 7 | -------------------------------------------------------------------------------- /src/lv_settings/lv_settings.mk: -------------------------------------------------------------------------------- 1 | CSRCS += lv_settings.c 2 | 3 | DEPPATH += --dep-path $(LVGL_DIR)/lv_apps/settings 4 | VPATH += :$(LVGL_DIR)/lv_apps/lv_settings 5 | 6 | CFLAGS += "-I$(LVGL_DIR)/lv_apps/lv_settings" 7 | -------------------------------------------------------------------------------- /src/lv_terminal/lv_terminal.mk: -------------------------------------------------------------------------------- 1 | CSRCS += lv_terminal.c 2 | 3 | DEPPATH += --dep-path $(LVGL_DIR)/lv_apps/lv_terminal 4 | VPATH += :$(LVGL_DIR)/lv_apps/lv_terminal 5 | 6 | CFLAGS += "-I$(LVGL_DIR)/lv_apps/lv_terminal" 7 | -------------------------------------------------------------------------------- /src/lv_demo/lv_demo.mk: -------------------------------------------------------------------------------- 1 | CSRCS += lv_demo.c 2 | CSRCS += lv_img_bubble_pattern.c 3 | 4 | DEPPATH += --dep-path $(LVGL_DIR)lv_apps/lv_demo 5 | VPATH += :$(LVGL_DIR)/lv_apps/lv_demo 6 | 7 | CFLAGS += "-I$(LVGL_DIR)/lv_apps/lv_demo" 8 | -------------------------------------------------------------------------------- /src/lv_benchmark/lv_benchmark.mk: -------------------------------------------------------------------------------- 1 | CSRCS += lv_benchmark.c 2 | CSRCS += lv_benchmark_bg.c 3 | 4 | DEPPATH += --dep-path $(LVGL_DIR)/lv_apps/lv_benchmark 5 | VPATH += :$(LVGL_DIR)/lv_apps/lv_benchmark 6 | 7 | CFLAGS += "-I$(LVGL_DIR)lv_apps/lv_benchmark" 8 | -------------------------------------------------------------------------------- /src/lv_apps.mk: -------------------------------------------------------------------------------- 1 | include $(LVGL_DIR)/lv_apps/lv_benchmark/lv_benchmark.mk 2 | include $(LVGL_DIR)/lv_apps/lv_demo/lv_demo.mk 3 | include $(LVGL_DIR)/lv_apps/lv_sysmon/lv_sysmon.mk 4 | include $(LVGL_DIR)/lv_apps/lv_terminal/lv_terminal.mk 5 | include $(LVGL_DIR)/lv_apps/lv_tpcal/lv_tpcal.mk 6 | include $(LVGL_DIR)/lv_apps/lv_menu/lv_menu.mk 7 | include $(LVGL_DIR)/lv_apps/lv_wifi/lv_wifi.mk 8 | include $(LVGL_DIR)/lv_apps/lv_settings/lv_settings.mk 9 | 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /src/lv_demo/lv_demo.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file demo.h 3 | * 4 | */ 5 | 6 | #ifndef DEMO_H 7 | #define DEMO_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lvgl.h" 19 | #include "lv_ex_conf.h" 20 | #else 21 | #include "../../../lvgl/lvgl.h" 22 | #include "../../../lv_ex_conf.h" 23 | #endif 24 | 25 | #if LV_USE_DEMO 26 | 27 | /********************* 28 | * DEFINES 29 | *********************/ 30 | 31 | /********************** 32 | * TYPEDEFS 33 | **********************/ 34 | 35 | /********************** 36 | * GLOBAL PROTOTYPES 37 | **********************/ 38 | 39 | /** 40 | * Create a demo application 41 | */ 42 | void demo_create(void); 43 | 44 | /********************** 45 | * MACROS 46 | **********************/ 47 | 48 | #endif /*LV_USE_DEMO*/ 49 | 50 | #ifdef __cplusplus 51 | } /* extern "C" */ 52 | #endif 53 | 54 | #endif /*DEMO_H*/ 55 | -------------------------------------------------------------------------------- /src/lv_sysmon/lv_sysmon.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file symon.h 3 | * 4 | */ 5 | 6 | #ifndef SYSMON_H 7 | #define SYSMON_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifdef LV_CONF_INCLUDE_SIMPLE 17 | #include "lvgl.h" 18 | #include "lv_ex_conf.h" 19 | #else 20 | #include "../../../lvgl/lvgl.h" 21 | #include "../../../lv_ex_conf.h" 22 | #endif 23 | #if LV_USE_DEMO 24 | 25 | /********************* 26 | * DEFINES 27 | *********************/ 28 | 29 | /********************** 30 | * TYPEDEFS 31 | **********************/ 32 | 33 | /********************** 34 | * GLOBAL PROTOTYPES 35 | **********************/ 36 | 37 | /** 38 | * Initialize the system monitor 39 | */ 40 | void sysmon_create(void); 41 | 42 | /********************** 43 | * MACROS 44 | **********************/ 45 | 46 | #endif /*LV_USE_SYSMON*/ 47 | 48 | #ifdef __cplusplus 49 | } /* extern "C" */ 50 | #endif 51 | 52 | #endif /* SYSMON_H */ 53 | -------------------------------------------------------------------------------- /src/lv_tpcal/lv_tpcal.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file tpcal.h 3 | * 4 | */ 5 | 6 | #ifndef TPCAL_H 7 | #define TPCAL_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifdef LV_CONF_INCLUDE_SIMPLE 17 | #include "lvgl.h" 18 | #include "lv_ex_conf.h" 19 | #else 20 | #include "../../../lvgl/lvgl.h" 21 | #include "../../../lv_ex_conf.h" 22 | #endif 23 | 24 | 25 | #if LV_USE_DEMO 26 | 27 | /********************* 28 | * DEFINES 29 | *********************/ 30 | 31 | /********************** 32 | * TYPEDEFS 33 | **********************/ 34 | 35 | /********************** 36 | * GLOBAL PROTOTYPES 37 | **********************/ 38 | 39 | /** 40 | * Create a touch pad calibration screen 41 | */ 42 | void tpcal_create(void); 43 | 44 | /********************** 45 | * MACROS 46 | **********************/ 47 | 48 | #endif /*LV_USE_TPCAL*/ 49 | 50 | #ifdef __cplusplus 51 | } /* extern "C" */ 52 | #endif 53 | 54 | #endif /*TP_CAL_H*/ 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 LittlevGL 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/lv_benchmark/lv_benchmark.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file benchmark.h 3 | * 4 | */ 5 | 6 | #ifndef BENCHMARK_H 7 | #define BENCHMARK_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lvgl.h" 19 | #include "lv_ex_conf.h" 20 | #else 21 | #include "../../../lvgl/lvgl.h" 22 | #include "../../../lv_ex_conf.h" 23 | #endif 24 | 25 | #if LV_USE_BENCHMARK 26 | 27 | 28 | /********************* 29 | * DEFINES 30 | *********************/ 31 | 32 | /********************** 33 | * TYPEDEFS 34 | **********************/ 35 | 36 | /********************** 37 | * GLOBAL PROTOTYPES 38 | **********************/ 39 | 40 | /** 41 | * Open a graphics benchmark 42 | */ 43 | void benchmark_create(void); 44 | 45 | void benchmark_start(void); 46 | 47 | bool benchmark_is_ready(void); 48 | 49 | uint32_t benchmark_get_refr_time(void); 50 | 51 | /********************** 52 | * MACROS 53 | **********************/ 54 | 55 | #endif /*LV_USE_BENCHMARK*/ 56 | 57 | #ifdef __cplusplus 58 | } /* extern "C" */ 59 | #endif 60 | 61 | #endif /* BENCHMARK_H */ 62 | -------------------------------------------------------------------------------- /src/lv_terminal/lv_terminal.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file terminal.h 3 | * 4 | */ 5 | 6 | #ifndef TERMINAL_H 7 | #define TERMINAL_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifdef LV_CONF_INCLUDE_SIMPLE 17 | #include "lvgl.h" 18 | #include "lv_ex_conf.h" 19 | #else 20 | #include "../../../lvgl/lvgl.h" 21 | #include "../../../lv_ex_conf.h" 22 | #endif 23 | 24 | #if LV_USE_DEMO 25 | 26 | /********************* 27 | * DEFINES 28 | *********************/ 29 | 30 | /********************** 31 | * TYPEDEFS 32 | **********************/ 33 | 34 | /********************** 35 | * GLOBAL PROTOTYPES 36 | **********************/ 37 | 38 | /** 39 | * Open a terminal 40 | * @return pointer to the terminal window 41 | */ 42 | lv_obj_t * terminal_create(void); 43 | 44 | /** 45 | * Add data to the terminal 46 | * @param txt_in character sting to add to the terminal 47 | */ 48 | void terminal_add(const char * txt_in); 49 | 50 | /********************** 51 | * MACROS 52 | **********************/ 53 | 54 | #endif /*LV_USE_TERMINAL*/ 55 | 56 | #ifdef __cplusplus 57 | } /* extern "C" */ 58 | #endif 59 | 60 | #endif /* LV_TERMINAL_H */ 61 | -------------------------------------------------------------------------------- /src/lv_settings/lv_settings.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file lv_settings.h 3 | * 4 | */ 5 | 6 | #ifndef LV_SETTINGS_H 7 | #define LV_SETTINGS_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | 17 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 18 | #include "lvgl.h" 19 | #else 20 | #include "lvgl/lvgl.h" 21 | #endif 22 | 23 | /********************* 24 | * DEFINES 25 | *********************/ 26 | 27 | /********************** 28 | * TYPEDEFS 29 | **********************/ 30 | 31 | typedef enum { 32 | LV_SETTINGS_TYPE_LIST_BTN, 33 | LV_SETTINGS_TYPE_BTN, 34 | LV_SETTINGS_TYPE_SW, 35 | LV_SETTINGS_TYPE_DDLIST, 36 | LV_SETTINGS_TYPE_NUMSET, 37 | LV_SETTINGS_TYPE_SLIDER, 38 | 39 | LV_SETTINGS_TYPE_INV = 0xff, 40 | }lv_settings_type_t; 41 | 42 | typedef struct { 43 | lv_settings_type_t type; 44 | char * name; /*Name or title of the item*/ 45 | char * value; /*The current value as string*/ 46 | int32_t state; /*The current state, e.g. slider's value, switch state as a number */ 47 | lv_obj_t * cont; 48 | union { 49 | void * ptr; 50 | int32_t int32; 51 | }user_data; 52 | }lv_settings_item_t; 53 | 54 | 55 | /********************** 56 | * GLOBAL PROTOTYPES 57 | **********************/ 58 | 59 | /** 60 | * Create a settings application 61 | * @param root_item descriptor of the settings button. For example: 62 | * `lv_settings_menu_item_t root_item = {.name = "Settings", .event_cb = root_event_cb};` 63 | * @return the created settings button 64 | */ 65 | lv_obj_t * lv_settings_create(lv_settings_item_t * root_item, lv_event_cb_t event_cb); 66 | 67 | /** 68 | * Automatically add the item to a group to allow navigation with keypad or encoder. 69 | * Should be called before `lv_settings_create` 70 | * The group can be change at any time. 71 | * @param g the group to use. `NULL` to not use this feature. 72 | */ 73 | void lv_settings_set_group(lv_group_t * g); 74 | 75 | /** 76 | * Change the maximum width of settings dialog object 77 | * @param max_width maximum width of the settings container page 78 | */ 79 | void lv_settings_set_max_width(lv_coord_t max_width); 80 | 81 | /** 82 | * Create a new page ask `event_cb` to add the item with `LV_EVENT_REFRESH` 83 | * @param parent_item pointer to an item which open the the new page. Its `name` will be the title 84 | * @param event_cb event handler of the menu page 85 | */ 86 | void lv_settings_open_page(lv_settings_item_t * parent_item, lv_event_cb_t event_cb); 87 | 88 | /** 89 | * Add a list element to the page. With `item->name` and `item->value` texts. 90 | * @param page pointer to a menu page created by `lv_settings_create_page` 91 | */ 92 | void lv_settings_add(lv_settings_item_t * item); 93 | 94 | 95 | /** 96 | * Refresh an item's name value and state. 97 | * @param item pointer to a an `lv_settings_item _t` item. 98 | */ 99 | void lv_settings_refr(lv_settings_item_t * item); 100 | 101 | /********************** 102 | * MACROS 103 | **********************/ 104 | 105 | #ifdef __cplusplus 106 | } /* extern "C" */ 107 | #endif 108 | 109 | #endif /*LV_TEMPL_H*/ 110 | -------------------------------------------------------------------------------- /src/lv_sysmon/lv_sysmon.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file lv_sysmon.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "lv_sysmon.h" 10 | #if LV_USE_SYSMON 11 | 12 | #include 13 | 14 | 15 | /********************* 16 | * DEFINES 17 | *********************/ 18 | #define CPU_LABEL_COLOR "FF0000" 19 | #define MEM_LABEL_COLOR "0000FF" 20 | #define CHART_POINT_NUM 100 21 | #define REFR_TIME 500 22 | 23 | /********************** 24 | * TYPEDEFS 25 | **********************/ 26 | 27 | /********************** 28 | * STATIC PROTOTYPES 29 | **********************/ 30 | static void sysmon_task(lv_task_t * param); 31 | static void win_close_action(lv_obj_t * btn, lv_event_t event); 32 | 33 | /********************** 34 | * STATIC VARIABLES 35 | **********************/ 36 | static lv_obj_t * win; 37 | static lv_obj_t * chart; 38 | static lv_chart_series_t * cpu_ser; 39 | static lv_chart_series_t * mem_ser; 40 | static lv_obj_t * info_label; 41 | static lv_task_t * refr_task; 42 | 43 | /********************** 44 | * MACROS 45 | **********************/ 46 | 47 | /********************** 48 | * GLOBAL FUNCTIONS 49 | **********************/ 50 | 51 | /** 52 | * Initialize the system monitor 53 | */ 54 | void sysmon_create(void) 55 | { 56 | refr_task = lv_task_create(sysmon_task, REFR_TIME, LV_TASK_PRIO_LOW, NULL); 57 | 58 | 59 | lv_coord_t hres = lv_disp_get_hor_res(NULL); 60 | lv_coord_t vres = lv_disp_get_ver_res(NULL); 61 | 62 | win = lv_win_create(lv_disp_get_scr_act(NULL), NULL); 63 | lv_obj_t * win_btn = lv_win_add_btn(win, LV_SYMBOL_CLOSE); 64 | lv_obj_set_event_cb(win_btn, win_close_action); 65 | 66 | /*Make the window content responsive*/ 67 | lv_win_set_layout(win, LV_LAYOUT_PRETTY); 68 | 69 | /*Create a chart with two data lines*/ 70 | chart = lv_chart_create(win, NULL); 71 | lv_obj_set_size(chart, hres / 2, vres / 2); 72 | lv_obj_set_pos(chart, LV_DPI / 10, LV_DPI / 10); 73 | lv_chart_set_point_count(chart, CHART_POINT_NUM); 74 | lv_chart_set_range(chart, 0, 100); 75 | lv_chart_set_type(chart, LV_CHART_TYPE_LINE); 76 | lv_chart_set_series_width(chart, 4); 77 | cpu_ser = lv_chart_add_series(chart, LV_COLOR_RED); 78 | mem_ser = lv_chart_add_series(chart, LV_COLOR_BLUE); 79 | 80 | /*Set the data series to zero*/ 81 | uint16_t i; 82 | for(i = 0; i < CHART_POINT_NUM; i++) { 83 | lv_chart_set_next(chart, cpu_ser, 0); 84 | lv_chart_set_next(chart, mem_ser, 0); 85 | } 86 | 87 | /*Create a label for the details of Memory and CPU usage*/ 88 | info_label = lv_label_create(win, NULL); 89 | lv_label_set_recolor(info_label, true); 90 | lv_obj_align(info_label, chart, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI / 4, 0); 91 | 92 | /*Refresh the chart and label manually at first*/ 93 | sysmon_task(NULL); 94 | } 95 | 96 | /********************** 97 | * STATIC FUNCTIONS 98 | **********************/ 99 | 100 | /** 101 | * Called periodically to monitor the CPU and memory usage. 102 | * @param param unused 103 | */ 104 | static void sysmon_task(lv_task_t * param) 105 | { 106 | 107 | (void) param; /*Unused*/ 108 | 109 | LV_LOG_TRACE("sys_mon task started"); 110 | 111 | /*Get CPU and memory information */ 112 | uint8_t cpu_busy; 113 | cpu_busy = 100 - lv_task_get_idle(); 114 | 115 | uint8_t mem_used_pct = 0; 116 | #if LV_MEM_CUSTOM == 0 117 | lv_mem_monitor_t mem_mon; 118 | lv_mem_monitor(&mem_mon); 119 | mem_used_pct = mem_mon.used_pct; 120 | #endif 121 | 122 | /*Add the CPU and memory data to the chart*/ 123 | lv_chart_set_next(chart, cpu_ser, cpu_busy); 124 | lv_chart_set_next(chart, mem_ser, mem_used_pct); 125 | 126 | /*Refresh the and windows*/ 127 | char buf_long[256]; 128 | sprintf(buf_long, "%s%s CPU: %d %%%s\n\n", 129 | LV_TXT_COLOR_CMD, 130 | CPU_LABEL_COLOR, 131 | cpu_busy, 132 | LV_TXT_COLOR_CMD); 133 | 134 | #if LV_MEM_CUSTOM == 0 135 | sprintf(buf_long, "%s"LV_TXT_COLOR_CMD"%s MEMORY: %d %%"LV_TXT_COLOR_CMD"\n" 136 | "Total: %d bytes\n" 137 | "Used: %d bytes\n" 138 | "Free: %d bytes\n" 139 | "Frag: %d %%", 140 | buf_long, 141 | MEM_LABEL_COLOR, 142 | mem_used_pct, 143 | (int)mem_mon.total_size, 144 | (int)mem_mon.total_size - mem_mon.free_size, mem_mon.free_size, mem_mon.frag_pct); 145 | 146 | #else 147 | sprintf(buf_long, "%s"LV_TXT_COLOR_CMD"%s MEMORY: N/A"LV_TXT_COLOR_CMD, 148 | buf_long, 149 | MEM_LABEL_COLOR); 150 | #endif 151 | lv_label_set_text(info_label, buf_long); 152 | 153 | 154 | LV_LOG_TRACE("sys_mon task finished"); 155 | } 156 | 157 | /** 158 | * Called when the window's close button is clicked 159 | * @param btn pointer to the close button 160 | * @param event the current event 161 | */ 162 | static void win_close_action(lv_obj_t * btn, lv_event_t event) 163 | { 164 | (void) btn; /*Unused*/ 165 | 166 | if(event != LV_EVENT_CLICKED) return; 167 | 168 | lv_obj_del(win); 169 | win = NULL; 170 | 171 | lv_task_del(refr_task); 172 | refr_task = NULL; 173 | } 174 | 175 | #endif /*LV_USE_SYMON*/ 176 | -------------------------------------------------------------------------------- /src/lv_terminal/lv_terminal.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file terminal.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "lv_terminal.h" 10 | #if LV_USE_TERMINAL 11 | 12 | /********************* 13 | * DEFINES 14 | *********************/ 15 | #define TERMINAL_ANIM_TIME 100 /*[ms]*/ 16 | #define TERMINAL_NO_INPUT 0 /*Do not create Text area and Keyboard*/ 17 | #define TERMINAL_LOG_LENGTH 512 /*Characters*/ 18 | 19 | /********************** 20 | * TYPEDEFS 21 | **********************/ 22 | 23 | /********************** 24 | * STATIC PROTOTYPES 25 | **********************/ 26 | static void clr_event_cb(lv_obj_t * btn, lv_event_t event); 27 | static void win_close_action(lv_obj_t * btn, lv_event_t event); 28 | 29 | /********************** 30 | * STATIC VARIABLES 31 | **********************/ 32 | static lv_obj_t * win; 33 | static char txt_log[TERMINAL_LOG_LENGTH + 1]; 34 | static lv_obj_t * label; 35 | static lv_obj_t * clr_btn; 36 | 37 | /********************** 38 | * MACROS 39 | **********************/ 40 | 41 | /********************** 42 | * GLOBAL FUNCTIONS 43 | **********************/ 44 | 45 | /** 46 | * Open a terminal 47 | * @return pointer to the terminal window 48 | */ 49 | lv_obj_t * terminal_create(void) 50 | { 51 | static lv_style_t style_bg; 52 | lv_style_copy(&style_bg, &lv_style_pretty); 53 | style_bg.body.main_color = lv_color_make(0x30, 0x30, 0x30); 54 | style_bg.body.grad_color = lv_color_make(0x30, 0x30, 0x30); 55 | style_bg.body.border.color = LV_COLOR_WHITE; 56 | style_bg.text.color = lv_color_make(0xE0, 0xE0, 0xE0); 57 | 58 | 59 | 60 | lv_coord_t hres = lv_disp_get_hor_res(NULL); 61 | lv_coord_t vres = lv_disp_get_ver_res(NULL); 62 | 63 | win = lv_win_create(lv_disp_get_scr_act(NULL), NULL); 64 | lv_win_set_style(win, LV_WIN_STYLE_BG, &style_bg); 65 | lv_obj_set_size(win, hres, vres); 66 | lv_win_set_sb_mode(win, LV_SB_MODE_AUTO); 67 | lv_obj_t * win_btn = lv_win_add_btn(win, LV_SYMBOL_CLOSE); 68 | lv_obj_set_event_cb(win_btn, win_close_action); 69 | 70 | /*Make the window's content responsive*/ 71 | lv_win_set_layout(win, LV_LAYOUT_PRETTY); 72 | 73 | /*Create a label for the text of the terminal*/ 74 | label = lv_label_create(win, NULL); 75 | lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK); 76 | lv_obj_set_width(label, lv_win_get_width(win)); 77 | lv_label_set_static_text(label, txt_log); /*Use the text array directly*/ 78 | 79 | /*Create a clear button*/ 80 | clr_btn = lv_btn_create(win, NULL); 81 | lv_btn_set_fit(clr_btn, LV_FIT_TIGHT); 82 | lv_obj_set_event_cb(clr_btn, clr_event_cb); 83 | lv_obj_t * btn_label = lv_label_create(clr_btn, NULL); 84 | lv_label_set_text(btn_label, "Clear"); 85 | 86 | return win; 87 | } 88 | 89 | /** 90 | * Add data to the terminal 91 | * @param txt_in character sting to add to the terminal 92 | */ 93 | void terminal_add(const char * txt_in) 94 | { 95 | if(win == NULL) return; /*Check if the window is exists*/ 96 | 97 | uint16_t txt_len = strlen(txt_in); 98 | uint16_t old_len = strlen(txt_log); 99 | 100 | /*If the data is longer then the terminal ax size show the last part of data*/ 101 | if(txt_len > TERMINAL_LOG_LENGTH) { 102 | txt_in += (txt_len - TERMINAL_LOG_LENGTH); 103 | txt_len = TERMINAL_LOG_LENGTH; 104 | old_len = 0; 105 | } 106 | /*If the text become too long 'forget' the oldest lines*/ 107 | else if(old_len + txt_len > TERMINAL_LOG_LENGTH) { 108 | uint16_t new_start; 109 | for(new_start = 0; new_start < old_len; new_start++) { 110 | if(txt_log[new_start] == '\n') { 111 | /*If there is enough space break*/ 112 | if(new_start >= txt_len) { 113 | /*Ignore line breaks*/ 114 | while(txt_log[new_start] == '\n' || txt_log[new_start] == '\r') new_start++; 115 | break; 116 | } 117 | } 118 | } 119 | 120 | /* If it wasn't able to make enough space on line breaks 121 | * simply forget the oldest characters*/ 122 | if(new_start == old_len) { 123 | new_start = old_len - (TERMINAL_LOG_LENGTH - txt_len); 124 | } 125 | /*Move the remaining text to the beginning*/ 126 | uint16_t j; 127 | for(j = new_start; j < old_len; j++) { 128 | txt_log[j - new_start] = txt_log[j]; 129 | } 130 | old_len = old_len - new_start; 131 | txt_log[old_len] = '\0'; 132 | 133 | } 134 | 135 | memcpy(&txt_log[old_len], txt_in, txt_len); 136 | txt_log[old_len + txt_len] = '\0'; 137 | 138 | lv_label_set_static_text(label, txt_log); 139 | lv_win_focus(win, clr_btn, TERMINAL_ANIM_TIME); 140 | } 141 | 142 | /********************** 143 | * STATIC FUNCTIONS 144 | **********************/ 145 | 146 | /** 147 | * Called when the Clear button is click to clear the text of the terminal 148 | * @param btn pointer to the clear button 149 | * @param event the current event 150 | */ 151 | static void clr_event_cb(lv_obj_t * btn, lv_event_t event) 152 | { 153 | (void) btn; /*Unused*/ 154 | 155 | if(event != LV_EVENT_CLICKED) return; 156 | 157 | txt_log[0] = '\0'; 158 | lv_label_set_static_text(label, txt_log); /*Refresh the text*/ 159 | } 160 | 161 | /** 162 | * Called when the window's close button is clicked 163 | * @param btn pointer to the close button 164 | * @return LV_ACTION_RES_INV because the button is deleted in the function 165 | */ 166 | static void win_close_action(lv_obj_t * btn, lv_event_t event) 167 | { 168 | (void) btn; /*Unused*/ 169 | 170 | if(event != LV_EVENT_CLICKED) return; 171 | 172 | lv_obj_del(win); 173 | win = NULL; 174 | } 175 | 176 | #endif /*LV_USE_TERMINAL*/ 177 | -------------------------------------------------------------------------------- /examples/lv_ex_settings/lv_ex_settings_1.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file lv_ex_settings_1.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "../../src/lv_settings/lv_settings.h" 10 | #include "lv_drivers/indev/keyboard.h" 11 | #include "lv_drivers/indev/mousewheel.h" 12 | 13 | /********************* 14 | * DEFINES 15 | *********************/ 16 | #ifndef LV_SETTINGS_KEYBOARD 17 | #define LV_SETTINGS_KEYBOARD 0 18 | #endif 19 | 20 | #ifndef LV_SETTINGS_MOUSEWHEEL 21 | #define LV_SETTINGS_MOUSEWHEEL 0 22 | #endif 23 | 24 | /********************** 25 | * TYPEDEFS 26 | **********************/ 27 | 28 | /********************** 29 | * STATIC PROTOTYPES 30 | **********************/ 31 | static void root_event_cb(lv_obj_t * btn, lv_event_t e); 32 | static void main_event_cb(lv_obj_t * btn, lv_event_t e); 33 | static void submenu_event_cb(lv_obj_t * btn, lv_event_t e); 34 | 35 | /********************** 36 | * STATIC VARIABLES 37 | **********************/ 38 | 39 | /*Declare items*/ 40 | static lv_settings_item_t root_item = {.name = "Settings", .value = ""}; 41 | 42 | static lv_settings_item_t main_menu_items[] = 43 | { 44 | {.type = LV_SETTINGS_TYPE_LIST_BTN, .name="Button", .value="Test button"}, 45 | {.type = LV_SETTINGS_TYPE_LIST_BTN, .name="Switch", .value="Test switch"}, 46 | {.type = LV_SETTINGS_TYPE_LIST_BTN, .name="Drop down list", .value="Test drop down list"}, 47 | {.type = LV_SETTINGS_TYPE_LIST_BTN, .name="Number set", .value="Test number set"}, 48 | {.type = LV_SETTINGS_TYPE_LIST_BTN, .name="Slider", .value="Test slider"}, 49 | {.type = LV_SETTINGS_TYPE_INV}, /*Mark the last item*/ 50 | }; 51 | 52 | /********************** 53 | * MACROS 54 | **********************/ 55 | 56 | /********************** 57 | * GLOBAL FUNCTIONS 58 | **********************/ 59 | 60 | void lv_ex_settings_1(void) 61 | { 62 | lv_theme_t *th = lv_theme_material_init(210, NULL); 63 | 64 | /*Try with different theme too*/ 65 | // lv_theme_t *th = lv_theme_material_init(10, NULL); 66 | // lv_theme_t *th = lv_theme_night_init(40, NULL); 67 | 68 | lv_theme_set_current(th); 69 | 70 | 71 | /*Add keyboard or mouswheel input devices if enabled*/ 72 | #if LV_SETTINGS_KEYBOARD 73 | keyboard_init(); 74 | lv_indev_drv_t indev_drv; 75 | lv_indev_drv_init(&indev_drv); /*Basic initialization*/ 76 | indev_drv.type = LV_INDEV_TYPE_KEYPAD; 77 | indev_drv.read_cb = keyboard_read; /*This function will be called periodically (by the library) to get the mouse position and state*/ 78 | 79 | #elif LV_SETTINGS_MOUSEWHEEL 80 | mousewheel_init(); 81 | lv_indev_drv_t indev_drv; 82 | lv_indev_drv_init(&indev_drv); /*Basic initialization*/ 83 | indev_drv.type = LV_INDEV_TYPE_ENCODER; 84 | indev_drv.read_cb = mousewheel_read; /*This function will be called periodically (by the library) to get the mouse position and state*/ 85 | #endif 86 | 87 | #if LV_SETTINGS_KEYBOARD || LV_SETTINGS_MOUSEWHEEL 88 | lv_indev_t * indev = lv_indev_drv_register(&indev_drv); 89 | 90 | lv_group_t * g = lv_group_create(); 91 | lv_indev_set_group(indev, g); 92 | lv_settings_set_group(g); 93 | #endif 94 | 95 | 96 | /*Create the settings menu with a root item*/ 97 | lv_settings_create(&root_item, root_event_cb); 98 | 99 | 100 | } 101 | 102 | /********************** 103 | * STATIC FUNCTIONS 104 | **********************/ 105 | 106 | static void root_event_cb(lv_obj_t * btn, lv_event_t e) 107 | { 108 | (void)btn; /*Unused*/ 109 | 110 | if(e == LV_EVENT_CLICKED) { 111 | /*Get the caller item*/ 112 | lv_settings_item_t * act_item = (lv_settings_item_t *)lv_event_get_data(); 113 | 114 | /*Create a new page in the menu*/ 115 | lv_settings_open_page(act_item, main_event_cb); 116 | } 117 | } 118 | 119 | static void main_event_cb(lv_obj_t * btn, lv_event_t e) 120 | { 121 | (void)btn; /*Unused*/ 122 | 123 | /*Get the caller item*/ 124 | lv_settings_item_t * act_item = (lv_settings_item_t *)lv_event_get_data(); 125 | 126 | /*Add the items*/ 127 | if(e == LV_EVENT_REFRESH) { 128 | uint32_t i; 129 | for(i = 0; main_menu_items[i].type != LV_SETTINGS_TYPE_INV; i++) { 130 | lv_settings_add(&main_menu_items[i]); 131 | } 132 | } 133 | /* Open submenus. 134 | * The submenus will be very simple so use a common event callback for them. 135 | * `act_item` is the clicked list button in the main menu. 136 | * It's name will be the title of the new page*/ 137 | else if(e == LV_EVENT_CLICKED) { 138 | lv_settings_open_page(act_item, submenu_event_cb); 139 | } 140 | } 141 | 142 | static void submenu_event_cb(lv_obj_t * btn, lv_event_t e) 143 | { 144 | (void)btn; /*Unused*/ 145 | 146 | /*Get the caller item*/ 147 | lv_settings_item_t * act_item = (lv_settings_item_t *)lv_event_get_data(); 148 | 149 | /*Add items to the submenus*/ 150 | if(e == LV_EVENT_REFRESH) { 151 | if(strcmp("Button", act_item->name) == 0) { 152 | static lv_settings_item_t item = { 153 | .type = LV_SETTINGS_TYPE_BTN, 154 | .name = "System test", 155 | .value = "Start"}; 156 | lv_settings_add(&item); 157 | } 158 | else if(strcmp("Slider", act_item->name) == 0) { 159 | 160 | static char value[16] = {"100 V"}; 161 | static lv_settings_item_t item = { 162 | .type = LV_SETTINGS_TYPE_SLIDER, 163 | .name = "Voltage", 164 | .value = value, 165 | .state = 0}; 166 | 167 | lv_settings_add(&item); 168 | } 169 | else if(strcmp("Switch", act_item->name) == 0) { 170 | 171 | static lv_settings_item_t item = { 172 | .type = LV_SETTINGS_TYPE_SW, 173 | .name = "Valve", 174 | .value = "Closed", 175 | .state = 0}; 176 | 177 | lv_settings_add(&item); 178 | } 179 | else if(strcmp("Number set", act_item->name) == 0) { 180 | static char value[16] = {"12"}; 181 | static lv_settings_item_t item = { 182 | .type = LV_SETTINGS_TYPE_NUMSET, 183 | .name = "Age", 184 | .value = value, 185 | .state = 12}; 186 | 187 | lv_settings_add(&item); 188 | } 189 | else if(strcmp("Drop down list", act_item->name) == 0) { 190 | static lv_settings_item_t item = { 191 | .type = LV_SETTINGS_TYPE_DDLIST, 192 | .name = "Size", 193 | .value = "S\nM\nL\nXL", 194 | .state = 0}; 195 | 196 | lv_settings_add(&item); 197 | } 198 | } 199 | /*Handle the items' events*/ 200 | else if(e == LV_EVENT_VALUE_CHANGED) { 201 | if(strcmp("Voltage", act_item->name) == 0) { 202 | sprintf(act_item->value, "%d V", act_item->state); 203 | lv_settings_refr(act_item); 204 | } 205 | else if(strcmp("Age", act_item->name) == 0) { 206 | if(act_item->state < 6) act_item->state = 6; 207 | if(act_item->state > 99) act_item->state = 99; 208 | 209 | sprintf(act_item->value, "%d", act_item->state); 210 | lv_settings_refr(act_item); 211 | } 212 | else if(strcmp("Valve", act_item->name) == 0) { 213 | if(act_item->state) act_item->value = "Open"; 214 | else act_item->value = "Close"; 215 | 216 | lv_settings_refr(act_item); 217 | } 218 | else if(strcmp("Size", act_item->name) == 0) { 219 | printf("Size: %d\n", act_item->state); 220 | } 221 | } else if(e == LV_EVENT_CLICKED) { 222 | if(strcmp("System test", act_item->name) == 0) { 223 | if(strcmp(act_item->value, "Start") == 0) { 224 | act_item->value = "Stop"; 225 | } else { 226 | act_item->value = "Start"; 227 | } 228 | lv_settings_refr(act_item); 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/lv_benchmark/lv_benchmark.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file benchmark.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "lv_benchmark.h" 10 | #if LV_USE_BENCHMARK 11 | 12 | #include 13 | 14 | /********************* 15 | * DEFINES 16 | *********************/ 17 | #define TEST_CYCLE_NUM 10 /*How many times run the test (will calculate the average)*/ 18 | #define SHADOW_WIDTH (LV_DPI / 8) 19 | #define IMG_RECOLOR LV_OPA_20 20 | #define OPACITY LV_OPA_60 21 | 22 | /********************** 23 | * TYPEDEFS 24 | **********************/ 25 | 26 | /********************** 27 | * STATIC PROTOTYPES 28 | **********************/ 29 | static void refr_monitor(lv_disp_drv_t * disp_drv, uint32_t time_ms, uint32_t px_num); 30 | static void run_test_event_cb(lv_obj_t * btn, lv_event_t event); 31 | static void wp_btn_event_cb(lv_obj_t * btn, lv_event_t event); 32 | static void recolor_btn_event_cb(lv_obj_t * btn, lv_event_t event); 33 | static void shadow_btn_event_cb(lv_obj_t * btn, lv_event_t event); 34 | static void opa_btn_event_cb(lv_obj_t * btn, lv_event_t event); 35 | 36 | /********************** 37 | * STATIC VARIABLES 38 | **********************/ 39 | static lv_obj_t * holder_page; 40 | static lv_obj_t * wp; 41 | static lv_obj_t * result_label; 42 | 43 | static lv_style_t style_wp; 44 | static lv_style_t style_btn_rel; 45 | static lv_style_t style_btn_pr; 46 | static lv_style_t style_btn_tgl_rel; 47 | static lv_style_t style_btn_tgl_pr; 48 | 49 | static uint32_t time_sum; 50 | static uint32_t refr_cnt; 51 | 52 | LV_IMG_DECLARE(benchmark_bg) 53 | 54 | /********************** 55 | * MACROS 56 | **********************/ 57 | 58 | /********************** 59 | * GLOBAL FUNCTIONS 60 | **********************/ 61 | 62 | /********************** 63 | * STATIC FUNCTIONS 64 | **********************/ 65 | 66 | 67 | /** 68 | * Open a graphics benchmark 69 | */ 70 | void benchmark_create(void) 71 | { 72 | 73 | lv_coord_t hres = lv_disp_get_hor_res(NULL); 74 | lv_coord_t vres = lv_disp_get_ver_res(NULL); 75 | 76 | /*Styles of the buttons*/ 77 | lv_style_copy(&style_btn_rel, &lv_style_btn_rel); 78 | lv_style_copy(&style_btn_pr, &lv_style_btn_pr); 79 | lv_style_copy(&style_btn_tgl_rel, &lv_style_btn_tgl_rel); 80 | lv_style_copy(&style_btn_tgl_pr, &lv_style_btn_tgl_pr); 81 | 82 | style_btn_rel.body.opa = LV_OPA_COVER; 83 | style_btn_pr.body.opa = LV_OPA_COVER; 84 | style_btn_tgl_rel.body.opa = LV_OPA_COVER; 85 | style_btn_tgl_pr.body.opa = LV_OPA_COVER; 86 | 87 | style_btn_rel.body.shadow.width = 0; 88 | style_btn_pr.body.shadow.width = 0; 89 | style_btn_tgl_rel.body.shadow.width = 0; 90 | style_btn_tgl_pr.body.shadow.width = 0; 91 | 92 | /*Style of the wallpaper*/ 93 | lv_style_copy(&style_wp, &lv_style_plain); 94 | style_wp.image.color = LV_COLOR_RED; 95 | 96 | /*Create a holder page (the page become scrollable on small displays )*/ 97 | holder_page = lv_page_create(lv_disp_get_scr_act(NULL), NULL); 98 | lv_obj_set_size(holder_page, hres, vres); 99 | lv_page_set_style(holder_page, LV_PAGE_STYLE_BG, &lv_style_transp_fit); 100 | lv_page_set_style(holder_page, LV_PAGE_STYLE_SCRL, &lv_style_transp); 101 | lv_page_set_scrl_layout(holder_page, LV_LAYOUT_PRETTY); 102 | 103 | /*Create a wallpaper on the page*/ 104 | wp = lv_img_create(holder_page, NULL); 105 | lv_obj_set_protect(wp, LV_PROTECT_PARENT); /*Don't let to move the wallpaper by the layout */ 106 | lv_obj_set_parent(wp, holder_page); 107 | lv_obj_set_parent(lv_page_get_scrl(holder_page), holder_page); 108 | lv_img_set_src(wp, &benchmark_bg); 109 | lv_obj_set_size(wp, hres, vres); 110 | lv_obj_set_pos(wp, 0, 0); 111 | lv_obj_set_hidden(wp, true); 112 | lv_img_set_style(wp, LV_IMG_STYLE_MAIN, &style_wp); 113 | lv_img_set_auto_size(wp, false); 114 | 115 | /*Create a label to show the test result*/ 116 | result_label = lv_label_create(holder_page, NULL); 117 | lv_label_set_text(result_label, "Run the test"); 118 | lv_label_set_body_draw(result_label, true); 119 | lv_label_set_style(result_label, LV_LABEL_STYLE_MAIN, &lv_style_pretty); 120 | 121 | /*Create a "Run test" button*/ 122 | lv_obj_t * btn; 123 | btn = lv_btn_create(holder_page, NULL); 124 | lv_page_glue_obj(btn, true); 125 | lv_btn_set_fit(btn, LV_FIT_TIGHT); 126 | lv_btn_set_style(btn, LV_BTN_STYLE_REL, &style_btn_rel); 127 | lv_btn_set_style(btn, LV_BTN_STYLE_PR, &style_btn_pr); 128 | lv_btn_set_style(btn, LV_BTN_STYLE_TGL_REL, &style_btn_tgl_rel); 129 | lv_btn_set_style(btn, LV_BTN_STYLE_TGL_PR, &style_btn_tgl_pr); 130 | lv_obj_set_event_cb(btn, run_test_event_cb); 131 | 132 | lv_obj_t * btn_l; 133 | btn_l = lv_label_create(btn, NULL); 134 | lv_label_set_text(btn_l, "Run\ntest!"); 135 | lv_obj_set_protect(btn, LV_PROTECT_FOLLOW); /*Line break in layout*/ 136 | 137 | 138 | /*Create a "Wallpaper show" button*/ 139 | btn = lv_btn_create(holder_page, btn); 140 | lv_btn_set_toggle(btn, true); 141 | lv_obj_clear_protect(btn, LV_PROTECT_FOLLOW); 142 | lv_obj_set_event_cb(btn, wp_btn_event_cb); 143 | btn_l = lv_label_create(btn, btn_l); 144 | lv_label_set_text(btn_l, "Wallpaper"); 145 | 146 | 147 | /*Create a "Wallpaper re-color" button*/ 148 | btn = lv_btn_create(holder_page, btn); 149 | lv_obj_set_event_cb(btn, recolor_btn_event_cb); 150 | btn_l = lv_label_create(btn, btn_l); 151 | lv_label_set_text(btn_l, "Wp. recolor!"); 152 | 153 | /*Create a "Shadow draw" button*/ 154 | btn = lv_btn_create(holder_page, btn); 155 | lv_obj_set_event_cb(btn, shadow_btn_event_cb); 156 | btn_l = lv_label_create(btn, btn_l); 157 | lv_label_set_text(btn_l, "Shadow"); 158 | 159 | /*Create an "Opacity enable" button*/ 160 | btn = lv_btn_create(holder_page, btn); 161 | lv_obj_set_event_cb(btn, opa_btn_event_cb); 162 | btn_l = lv_label_create(btn, btn_l); 163 | lv_label_set_text(btn_l, "Opacity"); 164 | } 165 | 166 | 167 | void benchmark_start(void) 168 | { 169 | lv_disp_t * disp = lv_obj_get_disp(holder_page); 170 | 171 | disp->driver.monitor_cb = refr_monitor; 172 | 173 | lv_obj_invalidate(lv_disp_get_scr_act(disp)); 174 | 175 | time_sum = 0; 176 | refr_cnt = 0; 177 | } 178 | 179 | bool benchmark_is_ready(void) 180 | { 181 | if(refr_cnt == TEST_CYCLE_NUM) return true; 182 | else return false; 183 | } 184 | 185 | uint32_t benchmark_get_refr_time(void) 186 | { 187 | if(benchmark_is_ready()) return time_sum / TEST_CYCLE_NUM; 188 | else return 0; 189 | } 190 | 191 | /*-------------------- 192 | * OTHER FUNCTIONS 193 | ---------------------*/ 194 | 195 | /** 196 | * Called when a the library finished rendering to monitor its performance 197 | * @param disp_drv pointer to the caller display driver 198 | * @param time_ms time of rendering in milliseconds 199 | * @param px_num Number of pixels drawn 200 | */ 201 | static void refr_monitor(lv_disp_drv_t * disp_drv, uint32_t time_ms, uint32_t px_num) 202 | { 203 | (void) px_num ; /*Unused*/ 204 | lv_disp_t * disp = lv_obj_get_disp(holder_page); 205 | time_sum += time_ms; 206 | refr_cnt ++; 207 | lv_obj_invalidate(lv_disp_get_scr_act(disp)); 208 | 209 | if(refr_cnt >= TEST_CYCLE_NUM) { 210 | int time_avg = (int)time_sum / (int)TEST_CYCLE_NUM; 211 | char buf[256]; 212 | sprintf(buf, "Screen load: %d ms\nAverage of %d", time_avg, TEST_CYCLE_NUM); 213 | lv_label_set_text(result_label, buf); 214 | disp_drv->monitor_cb = NULL; 215 | } else { 216 | char buf[256]; 217 | sprintf(buf, "Running %d/%d", refr_cnt, TEST_CYCLE_NUM); 218 | lv_label_set_text(result_label, buf); 219 | 220 | } 221 | } 222 | 223 | /** 224 | * Called when the "Run test" button is clicked 225 | * @param btn pointer to the button 226 | * @param event the current event 227 | */ 228 | static void run_test_event_cb(lv_obj_t * btn, lv_event_t event) 229 | { 230 | (void) btn; /*Unused*/ 231 | 232 | if(event != LV_EVENT_CLICKED) return; 233 | 234 | benchmark_start(); 235 | } 236 | 237 | /** 238 | * Called when the "Wallpaper" button is clicked 239 | * @param btn pointer to the button 240 | * @param event the current event 241 | */ 242 | static void wp_btn_event_cb(lv_obj_t * btn, lv_event_t event) 243 | { 244 | if(event != LV_EVENT_CLICKED) return; 245 | 246 | if(lv_btn_get_state(btn) == LV_BTN_STATE_TGL_REL) lv_obj_set_hidden(wp, false); 247 | else lv_obj_set_hidden(wp, true); 248 | } 249 | 250 | /** 251 | * Called when the "Wp. recolor" button is clicked 252 | * @param btn pointer to the button 253 | * @param event the current event 254 | */ 255 | static void recolor_btn_event_cb(lv_obj_t * btn, lv_event_t event) 256 | { 257 | if(event != LV_EVENT_CLICKED) return; 258 | 259 | if(lv_btn_get_state(btn) == LV_BTN_STATE_TGL_REL) style_wp.image.intense = IMG_RECOLOR; 260 | else style_wp.image.intense = LV_OPA_TRANSP; 261 | 262 | lv_obj_refresh_style(wp); 263 | } 264 | 265 | /** 266 | * Called when the "Shadow" button is clicked 267 | * @param btn pointer to the button 268 | * @param event the current event 269 | */ 270 | static void shadow_btn_event_cb(lv_obj_t * btn, lv_event_t event) 271 | { 272 | if(event != LV_EVENT_CLICKED) return; 273 | 274 | if(lv_btn_get_state(btn) == LV_BTN_STATE_TGL_REL) { 275 | style_btn_rel.body.shadow.width = SHADOW_WIDTH; 276 | style_btn_pr.body.shadow.width = SHADOW_WIDTH; 277 | style_btn_tgl_rel.body.shadow.width = SHADOW_WIDTH; 278 | style_btn_tgl_pr.body.shadow.width = SHADOW_WIDTH; 279 | } else { 280 | style_btn_rel.body.shadow.width = 0; 281 | style_btn_pr.body.shadow.width = 0; 282 | style_btn_tgl_rel.body.shadow.width = 0; 283 | style_btn_tgl_pr.body.shadow.width = 0; 284 | } 285 | 286 | lv_obj_report_style_mod(&style_btn_rel); 287 | lv_obj_report_style_mod(&style_btn_pr); 288 | lv_obj_report_style_mod(&style_btn_tgl_rel); 289 | lv_obj_report_style_mod(&style_btn_tgl_pr); 290 | } 291 | 292 | /** 293 | * Called when the "Opacity" button is clicked 294 | * @param btn pointer to the button 295 | * @param event the current event 296 | */ 297 | static void opa_btn_event_cb(lv_obj_t * btn, lv_event_t event) 298 | { 299 | if(event != LV_EVENT_CLICKED) return; 300 | 301 | if(lv_btn_get_state(btn) == LV_BTN_STATE_TGL_REL) { 302 | style_btn_rel.body.opa = OPACITY; 303 | style_btn_pr.body.opa = OPACITY; 304 | style_btn_tgl_rel.body.opa = OPACITY; 305 | style_btn_tgl_pr.body.opa = OPACITY; 306 | } else { 307 | style_btn_rel.body.opa = LV_OPA_COVER; 308 | style_btn_pr.body.opa = LV_OPA_COVER; 309 | style_btn_tgl_rel.body.opa = LV_OPA_COVER; 310 | style_btn_tgl_pr.body.opa = LV_OPA_COVER; 311 | } 312 | 313 | lv_obj_report_style_mod(&style_btn_rel); 314 | lv_obj_report_style_mod(&style_btn_pr); 315 | lv_obj_report_style_mod(&style_btn_tgl_rel); 316 | lv_obj_report_style_mod(&style_btn_tgl_pr); 317 | } 318 | 319 | #endif /*LV_USE_BENCHMARK*/ 320 | -------------------------------------------------------------------------------- /src/lv_settings/README.md: -------------------------------------------------------------------------------- 1 | # Settings menu 2 | 3 | **A collections of ready to use components to create smartphone-like menus** 4 | 5 | ![Settings menu with LittlevGL](../../examples/lv_ex_settings/lv_ex_settings_2.gif) 6 | 7 | _Created by calling `lv_ex_settings_2()`_ 8 | 9 | ### Table of content 10 | - [Overview](#overview) 11 | - [Create a menu](#create-a-menu) 12 | - [Refresh items' data](#refresh-items-data) 13 | - [Styling](#styling) 14 | - [Use with keyboard](#use-with-keyboard) 15 | - [Examples](#examples) 16 | 17 | ## Overview 18 | 19 | The menu builds-up from 20 | 1. A *root item* which opens the menu on click 21 | 2. Pages of the menu 22 | 23 | There is a back button every page to go back to the previous page or on the first page to close the menu. 24 | 25 | The descriptor elements of menu items have `lv_settings_item_t` type. It has the following fields: 26 | - **type** of the item (`LV_SETTINGS_TYPE_...`). See below. 27 | - **name** name of the item as a string 28 | - **value** current value of the item as a string 29 | - **state** the current or last state of the item as an integer (e.g. slider's value) 30 | - **user_date** a `void *` pointer to store any custom data 31 | - **cont** pointer to the created lvgl object if exists. (Used internally) 32 | 33 | ### Item types 34 | 35 | #### List button 36 | Referred as `LV_SETTINGS_TYPE_LIST_BTN`, 37 | 38 | A large button. Usually used to open new pages in the menu. 39 | 40 | ![List button in settings application - LittlevGL](https://github.com/littlevgl/lv_apps/raw/master/misc/lv_settings_list_btn.png) 41 | 42 | It displays the `name` and value of the `item`. If a theme is set `value` will use `theme.style.label.hint` style. 43 | 44 | The list buttons don't use `state` so it can be freely if required to keep track of the state of something. 45 | 46 | `LV_EVENT_CLICKED`, `LV_EVENT_SHORT_CLICKED`, `LV_EVENT_LONG_PRESSED` is sent to the `event_cb` 47 | 48 | 49 | #### Button 50 | Referred as `LV_SETTINGS_TYPE_BTN`, 51 | 52 | Displays `name` and a button with `value` text on it. 53 | 54 | ![Button in settings application - LittlevGL](https://github.com/littlevgl/lv_apps/blob/master/misc/lv_settings_btn.gif) 55 | 56 | The buttons don't use `state` so it can be freely if required to keep track of the state of something. 57 | 58 | In `event_cb` `LV_EVENT_CLICKED` is sent when the button is clicked 59 | 60 | #### Switch 61 | Referred as `LV_SETTINGS_TYPE_SW`, 62 | 63 | Displays a switch with `name` and `value` texts. 64 | 65 | ![Switch in settings application - LittlevGL](https://github.com/littlevgl/lv_apps/blob/master/misc/lv_settings_sw.gif) 66 | 67 | The current state is stored in the `state` filed. 68 | 69 | In `event_cb` `LV_EVENT_VALUE_CHANGED` is sent when the switch changes state. 70 | 71 | #### Drop down list 72 | Referred as `LV_SETTINGS_TYPE_DDLIST`, 73 | 74 | Displays a Drop down list with `name` as title and options stored in `value`. 75 | 76 | ![Drop down list in settings application - LittlevGL](https://github.com/littlevgl/lv_apps/blob/master/misc/lv_settings_ddlist.gif) 77 | 78 | The current options id is stored in the `state` filed. 79 | 80 | In `event_cb` `LV_EVENT_VALUE_CHANGED` is sent when a new option is selected. 81 | 82 | #### Number set 83 | Referred as `LV_SETTINGS_TYPE_NUMSET`, 84 | 85 | Displays the `name` as title, a `value` and `+`, `-` buttons. 86 | 87 | ![Number set in settings application - LittlevGL](https://github.com/littlevgl/lv_apps/blob/master/misc/lv_settings_numset.gif) 88 | 89 | The current value is stored in the `state` filed. 90 | 91 | In `event_cb` `LV_EVENT_VALUE_CHANGED` is sent when a new option is selected. 92 | 93 | 94 | #### Slider 95 | Referred as `LV_SETTINGS_TYPE_SLIDER`, 96 | 97 | Displays the `name` as title and `value` above a slider. 98 | 99 | ![Drop down list in settings application - LittlevGL](https://github.com/littlevgl/lv_apps/blob/master/misc/lv_settings_slider.gif) 100 | 101 | The sliders range is `[0..255]`. The current value is stored in the `state` filed. 102 | 103 | In `event_cb` `LV_EVENT_VALUE_CHANGED` is sent when a new option is selected. 104 | 105 | ## Create a menu 106 | 107 | ### Initialize items 108 | 109 | To initialize an item the field of an `lv_settings_item_t` variable needs to be filled. 110 | ```c 111 | static lv_settigns_item_t item1; 112 | item1.type = LV_SETTINGS_TYPE_SLIDER; 113 | item1.name = "Slider1"; 114 | item1.value = "30 %"; 115 | item1.state = (50 * 256) / 100; /*30 %, default slider range is 256*/ 116 | ``` 117 | 118 | It's a good practice to set a character array for `value` if it will change later. 119 | ```c 120 | static char slider2_value[32] = {"50 %"}; 121 | static lv_settigns_item_t item2; 122 | item2.type = LV_SETTINGS_TYPE_SLIDER; 123 | item2.name = "Slider2"; 124 | item2.value = slider_value; 125 | item2.state = (50 * 256) / 100 ; /*50 %*/ 126 | ``` 127 | 128 | The items can be initialized in compile time too. 129 | ```c 130 | static char slider3_value[32] = {"70 %"}; 131 | static const lv_settigns_item_t item3 = { 132 | .type = LV_SETTINGS_TYPE_SLIDER; 133 | .name = "Slider3"; 134 | .value = slider3_value; 135 | .state = (70 * 256) / 100 ; /*70 %*/ 136 | }; 137 | ``` 138 | 139 | And the item can be grouped into an array. 140 | ```c 141 | static char slider_values[3][32] = {"90 %", "91 %", "92 %"}; 142 | static const lv_settigns_item_t items[3] = { 143 | { .type = LV_SETTINGS_TYPE_SLIDER, .name = "Slider4_1", .value = slider_value[0] .state = (90 * 256) / 100}, 144 | { .type = LV_SETTINGS_TYPE_SLIDER, .name = "Slider4_2", .value = slider_value[1] .state = (91 * 256) / 100}, 145 | { .type = LV_SETTINGS_TYPE_SLIDER, .name = "Slider4_3", .value = slider_value[2] .state = (92 * 256) / 100}, 146 | }; 147 | ``` 148 | 149 | ### Root element 150 | The root element the button which opens the settings menu. It also has to be an item desriptor: 151 | ```c 152 | static lv_settings_item_t root_item = {.name = "Settings", .value = ""}; 153 | ``` 154 | The root element receives `LV_EVENT_CLICKED` event to create its menu. 155 | 156 | 157 | ### Create a page and add items 158 | In the root element's `LV_EVENT_CLICKED` event `lv_settings_open_page(act_item, main_menu_event_cb);` needs to be called to create a menu page: 159 | ```c 160 | void root_event_cb(lv_obj_t * btn, lv_event_t e) 161 | { 162 | if(e == LV_EVENT_CLICKED) { 163 | /*Get the caller item*/ 164 | lv_settings_item_t * act_item = (lv_settings_item_t *)lv_event_get_data(); 165 | 166 | /*Create a new page in the menu*/ 167 | lv_settings_open_page(act_item, main_menu_event_cb); 168 | } 169 | 170 | void main_menu_event_cb(lv_obj_t * btn, lv_event_t e) 171 | { 172 | /*Get the caller item*/ 173 | lv_settings_item_t * act_item = (lv_settings_item_t *)lv_event_get_data(); 174 | 175 | /*Add the meain menu's items */ 176 | if(e == LV_EVENT_REFRESH) { 177 | uint32_t i; 178 | for(i = 0; main_menu_items[i].type != LV_SETTINGS_TYPE_INV; i++) { 179 | lv_settings_add(&main_menu_items[i]); 180 | } 181 | } 182 | ``` 183 | 184 | The new page is created with `lv_settings_open_page` from the `act_item`. `act_item->name` will be the title of the menu page. 185 | `lv_settings_open_page` sends a `LV_EVENT_REFRESH` to the `event_cb` set in the second parameter. These callbacks will be used when: 186 | - the items need to be added again (Open this page when the "Back" button is pressed) 187 | - the items of this page are clicked or their value has been changed. 188 | 189 | ### Handle item events 190 | 191 | It's up to the developer how to handle the the items' event in the`event_cb` of the page. The common point is the triggering element can be get by `lv_settings_item_t * act_item = (lv_settings_item_t *)lv_event_get_data();` 192 | 193 | To figure out which item was triggered the event: 194 | 1. Compare the pointer: `if(act_item == &my_slider_item) { ... }` 195 | 2. Compare the name of item: `if(strcmp(act_item->name, "My slider") == 0) { ... }` 196 | 3. Use the `user_data` as you wish. 197 | 198 | ### Add the root menu button 199 | Once the items are initialized the menu can be created with 200 | ```c 201 | lv_settings_create(&root_item, event_cb); 202 | ``` 203 | 204 | ## Refresh items' data 205 | In the event function probably some data of the item should be refreshed. 206 | Mainly the `value` string formatted as required and the `state` if it needs to be limited or overwritten. 207 | The item's `name` ca ón be updated too. 208 | 209 | The items can be refreshed with `lv_settings_refr(act_item);`. 210 | 211 | For example for a "Number setting" item: 212 | ```c 213 | void motor_menu_event_cb(lv_obj_t * btn, lv_event_t e) 214 | { 215 | /*Get the caller item*/ 216 | lv_settings_item_t * act_item = (lv_settings_item_t *)lv_event_get_data(); 217 | 218 | /*Handle the events of the Motor settings items*/ 219 | if(e == LV_EVENT_VALUE_CHANGED) { 220 | if(strcmp("Max Current", act_item->name) == 0) { 221 | /*Limit the values*/ 222 | if(act_item->state > 10) act_item->state = 10; 223 | if(act_item->state < 1) act_item->state = 1; 224 | 225 | /*Format the value. Assuming `item.value` is set to an array when initialized*/ 226 | sprintf(act_item->value, "%dA", act_item->state); 227 | 228 | /*Refresh the item with the new `state` and `value`*/ 229 | lv_settings_refr(act_item); 230 | } 231 | } 232 | } 233 | ``` 234 | 235 | ## Styling 236 | It's recommended to use a theme to make the menu stylish. `lv_theme_night` and `lv_theme_material` work well with it. Before calling `lv_settings_create` a theme can be applied like this: 237 | ```c 238 | lv_theme_t *th = lv_theme_material_init(210, NULL); 239 | 240 | /*Try with different theme too*/ 241 | // lv_theme_t *th = lv_theme_material_init(10, NULL); 242 | // lv_theme_t *th = lv_theme_night_init(40, NULL); 243 | 244 | lv_theme_set_current(th); 245 | 246 | /*Create the settings menu with a root item*/ 247 | lv_settings_create(&root_item, event_cb); 248 | 249 | ``` 250 | 251 | ## Use with keyboard 252 | The settingsmmenu workd well with keybords too using LittlevGL's [group system](https://docs.littlevgl.com/en/html/overview/indev.html#keypad-and-encoder). Once you have a group is created it can be set in the application. After that, the relevant objects of the items will be automatically added to the group. It workw with `LV_INDEV_TYPE_KEYPAD` and `LV_INDEV_TYPE_ENCODER` too. 253 | ```c 254 | /*Add keyboard or mouswheel input devices if enabled*/ 255 | keyboard_init(); 256 | lv_indev_drv_t indev_drv; 257 | lv_indev_drv_init(&indev_drv); /*Basic initialization*/ 258 | indev_drv.type = LV_INDEV_TYPE_KEYPAD; 259 | indev_drv.read_cb = keyboard_read; /*This function will be called periodically (by the library) to get the mouse position and state*/ 260 | 261 | lv_indev_t * indev = lv_indev_drv_register(&indev_drv); 262 | 263 | lv_group_t * g = lv_group_create(); 264 | lv_indev_set_group(indev, g); 265 | 266 | lv_settings_set_group(g); 267 | 268 | /*Create the settings menu with a root item*/ 269 | lv_settings_create(&root_item, event_cb); 270 | ``` 271 | 272 | ## Examples 273 | 274 | See the [lv_ex_settings](https://github.com/littlevgl/lv_apps/tree/master/examples/lv_ex_settings) folder for examples. 275 | 276 | Just simply call `lv_ex_settings_1()` or `lv_ex_settings_2()` to see some examples of what kind of settings menu you can create. 277 | -------------------------------------------------------------------------------- /examples/lv_ex_settings/lv_ex_settings_2.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file lv_ex_settings_2.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "../../src/lv_settings/lv_settings.h" 10 | #include "lv_drivers/indev/keyboard.h" 11 | #include "lv_drivers/indev/mousewheel.h" 12 | 13 | /********************* 14 | * DEFINES 15 | *********************/ 16 | #ifndef LV_SETTINGS_KEYBOARD 17 | #define LV_SETTINGS_KEYBOARD 0 18 | #endif 19 | 20 | #ifndef LV_SETTINGS_MOUSEWHEEL 21 | #define LV_SETTINGS_MOUSEWHEEL 0 22 | #endif 23 | 24 | /********************** 25 | * TYPEDEFS 26 | **********************/ 27 | typedef enum { 28 | MOTOR_ITEM_RPM = 0, 29 | MOTOR_ITEM_CURRENT, 30 | MOTOR_ITEM_TYPE, 31 | MOTOR_ITEM_PROTECT, 32 | MOTOR_ITEM_TEST, 33 | }motor_item_t; 34 | 35 | typedef enum { 36 | MISC_ITEM_TIME = 0, 37 | MISC_ITEM_BRIGHTNESS, 38 | }misc_item_t; 39 | 40 | typedef enum { 41 | TIME_ITEM_HOURS = 0, 42 | TIME_ITEM_MINS, 43 | }time_item_t; 44 | 45 | /********************** 46 | * STATIC PROTOTYPES 47 | **********************/ 48 | static void root_event_cb(lv_obj_t * btn, lv_event_t e); 49 | static void main_menu_event_cb(lv_obj_t * btn, lv_event_t e); 50 | static void motor_menu_event_cb(lv_obj_t * btn, lv_event_t e); 51 | static void misc_menu_event_cb(lv_obj_t * btn, lv_event_t e); 52 | static void time_menu_event_cb(lv_obj_t * btn, lv_event_t e); 53 | 54 | /********************** 55 | * STATIC VARIABLES 56 | **********************/ 57 | 58 | /*Declare items*/ 59 | static lv_settings_item_t root_item = {.name = "Settings", .value = ""}; 60 | 61 | static lv_settings_item_t main_menu_items[] = 62 | { 63 | {.type = LV_SETTINGS_TYPE_LIST_BTN, .name="Motor settings", .value="Current, RPM, etc"}, 64 | {.type = LV_SETTINGS_TYPE_LIST_BTN, .name="Misc. settings", .value="Time, brightness, etc."}, 65 | {.type = LV_SETTINGS_TYPE_INV}, /*Mark the last item*/ 66 | }; 67 | 68 | static char max_rpm_value[8]; 69 | static char max_current_value[8]; 70 | /*Follow the order of `motor_item_t`*/ 71 | static lv_settings_item_t motor_menu_items[] = { 72 | {.type = LV_SETTINGS_TYPE_SLIDER, .name = "Max RPM", .value = max_rpm_value}, 73 | {.type = LV_SETTINGS_TYPE_NUMSET, .name = "Max Current", .value = max_current_value}, 74 | {.type = LV_SETTINGS_TYPE_DDLIST, .name = "Motor type", .value = "Type 1\n" 75 | "Type 2\n" 76 | "Type 3"}, 77 | {.type = LV_SETTINGS_TYPE_SW, .name = "Short circuit protect", .value = ""}, 78 | {.type = LV_SETTINGS_TYPE_BTN, .name = "Test motor", .value = "Start"}, 79 | {.type = LV_SETTINGS_TYPE_INV}, /*Mark the last item*/ 80 | }; 81 | 82 | 83 | static char time_value[8]; 84 | static char brightness_value[8]; 85 | /*Follow the order of `mics_item_t`*/ 86 | static lv_settings_item_t misc_menu_items[] = 87 | { 88 | {.type = LV_SETTINGS_TYPE_LIST_BTN, .name="Time", .value=time_value}, 89 | {.type = LV_SETTINGS_TYPE_SLIDER, .name="Brightness", .value=brightness_value}, 90 | {.type=LV_SETTINGS_TYPE_INV}, /*Mark the last item*/ 91 | }; 92 | 93 | static char hours_value[3]; 94 | static char mins_value[3]; 95 | /*Follow the order of `time_item_t`*/ 96 | static lv_settings_item_t time_menu_items[] = 97 | { 98 | {.type = LV_SETTINGS_TYPE_NUMSET, .name="Hour", .value=hours_value}, 99 | {.type = LV_SETTINGS_TYPE_NUMSET, .name="Minute", .value=mins_value}, 100 | {.type=LV_SETTINGS_TYPE_INV}, /*Mark the last item*/ 101 | }; 102 | 103 | 104 | 105 | /********************** 106 | * MACROS 107 | **********************/ 108 | 109 | /********************** 110 | * GLOBAL FUNCTIONS 111 | **********************/ 112 | 113 | void lv_ex_settings_2(void) 114 | { 115 | lv_theme_t *th = lv_theme_material_init(210, NULL); 116 | 117 | /*Try with different theme too*/ 118 | // lv_theme_t *th = lv_theme_material_init(10, NULL); 119 | // lv_theme_t *th = lv_theme_night_init(40, NULL); 120 | 121 | lv_theme_set_current(th); 122 | 123 | 124 | /*Add keyboard or mousewheel input devices if enabled*/ 125 | #if LV_SETTINGS_KEYBOARD 126 | keyboard_init(); 127 | lv_indev_drv_t indev_drv; 128 | lv_indev_drv_init(&indev_drv); /*Basic initialization*/ 129 | indev_drv.type = LV_INDEV_TYPE_KEYPAD; 130 | indev_drv.read_cb = keyboard_read; /*This function will be called periodically (by the library) to get the mouse position and state*/ 131 | 132 | #elif LV_SETTINGS_MOUSEWHEEL 133 | mousewheel_init(); 134 | lv_indev_drv_t indev_drv; 135 | lv_indev_drv_init(&indev_drv); /*Basic initialization*/ 136 | indev_drv.type = LV_INDEV_TYPE_ENCODER; 137 | indev_drv.read_cb = mousewheel_read; /*This function will be called periodically (by the library) to get the mouse position and state*/ 138 | #endif 139 | 140 | #if LV_SETTINGS_KEYBOARD || LV_SETTINGS_MOUSEWHEEL 141 | lv_indev_t * indev = lv_indev_drv_register(&indev_drv); 142 | 143 | lv_group_t * g = lv_group_create(); 144 | lv_indev_set_group(indev, g); 145 | lv_settings_set_group(g); 146 | #endif 147 | 148 | 149 | /*Load the default values*/ 150 | lv_settings_item_t * i; 151 | 152 | /*Motor menu*/ 153 | i = &motor_menu_items[MOTOR_ITEM_RPM]; 154 | i->state = 80; 155 | sprintf(i->value, "%dRPM", i->state); 156 | 157 | 158 | i = &motor_menu_items[MOTOR_ITEM_CURRENT]; 159 | i->state = 3; 160 | sprintf(i->value, "%dA", i->state); 161 | 162 | i = &motor_menu_items[MOTOR_ITEM_TYPE]; 163 | i->state = 1; 164 | 165 | i = &motor_menu_items[MOTOR_ITEM_PROTECT]; 166 | i->state = 0; 167 | i->value = "Not protected"; 168 | 169 | i = &motor_menu_items[MOTOR_ITEM_TEST]; 170 | i->value = "Start"; 171 | 172 | /*Time menu*/ 173 | i = &time_menu_items[TIME_ITEM_HOURS]; 174 | i->state = 10; 175 | sprintf(i->value, "%d", i->state); 176 | 177 | i = &time_menu_items[TIME_ITEM_MINS]; 178 | i->state = 35; 179 | sprintf(i->value, "%d", i->state); 180 | 181 | /*Misc menu*/ 182 | i = &misc_menu_items[MISC_ITEM_BRIGHTNESS]; 183 | i->state = 128; 184 | sprintf(i->value, "%d%%", (i->state * 100) / 256); 185 | 186 | i = &misc_menu_items[MISC_ITEM_TIME]; 187 | sprintf(i->value, "%d:%d", time_menu_items[TIME_ITEM_HOURS].state, time_menu_items[TIME_ITEM_MINS].state); 188 | 189 | 190 | /*Create the settings menu with a root item*/ 191 | lv_obj_t *btn = lv_settings_create(&root_item, root_event_cb); 192 | lv_obj_align(btn, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 0); 193 | lv_settings_set_max_width(lv_obj_get_width(lv_scr_act())/2); 194 | } 195 | 196 | /********************** 197 | * STATIC FUNCTIONS 198 | **********************/ 199 | 200 | static void root_event_cb(lv_obj_t * btn, lv_event_t e) 201 | { 202 | (void)btn; /*Unused*/ 203 | 204 | /*If the root element was clicked or asks for create a main menu*/ 205 | if(e == LV_EVENT_CLICKED) { 206 | /*Get the caller item*/ 207 | lv_settings_item_t * act_item = (lv_settings_item_t *)lv_event_get_data(); 208 | 209 | lv_settings_open_page(act_item, main_menu_event_cb); 210 | } 211 | } 212 | 213 | static void main_menu_event_cb(lv_obj_t * btn, lv_event_t e) 214 | { 215 | (void)btn; /*Unused*/ 216 | 217 | /*Get the caller item*/ 218 | lv_settings_item_t * act_item = (lv_settings_item_t *)lv_event_get_data(); 219 | 220 | if(e == LV_EVENT_REFRESH) { 221 | 222 | uint32_t i; 223 | for(i = 0; main_menu_items[i].type != LV_SETTINGS_TYPE_INV; i++) { 224 | lv_settings_add(&main_menu_items[i]); 225 | } 226 | } 227 | else if(e == LV_EVENT_CLICKED) { 228 | if(strcmp(act_item->name, "Motor settings") == 0) { 229 | lv_settings_open_page(act_item, motor_menu_event_cb); 230 | } 231 | else if(strcmp(act_item->name, "Misc. settings") == 0) { 232 | lv_settings_open_page(act_item, misc_menu_event_cb); 233 | } 234 | } 235 | } 236 | 237 | static void motor_menu_event_cb(lv_obj_t * btn, lv_event_t e) 238 | { 239 | (void)btn; /*Unused*/ 240 | 241 | /*Get the caller item*/ 242 | lv_settings_item_t * act_item = (lv_settings_item_t *)lv_event_get_data(); 243 | 244 | if(e == LV_EVENT_REFRESH) { 245 | /*Add the motor_menu_items*/ 246 | uint32_t i; 247 | for(i = 0; motor_menu_items[i].type != LV_SETTINGS_TYPE_INV; i++) { 248 | lv_settings_add(&motor_menu_items[i]); 249 | } 250 | } 251 | else if(e == LV_EVENT_VALUE_CHANGED) { 252 | if(strcmp("Max RPM", act_item->name) == 0) { 253 | sprintf(act_item->value, "%dRPM", act_item->state); 254 | lv_settings_refr(act_item); 255 | } 256 | if(strcmp("Max Current", act_item->name) == 0) { 257 | if(act_item->state > 10) act_item->state = 10; 258 | if(act_item->state < 1) act_item->state = 1; 259 | sprintf(act_item->value, "%dA", act_item->state); 260 | lv_settings_refr(act_item); 261 | } 262 | else if(strcmp("Motor type", act_item->name) == 0) { 263 | printf("ddlist: %d\n", act_item->state); 264 | } 265 | else if(strcmp("Short circuit protect", act_item->name) == 0) { 266 | if(act_item->state) act_item->value = "Protected"; 267 | else act_item->value = "Not protected"; 268 | lv_settings_refr(act_item); 269 | } 270 | } 271 | else if(e == LV_EVENT_CLICKED) { 272 | if(strcmp("Test motor", act_item->name) == 0) { 273 | if(strcmp("Start", act_item->value) == 0) act_item->value = "Stop"; 274 | else act_item->value = "Start"; 275 | 276 | lv_settings_refr(act_item); 277 | } 278 | } 279 | } 280 | 281 | static void misc_menu_event_cb(lv_obj_t * btn, lv_event_t e) 282 | { 283 | (void)btn; /*Unused*/ 284 | 285 | /*Get the caller act_item*/ 286 | lv_settings_item_t * act_item = (lv_settings_item_t *)lv_event_get_data(); 287 | 288 | if(e == LV_EVENT_REFRESH) { 289 | 290 | /*Add the misc_menu_items*/ 291 | uint32_t i; 292 | for(i = 0; misc_menu_items[i].type != LV_SETTINGS_TYPE_INV; i++) { 293 | lv_settings_add(&misc_menu_items[i]); 294 | } 295 | } 296 | /*Handle the events of the Misc menu items*/ 297 | else if(e == LV_EVENT_CLICKED) { 298 | if(strcmp("Time", act_item->name) == 0) { 299 | lv_settings_open_page(act_item, time_menu_event_cb); 300 | } 301 | 302 | } 303 | else if(e == LV_EVENT_VALUE_CHANGED) { 304 | if(strcmp("Brightness", act_item->name) == 0) { 305 | sprintf(act_item->value, "%d%%", (act_item->state * 100) / 256); 306 | lv_settings_refr(act_item); 307 | } 308 | } 309 | } 310 | 311 | static void time_menu_event_cb(lv_obj_t * obj, lv_event_t e) 312 | { 313 | (void)obj; /*Unused*/ 314 | 315 | /*Get the caller act_item*/ 316 | lv_settings_item_t * act_item = (lv_settings_item_t *)lv_event_get_data(); 317 | 318 | if(e == LV_EVENT_REFRESH) { 319 | 320 | /*Add the items*/ 321 | uint32_t i; 322 | for(i = 0; time_menu_items[i].type != LV_SETTINGS_TYPE_INV; i++) { 323 | lv_settings_add(&time_menu_items[i]); 324 | } 325 | } 326 | else if(e == LV_EVENT_VALUE_CHANGED) { 327 | if(strcmp("Hour", act_item->name) == 0) { 328 | if(act_item->state > 23) act_item->state = 0; 329 | if(act_item->state < 0) act_item->state = 23; 330 | 331 | sprintf(act_item->value, "%d", act_item->state); 332 | lv_settings_refr(act_item); 333 | 334 | sprintf(misc_menu_items[0].value, "%02d:%02d", time_menu_items[0].state, time_menu_items[1].state); 335 | 336 | } 337 | else if(strcmp("Minute", act_item->name) == 0) { 338 | if(act_item->state > 59) act_item->state = 0; 339 | if(act_item->state < 0) act_item->state = 59; 340 | 341 | sprintf(act_item->value, "%d", act_item->state); 342 | lv_settings_refr(act_item); 343 | 344 | sprintf(misc_menu_items[0].value, "%02d:%02d", time_menu_items[0].state, time_menu_items[1].state); 345 | } 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /src/lv_tpcal/lv_tpcal.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file tpcal.c 3 | * 4 | * TOUCHPAD CALIBRATION 5 | * --------------------- 6 | * 7 | * This application creates a GUI and instruct the user 8 | * to click the four corners to get data for touchpad calibration. 9 | * 10 | * - You display driver should have two functions: `xxx_read` and `xxx_set_cal_data`. 11 | * - At first run run the touchpad is not calibrated therefore your `xxx_read` function should provide raw data. 12 | * - When the user touched all four corners you should call the `xxx_set_cal_data` function in 13 | * ` TP_CAL_STATE_WAIT_LEAVE` state. As arguments you should pass `point[0]`, `point[1]`, `point[2]` and `point[3]` 14 | * which are the coordinates read on corner pressing. 15 | * - `xxx_set_cal_data` should mark the display as calibrated, save the raw coordinates 16 | * and use them in the upcoming calls of `xxx_read` to adjust the coordinates. 17 | * - A simple equation to adjust the coordinates: x_cal = ((x_act - x1_saved) * lcd_hor_res) / (x2_saved - x1_saved); 18 | * - x_cal: the calibrated X coordinate 19 | * - x_act: the currently measured X coordinate 20 | * - x1_saved, x2_saved: The raw X coordinates saved as calibration data 21 | */ 22 | 23 | /********************* 24 | * INCLUDES 25 | *********************/ 26 | #include "lv_tpcal.h" 27 | #if LV_USE_TPCAL 28 | #include 29 | 30 | /********************* 31 | * DEFINES 32 | *********************/ 33 | #define CIRCLE_SIZE 20 34 | #define CIRCLE_OFFSET 20 35 | #define TP_MAX_VALUE 5000 36 | #define TOUCH_NUMBER 3 37 | 38 | /********************** 39 | * TYPEDEFS 40 | **********************/ 41 | typedef enum { 42 | TP_CAL_STATE_INIT, 43 | TP_CAL_STATE_WAIT_TOP_LEFT, 44 | TP_CAL_STATE_WAIT_TOP_RIGHT, 45 | TP_CAL_STATE_WAIT_BOTTOM_RIGHT, 46 | TP_CAL_STATE_WAIT_BOTTOM_LEFT, 47 | TP_CAL_STATE_WAIT_LEAVE, 48 | TP_CAL_STATE_READY, 49 | } tp_cal_state_t; 50 | 51 | /********************** 52 | * STATIC PROTOTYPES 53 | **********************/ 54 | static void get_avr_value(lv_point_t * p); 55 | static void btn_event_cb(lv_obj_t * scr, lv_event_t event); 56 | 57 | /********************** 58 | * STATIC VARIABLES 59 | **********************/ 60 | static lv_point_t point[4]; /*Calibration points: [0]: top-left; [1]: top-right, [2]: bottom-right, [3]: bottom-left */ 61 | static lv_point_t avr[TOUCH_NUMBER]; /*Storage point to calculate average*/ 62 | 63 | static tp_cal_state_t state; 64 | static lv_obj_t * prev_scr; 65 | static lv_obj_t * big_btn; 66 | static lv_obj_t * label_main; 67 | static lv_obj_t * circ_area; 68 | 69 | /********************** 70 | * MACROS 71 | **********************/ 72 | 73 | /********************** 74 | * GLOBAL FUNCTIONS 75 | **********************/ 76 | 77 | /** 78 | * Create a touch pad calibration screen 79 | */ 80 | void tpcal_create(void) 81 | { 82 | state = TP_CAL_STATE_INIT; 83 | 84 | prev_scr = lv_disp_get_scr_act(NULL); 85 | 86 | lv_obj_t * scr = lv_obj_create(NULL, NULL); 87 | lv_obj_set_size(scr, TP_MAX_VALUE, TP_MAX_VALUE); 88 | lv_disp_load_scr(scr); 89 | 90 | /*Create a big transparent button screen to receive clicks*/ 91 | big_btn = lv_btn_create(lv_disp_get_scr_act(NULL), NULL); 92 | lv_obj_set_size(big_btn, TP_MAX_VALUE, TP_MAX_VALUE); 93 | lv_btn_set_style(big_btn, LV_BTN_STYLE_REL, &lv_style_transp); 94 | lv_btn_set_style(big_btn, LV_BTN_STYLE_PR, &lv_style_transp); 95 | lv_obj_set_event_cb(big_btn, btn_event_cb); 96 | lv_btn_set_layout(big_btn, LV_LAYOUT_OFF); 97 | 98 | label_main = lv_label_create(lv_disp_get_scr_act(NULL), NULL); 99 | char buf[64]; 100 | sprintf(buf, "Click the circle in\n" 101 | "upper left-hand corner\n" 102 | "%u left", TOUCH_NUMBER); 103 | lv_label_set_text(label_main, buf); 104 | lv_label_set_align(label_main, LV_LABEL_ALIGN_CENTER); 105 | 106 | lv_coord_t hres = lv_disp_get_hor_res(NULL); 107 | lv_coord_t vres = lv_disp_get_ver_res(NULL); 108 | 109 | lv_obj_set_pos(label_main, (hres - lv_obj_get_width(label_main)) / 2, 110 | (vres - lv_obj_get_height(label_main)) / 2); 111 | 112 | 113 | static lv_style_t style_circ; 114 | lv_style_copy(&style_circ, &lv_style_pretty_color); 115 | style_circ.body.radius = LV_RADIUS_CIRCLE; 116 | 117 | circ_area = lv_obj_create(lv_disp_get_scr_act(NULL), NULL); 118 | lv_obj_set_size(circ_area, CIRCLE_SIZE, CIRCLE_SIZE); 119 | lv_obj_set_style(circ_area, &style_circ); 120 | lv_obj_set_click(circ_area, false); 121 | 122 | #if LV_USE_ANIMATION 123 | lv_anim_t a; 124 | a.var = circ_area; 125 | a.start = hres / 2; 126 | a.end = CIRCLE_OFFSET; 127 | a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_x; 128 | a.path_cb = lv_anim_path_linear; 129 | a.ready_cb = NULL; 130 | a.act_time = -500; 131 | a.time = 200; 132 | a.playback = 0; 133 | a.playback_pause = 0; 134 | a.repeat = 0; 135 | a.repeat_pause = 0; 136 | lv_anim_create(&a); 137 | 138 | a.start = vres / 2; 139 | a.end = CIRCLE_OFFSET; 140 | a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_y; 141 | a.ready_cb = NULL; 142 | a.time = 200; 143 | lv_anim_create(&a); 144 | #else 145 | lv_obj_set_pos(circ_area, CIRCLE_OFFSET, CIRCLE_OFFSET); 146 | #endif 147 | 148 | state = TP_CAL_STATE_WAIT_TOP_LEFT; 149 | } 150 | 151 | /********************** 152 | * STATIC FUNCTIONS 153 | **********************/ 154 | 155 | static void get_avr_value(lv_point_t * p) 156 | { 157 | int32_t x_sum = 0; 158 | int32_t y_sum = 0; 159 | uint8_t i = 0; 160 | for(; i < TOUCH_NUMBER ; i++) { 161 | x_sum += avr[i].x; 162 | y_sum += avr[i].y; 163 | } 164 | p->x = x_sum / TOUCH_NUMBER; 165 | p->y = y_sum / TOUCH_NUMBER; 166 | } 167 | 168 | static void btn_event_cb(lv_obj_t * scr, lv_event_t event) 169 | { 170 | (void) scr; /*Unused*/ 171 | 172 | if(event != LV_EVENT_CLICKED) return; 173 | 174 | lv_disp_t * disp = lv_obj_get_disp(prev_scr); 175 | lv_coord_t hres = lv_disp_get_hor_res(disp); 176 | lv_coord_t vres = lv_disp_get_ver_res(disp); 177 | 178 | static uint8_t touch_nb = TOUCH_NUMBER; 179 | 180 | if(state == TP_CAL_STATE_WAIT_TOP_LEFT) { 181 | char buf[64]; 182 | touch_nb--; 183 | lv_indev_t * indev = lv_indev_get_act(); 184 | lv_indev_get_point(indev, &avr[touch_nb]); 185 | 186 | if(!touch_nb) { 187 | touch_nb = TOUCH_NUMBER; 188 | get_avr_value(&point[0]); 189 | sprintf(buf, "x: %d\ny: %d", point[0].x, point[0].y); 190 | lv_obj_t * label_coord = lv_label_create(lv_disp_get_scr_act(disp), NULL); 191 | lv_label_set_text(label_coord, buf); 192 | sprintf(buf, "Click the circle in\n" 193 | "upper right-hand corner\n" 194 | " %u Left", TOUCH_NUMBER); 195 | #if LV_USE_ANIMATION 196 | lv_anim_t a; 197 | a.var = circ_area; 198 | a.start = CIRCLE_OFFSET; 199 | a.end = hres - CIRCLE_SIZE - CIRCLE_OFFSET; 200 | a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_x; 201 | a.path_cb = lv_anim_path_linear; 202 | a.ready_cb = NULL; 203 | a.act_time = 0; 204 | a.time = 200; 205 | a.playback = 0; 206 | a.playback_pause = 0; 207 | a.repeat = 0; 208 | a.repeat_pause = 0; 209 | lv_anim_create(&a); 210 | 211 | a.start = CIRCLE_OFFSET; 212 | a.end = CIRCLE_OFFSET; 213 | a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_y; 214 | a.ready_cb = NULL; 215 | a.time = 200; 216 | lv_anim_create(&a); 217 | #else 218 | lv_obj_set_pos(circ_area, LV_HOR_RES - CIRCLE_SIZE - CIRCLE_OFFSET, CIRCLE_OFFSET); 219 | #endif 220 | state = TP_CAL_STATE_WAIT_TOP_RIGHT; 221 | } else { 222 | sprintf(buf, "Click the circle in\n" 223 | "upper left-hand corner\n" 224 | " %u Left", touch_nb); 225 | } 226 | lv_label_set_text(label_main, buf); 227 | lv_obj_set_pos(label_main, (hres - lv_obj_get_width(label_main)) / 2, 228 | (vres - lv_obj_get_height(label_main)) / 2); 229 | 230 | 231 | } else if(state == TP_CAL_STATE_WAIT_TOP_RIGHT) { 232 | char buf[64]; 233 | touch_nb--; 234 | lv_indev_t * indev = lv_indev_get_act(); 235 | lv_indev_get_point(indev, &avr[touch_nb]); 236 | 237 | if(!touch_nb) { 238 | touch_nb = TOUCH_NUMBER; 239 | get_avr_value(&point[1]); 240 | sprintf(buf, "x: %d\ny: %d", point[1].x, point[1].y); 241 | lv_obj_t * label_coord = lv_label_create(lv_disp_get_scr_act(disp), NULL); 242 | lv_label_set_text(label_coord, buf); 243 | lv_obj_set_pos(label_coord, hres - lv_obj_get_width(label_coord), 0); 244 | sprintf(buf, "Click the circle in\n" 245 | "lower right-hand corner\n" 246 | " %u Left", TOUCH_NUMBER); 247 | #if LV_USE_ANIMATION 248 | lv_anim_t a; 249 | a.var = circ_area; 250 | a.start = hres - CIRCLE_SIZE - CIRCLE_OFFSET; 251 | a.end = hres - CIRCLE_SIZE - CIRCLE_OFFSET; 252 | a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_x; 253 | a.path_cb = lv_anim_path_linear; 254 | a.ready_cb = NULL; 255 | a.act_time = 0; 256 | a.time = 200; 257 | a.playback = 0; 258 | a.playback_pause = 0; 259 | a.repeat = 0; 260 | a.repeat_pause = 0; 261 | lv_anim_create(&a); 262 | 263 | a.start = CIRCLE_OFFSET; 264 | a.end = vres - CIRCLE_SIZE - CIRCLE_OFFSET; 265 | a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_y; 266 | a.ready_cb = NULL; 267 | a.time = 200; 268 | lv_anim_create(&a); 269 | #else 270 | lv_obj_set_pos(circ_area, hres - CIRCLE_SIZE - CIRCLE_OFFSET, vres - CIRCLE_SIZE - CIRCLE_OFFSET); 271 | #endif 272 | state = TP_CAL_STATE_WAIT_BOTTOM_RIGHT; 273 | } else { 274 | sprintf(buf, "Click the circle in\n" 275 | "upper right-hand corner\n" 276 | " %u Left", touch_nb); 277 | } 278 | lv_label_set_text(label_main, buf); 279 | lv_obj_set_pos(label_main, (hres - lv_obj_get_width(label_main)) / 2, 280 | (vres - lv_obj_get_height(label_main)) / 2); 281 | 282 | } else if(state == TP_CAL_STATE_WAIT_BOTTOM_RIGHT) { 283 | char buf[64]; 284 | touch_nb--; 285 | lv_indev_t * indev = lv_indev_get_act(); 286 | lv_indev_get_point(indev, &avr[touch_nb]); 287 | 288 | if(!touch_nb) { 289 | touch_nb = TOUCH_NUMBER; 290 | get_avr_value(&point[2]); 291 | sprintf(buf, "x: %d\ny: %d", point[2].x, point[2].y); 292 | lv_obj_t * label_coord = lv_label_create(scr, NULL); 293 | lv_label_set_text(label_coord, buf); 294 | sprintf(buf, "Click the circle in\n" 295 | "lower left-hand corner\n" 296 | " %u Left", TOUCH_NUMBER); 297 | lv_obj_set_pos(label_coord, hres - lv_obj_get_width(label_coord), 298 | vres - lv_obj_get_height(label_coord)); 299 | #if LV_USE_ANIMATION 300 | lv_anim_t a; 301 | a.var = circ_area; 302 | a.start = hres - CIRCLE_SIZE - CIRCLE_OFFSET; 303 | a.end = CIRCLE_OFFSET; 304 | a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_x; 305 | a.path_cb = lv_anim_path_linear; 306 | a.ready_cb = NULL; 307 | a.act_time = 0; 308 | a.time = 200; 309 | a.playback = 0; 310 | a.playback_pause = 0; 311 | a.repeat = 0; 312 | a.repeat_pause = 0; 313 | lv_anim_create(&a); 314 | 315 | a.start = vres - CIRCLE_SIZE - CIRCLE_OFFSET; 316 | a.end = vres - CIRCLE_SIZE - CIRCLE_OFFSET; 317 | a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_y; 318 | a.ready_cb = NULL; 319 | a.time = 200; 320 | lv_anim_create(&a); 321 | #else 322 | lv_obj_set_pos(circ_area, CIRCLE_OFFSET, LV_VER_RES - CIRCLE_SIZE - CIRCLE_OFFSET); 323 | #endif 324 | state = TP_CAL_STATE_WAIT_BOTTOM_LEFT; 325 | } else { 326 | sprintf(buf, "Click the circle in\n" 327 | "lower right-hand corner\n" 328 | " %u Left", touch_nb); 329 | } 330 | lv_label_set_text(label_main, buf); 331 | lv_obj_set_pos(label_main, (hres - lv_obj_get_width(label_main)) / 2, 332 | (vres - lv_obj_get_height(label_main)) / 2); 333 | } else if(state == TP_CAL_STATE_WAIT_BOTTOM_LEFT) { 334 | char buf[64]; 335 | touch_nb--; 336 | lv_indev_t * indev = lv_indev_get_act(); 337 | lv_indev_get_point(indev, &avr[touch_nb]); 338 | 339 | if(!touch_nb) { 340 | touch_nb = TOUCH_NUMBER; 341 | get_avr_value(&point[3]); 342 | sprintf(buf, "x: %d\ny: %d", point[3].x, point[3].y); 343 | lv_obj_t * label_coord = lv_label_create(scr, NULL); 344 | lv_label_set_text(label_coord, buf); 345 | lv_obj_set_pos(label_coord, 0, vres - lv_obj_get_height(label_coord)); 346 | sprintf(buf, "Click the screen\n" 347 | "to leave calibration"); 348 | lv_obj_del(circ_area); 349 | state = TP_CAL_STATE_WAIT_LEAVE; 350 | } else { 351 | sprintf(buf, "Click the circle in\n" 352 | "lower left-hand corner\n" 353 | " %u Left", touch_nb); 354 | } 355 | lv_label_set_text(label_main, buf); 356 | lv_obj_set_pos(label_main, (hres - lv_obj_get_width(label_main)) / 2, 357 | (vres - lv_obj_get_height(label_main)) / 2); 358 | } else if(state == TP_CAL_STATE_WAIT_LEAVE) { 359 | lv_disp_load_scr(prev_scr); 360 | 361 | /* 362 | * TODO Process 'p' points here to calibrate the touch pad 363 | * Offset will be: CIRCLE_SIZE/2 + CIRCLE_OFFSET 364 | */ 365 | 366 | /* 367 | * TODO: you can change the calibrate input callback here e.g: 368 | * lv_indev_t *indev = lv_indev_get_act(); 369 | * indev->driver.read = xxxx_input_get_calib; 370 | */ 371 | 372 | state = TP_CAL_STATE_READY; 373 | 374 | } else if(state == TP_CAL_STATE_READY) { 375 | } 376 | } 377 | 378 | #endif /*LV_USE_TPCAL*/ 379 | -------------------------------------------------------------------------------- /src/lv_demo/lv_demo.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file demo.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "lv_demo.h" 10 | #if LV_USE_DEMO 11 | 12 | /********************* 13 | * DEFINES 14 | *********************/ 15 | 16 | /********************** 17 | * TYPEDEFS 18 | **********************/ 19 | 20 | /********************** 21 | * STATIC PROTOTYPES 22 | **********************/ 23 | static void write_create(lv_obj_t * parent); 24 | static void text_area_event_handler(lv_obj_t * text_area, lv_event_t event); 25 | static void keyboard_event_cb(lv_obj_t * keyboard, lv_event_t event); 26 | #if LV_USE_ANIMATION 27 | static void kb_hide_anim_end(lv_anim_t * a); 28 | #endif 29 | static void list_create(lv_obj_t * parent); 30 | static void chart_create(lv_obj_t * parent); 31 | static void slider_event_handler(lv_obj_t * slider, lv_event_t event); 32 | static void list_btn_event_handler(lv_obj_t * slider, lv_event_t event); 33 | #if LV_DEMO_SLIDE_SHOW 34 | static void tab_switcher(lv_task_t * task); 35 | #endif 36 | 37 | /********************** 38 | * STATIC VARIABLES 39 | **********************/ 40 | static lv_obj_t * chart; 41 | static lv_obj_t * ta; 42 | static lv_obj_t * kb; 43 | 44 | static lv_style_t style_kb; 45 | static lv_style_t style_kb_rel; 46 | static lv_style_t style_kb_pr; 47 | 48 | #if LV_DEMO_WALLPAPER 49 | LV_IMG_DECLARE(img_bubble_pattern) 50 | #endif 51 | 52 | /********************** 53 | * MACROS 54 | **********************/ 55 | 56 | /********************** 57 | * GLOBAL FUNCTIONS 58 | **********************/ 59 | 60 | /** 61 | * Create a demo application 62 | */ 63 | void demo_create(void) 64 | { 65 | lv_coord_t hres = lv_disp_get_hor_res(NULL); 66 | lv_coord_t vres = lv_disp_get_ver_res(NULL); 67 | 68 | #if LV_DEMO_WALLPAPER 69 | lv_obj_t * wp = lv_img_create(lv_disp_get_scr_act(NULL), NULL); 70 | lv_img_set_src(wp, &img_bubble_pattern); 71 | lv_obj_set_width(wp, hres * 4); 72 | lv_obj_set_protect(wp, LV_PROTECT_POS); 73 | #endif 74 | 75 | static lv_style_t style_tv_btn_bg; 76 | lv_style_copy(&style_tv_btn_bg, &lv_style_plain); 77 | style_tv_btn_bg.body.main_color = lv_color_hex(0x487fb7); 78 | style_tv_btn_bg.body.grad_color = lv_color_hex(0x487fb7); 79 | style_tv_btn_bg.body.padding.top = 0; 80 | style_tv_btn_bg.body.padding.bottom = 0; 81 | 82 | static lv_style_t style_tv_btn_rel; 83 | lv_style_copy(&style_tv_btn_rel, &lv_style_btn_rel); 84 | style_tv_btn_rel.body.opa = LV_OPA_TRANSP; 85 | style_tv_btn_rel.body.border.width = 0; 86 | 87 | static lv_style_t style_tv_btn_pr; 88 | lv_style_copy(&style_tv_btn_pr, &lv_style_btn_pr); 89 | style_tv_btn_pr.body.radius = 0; 90 | style_tv_btn_pr.body.opa = LV_OPA_50; 91 | style_tv_btn_pr.body.main_color = LV_COLOR_WHITE; 92 | style_tv_btn_pr.body.grad_color = LV_COLOR_WHITE; 93 | style_tv_btn_pr.body.border.width = 0; 94 | style_tv_btn_pr.text.color = LV_COLOR_GRAY; 95 | 96 | lv_obj_t * tv = lv_tabview_create(lv_disp_get_scr_act(NULL), NULL); 97 | lv_obj_set_size(tv, hres, vres); 98 | 99 | #if LV_DEMO_WALLPAPER 100 | lv_obj_set_parent(wp, ((lv_tabview_ext_t *) tv->ext_attr)->content); 101 | lv_obj_set_pos(wp, 0, -5); 102 | #endif 103 | 104 | lv_obj_t * tab1 = lv_tabview_add_tab(tv, "Write"); 105 | lv_obj_t * tab2 = lv_tabview_add_tab(tv, "List"); 106 | lv_obj_t * tab3 = lv_tabview_add_tab(tv, "Chart"); 107 | 108 | #if LV_DEMO_WALLPAPER == 0 109 | /*Blue bg instead of wallpaper*/ 110 | lv_tabview_set_style(tv, LV_TABVIEW_STYLE_BG, &style_tv_btn_bg); 111 | #endif 112 | lv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_BG, &style_tv_btn_bg); 113 | lv_tabview_set_style(tv, LV_TABVIEW_STYLE_INDIC, &lv_style_plain); 114 | lv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_REL, &style_tv_btn_rel); 115 | lv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_PR, &style_tv_btn_pr); 116 | lv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_TGL_REL, &style_tv_btn_rel); 117 | lv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_TGL_PR, &style_tv_btn_pr); 118 | 119 | write_create(tab1); 120 | list_create(tab2); 121 | chart_create(tab3); 122 | 123 | #if LV_DEMO_SLIDE_SHOW 124 | lv_task_create(tab_switcher, 3000, LV_TASK_PRIO_MID, tv); 125 | #endif 126 | } 127 | 128 | 129 | /********************** 130 | * STATIC FUNCTIONS 131 | **********************/ 132 | 133 | static void write_create(lv_obj_t * parent) 134 | { 135 | lv_page_set_style(parent, LV_PAGE_STYLE_BG, &lv_style_transp_fit); 136 | lv_page_set_style(parent, LV_PAGE_STYLE_SCRL, &lv_style_transp_fit); 137 | 138 | lv_page_set_sb_mode(parent, LV_SB_MODE_OFF); 139 | 140 | static lv_style_t style_ta; 141 | lv_style_copy(&style_ta, &lv_style_pretty); 142 | style_ta.body.opa = LV_OPA_30; 143 | style_ta.body.radius = 0; 144 | style_ta.text.color = lv_color_hex3(0x222); 145 | 146 | ta = lv_ta_create(parent, NULL); 147 | lv_obj_set_size(ta, lv_page_get_scrl_width(parent), lv_obj_get_height(parent) / 2); 148 | lv_ta_set_style(ta, LV_TA_STYLE_BG, &style_ta); 149 | lv_ta_set_text(ta, ""); 150 | lv_obj_set_event_cb(ta, text_area_event_handler); 151 | lv_style_copy(&style_kb, &lv_style_plain); 152 | lv_ta_set_text_sel(ta, true); 153 | 154 | style_kb.body.opa = LV_OPA_70; 155 | style_kb.body.main_color = lv_color_hex3(0x333); 156 | style_kb.body.grad_color = lv_color_hex3(0x333); 157 | style_kb.body.padding.left = 0; 158 | style_kb.body.padding.right = 0; 159 | style_kb.body.padding.top = 0; 160 | style_kb.body.padding.bottom = 0; 161 | style_kb.body.padding.inner = 0; 162 | 163 | lv_style_copy(&style_kb_rel, &lv_style_plain); 164 | style_kb_rel.body.opa = LV_OPA_TRANSP; 165 | style_kb_rel.body.radius = 0; 166 | style_kb_rel.body.border.width = 1; 167 | style_kb_rel.body.border.color = LV_COLOR_SILVER; 168 | style_kb_rel.body.border.opa = LV_OPA_50; 169 | style_kb_rel.body.main_color = lv_color_hex3(0x333); /*Recommended if LV_VDB_SIZE == 0 and bpp > 1 fonts are used*/ 170 | style_kb_rel.body.grad_color = lv_color_hex3(0x333); 171 | style_kb_rel.text.color = LV_COLOR_WHITE; 172 | 173 | lv_style_copy(&style_kb_pr, &lv_style_plain); 174 | style_kb_pr.body.radius = 0; 175 | style_kb_pr.body.opa = LV_OPA_50; 176 | style_kb_pr.body.main_color = LV_COLOR_WHITE; 177 | style_kb_pr.body.grad_color = LV_COLOR_WHITE; 178 | style_kb_pr.body.border.width = 1; 179 | style_kb_pr.body.border.color = LV_COLOR_SILVER; 180 | 181 | } 182 | 183 | static void text_area_event_handler(lv_obj_t * text_area, lv_event_t event) 184 | { 185 | (void) text_area; /*Unused*/ 186 | 187 | /*Text area is on the scrollable part of the page but we need the page itself*/ 188 | lv_obj_t * parent = lv_obj_get_parent(lv_obj_get_parent(ta)); 189 | 190 | if(event == LV_EVENT_CLICKED) { 191 | if(kb == NULL) { 192 | kb = lv_kb_create(parent, NULL); 193 | lv_obj_set_size(kb, lv_obj_get_width_fit(parent), lv_obj_get_height_fit(parent) / 2); 194 | lv_obj_align(kb, ta, LV_ALIGN_OUT_BOTTOM_MID, 0, 0); 195 | lv_kb_set_ta(kb, ta); 196 | lv_kb_set_style(kb, LV_KB_STYLE_BG, &style_kb); 197 | lv_kb_set_style(kb, LV_KB_STYLE_BTN_REL, &style_kb_rel); 198 | lv_kb_set_style(kb, LV_KB_STYLE_BTN_PR, &style_kb_pr); 199 | lv_obj_set_event_cb(kb, keyboard_event_cb); 200 | 201 | #if LV_USE_ANIMATION 202 | lv_anim_t a; 203 | a.var = kb; 204 | a.start = LV_VER_RES; 205 | a.end = lv_obj_get_y(kb); 206 | a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_y; 207 | a.path_cb = lv_anim_path_linear; 208 | a.ready_cb = NULL; 209 | a.act_time = 0; 210 | a.time = 300; 211 | a.playback = 0; 212 | a.playback_pause = 0; 213 | a.repeat = 0; 214 | a.repeat_pause = 0; 215 | lv_anim_create(&a); 216 | #endif 217 | } 218 | } 219 | 220 | } 221 | 222 | /** 223 | * Called when the close or ok button is pressed on the keyboard 224 | * @param keyboard pointer to the keyboard 225 | * @return 226 | */ 227 | static void keyboard_event_cb(lv_obj_t * keyboard, lv_event_t event) 228 | { 229 | (void) keyboard; /*Unused*/ 230 | 231 | lv_kb_def_event_cb(kb, event); 232 | 233 | if(event == LV_EVENT_APPLY || event == LV_EVENT_CANCEL) { 234 | #if LV_USE_ANIMATION 235 | lv_anim_t a; 236 | a.var = kb; 237 | a.start = lv_obj_get_y(kb); 238 | a.end = LV_VER_RES; 239 | a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_y; 240 | a.path_cb = lv_anim_path_linear; 241 | a.ready_cb = kb_hide_anim_end; 242 | a.act_time = 0; 243 | a.time = 300; 244 | a.playback = 0; 245 | a.playback_pause = 0; 246 | a.repeat = 0; 247 | a.repeat_pause = 0; 248 | lv_anim_create(&a); 249 | #else 250 | lv_obj_del(kb); 251 | kb = NULL; 252 | #endif 253 | } 254 | } 255 | 256 | static void list_create(lv_obj_t * parent) 257 | { 258 | lv_coord_t hres = lv_disp_get_hor_res(NULL); 259 | 260 | lv_page_set_style(parent, LV_PAGE_STYLE_BG, &lv_style_transp_fit); 261 | lv_page_set_style(parent, LV_PAGE_STYLE_SCRL, &lv_style_transp_fit); 262 | 263 | lv_page_set_sb_mode(parent, LV_SB_MODE_OFF); 264 | 265 | /*Create styles for the buttons*/ 266 | static lv_style_t style_btn_rel; 267 | static lv_style_t style_btn_pr; 268 | lv_style_copy(&style_btn_rel, &lv_style_btn_rel); 269 | style_btn_rel.body.main_color = lv_color_hex3(0x333); 270 | style_btn_rel.body.grad_color = LV_COLOR_BLACK; 271 | style_btn_rel.body.border.color = LV_COLOR_SILVER; 272 | style_btn_rel.body.border.width = 1; 273 | style_btn_rel.body.border.opa = LV_OPA_50; 274 | style_btn_rel.body.radius = 0; 275 | 276 | lv_style_copy(&style_btn_pr, &style_btn_rel); 277 | style_btn_pr.body.main_color = lv_color_make(0x55, 0x96, 0xd8); 278 | style_btn_pr.body.grad_color = lv_color_make(0x37, 0x62, 0x90); 279 | style_btn_pr.text.color = lv_color_make(0xbb, 0xd5, 0xf1); 280 | 281 | lv_obj_t * list = lv_list_create(parent, NULL); 282 | lv_obj_set_height(list, 2 * lv_obj_get_height(parent) / 3); 283 | lv_list_set_style(list, LV_LIST_STYLE_BG, &lv_style_transp_tight); 284 | lv_list_set_style(list, LV_LIST_STYLE_SCRL, &lv_style_transp_tight); 285 | lv_list_set_style(list, LV_LIST_STYLE_BTN_REL, &style_btn_rel); 286 | lv_list_set_style(list, LV_LIST_STYLE_BTN_PR, &style_btn_pr); 287 | lv_obj_align(list, NULL, LV_ALIGN_IN_TOP_MID, 0, LV_DPI / 4); 288 | 289 | lv_obj_t * list_btn; 290 | list_btn = lv_list_add_btn(list, LV_SYMBOL_FILE, "New"); 291 | lv_obj_set_event_cb(list_btn, list_btn_event_handler); 292 | 293 | list_btn = lv_list_add_btn(list, LV_SYMBOL_DIRECTORY, "Open"); 294 | lv_obj_set_event_cb(list_btn, list_btn_event_handler); 295 | 296 | list_btn = lv_list_add_btn(list, LV_SYMBOL_TRASH, "Delete"); 297 | lv_obj_set_event_cb(list_btn, list_btn_event_handler); 298 | 299 | list_btn = lv_list_add_btn(list, LV_SYMBOL_EDIT, "Edit"); 300 | lv_obj_set_event_cb(list_btn, list_btn_event_handler); 301 | 302 | list_btn = lv_list_add_btn(list, LV_SYMBOL_SAVE, "Save"); 303 | lv_obj_set_event_cb(list_btn, list_btn_event_handler); 304 | 305 | list_btn = lv_list_add_btn(list, LV_SYMBOL_WIFI, "WiFi"); 306 | lv_obj_set_event_cb(list_btn, list_btn_event_handler); 307 | 308 | list_btn = lv_list_add_btn(list, LV_SYMBOL_GPS, "GPS"); 309 | lv_obj_set_event_cb(list_btn, list_btn_event_handler); 310 | 311 | lv_obj_t * mbox = lv_mbox_create(parent, NULL); 312 | lv_mbox_set_text(mbox, "Click a button to copy its text to the Text area "); 313 | lv_obj_set_width(mbox, hres - LV_DPI); 314 | static const char * mbox_btns[] = {"Got it", ""}; 315 | lv_mbox_add_btns(mbox, mbox_btns); /*The default action is close*/ 316 | lv_obj_align(mbox, parent, LV_ALIGN_IN_TOP_MID, 0, LV_DPI / 2); 317 | } 318 | 319 | #if LV_USE_ANIMATION 320 | static void kb_hide_anim_end(lv_anim_t * a) 321 | { 322 | lv_obj_del(a->var); 323 | kb = NULL; 324 | } 325 | #endif 326 | 327 | static void chart_create(lv_obj_t * parent) 328 | { 329 | 330 | lv_coord_t vres = lv_disp_get_ver_res(NULL); 331 | 332 | lv_page_set_style(parent, LV_PAGE_STYLE_BG, &lv_style_transp_fit); 333 | lv_page_set_style(parent, LV_PAGE_STYLE_SCRL, &lv_style_transp_fit); 334 | 335 | lv_page_set_scrl_height(parent, lv_obj_get_height(parent)); 336 | lv_page_set_sb_mode(parent, LV_SB_MODE_OFF); 337 | 338 | static lv_style_t style_chart; 339 | lv_style_copy(&style_chart, &lv_style_pretty); 340 | style_chart.body.opa = LV_OPA_60; 341 | style_chart.body.radius = 0; 342 | style_chart.line.color = LV_COLOR_GRAY; 343 | 344 | chart = lv_chart_create(parent, NULL); 345 | lv_obj_set_size(chart, 2 * lv_obj_get_width(parent) / 3, lv_obj_get_height(parent) / 2); 346 | lv_obj_align(chart, NULL, LV_ALIGN_IN_TOP_MID, 0, LV_DPI / 4); 347 | lv_chart_set_type(chart, LV_CHART_TYPE_COLUMN); 348 | lv_chart_set_style(chart, LV_CHART_STYLE_MAIN, &style_chart); 349 | lv_chart_set_series_opa(chart, LV_OPA_70); 350 | lv_chart_series_t * ser1; 351 | ser1 = lv_chart_add_series(chart, LV_COLOR_RED); 352 | lv_chart_set_next(chart, ser1, 40); 353 | lv_chart_set_next(chart, ser1, 30); 354 | lv_chart_set_next(chart, ser1, 47); 355 | lv_chart_set_next(chart, ser1, 59); 356 | lv_chart_set_next(chart, ser1, 59); 357 | lv_chart_set_next(chart, ser1, 31); 358 | lv_chart_set_next(chart, ser1, 55); 359 | lv_chart_set_next(chart, ser1, 70); 360 | lv_chart_set_next(chart, ser1, 82); 361 | lv_chart_set_next(chart, ser1, 91); 362 | 363 | /*Create a bar, an indicator and a knob style*/ 364 | static lv_style_t style_bar; 365 | static lv_style_t style_indic; 366 | static lv_style_t style_knob; 367 | 368 | lv_style_copy(&style_bar, &lv_style_pretty); 369 | style_bar.body.main_color = LV_COLOR_BLACK; 370 | style_bar.body.grad_color = LV_COLOR_GRAY; 371 | style_bar.body.radius = LV_RADIUS_CIRCLE; 372 | style_bar.body.border.color = LV_COLOR_WHITE; 373 | style_bar.body.opa = LV_OPA_60; 374 | style_bar.body.padding.left = 0; 375 | style_bar.body.padding.right = 0; 376 | style_bar.body.padding.top = LV_DPI / 10; 377 | style_bar.body.padding.bottom = LV_DPI / 10; 378 | 379 | lv_style_copy(&style_indic, &lv_style_pretty); 380 | style_indic.body.grad_color = LV_COLOR_MAROON; 381 | style_indic.body.main_color = LV_COLOR_RED; 382 | style_indic.body.radius = LV_RADIUS_CIRCLE; 383 | style_indic.body.shadow.width = LV_DPI / 10; 384 | style_indic.body.shadow.color = LV_COLOR_RED; 385 | style_indic.body.padding.left = LV_DPI / 30; 386 | style_indic.body.padding.right = LV_DPI / 30; 387 | style_indic.body.padding.top = LV_DPI / 30; 388 | style_indic.body.padding.bottom = LV_DPI / 30; 389 | 390 | lv_style_copy(&style_knob, &lv_style_pretty); 391 | style_knob.body.radius = LV_RADIUS_CIRCLE; 392 | style_knob.body.opa = LV_OPA_70; 393 | 394 | /*Create a second slider*/ 395 | lv_obj_t * slider = lv_slider_create(parent, NULL); 396 | lv_slider_set_style(slider, LV_SLIDER_STYLE_BG, &style_bar); 397 | lv_slider_set_style(slider, LV_SLIDER_STYLE_INDIC, &style_indic); 398 | lv_slider_set_style(slider, LV_SLIDER_STYLE_KNOB, &style_knob); 399 | lv_obj_set_size(slider, lv_obj_get_width(chart), LV_DPI / 3); 400 | lv_obj_align(slider, chart, LV_ALIGN_OUT_BOTTOM_MID, 0, (vres - chart->coords.y2 - lv_obj_get_height(slider)) / 2); /*Align to below the chart*/ 401 | lv_obj_set_event_cb(slider, slider_event_handler); 402 | lv_slider_set_range(slider, 10, 1000); 403 | lv_slider_set_value(slider, 700, false); 404 | slider_event_handler(slider, LV_EVENT_VALUE_CHANGED); /*Simulate a user value set the refresh the chart*/ 405 | } 406 | 407 | /** 408 | * Called when a new value on the slider on the Chart tab is set 409 | * @param slider pointer to the slider 410 | * @return LV_RES_OK because the slider is not deleted in the function 411 | */ 412 | static void slider_event_handler(lv_obj_t * slider, lv_event_t event) 413 | { 414 | 415 | if(event == LV_EVENT_VALUE_CHANGED) { 416 | int16_t v = lv_slider_get_value(slider); 417 | v = 1000 * 100 / v; /*Convert to range modify values linearly*/ 418 | lv_chart_set_range(chart, 0, v); 419 | } 420 | } 421 | 422 | /** 423 | * Called when a a list button is clicked on the List tab 424 | * @param btn pointer to a list button 425 | * @return LV_RES_OK because the button is not deleted in the function 426 | */ 427 | static void list_btn_event_handler(lv_obj_t * btn, lv_event_t event) 428 | { 429 | 430 | if(event == LV_EVENT_SHORT_CLICKED) { 431 | lv_ta_add_char(ta, '\n'); 432 | lv_ta_add_text(ta, lv_list_get_btn_text(btn)); 433 | } 434 | } 435 | 436 | #if LV_DEMO_SLIDE_SHOW 437 | /** 438 | * Called periodically (lv_task) to switch to the next tab 439 | */ 440 | static void tab_switcher(lv_task_t * task) 441 | { 442 | static uint8_t tab = 0; 443 | lv_obj_t * tv = task->user_data; 444 | tab++; 445 | if(tab >= 3) tab = 0; 446 | lv_tabview_set_tab_act(tv, tab, true); 447 | } 448 | #endif 449 | 450 | 451 | #endif /*LV_USE_DEMO*/ 452 | -------------------------------------------------------------------------------- /src/lv_settings/lv_settings.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file lv_settings.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "lv_settings.h" 10 | 11 | /********************* 12 | * DEFINES 13 | *********************/ 14 | #define LV_SETTINGS_ANIM_TIME 300 /*[ms]*/ 15 | #define LV_SETTINGS_MAX_WIDTH 250 16 | 17 | /********************** 18 | * TYPEDEFS 19 | **********************/ 20 | 21 | typedef struct 22 | { 23 | lv_btn_ext_t btn; 24 | lv_settings_item_t * item; 25 | lv_event_cb_t event_cb; 26 | }root_ext_t; 27 | 28 | typedef struct 29 | { 30 | lv_btn_ext_t btn; 31 | lv_settings_item_t * item; 32 | }list_btn_ext_t; 33 | 34 | typedef struct 35 | { 36 | lv_cont_ext_t cont; 37 | lv_settings_item_t * item; 38 | }item_cont_ext_t; 39 | 40 | typedef struct 41 | { 42 | lv_cont_ext_t cont; 43 | lv_event_cb_t event_cb; 44 | lv_obj_t * menu_page; 45 | }menu_cont_ext_t; 46 | 47 | typedef struct { 48 | lv_event_cb_t event_cb; 49 | lv_settings_item_t * item; 50 | }histroy_t; 51 | 52 | 53 | /********************** 54 | * STATIC PROTOTYPES 55 | **********************/ 56 | static void create_page(lv_settings_item_t * parent_item, lv_event_cb_t event_cb); 57 | 58 | static void add_list_btn(lv_obj_t * page, lv_settings_item_t * item); 59 | static void add_btn(lv_obj_t * page, lv_settings_item_t * item); 60 | static void add_sw(lv_obj_t * page, lv_settings_item_t * item); 61 | static void add_ddlist(lv_obj_t * page, lv_settings_item_t * item); 62 | static void add_numset(lv_obj_t * page, lv_settings_item_t * item); 63 | static void add_slider(lv_obj_t * page, lv_settings_item_t * item); 64 | 65 | static void refr_list_btn(lv_settings_item_t * item); 66 | static void refr_btn(lv_settings_item_t * item); 67 | static void refr_sw(lv_settings_item_t * item); 68 | static void refr_ddlist(lv_settings_item_t * item); 69 | static void refr_numset(lv_settings_item_t * item); 70 | static void refr_slider(lv_settings_item_t * item); 71 | 72 | static void root_event_cb(lv_obj_t * btn, lv_event_t e); 73 | static void list_btn_event_cb(lv_obj_t * btn, lv_event_t e); 74 | static void slider_event_cb(lv_obj_t * slider, lv_event_t e); 75 | static void sw_event_cb(lv_obj_t * sw, lv_event_t e); 76 | static void btn_event_cb(lv_obj_t * btn, lv_event_t e); 77 | static void ddlist_event_cb(lv_obj_t * ddlist, lv_event_t e); 78 | static void numset_event_cb(lv_obj_t * btn, lv_event_t e); 79 | 80 | static void header_back_event_cb(lv_obj_t * btn, lv_event_t e); 81 | static lv_obj_t * item_cont_create(lv_obj_t * page, lv_settings_item_t * item); 82 | static void old_cont_del_cb(lv_anim_t * a); 83 | static void remove_children_from_group(lv_obj_t * obj); 84 | 85 | /********************** 86 | * STATIC VARIABLES 87 | **********************/ 88 | static lv_obj_t * act_cont; 89 | static lv_obj_t * menu_btn; 90 | static lv_style_t style_menu_bg; 91 | static lv_style_t style_bg; 92 | static lv_style_t style_item_cont; 93 | static lv_ll_t history_ll; 94 | static lv_group_t * group; 95 | static lv_coord_t settings_max_width = LV_SETTINGS_MAX_WIDTH; 96 | 97 | /********************** 98 | * MACROS 99 | **********************/ 100 | 101 | /********************** 102 | * GLOBAL FUNCTIONS 103 | **********************/ 104 | 105 | /** 106 | * Create a settings application 107 | * @param root_item descriptor of the settings button. For example: 108 | * `lv_settings_menu_item_t root_item = {.name = "Settings", .event_cb = root_event_cb};` 109 | * @return the created settings button 110 | */ 111 | lv_obj_t * lv_settings_create(lv_settings_item_t * root_item, lv_event_cb_t event_cb) 112 | { 113 | lv_theme_t *th = lv_theme_get_current(); 114 | if(th) { 115 | lv_style_copy(&style_menu_bg, th->style.cont); 116 | lv_style_copy(&style_item_cont, th->style.list.btn.rel); 117 | } else { 118 | lv_style_copy(&style_menu_bg, &lv_style_pretty); 119 | lv_style_copy(&style_item_cont, &lv_style_transp); 120 | } 121 | 122 | lv_style_copy(&style_bg, &lv_style_transp_tight); 123 | style_menu_bg.body.radius = 0; 124 | 125 | style_item_cont.body.padding.left = LV_DPI / 5; 126 | style_item_cont.body.padding.right = LV_DPI / 5; 127 | style_item_cont.body.padding.top = LV_DPI / 10; 128 | style_item_cont.body.padding.bottom = LV_DPI / 10; 129 | style_item_cont.body.padding.inner = LV_DPI / 20; 130 | 131 | 132 | menu_btn = lv_btn_create(lv_scr_act(), NULL); 133 | lv_btn_set_fit(menu_btn, LV_FIT_TIGHT); 134 | root_ext_t * ext = lv_obj_allocate_ext_attr(menu_btn, sizeof(root_ext_t)); 135 | ext->item = root_item; 136 | ext->event_cb = event_cb; 137 | 138 | lv_obj_set_event_cb(menu_btn, root_event_cb); 139 | if(group) lv_group_add_obj(group, menu_btn); 140 | 141 | lv_obj_t * menu_label = lv_label_create(menu_btn, NULL); 142 | lv_label_set_text(menu_label, LV_SYMBOL_LIST); 143 | 144 | lv_obj_set_pos(menu_btn, 0, 0); 145 | 146 | lv_ll_init(&history_ll, sizeof(histroy_t)); 147 | 148 | return menu_btn; 149 | } 150 | 151 | /** 152 | * Automatically add the item to a group to allow navigation with keypad or encoder. 153 | * Should be called before `lv_settings_create` 154 | * The group can be change at any time. 155 | * @param g the group to use. `NULL` to not use this feature. 156 | */ 157 | void lv_settings_set_group(lv_group_t * g) 158 | { 159 | group = g; 160 | } 161 | 162 | /** 163 | * Change the maximum width of settings dialog object 164 | * @param max_width maximum width of the settings container page 165 | */ 166 | void lv_settings_set_max_width(lv_coord_t max_width) 167 | { 168 | settings_max_width = max_width; 169 | } 170 | 171 | /** 172 | * Create a new page ask `event_cb` to add the item with `LV_EVENT_REFRESH` 173 | * @param parent_item pointer to an item which open the the new page. Its `name` will be the title 174 | * @param event_cb event handler of the menu page 175 | */ 176 | void lv_settings_open_page(lv_settings_item_t * parent_item, lv_event_cb_t event_cb) 177 | { 178 | /*Create a new page in the menu*/ 179 | create_page(parent_item, event_cb); 180 | 181 | /*Add the items*/ 182 | lv_event_send_func(event_cb, NULL, LV_EVENT_REFRESH, parent_item); 183 | } 184 | 185 | /** 186 | * Add a list element to the page. With `item->name` and `item->value` texts. 187 | * @param item pointer to a an `lv_settings_item_t` item. 188 | */ 189 | void lv_settings_add(lv_settings_item_t * item) 190 | { 191 | if(act_cont == NULL) return; 192 | 193 | menu_cont_ext_t * ext = lv_obj_get_ext_attr(act_cont); 194 | lv_obj_t * page = ext->menu_page; 195 | 196 | 197 | switch(item->type) { 198 | case LV_SETTINGS_TYPE_LIST_BTN: add_list_btn(page, item); break; 199 | case LV_SETTINGS_TYPE_BTN: add_btn(page, item); break; 200 | case LV_SETTINGS_TYPE_SLIDER: add_slider(page, item); break; 201 | case LV_SETTINGS_TYPE_SW: add_sw(page, item); break; 202 | case LV_SETTINGS_TYPE_DDLIST: add_ddlist(page, item); break; 203 | case LV_SETTINGS_TYPE_NUMSET: add_numset(page, item); break; 204 | default: break; 205 | } 206 | } 207 | 208 | /** 209 | * Refresh an item's name value and state. 210 | * @param item pointer to a an `lv_settings_item _t` item. 211 | */ 212 | void lv_settings_refr(lv_settings_item_t * item) 213 | { 214 | /*Return if there is nothing to refresh*/ 215 | if(item->cont == NULL) return; 216 | 217 | switch(item->type) { 218 | case LV_SETTINGS_TYPE_LIST_BTN: refr_list_btn(item); break; 219 | case LV_SETTINGS_TYPE_BTN: refr_btn(item); break; 220 | case LV_SETTINGS_TYPE_SLIDER: refr_slider(item); break; 221 | case LV_SETTINGS_TYPE_SW: refr_sw(item); break; 222 | case LV_SETTINGS_TYPE_DDLIST: refr_ddlist(item); break; 223 | case LV_SETTINGS_TYPE_NUMSET: refr_numset(item); break; 224 | default: break; 225 | } 226 | } 227 | 228 | /********************** 229 | * STATIC FUNCTIONS 230 | **********************/ 231 | 232 | /** 233 | * Create a new settings container with header, hack button ,title and an empty page 234 | * @param item pointer to a an `lv_settings_item_t` item. 235 | * `item->name` will be the title of the page. 236 | * `LV_EVENT_REFRESH` will be sent to `item->event_cb` to create the page again when the back button is pressed. 237 | */ 238 | static void create_page(lv_settings_item_t * parent_item, lv_event_cb_t event_cb) 239 | { 240 | lv_coord_t w = LV_MATH_MIN(lv_obj_get_width(lv_scr_act()), settings_max_width); 241 | 242 | if(group) { 243 | if(act_cont) { 244 | remove_children_from_group(act_cont); 245 | } else { 246 | lv_group_remove_obj(menu_btn); 247 | } 248 | } 249 | 250 | lv_obj_t * old_menu_cont = act_cont; 251 | 252 | act_cont = lv_cont_create(lv_scr_act(), NULL); 253 | lv_cont_set_style(act_cont, LV_CONT_STYLE_MAIN, &style_menu_bg); 254 | lv_obj_set_size(act_cont, w, lv_obj_get_height(lv_scr_act())); 255 | 256 | menu_cont_ext_t * ext = lv_obj_allocate_ext_attr(act_cont, sizeof(menu_cont_ext_t)); 257 | ext->event_cb = event_cb; 258 | ext->menu_page = NULL; 259 | 260 | lv_obj_t * header = lv_cont_create(act_cont, NULL); 261 | lv_cont_set_style(header, LV_CONT_STYLE_MAIN, &lv_style_transp_fit); 262 | lv_cont_set_fit2(header, LV_FIT_NONE, LV_FIT_TIGHT); 263 | lv_obj_set_width(header, lv_obj_get_width(act_cont)); 264 | 265 | lv_obj_t * header_back_btn = lv_btn_create(header, NULL); 266 | lv_btn_set_fit(header_back_btn, LV_FIT_TIGHT); 267 | lv_obj_set_event_cb(header_back_btn, header_back_event_cb); 268 | if(group) lv_group_add_obj(group, header_back_btn); 269 | lv_group_focus_obj(header_back_btn); 270 | 271 | lv_obj_t * header_back_label = lv_label_create(header_back_btn, NULL); 272 | 273 | lv_obj_t * header_title = lv_label_create(header, NULL); 274 | lv_label_set_text(header_title, parent_item->name); 275 | 276 | bool menu_btn_right = lv_obj_get_x(menu_btn) >= lv_obj_get_width(lv_scr_act())/2; 277 | 278 | if(!menu_btn_right) { 279 | lv_cont_set_layout(header, LV_LAYOUT_ROW_M); 280 | lv_label_set_text(header_back_label, LV_SYMBOL_LEFT); 281 | } else { 282 | lv_label_set_text(header_back_label, LV_SYMBOL_RIGHT); 283 | lv_obj_align(header_back_btn, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 0); 284 | lv_obj_align(header_title, header_back_btn, LV_ALIGN_OUT_LEFT_MID, -act_cont->style_p->body.padding.right, 0); 285 | } 286 | 287 | lv_obj_set_pos(header, 0, 0); 288 | 289 | lv_obj_t * page = lv_page_create(act_cont, NULL); 290 | lv_page_set_style(page, LV_PAGE_STYLE_BG, &style_bg); 291 | lv_page_set_style(page, LV_PAGE_STYLE_SCRL, &lv_style_transp_tight); 292 | lv_page_set_scrl_layout(page, LV_LAYOUT_COL_M); 293 | lv_list_set_edge_flash(page, true); 294 | lv_obj_set_size(page, lv_obj_get_width(act_cont), lv_obj_get_height(lv_scr_act()) - lv_obj_get_height(header)); 295 | lv_obj_align(page, header, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); 296 | 297 | ext->menu_page = page; 298 | 299 | histroy_t * new_node = lv_ll_ins_head(&history_ll); 300 | new_node->event_cb = event_cb; 301 | new_node->item = parent_item; 302 | 303 | /*Delete the old menu container after some time*/ 304 | if(old_menu_cont) { 305 | lv_anim_t a; 306 | lv_anim_init(&a); 307 | lv_anim_set_exec_cb(&a, old_menu_cont, NULL); 308 | lv_anim_set_values(&a, 0, 1); 309 | lv_anim_set_path_cb(&a, lv_anim_path_step); 310 | lv_anim_set_time(&a, LV_SETTINGS_ANIM_TIME, 0); 311 | lv_anim_set_ready_cb(&a, old_cont_del_cb); 312 | lv_anim_create(&a); 313 | } 314 | 315 | /*Float in the new menu*/ 316 | lv_anim_t a; 317 | lv_anim_init(&a); 318 | lv_anim_set_exec_cb(&a, act_cont, (lv_anim_exec_xcb_t)lv_obj_set_x); 319 | lv_coord_t w_cont = lv_obj_get_width(act_cont); 320 | lv_coord_t w_scr = lv_obj_get_width(lv_scr_act()); 321 | uint32_t start = !menu_btn_right ? -w_cont : w_scr; 322 | uint32_t end = !menu_btn_right ? 0 : w_scr-w_cont; 323 | lv_anim_set_values(&a, start, end); 324 | lv_anim_set_time(&a, LV_SETTINGS_ANIM_TIME, 0); 325 | lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out); 326 | lv_anim_create(&a); 327 | } 328 | 329 | /** 330 | * Add a list element to the page. With `item->name` and `item->value` texts. 331 | * @param page pointer to a menu page created by `lv_settings_create_page` 332 | * @param item pointer to a an `lv_settings_item_t` item. 333 | */ 334 | static void add_list_btn(lv_obj_t * page, lv_settings_item_t * item) 335 | { 336 | lv_obj_t * liste = lv_btn_create(page, NULL); 337 | lv_btn_set_layout(liste, LV_LAYOUT_COL_L); 338 | lv_btn_set_fit2(liste, LV_FIT_FLOOD, LV_FIT_TIGHT); 339 | lv_page_glue_obj(liste, true); 340 | lv_obj_set_event_cb(liste, list_btn_event_cb); 341 | if(group) lv_group_add_obj(group, liste); 342 | 343 | list_btn_ext_t * ext = lv_obj_allocate_ext_attr(liste, sizeof(list_btn_ext_t)); 344 | ext->item = item; 345 | ext->item->cont = liste; 346 | 347 | lv_obj_t * name = lv_label_create(liste, NULL); 348 | lv_label_set_text(name, item->name); 349 | 350 | lv_obj_t * value = lv_label_create(liste, NULL); 351 | lv_label_set_text(value, item->value); 352 | 353 | lv_theme_t * th = lv_theme_get_current(); 354 | if(th) { 355 | lv_btn_set_style(liste, LV_BTN_STYLE_REL, th->style.list.btn.rel); 356 | lv_btn_set_style(liste, LV_BTN_STYLE_PR, th->style.list.btn.pr); 357 | lv_label_set_style(value, LV_LABEL_STYLE_MAIN, th->style.label.hint); 358 | } 359 | } 360 | 361 | 362 | /** 363 | * Create a button. Write `item->name` on create a button on the right with `item->value` text. 364 | * @param page pointer to a menu page created by `lv_settings_create_page` 365 | * @param item pointer to a an `lv_settings_item_t` item. 366 | */ 367 | static void add_btn(lv_obj_t * page, lv_settings_item_t * item) 368 | { 369 | lv_obj_t * cont = item_cont_create(page, item); 370 | 371 | lv_obj_t * name = lv_label_create(cont, NULL); 372 | lv_label_set_text(name, item->name); 373 | 374 | lv_obj_t * btn = lv_btn_create(cont, NULL); 375 | lv_btn_set_fit(btn, LV_FIT_TIGHT); 376 | lv_obj_set_event_cb(btn, btn_event_cb); 377 | if(group) lv_group_add_obj(group, btn); 378 | 379 | lv_obj_t * value = lv_label_create(btn, NULL); 380 | lv_label_set_text(value, item->value); 381 | 382 | lv_obj_align(btn, NULL, LV_ALIGN_IN_RIGHT_MID, -style_item_cont.body.padding.right, 0); 383 | lv_obj_align(name, NULL, LV_ALIGN_IN_LEFT_MID, style_item_cont.body.padding.left, 0); 384 | } 385 | 386 | /** 387 | * Create a switch with `item->name` text. The state is set from `item->state`. 388 | * @param page pointer to a menu page created by `lv_settings_create_page` 389 | * @param item pointer to a an `lv_settings_item_t` item. 390 | */ 391 | static void add_sw(lv_obj_t * page, lv_settings_item_t * item) 392 | { 393 | lv_obj_t * cont = item_cont_create(page, item); 394 | 395 | lv_obj_t * name = lv_label_create(cont, NULL); 396 | lv_label_set_text(name, item->name); 397 | 398 | lv_obj_t * value = lv_label_create(cont, NULL); 399 | lv_label_set_text(value, item->value); 400 | 401 | lv_theme_t * th = lv_theme_get_current(); 402 | if(th) { 403 | lv_label_set_style(value, LV_LABEL_STYLE_MAIN, th->style.label.hint); 404 | } 405 | 406 | lv_obj_t * sw = lv_sw_create(cont, NULL); 407 | lv_obj_set_event_cb(sw, sw_event_cb); 408 | lv_obj_set_size(sw, LV_DPI / 2, LV_DPI / 4); 409 | if(item->state) lv_sw_on(sw, LV_ANIM_OFF); 410 | if(group) lv_group_add_obj(group, sw); 411 | 412 | lv_obj_align(name, NULL, LV_ALIGN_IN_TOP_LEFT, style_item_cont.body.padding.left, style_item_cont.body.padding.top); 413 | lv_obj_align(value, name, LV_ALIGN_OUT_BOTTOM_LEFT, 0, style_item_cont.body.padding.inner); 414 | lv_obj_align(sw, NULL, LV_ALIGN_IN_RIGHT_MID, -style_item_cont.body.padding.right, 0); 415 | } 416 | 417 | /** 418 | * Create a drop down list with `item->name` title and `item->value` options. The `item->state` option will be selected. 419 | * @param page pointer to a menu page created by `lv_settings_create_page` 420 | * @param item pointer to a an `lv_settings_item_t` item. 421 | */ 422 | static void add_ddlist(lv_obj_t * page, lv_settings_item_t * item) 423 | { 424 | lv_obj_t * cont = item_cont_create(page, item); 425 | 426 | lv_obj_t * label = lv_label_create(cont, NULL); 427 | lv_label_set_text(label, item->name); 428 | lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_LEFT, style_item_cont.body.padding.left, style_item_cont.body.padding.top); 429 | 430 | lv_obj_t * ddlist = lv_ddlist_create(cont, NULL); 431 | lv_ddlist_set_options(ddlist, item->value); 432 | lv_ddlist_set_draw_arrow(ddlist, true); 433 | lv_ddlist_set_fix_height(ddlist, lv_obj_get_height(page) / 2); 434 | lv_ddlist_set_fix_width(ddlist, lv_obj_get_width_fit(cont)); 435 | lv_obj_align(ddlist, label, LV_ALIGN_OUT_BOTTOM_LEFT, 0, style_item_cont.body.padding.inner); 436 | lv_obj_set_event_cb(ddlist, ddlist_event_cb); 437 | lv_ddlist_set_selected(ddlist, item->state); 438 | if(group) lv_group_add_obj(group, ddlist); 439 | } 440 | 441 | /** 442 | * Create a drop down list with `item->name` title and `item->value` options. The `item->state` option will be selected. 443 | * @param page pointer to a menu page created by `lv_settings_create_page` 444 | * @param item pointer to a an `lv_settings_item_t` item. 445 | */ 446 | static void add_numset(lv_obj_t * page, lv_settings_item_t * item) 447 | { 448 | lv_obj_t * cont = item_cont_create(page, item); 449 | lv_cont_set_layout(cont, LV_LAYOUT_PRETTY); 450 | 451 | lv_obj_t * label = lv_label_create(cont, NULL); 452 | lv_label_set_text(label, item->name); 453 | lv_obj_set_protect(label, LV_PROTECT_FOLLOW); 454 | 455 | 456 | lv_obj_t * btn_dec = lv_btn_create(cont, NULL); 457 | lv_obj_set_size(btn_dec, LV_DPI / 2, LV_DPI / 2); 458 | lv_obj_set_event_cb(btn_dec, numset_event_cb); 459 | if(group) lv_group_add_obj(group, btn_dec); 460 | 461 | label = lv_label_create(btn_dec, NULL); 462 | lv_label_set_text(label, LV_SYMBOL_MINUS); 463 | 464 | label = lv_label_create(cont, NULL); 465 | lv_label_set_text(label, item->value); 466 | 467 | lv_obj_t * btn_inc = lv_btn_create(cont, btn_dec); 468 | lv_obj_set_size(btn_inc, LV_DPI / 2, LV_DPI / 2); 469 | if(group) lv_group_add_obj(group, btn_inc); 470 | 471 | label = lv_label_create(btn_inc, NULL); 472 | lv_label_set_text(label, LV_SYMBOL_PLUS); 473 | 474 | } 475 | 476 | /** 477 | * Create a slider with 0..256 range. Write `item->name` and `item->value` on top of the slider. The current value is loaded from `item->state` 478 | * @param page pointer to a menu page created by `lv_settings_create_page` 479 | * @param item pointer to a an `lv_settings_item_t` item. 480 | */ 481 | static void add_slider(lv_obj_t * page, lv_settings_item_t * item) 482 | { 483 | lv_obj_t * cont = item_cont_create(page, item); 484 | 485 | lv_obj_t * name = lv_label_create(cont, NULL); 486 | lv_label_set_text(name, item->name); 487 | 488 | lv_obj_t * value = lv_label_create(cont, NULL); 489 | lv_label_set_text(value, item->value); 490 | lv_obj_set_auto_realign(value, true); 491 | 492 | lv_obj_align(name, NULL, LV_ALIGN_IN_TOP_LEFT, style_item_cont.body.padding.left, 493 | style_item_cont.body.padding.top); 494 | lv_obj_align(value, NULL, LV_ALIGN_IN_TOP_RIGHT, -style_item_cont.body.padding.right, 495 | style_item_cont.body.padding.top); 496 | lv_obj_t * slider = lv_slider_create(cont, NULL); 497 | lv_obj_set_size(slider, lv_obj_get_width_fit(cont), LV_DPI / 4); 498 | lv_obj_align(slider, NULL, LV_ALIGN_IN_TOP_MID, 0, lv_obj_get_y(name) + 499 | lv_obj_get_height(name) + 500 | style_item_cont.body.padding.inner); 501 | lv_obj_set_event_cb(slider, slider_event_cb); 502 | lv_slider_set_range(slider, 0, 256); 503 | lv_slider_set_value(slider, item->state, LV_ANIM_OFF); 504 | if(group) lv_group_add_obj(group, slider); 505 | } 506 | 507 | static void refr_list_btn(lv_settings_item_t * item) 508 | { 509 | lv_obj_t * name = lv_obj_get_child(item->cont, NULL); 510 | lv_obj_t * value = lv_obj_get_child(item->cont, name); 511 | 512 | lv_label_set_text(name, item->name); 513 | lv_label_set_text(value, item->value); 514 | } 515 | 516 | static void refr_btn(lv_settings_item_t * item) 517 | { 518 | lv_obj_t * btn = lv_obj_get_child(item->cont, NULL); 519 | lv_obj_t * name = lv_obj_get_child(item->cont, btn); 520 | lv_obj_t * value = lv_obj_get_child(btn, NULL); 521 | 522 | lv_label_set_text(name, item->name); 523 | lv_label_set_text(value, item->value); 524 | } 525 | 526 | 527 | static void refr_sw(lv_settings_item_t * item) 528 | { 529 | lv_obj_t * sw = lv_obj_get_child(item->cont, NULL); 530 | lv_obj_t * value = lv_obj_get_child(item->cont, sw); 531 | lv_obj_t * name = lv_obj_get_child(item->cont, value); 532 | 533 | lv_label_set_text(name, item->name); 534 | lv_label_set_text(value, item->value); 535 | 536 | bool tmp_state = lv_sw_get_state(sw) ? true : false; 537 | if(tmp_state != item->state) { 538 | if(tmp_state == false) lv_sw_off(sw, LV_ANIM_OFF); 539 | else lv_sw_on(sw, LV_ANIM_OFF); 540 | } 541 | } 542 | 543 | static void refr_ddlist(lv_settings_item_t * item) 544 | { 545 | lv_obj_t * name = lv_obj_get_child(item->cont, NULL); 546 | lv_obj_t * ddlist = lv_obj_get_child(item->cont, name); 547 | 548 | lv_label_set_text(name, item->name); 549 | 550 | lv_ddlist_set_options(ddlist, item->value); 551 | 552 | lv_ddlist_set_selected(ddlist, item->state); 553 | } 554 | 555 | static void refr_numset(lv_settings_item_t * item) 556 | { 557 | lv_obj_t * name = lv_obj_get_child_back(item->cont, NULL); 558 | lv_obj_t * value = lv_obj_get_child_back(item->cont, name); /*It's the minus button*/ 559 | value = lv_obj_get_child_back(item->cont, value); 560 | 561 | lv_label_set_text(name, item->name); 562 | lv_label_set_text(value, item->value); 563 | } 564 | 565 | static void refr_slider(lv_settings_item_t * item) 566 | { 567 | lv_obj_t * slider = lv_obj_get_child(item->cont, NULL); 568 | lv_obj_t * value = lv_obj_get_child(item->cont, slider); 569 | lv_obj_t * name = lv_obj_get_child(item->cont, value); 570 | 571 | lv_label_set_text(name, item->name); 572 | lv_label_set_text(value, item->value); 573 | 574 | if(lv_slider_get_value(slider) != item->state) lv_slider_set_value(slider, item->state, LV_ANIM_OFF); 575 | } 576 | 577 | static void root_event_cb(lv_obj_t * btn, lv_event_t e) 578 | { 579 | 580 | if(e == LV_EVENT_CLICKED) { 581 | root_ext_t * ext = lv_obj_get_ext_attr(btn); 582 | 583 | /*Call the button's event handler to create the menu*/ 584 | lv_event_send_func(ext->event_cb, NULL, e, ext->item); 585 | } 586 | } 587 | 588 | /** 589 | * List button event callback. The following events are sent: 590 | * - `LV_EVENT_CLICKED` 591 | * - `LV_EEVNT_SHORT_CLICKED` 592 | * - `LV_EEVNT_LONG_PRESSED` 593 | * @param btn pointer to the back button 594 | * @param e the event 595 | */ 596 | static void list_btn_event_cb(lv_obj_t * btn, lv_event_t e) 597 | { 598 | /*Save the menu item because the button will be deleted in `menu_cont_create` and `ext` will be invalid */ 599 | list_btn_ext_t * item_ext = lv_obj_get_ext_attr(btn); 600 | 601 | if(e == LV_EVENT_CLICKED || 602 | e == LV_EVENT_SHORT_CLICKED || 603 | e == LV_EVENT_LONG_PRESSED) { 604 | menu_cont_ext_t * menu_ext = lv_obj_get_ext_attr(act_cont); 605 | 606 | /*Call the button's event handler to create the menu*/ 607 | lv_event_send_func(menu_ext->event_cb, NULL, e, item_ext->item); 608 | } 609 | else if(e == LV_EVENT_DELETE) { 610 | item_ext->item->cont = NULL; 611 | } 612 | else if (e ==LV_EVENT_FOCUSED) { 613 | menu_cont_ext_t * ext = lv_obj_get_ext_attr(act_cont); 614 | lv_obj_t * page = ext->menu_page; 615 | lv_page_focus(page, btn, LV_ANIM_ON); 616 | } 617 | } 618 | 619 | /** 620 | * Slider event callback. Call the item's `event_cb` with `LV_EVENT_VALUE_CHANGED`, 621 | * save the state and refresh the value label. 622 | * @param slider pointer to the slider 623 | * @param e the event 624 | */ 625 | static void slider_event_cb(lv_obj_t * slider, lv_event_t e) 626 | { 627 | lv_obj_t * cont = lv_obj_get_parent(slider); 628 | item_cont_ext_t * item_ext = lv_obj_get_ext_attr(cont); 629 | 630 | if(e == LV_EVENT_VALUE_CHANGED) { 631 | item_ext->item->state = lv_slider_get_value(slider); 632 | menu_cont_ext_t * menu_ext = lv_obj_get_ext_attr(act_cont); 633 | 634 | /*Call the button's event handler to create the menu*/ 635 | lv_event_send_func(menu_ext->event_cb, NULL, e, item_ext->item); 636 | } 637 | else if(e == LV_EVENT_DELETE) { 638 | item_ext->item->cont = NULL; 639 | } 640 | else if (e ==LV_EVENT_FOCUSED) { 641 | menu_cont_ext_t * ext = lv_obj_get_ext_attr(act_cont); 642 | lv_obj_t * page = ext->menu_page; 643 | lv_page_focus(page, lv_obj_get_parent(slider), LV_ANIM_ON); 644 | } 645 | } 646 | 647 | /** 648 | * Switch event callback. Call the item's `event_cb` with `LV_EVENT_VALUE_CHANGED` and save the state. 649 | * @param sw pointer to the switch 650 | * @param e the event 651 | */ 652 | static void sw_event_cb(lv_obj_t * sw, lv_event_t e) 653 | { 654 | lv_obj_t * cont = lv_obj_get_parent(sw); 655 | item_cont_ext_t * item_ext = lv_obj_get_ext_attr(cont); 656 | 657 | if(e == LV_EVENT_VALUE_CHANGED) { 658 | 659 | item_ext->item->state = lv_sw_get_state(sw); 660 | menu_cont_ext_t * menu_ext = lv_obj_get_ext_attr(act_cont); 661 | 662 | /*Call the button's event handler to create the menu*/ 663 | lv_event_send_func(menu_ext->event_cb, NULL, e, item_ext->item); 664 | } 665 | else if(e == LV_EVENT_DELETE) { 666 | item_ext->item->cont = NULL; 667 | } 668 | else if (e ==LV_EVENT_FOCUSED) { 669 | menu_cont_ext_t * ext = lv_obj_get_ext_attr(act_cont); 670 | lv_obj_t * page = ext->menu_page; 671 | lv_page_focus(page, lv_obj_get_parent(sw), LV_ANIM_ON); 672 | } 673 | } 674 | 675 | /** 676 | * Button event callback. Call the item's `event_cb` with `LV_EVENT_VALUE_CHANGED` when clicked. 677 | * @param obj pointer to the switch or the container in case of `LV_EVENT_REFRESH` 678 | * @param e the event 679 | */ 680 | static void btn_event_cb(lv_obj_t * obj, lv_event_t e) 681 | { 682 | lv_obj_t * cont = lv_obj_get_parent(obj); 683 | item_cont_ext_t * item_ext = lv_obj_get_ext_attr(cont); 684 | 685 | if(e == LV_EVENT_CLICKED) { 686 | menu_cont_ext_t * menu_ext = lv_obj_get_ext_attr(act_cont); 687 | 688 | /*Call the button's event handler to create the menu*/ 689 | lv_event_send_func(menu_ext->event_cb, NULL, e, item_ext->item); 690 | } 691 | else if(e == LV_EVENT_DELETE) { 692 | item_ext->item->cont = NULL; 693 | } 694 | else if (e ==LV_EVENT_FOCUSED) { 695 | menu_cont_ext_t * ext = lv_obj_get_ext_attr(act_cont); 696 | lv_obj_t * page = ext->menu_page; 697 | lv_page_focus(page, lv_obj_get_parent(obj), LV_ANIM_ON); 698 | } 699 | } 700 | 701 | /** 702 | * Drop down list event callback. Call the item's `event_cb` with `LV_EVENT_VALUE_CHANGED` and save the state. 703 | * @param ddlist pointer to the Drop down lsit 704 | * @param e the event 705 | */ 706 | static void ddlist_event_cb(lv_obj_t * ddlist, lv_event_t e) 707 | { 708 | lv_obj_t * cont = lv_obj_get_parent(ddlist); 709 | item_cont_ext_t * item_ext = lv_obj_get_ext_attr(cont); 710 | 711 | if(e == LV_EVENT_VALUE_CHANGED) { 712 | item_ext->item->state = lv_ddlist_get_selected(ddlist); 713 | 714 | menu_cont_ext_t * menu_ext = lv_obj_get_ext_attr(act_cont); 715 | 716 | /*Call the button's event handler to create the menu*/ 717 | lv_event_send_func(menu_ext->event_cb, NULL, e, item_ext->item); 718 | } 719 | else if(e == LV_EVENT_DELETE) { 720 | item_ext->item->cont = NULL; 721 | } 722 | else if (e ==LV_EVENT_FOCUSED) { 723 | menu_cont_ext_t * ext = lv_obj_get_ext_attr(act_cont); 724 | lv_obj_t * page = ext->menu_page; 725 | lv_page_focus(page, lv_obj_get_parent(ddlist), LV_ANIM_ON); 726 | } 727 | } 728 | 729 | /** 730 | * Number set buttons' event callback. Increment/decrement the state and call the item's `event_cb` with `LV_EVENT_VALUE_CHANGED`. 731 | * @param btn pointer to the plus or minus button 732 | * @param e the event 733 | */ 734 | static void numset_event_cb(lv_obj_t * btn, lv_event_t e) 735 | { 736 | lv_obj_t * cont = lv_obj_get_parent(btn); 737 | item_cont_ext_t * item_ext = lv_obj_get_ext_attr(cont); 738 | if(e == LV_EVENT_SHORT_CLICKED || e == LV_EVENT_LONG_PRESSED_REPEAT) { 739 | 740 | lv_obj_t * label = lv_obj_get_child(btn, NULL); 741 | if(strcmp(lv_label_get_text(label), LV_SYMBOL_MINUS) == 0) item_ext->item->state--; 742 | else item_ext->item->state ++; 743 | 744 | menu_cont_ext_t * menu_ext = lv_obj_get_ext_attr(act_cont); 745 | 746 | /*Call the button's event handler to create the menu*/ 747 | lv_event_send_func(menu_ext->event_cb, NULL, LV_EVENT_VALUE_CHANGED, item_ext->item); 748 | 749 | /*Get the value label*/ 750 | label = lv_obj_get_child(cont, NULL); 751 | label = lv_obj_get_child(cont, label); 752 | 753 | lv_label_set_text(label, item_ext->item->value); 754 | } 755 | else if(e == LV_EVENT_DELETE) { 756 | item_ext->item->cont = NULL; 757 | } 758 | else if (e ==LV_EVENT_FOCUSED) { 759 | menu_cont_ext_t * ext = lv_obj_get_ext_attr(act_cont); 760 | lv_obj_t * page = ext->menu_page; 761 | lv_page_focus(page, lv_obj_get_parent(btn), LV_ANIM_ON); 762 | } 763 | } 764 | 765 | /** 766 | * Back button event callback. Load the previous menu on click and delete the current. 767 | * @param btn pointer to the back button 768 | * @param e the event 769 | */ 770 | static void header_back_event_cb(lv_obj_t * btn, lv_event_t e) 771 | { 772 | (void) btn; /*Unused*/ 773 | 774 | if(e != LV_EVENT_CLICKED) return; 775 | 776 | lv_obj_t * old_menu_cont = act_cont; 777 | 778 | /*Delete the current item form the history. The goal is the previous.*/ 779 | histroy_t * act_hist; 780 | act_hist = lv_ll_get_head(&history_ll); 781 | if(act_hist) { 782 | lv_ll_rem(&history_ll, act_hist); 783 | lv_mem_free(act_hist); 784 | 785 | /*Get the real previous item and open it*/ 786 | histroy_t * prev_hist = lv_ll_get_head(&history_ll); 787 | 788 | if(prev_hist) { 789 | /* Create the previous menu. 790 | * Remove it from the history because `lv_settings_create_page` will add it again */ 791 | lv_ll_rem(&history_ll, prev_hist); 792 | lv_settings_open_page( prev_hist->item, prev_hist->event_cb); 793 | lv_mem_free(prev_hist); 794 | } 795 | else { 796 | /*No previous menu, so no main container*/ 797 | act_cont = NULL; 798 | root_ext_t * ext = lv_obj_get_ext_attr(menu_btn); 799 | lv_event_send_func(ext->event_cb, NULL, LV_EVENT_CANCEL, ext->item); 800 | if(group) lv_group_add_obj(group, menu_btn); 801 | } 802 | } 803 | 804 | /*Float out the old menu container*/ 805 | if(old_menu_cont) { 806 | lv_anim_t a; 807 | lv_anim_init(&a); 808 | lv_anim_set_exec_cb(&a, old_menu_cont, (lv_anim_exec_xcb_t)lv_obj_set_x); 809 | lv_coord_t w_scr = lv_obj_get_width(lv_scr_act()); 810 | bool menu_btn_right = lv_obj_get_x(menu_btn) >= w_scr/2; 811 | lv_coord_t w_cont = lv_obj_get_width(old_menu_cont); 812 | uint32_t start = !menu_btn_right ? 0 : w_scr-w_cont; 813 | uint32_t end = !menu_btn_right ? -w_cont : w_scr; 814 | lv_anim_set_values(&a, start, end); 815 | lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out); 816 | lv_anim_set_time(&a, LV_SETTINGS_ANIM_TIME, 0); 817 | lv_anim_set_ready_cb(&a, old_cont_del_cb); 818 | lv_anim_create(&a); 819 | 820 | /*Move the old menu to the for ground. */ 821 | lv_obj_move_foreground(old_menu_cont); 822 | } 823 | 824 | if(act_cont) { 825 | lv_anim_del(act_cont, (lv_anim_exec_xcb_t)lv_obj_set_x); 826 | lv_coord_t w_scr = lv_obj_get_width(lv_scr_act()); 827 | bool menu_btn_right = lv_obj_get_x(menu_btn) >= w_scr/2; 828 | lv_coord_t w_cont = lv_obj_get_width(act_cont); 829 | lv_obj_set_x(act_cont, !menu_btn_right ? 0 : w_scr-w_cont); 830 | } 831 | } 832 | 833 | /** 834 | * Create a container for the items of a page 835 | * @param page pointer to a page where to create the container 836 | * @param item pointer to a `lv_settings_item_t` variable. The pointer will be saved in the container's `ext`. 837 | * @return the created container 838 | */ 839 | static lv_obj_t * item_cont_create(lv_obj_t * page, lv_settings_item_t * item) 840 | { 841 | lv_obj_t * cont = lv_cont_create(page, NULL); 842 | lv_cont_set_style(cont, LV_CONT_STYLE_MAIN, &style_item_cont); 843 | lv_cont_set_fit2(cont, LV_FIT_FLOOD, LV_FIT_TIGHT); 844 | lv_obj_set_click(cont, false); 845 | 846 | item_cont_ext_t * ext = lv_obj_allocate_ext_attr(cont, sizeof(item_cont_ext_t)); 847 | ext->item = item; 848 | ext->item->cont = cont; 849 | 850 | return cont; 851 | } 852 | 853 | /** 854 | * Delete the old main container when the animation is ready 855 | * @param a pointer to the animation 856 | */ 857 | static void old_cont_del_cb(lv_anim_t * a) 858 | { 859 | lv_obj_del(a->var); 860 | } 861 | 862 | static void remove_children_from_group(lv_obj_t * obj) 863 | { 864 | lv_obj_t *child = lv_obj_get_child(obj, NULL); 865 | while(child) { 866 | if(lv_obj_get_group(child) == group) { 867 | lv_group_remove_obj(child); 868 | } 869 | remove_children_from_group(child); 870 | child = lv_obj_get_child(obj, child); 871 | } 872 | 873 | 874 | } 875 | 876 | --------------------------------------------------------------------------------