move lvgl files to src folder
This commit is contained in:
598
src/lv_conf_checker.h
Normal file
598
src/lv_conf_checker.h
Normal file
@@ -0,0 +1,598 @@
|
||||
/**
|
||||
* GENERATED FILE, DO NOT EDIT IT!
|
||||
* @file lv_conf_checker.h
|
||||
* Make sure all the defines of lv_conf.h have a default value
|
||||
**/
|
||||
|
||||
#ifndef LV_CONF_CHECKER_H
|
||||
#define LV_CONF_CHECKER_H
|
||||
|
||||
/*===================
|
||||
Graphical settings
|
||||
*===================*/
|
||||
|
||||
/* Horizontal and vertical resolution of the library.*/
|
||||
#ifndef LV_HOR_RES_MAX
|
||||
#define LV_HOR_RES_MAX (480)
|
||||
#endif
|
||||
#ifndef LV_VER_RES_MAX
|
||||
#define LV_VER_RES_MAX (320)
|
||||
#endif
|
||||
|
||||
/*Color settings*/
|
||||
#ifndef LV_COLOR_DEPTH
|
||||
#define LV_COLOR_DEPTH 16 /*Color depth: 1/8/16/32*/
|
||||
#endif
|
||||
#ifndef LV_COLOR_16_SWAP
|
||||
#define LV_COLOR_16_SWAP 0 /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/
|
||||
#endif
|
||||
#ifndef LV_COLOR_SCREEN_TRANSP
|
||||
#define LV_COLOR_SCREEN_TRANSP 0 /*1: Enable screen transparency. Useful for OSD or other overlapping GUIs. Requires ARGB8888 colors*/
|
||||
#endif
|
||||
#ifndef LV_COLOR_TRANSP
|
||||
#define LV_COLOR_TRANSP LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma keying)*/
|
||||
#endif
|
||||
|
||||
/* Enable anti-aliasing (lines, and radiuses will be smoothed) */
|
||||
#ifndef LV_ANTIALIAS
|
||||
#define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/
|
||||
#endif
|
||||
|
||||
|
||||
/*Screen refresh period in milliseconds. LittlevGL will redraw the screen with this period*/
|
||||
#ifndef LV_REFR_PERIOD
|
||||
#define LV_REFR_PERIOD 30 /*[ms]*/
|
||||
#endif
|
||||
|
||||
/* Dot Per Inch: used to initialize default sizes. E.g. a button with width = LV_DPI / 2 -> half inch wide
|
||||
* (Not so important, you can adjust it to modify default sizes and spaces)*/
|
||||
#ifndef LV_DPI
|
||||
#define LV_DPI 100 /*[px]*/
|
||||
#endif
|
||||
|
||||
/*===================
|
||||
Dynamic memory
|
||||
*===================*/
|
||||
|
||||
/* Memory size which will be used by the library
|
||||
* to store the graphical objects and other data */
|
||||
#ifndef LV_MEM_CUSTOM
|
||||
#define LV_MEM_CUSTOM 0 /*1: use custom malloc/free, 0: use the built-in lv_mem_alloc/lv_mem_free*/
|
||||
#endif
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
#ifndef LV_MEM_SIZE
|
||||
# define LV_MEM_SIZE (32U * 1024U) /*Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/
|
||||
#endif
|
||||
#ifndef LV_MEM_ATTR
|
||||
# define LV_MEM_ATTR /*Complier prefix for big array declaration*/
|
||||
#endif
|
||||
#ifndef LV_MEM_ADR
|
||||
# define LV_MEM_ADR 0 /*Set an address for memory pool instead of allocation it as an array. Can be in external SRAM too.*/
|
||||
#endif
|
||||
#ifndef LV_MEM_AUTO_DEFRAG
|
||||
# define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/
|
||||
#endif
|
||||
#else /*LV_MEM_CUSTOM*/
|
||||
#ifndef LV_MEM_CUSTOM_INCLUDE
|
||||
# define LV_MEM_CUSTOM_INCLUDE <stdlib.h> /*Header for the dynamic memory function*/
|
||||
#endif
|
||||
#ifndef LV_MEM_CUSTOM_ALLOC
|
||||
# define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/
|
||||
#endif
|
||||
#ifndef LV_MEM_CUSTOM_FREE
|
||||
# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/
|
||||
#endif
|
||||
#endif /*LV_MEM_CUSTOM*/
|
||||
|
||||
/* Garbage Collector settings
|
||||
* Used if lvgl is binded to higher language and the memory is managed by that language */
|
||||
#ifndef LV_ENABLE_GC
|
||||
#define LV_ENABLE_GC 0
|
||||
#endif
|
||||
#if LV_ENABLE_GC != 0
|
||||
#ifndef LV_MEM_CUSTOM_REALLOC
|
||||
# define LV_MEM_CUSTOM_REALLOC your_realloc /*Wrapper to realloc*/
|
||||
#endif
|
||||
#ifndef LV_MEM_CUSTOM_GET_SIZE
|
||||
# define LV_MEM_CUSTOM_GET_SIZE your_mem_get_size /*Wrapper to lv_mem_get_size*/
|
||||
#endif
|
||||
#ifndef LV_GC_INCLUDE
|
||||
# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/
|
||||
#endif
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
/*=================
|
||||
Misc. setting
|
||||
*=================*/
|
||||
|
||||
/*Input device settings*/
|
||||
#ifndef LV_INDEV_READ_PERIOD
|
||||
#define LV_INDEV_READ_PERIOD 30 /*Input device read period in milliseconds*/
|
||||
#endif
|
||||
#ifndef LV_INDEV_POINT_MARKER
|
||||
#define LV_INDEV_POINT_MARKER 0 /*Mark the pressed points (required: LV_USE_REAL_DRAW = 1)*/
|
||||
#endif
|
||||
#ifndef LV_INDEV_DRAG_LIMIT
|
||||
#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */
|
||||
#endif
|
||||
#ifndef LV_INDEV_DRAG_THROW
|
||||
#define LV_INDEV_DRAG_THROW 20 /*Drag throw slow-down in [%]. Greater value means faster slow-down */
|
||||
#endif
|
||||
#ifndef LV_INDEV_LONG_PRESS_TIME
|
||||
#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/
|
||||
#endif
|
||||
#ifndef LV_INDEV_LONG_PRESS_REP_TIME
|
||||
#define LV_INDEV_LONG_PRESS_REP_TIME 100 /*Repeated trigger period in long press [ms] */
|
||||
#endif
|
||||
|
||||
/*Text settings*/
|
||||
#ifndef LV_TXT_UTF8
|
||||
#define LV_TXT_UTF8 1 /*Enable UTF-8 coded Unicode character usage */
|
||||
#endif
|
||||
#ifndef LV_TXT_BREAK_CHARS
|
||||
#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/
|
||||
#endif
|
||||
#ifndef LV_TXT_LINE_BREAK_LONG_LEN
|
||||
#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */
|
||||
#endif
|
||||
#ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN
|
||||
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */
|
||||
#endif
|
||||
#ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN
|
||||
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */
|
||||
#endif
|
||||
|
||||
/*Feature usage*/
|
||||
#ifndef LV_USE_ANIMATION
|
||||
#define LV_USE_ANIMATION 1 /*1: Enable all animations*/
|
||||
#endif
|
||||
#ifndef LV_USE_SHADOW
|
||||
#define LV_USE_SHADOW 1 /*1: Enable shadows*/
|
||||
#endif
|
||||
#ifndef LV_USE_GROUP
|
||||
#define LV_USE_GROUP 1 /*1: Enable object groups (for keyboards)*/
|
||||
#endif
|
||||
#if LV_USE_GROUP
|
||||
#endif /*LV_USE_GROUP*/
|
||||
#ifndef LV_USE_GPU
|
||||
#define LV_USE_GPU 1 /*1: Enable GPU interface*/
|
||||
#endif
|
||||
#ifndef LV_USE_FILESYSTEM
|
||||
#define LV_USE_FILESYSTEM 1 /*1: Enable file system (might be required for images*/
|
||||
#endif
|
||||
#ifndef LV_USE_USER_DATA_SINGLE
|
||||
#define LV_USE_USER_DATA_SINGLE 1 /*1: Add a `user_data` to drivers and objects*/
|
||||
#endif
|
||||
#ifndef LV_USE_USER_DATA_MULTI
|
||||
#define LV_USE_USER_DATA_MULTI 0 /*1: Add separate `user_data` for every callback*/
|
||||
#endif
|
||||
|
||||
/*Compiler settings*/
|
||||
#ifndef LV_ATTRIBUTE_TICK_INC
|
||||
#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to `lv_tick_inc` function */
|
||||
#endif
|
||||
#ifndef LV_ATTRIBUTE_TASK_HANDLER
|
||||
#define LV_ATTRIBUTE_TASK_HANDLER /* Define a custom attribute to `lv_task_handler` function */
|
||||
#endif
|
||||
#ifndef LV_COMPILER_VLA_SUPPORTED
|
||||
#define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/
|
||||
#endif
|
||||
#ifndef LV_COMPILER_NON_CONST_INIT_SUPPORTED
|
||||
#define LV_COMPILER_NON_CONST_INIT_SUPPORTED 1 /* 1: Initialization with non constant values are supported */
|
||||
#endif
|
||||
|
||||
/*HAL settings*/
|
||||
#ifndef LV_TICK_CUSTOM
|
||||
#define LV_TICK_CUSTOM 0 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */
|
||||
#endif
|
||||
#if LV_TICK_CUSTOM == 1
|
||||
#ifndef LV_TICK_CUSTOM_INCLUDE
|
||||
#define LV_TICK_CUSTOM_INCLUDE "something.h" /*Header for the sys time function*/
|
||||
#endif
|
||||
#ifndef LV_TICK_CUSTOM_SYS_TIME_EXPR
|
||||
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current systime in ms*/
|
||||
#endif
|
||||
#endif /*LV_TICK_CUSTOM*/
|
||||
|
||||
|
||||
/*Log settings*/
|
||||
#ifndef LV_USE_LOG
|
||||
#define LV_USE_LOG 1 /*Enable/disable the log module*/
|
||||
#endif
|
||||
#if LV_USE_LOG
|
||||
/* How important log should be added:
|
||||
* LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
|
||||
* LV_LOG_LEVEL_INFO Log important events
|
||||
* LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem
|
||||
* LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
|
||||
*/
|
||||
#ifndef LV_LOG_LEVEL
|
||||
# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN
|
||||
#endif
|
||||
|
||||
/* 1: Print the log with 'printf'; 0: user need to register a callback*/
|
||||
#ifndef LV_LOG_PRINTF
|
||||
# define LV_LOG_PRINTF 0
|
||||
#endif
|
||||
#endif /*LV_USE_LOG*/
|
||||
|
||||
/*================
|
||||
* THEME USAGE
|
||||
*================*/
|
||||
#ifndef LV_THEME_LIVE_UPDATE
|
||||
#define LV_THEME_LIVE_UPDATE 0 /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/
|
||||
#endif
|
||||
|
||||
#ifndef LV_USE_THEME_TEMPL
|
||||
#define LV_USE_THEME_TEMPL 0 /*Just for test*/
|
||||
#endif
|
||||
#ifndef LV_USE_THEME_DEFAULT
|
||||
#define LV_USE_THEME_DEFAULT 0 /*Built mainly from the built-in styles. Consumes very few RAM*/
|
||||
#endif
|
||||
#ifndef LV_USE_THEME_ALIEN
|
||||
#define LV_USE_THEME_ALIEN 0 /*Dark futuristic theme*/
|
||||
#endif
|
||||
#ifndef LV_USE_THEME_NIGHT
|
||||
#define LV_USE_THEME_NIGHT 0 /*Dark elegant theme*/
|
||||
#endif
|
||||
#ifndef LV_USE_THEME_MONO
|
||||
#define LV_USE_THEME_MONO 0 /*Mono color theme for monochrome displays*/
|
||||
#endif
|
||||
#ifndef LV_USE_THEME_MATERIAL
|
||||
#define LV_USE_THEME_MATERIAL 0 /*Flat theme with bold colors and light shadows*/
|
||||
#endif
|
||||
#ifndef LV_USE_THEME_ZEN
|
||||
#define LV_USE_THEME_ZEN 0 /*Peaceful, mainly light theme */
|
||||
#endif
|
||||
#ifndef LV_USE_THEME_NEMO
|
||||
#define LV_USE_THEME_NEMO 0 /*Water-like theme based on the movie "Finding Nemo"*/
|
||||
#endif
|
||||
|
||||
/*==================
|
||||
* FONT USAGE
|
||||
*===================*/
|
||||
|
||||
/* More info about fonts: https://docs.littlevgl.com/#Fonts
|
||||
* To enable a built-in font use 1,2,4 or 8 values
|
||||
* which will determine the bit-per-pixel. Higher value means smoother fonts */
|
||||
#ifndef LV_USE_FONT_DEJAVU_10
|
||||
#define LV_USE_FONT_DEJAVU_10 0
|
||||
#endif
|
||||
#ifndef LV_USE_FONT_DEJAVU_10_LATIN_SUP
|
||||
#define LV_USE_FONT_DEJAVU_10_LATIN_SUP 0
|
||||
#endif
|
||||
#ifndef LV_USE_FONT_DEJAVU_10_CYRILLIC
|
||||
#define LV_USE_FONT_DEJAVU_10_CYRILLIC 0
|
||||
#endif
|
||||
#ifndef LV_USE_FONT_SYMBOL_10
|
||||
#define LV_USE_FONT_SYMBOL_10 0
|
||||
#endif
|
||||
|
||||
#ifndef LV_USE_FONT_DEJAVU_20
|
||||
#define LV_USE_FONT_DEJAVU_20 4
|
||||
#endif
|
||||
#ifndef LV_USE_FONT_DEJAVU_20_LATIN_SUP
|
||||
#define LV_USE_FONT_DEJAVU_20_LATIN_SUP 4
|
||||
#endif
|
||||
#ifndef LV_USE_FONT_DEJAVU_20_CYRILLIC
|
||||
#define LV_USE_FONT_DEJAVU_20_CYRILLIC 4
|
||||
#endif
|
||||
#ifndef LV_USE_FONT_SYMBOL_20
|
||||
#define LV_USE_FONT_SYMBOL_20 4
|
||||
#endif
|
||||
|
||||
#ifndef LV_USE_FONT_DEJAVU_30
|
||||
#define LV_USE_FONT_DEJAVU_30 0
|
||||
#endif
|
||||
#ifndef LV_USE_FONT_DEJAVU_30_LATIN_SUP
|
||||
#define LV_USE_FONT_DEJAVU_30_LATIN_SUP 0
|
||||
#endif
|
||||
#ifndef LV_USE_FONT_DEJAVU_30_CYRILLIC
|
||||
#define LV_USE_FONT_DEJAVU_30_CYRILLIC 0
|
||||
#endif
|
||||
#ifndef LV_USE_FONT_SYMBOL_30
|
||||
#define LV_USE_FONT_SYMBOL_30 0
|
||||
#endif
|
||||
|
||||
#ifndef LV_USE_FONT_DEJAVU_40
|
||||
#define LV_USE_FONT_DEJAVU_40 0
|
||||
#endif
|
||||
#ifndef LV_USE_FONT_DEJAVU_40_LATIN_SUP
|
||||
#define LV_USE_FONT_DEJAVU_40_LATIN_SUP 0
|
||||
#endif
|
||||
#ifndef LV_USE_FONT_DEJAVU_40_CYRILLIC
|
||||
#define LV_USE_FONT_DEJAVU_40_CYRILLIC 0
|
||||
#endif
|
||||
#ifndef LV_USE_FONT_SYMBOL_40
|
||||
#define LV_USE_FONT_SYMBOL_40 0
|
||||
#endif
|
||||
|
||||
#ifndef LV_USE_FONT_MONOSPACE_8
|
||||
#define LV_USE_FONT_MONOSPACE_8 0
|
||||
#endif
|
||||
|
||||
/* Optionally declare your custom fonts here.
|
||||
* You can use these fonts as default font too
|
||||
* and they will be available globally. E.g.
|
||||
* #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \
|
||||
* LV_FONT_DECLARE(my_font_2) \
|
||||
*/
|
||||
#ifndef LV_FONT_CUSTOM_DECLARE
|
||||
#define LV_FONT_CUSTOM_DECLARE
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef LV_FONT_DEFAULT
|
||||
#define LV_FONT_DEFAULT &lv_font_dejavu_20 /*Always set a default font from the built-in fonts*/
|
||||
#endif
|
||||
|
||||
/*===================
|
||||
* LV_OBJ SETTINGS
|
||||
*==================*/
|
||||
#ifndef LV_OBJ_REALIGN
|
||||
#define LV_OBJ_REALIGN 0 /*Enable `lv_obj_realign()` based on `lv_obj_align()` parameters*/
|
||||
#endif
|
||||
|
||||
/*==================
|
||||
* LV OBJ X USAGE
|
||||
*================*/
|
||||
/*
|
||||
* Documentation of the object types: https://docs.littlevgl.com/#Object-types
|
||||
*/
|
||||
|
||||
/*****************
|
||||
* Simple object
|
||||
*****************/
|
||||
|
||||
/*Label (dependencies: -*/
|
||||
#ifndef LV_USE_LABEL
|
||||
#define LV_USE_LABEL 1
|
||||
#endif
|
||||
#if LV_USE_LABEL != 0
|
||||
#ifndef LV_LABEL_SCROLL_SPEED
|
||||
# define LV_LABEL_SCROLL_SPEED 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Image (dependencies: lv_label*/
|
||||
#ifndef LV_USE_IMG
|
||||
#define LV_USE_IMG 1
|
||||
#endif
|
||||
#if LV_USE_IMG != 0
|
||||
#ifndef LV_IMG_CF_INDEXED
|
||||
# define LV_IMG_CF_INDEXED 1 /*Enable indexed (palette) images*/
|
||||
#endif
|
||||
#ifndef LV_IMG_CF_ALPHA
|
||||
# define LV_IMG_CF_ALPHA 1 /*Enable alpha indexed images*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Line (dependencies: -*/
|
||||
#ifndef LV_USE_LINE
|
||||
#define LV_USE_LINE 1
|
||||
#endif
|
||||
|
||||
/*Arc (dependencies: -)*/
|
||||
#ifndef LV_USE_ARC
|
||||
#define LV_USE_ARC 1
|
||||
#endif
|
||||
|
||||
/*******************
|
||||
* Container objects
|
||||
*******************/
|
||||
|
||||
/*Container (dependencies: -*/
|
||||
#ifndef LV_USE_CONT
|
||||
#define LV_USE_CONT 1
|
||||
#endif
|
||||
|
||||
/*Page (dependencies: lv_cont)*/
|
||||
#ifndef LV_USE_PAGE
|
||||
#define LV_USE_PAGE 1
|
||||
#endif
|
||||
|
||||
/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/
|
||||
#ifndef LV_USE_WIN
|
||||
#define LV_USE_WIN 1
|
||||
#endif
|
||||
|
||||
/*Tab (dependencies: lv_page, lv_btnm)*/
|
||||
#ifndef LV_USE_TABVIEW
|
||||
#define LV_USE_TABVIEW 1
|
||||
#endif
|
||||
# if LV_USE_TABVIEW != 0
|
||||
#ifndef LV_TABVIEW_ANIM_TIME
|
||||
# define LV_TABVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Tileview (dependencies: lv_page) */
|
||||
#ifndef LV_USE_TILEVIEW
|
||||
#define LV_USE_TILEVIEW 1
|
||||
#endif
|
||||
#if LV_USE_TILEVIEW
|
||||
#ifndef LV_TILEVIEW_ANIM_TIME
|
||||
# define LV_TILEVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*************************
|
||||
* Data visualizer objects
|
||||
*************************/
|
||||
|
||||
/*Bar (dependencies: -)*/
|
||||
#ifndef LV_USE_BAR
|
||||
#define LV_USE_BAR 1
|
||||
#endif
|
||||
|
||||
/*Line meter (dependencies: *;)*/
|
||||
#ifndef LV_USE_LMETER
|
||||
#define LV_USE_LMETER 1
|
||||
#endif
|
||||
|
||||
/*Gauge (dependencies:lv_bar, lv_lmeter)*/
|
||||
#ifndef LV_USE_GAUGE
|
||||
#define LV_USE_GAUGE 1
|
||||
#endif
|
||||
|
||||
/*Chart (dependencies: -)*/
|
||||
#ifndef LV_USE_CHART
|
||||
#define LV_USE_CHART 1
|
||||
#endif
|
||||
|
||||
/*Table (dependencies: lv_label)*/
|
||||
#ifndef LV_USE_TABLE
|
||||
#define LV_USE_TABLE 1
|
||||
#endif
|
||||
#if LV_USE_TABLE
|
||||
#ifndef LV_TABLE_COL_MAX
|
||||
# define LV_TABLE_COL_MAX 12
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*LED (dependencies: -)*/
|
||||
#ifndef LV_USE_LED
|
||||
#define LV_USE_LED 1
|
||||
#endif
|
||||
|
||||
/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/
|
||||
#ifndef LV_USE_MBOX
|
||||
#define LV_USE_MBOX 1
|
||||
#endif
|
||||
|
||||
/*Text area (dependencies: lv_label, lv_page)*/
|
||||
#ifndef LV_USE_TA
|
||||
#define LV_USE_TA 1
|
||||
#endif
|
||||
#if LV_USE_TA != 0
|
||||
#ifndef LV_TA_CURSOR_BLINK_TIME
|
||||
# define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/
|
||||
#endif
|
||||
#ifndef LV_TA_PWD_SHOW_TIME
|
||||
# define LV_TA_PWD_SHOW_TIME 1500 /*ms*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Spinbox (dependencies: lv_ta)*/
|
||||
#ifndef LV_USE_SPINBOX
|
||||
#define LV_USE_SPINBOX 1
|
||||
#endif
|
||||
|
||||
/*Calendar (dependencies: -)*/
|
||||
#ifndef LV_USE_CALENDAR
|
||||
#define LV_USE_CALENDAR 1
|
||||
#endif
|
||||
|
||||
/*Preload (dependencies: lv_arc)*/
|
||||
#ifndef LV_USE_PRELOAD
|
||||
#define LV_USE_PRELOAD 1
|
||||
#endif
|
||||
#if LV_USE_PRELOAD != 0
|
||||
#ifndef LV_PRELOAD_DEF_ARC_LENGTH
|
||||
# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/
|
||||
#endif
|
||||
#ifndef LV_PRELOAD_DEF_SPIN_TIME
|
||||
# define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/
|
||||
#endif
|
||||
#ifndef LV_PRELOAD_DEF_ANIM
|
||||
# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Canvas (dependencies: lv_img)*/
|
||||
#ifndef LV_USE_CANVAS
|
||||
#define LV_USE_CANVAS 1
|
||||
#endif
|
||||
/*************************
|
||||
* User input objects
|
||||
*************************/
|
||||
|
||||
/*Button (dependencies: lv_cont*/
|
||||
#ifndef LV_USE_BTN
|
||||
#define LV_USE_BTN 1
|
||||
#endif
|
||||
#if LV_USE_BTN != 0
|
||||
#ifndef LV_BTN_INK_EFFECT
|
||||
# define LV_BTN_INK_EFFECT 1 /*Enable button-state animations - draw a circle on click (dependencies: LV_USE_ANIMATION)*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Image Button (dependencies: lv_btn*/
|
||||
#ifndef LV_USE_IMGBTN
|
||||
#define LV_USE_IMGBTN 1
|
||||
#endif
|
||||
#if LV_USE_IMGBTN
|
||||
#ifndef LV_IMGBTN_TILED
|
||||
# define LV_IMGBTN_TILED 0 /*1: The imgbtn requires left, mid and right parts and the width can be set freely*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Button matrix (dependencies: -)*/
|
||||
#ifndef LV_USE_BTNM
|
||||
#define LV_USE_BTNM 1
|
||||
#endif
|
||||
|
||||
/*Keyboard (dependencies: lv_btnm)*/
|
||||
#ifndef LV_USE_KB
|
||||
#define LV_USE_KB 1
|
||||
#endif
|
||||
|
||||
/*Check box (dependencies: lv_btn, lv_label)*/
|
||||
#ifndef LV_USE_CB
|
||||
#define LV_USE_CB 1
|
||||
#endif
|
||||
|
||||
/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/
|
||||
#ifndef LV_USE_LIST
|
||||
#define LV_USE_LIST 1
|
||||
#endif
|
||||
#if LV_USE_LIST != 0
|
||||
#ifndef LV_LIST_FOCUS_TIME
|
||||
# define LV_LIST_FOCUS_TIME 100 /*Default animation time of focusing to a list element [ms] (0: no animation) */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/
|
||||
#ifndef LV_USE_DDLIST
|
||||
#define LV_USE_DDLIST 1
|
||||
#endif
|
||||
#if LV_USE_DDLIST != 0
|
||||
#ifndef LV_DDLIST_ANIM_TIME
|
||||
# define LV_DDLIST_ANIM_TIME 200 /*Open and close default animation time [ms] (0: no animation)*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Roller (dependencies: lv_ddlist)*/
|
||||
#ifndef LV_USE_ROLLER
|
||||
#define LV_USE_ROLLER 1
|
||||
#endif
|
||||
#if LV_USE_ROLLER != 0
|
||||
#ifndef LV_ROLLER_ANIM_TIME
|
||||
# define LV_ROLLER_ANIM_TIME 200 /*Focus animation time [ms] (0: no animation)*/
|
||||
#endif
|
||||
#ifndef LV_ROLLER_INF_PAGES
|
||||
# define LV_ROLLER_INF_PAGES 7 /*With inifinite rollers the options are added multiple times (on select positioned back to the center)*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Slider (dependencies: lv_bar)*/
|
||||
#ifndef LV_USE_SLIDER
|
||||
#define LV_USE_SLIDER 1
|
||||
#endif
|
||||
|
||||
/*Switch (dependencies: lv_slider)*/
|
||||
#ifndef LV_USE_SW
|
||||
#define LV_USE_SW 1
|
||||
#endif
|
||||
|
||||
/*************************
|
||||
* Non-user section
|
||||
*************************/
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) /* Disable warnings for Visual Studio*/
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*LV_CONF_CHECKER_H*/
|
||||
361
src/lv_conf_templ.h
Normal file
361
src/lv_conf_templ.h
Normal file
@@ -0,0 +1,361 @@
|
||||
/**
|
||||
* @file lv_conf.h
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* COPY THIS FILE AS lv_conf.h
|
||||
*/
|
||||
|
||||
#if 0 /*Set it to "1" to enable content*/
|
||||
|
||||
|
||||
#ifndef LV_CONF_H
|
||||
#define LV_CONF_H
|
||||
|
||||
/*===================
|
||||
Graphical settings
|
||||
*===================*/
|
||||
|
||||
/* Horizontal and vertical resolution of the library.*/
|
||||
#define LV_HOR_RES_MAX (480)
|
||||
#define LV_VER_RES_MAX (320)
|
||||
|
||||
/*Color settings*/
|
||||
#define LV_COLOR_DEPTH 16 /*Color depth: 1/8/16/32*/
|
||||
#define LV_COLOR_16_SWAP 0 /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/
|
||||
#define LV_COLOR_SCREEN_TRANSP 0 /*1: Enable screen transparency. Useful for OSD or other overlapping GUIs. Requires ARGB8888 colors*/
|
||||
#define LV_COLOR_TRANSP LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma keying)*/
|
||||
|
||||
/* Enable anti-aliasing (lines, and radiuses will be smoothed) */
|
||||
#define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/
|
||||
|
||||
|
||||
/*Screen refresh period in milliseconds. LittlevGL will redraw the screen with this period*/
|
||||
#define LV_REFR_PERIOD 30 /*[ms]*/
|
||||
|
||||
/* Dot Per Inch: used to initialize default sizes. E.g. a button with width = LV_DPI / 2 -> half inch wide
|
||||
* (Not so important, you can adjust it to modify default sizes and spaces)*/
|
||||
#define LV_DPI 100 /*[px]*/
|
||||
|
||||
/*===================
|
||||
Dynamic memory
|
||||
*===================*/
|
||||
|
||||
/* Memory size which will be used by the library
|
||||
* to store the graphical objects and other data */
|
||||
#define LV_MEM_CUSTOM 0 /*1: use custom malloc/free, 0: use the built-in lv_mem_alloc/lv_mem_free*/
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
# define LV_MEM_SIZE (32U * 1024U) /*Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/
|
||||
# define LV_MEM_ATTR /*Complier prefix for big array declaration*/
|
||||
# define LV_MEM_ADR 0 /*Set an address for memory pool instead of allocation it as an array. Can be in external SRAM too.*/
|
||||
# define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/
|
||||
#else /*LV_MEM_CUSTOM*/
|
||||
# define LV_MEM_CUSTOM_INCLUDE <stdlib.h> /*Header for the dynamic memory function*/
|
||||
# define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/
|
||||
# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/
|
||||
#endif /*LV_MEM_CUSTOM*/
|
||||
|
||||
/* Garbage Collector settings
|
||||
* Used if lvgl is binded to higher language and the memory is managed by that language */
|
||||
#define LV_ENABLE_GC 0
|
||||
#if LV_ENABLE_GC != 0
|
||||
# define LV_MEM_CUSTOM_REALLOC your_realloc /*Wrapper to realloc*/
|
||||
# define LV_MEM_CUSTOM_GET_SIZE your_mem_get_size /*Wrapper to lv_mem_get_size*/
|
||||
# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
/*=================
|
||||
Misc. setting
|
||||
*=================*/
|
||||
|
||||
/*Input device settings*/
|
||||
#define LV_INDEV_READ_PERIOD 30 /*Input device read period in milliseconds*/
|
||||
#define LV_INDEV_POINT_MARKER 0 /*Mark the pressed points (required: LV_USE_REAL_DRAW = 1)*/
|
||||
#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */
|
||||
#define LV_INDEV_DRAG_THROW 20 /*Drag throw slow-down in [%]. Greater value means faster slow-down */
|
||||
#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/
|
||||
#define LV_INDEV_LONG_PRESS_REP_TIME 100 /*Repeated trigger period in long press [ms] */
|
||||
|
||||
/*Text settings*/
|
||||
#define LV_TXT_UTF8 1 /*Enable UTF-8 coded Unicode character usage */
|
||||
#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/
|
||||
#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */
|
||||
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */
|
||||
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */
|
||||
|
||||
/*Feature usage*/
|
||||
#define LV_USE_ANIMATION 1 /*1: Enable all animations*/
|
||||
#define LV_USE_SHADOW 1 /*1: Enable shadows*/
|
||||
#define LV_USE_GROUP 1 /*1: Enable object groups (for keyboards)*/
|
||||
#if LV_USE_GROUP
|
||||
typedef void * lv_group_user_data_t;
|
||||
#endif /*LV_USE_GROUP*/
|
||||
#define LV_USE_GPU 1 /*1: Enable GPU interface*/
|
||||
#define LV_USE_FILESYSTEM 1 /*1: Enable file system (might be required for images*/
|
||||
#define LV_USE_USER_DATA_SINGLE 1 /*1: Add a `user_data` to drivers and objects*/
|
||||
#define LV_USE_USER_DATA_MULTI 0 /*1: Add separate `user_data` for every callback*/
|
||||
|
||||
/*Compiler settings*/
|
||||
#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to `lv_tick_inc` function */
|
||||
#define LV_ATTRIBUTE_TASK_HANDLER /* Define a custom attribute to `lv_task_handler` function */
|
||||
#define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/
|
||||
#define LV_COMPILER_NON_CONST_INIT_SUPPORTED 1 /* 1: Initialization with non constant values are supported */
|
||||
|
||||
/*HAL settings*/
|
||||
#define LV_TICK_CUSTOM 0 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */
|
||||
#if LV_TICK_CUSTOM == 1
|
||||
#define LV_TICK_CUSTOM_INCLUDE "something.h" /*Header for the sys time function*/
|
||||
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current systime in ms*/
|
||||
#endif /*LV_TICK_CUSTOM*/
|
||||
|
||||
typedef void * lv_disp_drv_user_data_t; /*Type of user data in the display driver*/
|
||||
typedef void * lv_indev_drv_user_data_t; /*Type of user data in the display driver*/
|
||||
|
||||
/*Log settings*/
|
||||
#define LV_USE_LOG 1 /*Enable/disable the log module*/
|
||||
#if LV_USE_LOG
|
||||
/* How important log should be added:
|
||||
* LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
|
||||
* LV_LOG_LEVEL_INFO Log important events
|
||||
* LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem
|
||||
* LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
|
||||
*/
|
||||
# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN
|
||||
|
||||
/* 1: Print the log with 'printf'; 0: user need to register a callback*/
|
||||
# define LV_LOG_PRINTF 0
|
||||
#endif /*LV_USE_LOG*/
|
||||
|
||||
/*================
|
||||
* THEME USAGE
|
||||
*================*/
|
||||
#define LV_THEME_LIVE_UPDATE 0 /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/
|
||||
|
||||
#define LV_USE_THEME_TEMPL 0 /*Just for test*/
|
||||
#define LV_USE_THEME_DEFAULT 0 /*Built mainly from the built-in styles. Consumes very few RAM*/
|
||||
#define LV_USE_THEME_ALIEN 0 /*Dark futuristic theme*/
|
||||
#define LV_USE_THEME_NIGHT 0 /*Dark elegant theme*/
|
||||
#define LV_USE_THEME_MONO 0 /*Mono color theme for monochrome displays*/
|
||||
#define LV_USE_THEME_MATERIAL 0 /*Flat theme with bold colors and light shadows*/
|
||||
#define LV_USE_THEME_ZEN 0 /*Peaceful, mainly light theme */
|
||||
#define LV_USE_THEME_NEMO 0 /*Water-like theme based on the movie "Finding Nemo"*/
|
||||
|
||||
/*==================
|
||||
* FONT USAGE
|
||||
*===================*/
|
||||
|
||||
/* More info about fonts: https://docs.littlevgl.com/#Fonts
|
||||
* To enable a built-in font use 1,2,4 or 8 values
|
||||
* which will determine the bit-per-pixel. Higher value means smoother fonts */
|
||||
#define LV_USE_FONT_DEJAVU_10 0
|
||||
#define LV_USE_FONT_DEJAVU_10_LATIN_SUP 0
|
||||
#define LV_USE_FONT_DEJAVU_10_CYRILLIC 0
|
||||
#define LV_USE_FONT_SYMBOL_10 0
|
||||
|
||||
#define LV_USE_FONT_DEJAVU_20 4
|
||||
#define LV_USE_FONT_DEJAVU_20_LATIN_SUP 4
|
||||
#define LV_USE_FONT_DEJAVU_20_CYRILLIC 4
|
||||
#define LV_USE_FONT_SYMBOL_20 4
|
||||
|
||||
#define LV_USE_FONT_DEJAVU_30 0
|
||||
#define LV_USE_FONT_DEJAVU_30_LATIN_SUP 0
|
||||
#define LV_USE_FONT_DEJAVU_30_CYRILLIC 0
|
||||
#define LV_USE_FONT_SYMBOL_30 0
|
||||
|
||||
#define LV_USE_FONT_DEJAVU_40 0
|
||||
#define LV_USE_FONT_DEJAVU_40_LATIN_SUP 0
|
||||
#define LV_USE_FONT_DEJAVU_40_CYRILLIC 0
|
||||
#define LV_USE_FONT_SYMBOL_40 0
|
||||
|
||||
#define LV_USE_FONT_MONOSPACE_8 0
|
||||
|
||||
/* Optionally declare your custom fonts here.
|
||||
* You can use these fonts as default font too
|
||||
* and they will be available globally. E.g.
|
||||
* #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \
|
||||
* LV_FONT_DECLARE(my_font_2) \
|
||||
*/
|
||||
#define LV_FONT_CUSTOM_DECLARE
|
||||
|
||||
|
||||
#define LV_FONT_DEFAULT &lv_font_dejavu_20 /*Always set a default font from the built-in fonts*/
|
||||
|
||||
/*===================
|
||||
* LV_OBJ SETTINGS
|
||||
*==================*/
|
||||
typedef void * lv_obj_user_data_t; /*Declare the type of the user data of object (can be e.g. `void *`, `int`, `struct`)*/
|
||||
#define LV_OBJ_REALIGN 0 /*Enable `lv_obj_realign()` based on `lv_obj_align()` parameters*/
|
||||
|
||||
/*==================
|
||||
* LV OBJ X USAGE
|
||||
*================*/
|
||||
/*
|
||||
* Documentation of the object types: https://docs.littlevgl.com/#Object-types
|
||||
*/
|
||||
|
||||
/*****************
|
||||
* Simple object
|
||||
*****************/
|
||||
|
||||
/*Label (dependencies: -*/
|
||||
#define LV_USE_LABEL 1
|
||||
#if LV_USE_LABEL != 0
|
||||
# define LV_LABEL_SCROLL_SPEED 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/
|
||||
#endif
|
||||
|
||||
/*Image (dependencies: lv_label*/
|
||||
#define LV_USE_IMG 1
|
||||
#if LV_USE_IMG != 0
|
||||
# define LV_IMG_CF_INDEXED 1 /*Enable indexed (palette) images*/
|
||||
# define LV_IMG_CF_ALPHA 1 /*Enable alpha indexed images*/
|
||||
#endif
|
||||
|
||||
/*Line (dependencies: -*/
|
||||
#define LV_USE_LINE 1
|
||||
|
||||
/*Arc (dependencies: -)*/
|
||||
#define LV_USE_ARC 1
|
||||
|
||||
/*******************
|
||||
* Container objects
|
||||
*******************/
|
||||
|
||||
/*Container (dependencies: -*/
|
||||
#define LV_USE_CONT 1
|
||||
|
||||
/*Page (dependencies: lv_cont)*/
|
||||
#define LV_USE_PAGE 1
|
||||
|
||||
/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/
|
||||
#define LV_USE_WIN 1
|
||||
|
||||
/*Tab (dependencies: lv_page, lv_btnm)*/
|
||||
#define LV_USE_TABVIEW 1
|
||||
# if LV_USE_TABVIEW != 0
|
||||
# define LV_TABVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/
|
||||
#endif
|
||||
|
||||
/*Tileview (dependencies: lv_page) */
|
||||
#define LV_USE_TILEVIEW 1
|
||||
#if LV_USE_TILEVIEW
|
||||
# define LV_TILEVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/
|
||||
#endif
|
||||
|
||||
/*************************
|
||||
* Data visualizer objects
|
||||
*************************/
|
||||
|
||||
/*Bar (dependencies: -)*/
|
||||
#define LV_USE_BAR 1
|
||||
|
||||
/*Line meter (dependencies: *;)*/
|
||||
#define LV_USE_LMETER 1
|
||||
|
||||
/*Gauge (dependencies:lv_bar, lv_lmeter)*/
|
||||
#define LV_USE_GAUGE 1
|
||||
|
||||
/*Chart (dependencies: -)*/
|
||||
#define LV_USE_CHART 1
|
||||
|
||||
/*Table (dependencies: lv_label)*/
|
||||
#define LV_USE_TABLE 1
|
||||
#if LV_USE_TABLE
|
||||
# define LV_TABLE_COL_MAX 12
|
||||
#endif
|
||||
|
||||
/*LED (dependencies: -)*/
|
||||
#define LV_USE_LED 1
|
||||
|
||||
/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/
|
||||
#define LV_USE_MBOX 1
|
||||
|
||||
/*Text area (dependencies: lv_label, lv_page)*/
|
||||
#define LV_USE_TA 1
|
||||
#if LV_USE_TA != 0
|
||||
# define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/
|
||||
# define LV_TA_PWD_SHOW_TIME 1500 /*ms*/
|
||||
#endif
|
||||
|
||||
/*Spinbox (dependencies: lv_ta)*/
|
||||
#define LV_USE_SPINBOX 1
|
||||
|
||||
/*Calendar (dependencies: -)*/
|
||||
#define LV_USE_CALENDAR 1
|
||||
|
||||
/*Preload (dependencies: lv_arc)*/
|
||||
#define LV_USE_PRELOAD 1
|
||||
#if LV_USE_PRELOAD != 0
|
||||
# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/
|
||||
# define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/
|
||||
# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC
|
||||
#endif
|
||||
|
||||
/*Canvas (dependencies: lv_img)*/
|
||||
#define LV_USE_CANVAS 1
|
||||
/*************************
|
||||
* User input objects
|
||||
*************************/
|
||||
|
||||
/*Button (dependencies: lv_cont*/
|
||||
#define LV_USE_BTN 1
|
||||
#if LV_USE_BTN != 0
|
||||
# define LV_BTN_INK_EFFECT 1 /*Enable button-state animations - draw a circle on click (dependencies: LV_USE_ANIMATION)*/
|
||||
#endif
|
||||
|
||||
/*Image Button (dependencies: lv_btn*/
|
||||
#define LV_USE_IMGBTN 1
|
||||
#if LV_USE_IMGBTN
|
||||
# define LV_IMGBTN_TILED 0 /*1: The imgbtn requires left, mid and right parts and the width can be set freely*/
|
||||
#endif
|
||||
|
||||
/*Button matrix (dependencies: -)*/
|
||||
#define LV_USE_BTNM 1
|
||||
|
||||
/*Keyboard (dependencies: lv_btnm)*/
|
||||
#define LV_USE_KB 1
|
||||
|
||||
/*Check box (dependencies: lv_btn, lv_label)*/
|
||||
#define LV_USE_CB 1
|
||||
|
||||
/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/
|
||||
#define LV_USE_LIST 1
|
||||
#if LV_USE_LIST != 0
|
||||
# define LV_LIST_FOCUS_TIME 100 /*Default animation time of focusing to a list element [ms] (0: no animation) */
|
||||
#endif
|
||||
|
||||
/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/
|
||||
#define LV_USE_DDLIST 1
|
||||
#if LV_USE_DDLIST != 0
|
||||
# define LV_DDLIST_ANIM_TIME 200 /*Open and close default animation time [ms] (0: no animation)*/
|
||||
#endif
|
||||
|
||||
/*Roller (dependencies: lv_ddlist)*/
|
||||
#define LV_USE_ROLLER 1
|
||||
#if LV_USE_ROLLER != 0
|
||||
# define LV_ROLLER_ANIM_TIME 200 /*Focus animation time [ms] (0: no animation)*/
|
||||
# define LV_ROLLER_INF_PAGES 7 /*With inifinite rollers the options are added multiple times (on select positioned back to the center)*/
|
||||
#endif
|
||||
|
||||
/*Slider (dependencies: lv_bar)*/
|
||||
#define LV_USE_SLIDER 1
|
||||
|
||||
/*Switch (dependencies: lv_slider)*/
|
||||
#define LV_USE_SW 1
|
||||
|
||||
/*************************
|
||||
* Non-user section
|
||||
*************************/
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) /* Disable warnings for Visual Studio*/
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
/*--END OF LV_CONF_H--*/
|
||||
|
||||
/*Be sure every define has a default value*/
|
||||
#include "lvgl/src/lv_conf_checker.h"
|
||||
|
||||
#endif /*LV_CONF_H*/
|
||||
|
||||
|
||||
#endif /*End of "Content enable"*/
|
||||
11
src/lv_core/lv_core.mk
Normal file
11
src/lv_core/lv_core.mk
Normal file
@@ -0,0 +1,11 @@
|
||||
CSRCS += lv_group.c
|
||||
CSRCS += lv_indev.c
|
||||
CSRCS += lv_disp.c
|
||||
CSRCS += lv_obj.c
|
||||
CSRCS += lv_refr.c
|
||||
CSRCS += lv_style.c
|
||||
|
||||
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/src/lv_core
|
||||
VPATH += :$(LVGL_DIR)/lvgl/src/lv_core
|
||||
|
||||
CFLAGS += "-I$(LVGL_DIR)/lvgl/src/lv_core"
|
||||
117
src/lv_core/lv_disp.c
Normal file
117
src/lv_core/lv_disp.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @file lv_disp.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_disp.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Return with a pointer to the active screen
|
||||
* @param disp pointer to display which active screen should be get. (NULL to use the default screen)
|
||||
* @return pointer to the active screen object (loaded by 'lv_scr_load()')
|
||||
*/
|
||||
lv_obj_t * lv_disp_get_scr_act(lv_disp_t * disp)
|
||||
{
|
||||
if(!disp) disp = lv_disp_get_default();
|
||||
if(!disp) {
|
||||
LV_LOG_WARN("lv_scr_act: no display registered to get its top layer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return disp->act_scr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a screen active
|
||||
* @param scr pointer to a screen
|
||||
*/
|
||||
void lv_disp_set_scr_act(lv_obj_t * scr)
|
||||
{
|
||||
lv_disp_t * d = lv_obj_get_disp(scr);
|
||||
|
||||
d->act_scr = scr;
|
||||
|
||||
lv_obj_invalidate(scr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with the top layer. (Same on every screen and it is above the normal screen layer)
|
||||
* @param disp pointer to display which top layer should be get. (NULL to use the default screen)
|
||||
* @return pointer to the top layer object (transparent screen sized lv_obj)
|
||||
*/
|
||||
lv_obj_t * lv_disp_get_layer_top(lv_disp_t * disp)
|
||||
{
|
||||
if(!disp) disp = lv_disp_get_default();
|
||||
if(!disp) {
|
||||
LV_LOG_WARN("lv_layer_top: no display registered to get its top layer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return disp->top_layer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with the sys. layer. (Same on every screen and it is above the normal screen and the top layer)
|
||||
* @param disp pointer to display which sys. layer should be get. (NULL to use the default screen)
|
||||
* @return pointer to the sys layer object (transparent screen sized lv_obj)
|
||||
*/
|
||||
lv_obj_t * lv_disp_get_layer_sys(lv_disp_t * disp)
|
||||
{
|
||||
if(!disp) disp = lv_disp_get_default();
|
||||
if(!disp) {
|
||||
LV_LOG_WARN("lv_layer_sys: no display registered to get its top layer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return disp->sys_layer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a screen to a display.
|
||||
* @param disp pointer to a display where to assign the screen
|
||||
* @param scr pointer to a screen object to assign
|
||||
*/
|
||||
void lv_disp_assign_screen(lv_disp_t * disp, lv_obj_t * scr)
|
||||
{
|
||||
if(lv_obj_get_parent(scr) != NULL) {
|
||||
LV_LOG_WARN("lv_disp_assign_screen: try to assign a non-screen object");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_disp_t * old_disp = lv_obj_get_disp(scr);
|
||||
|
||||
if(old_disp == disp) return;
|
||||
|
||||
lv_ll_chg_list(&old_disp->scr_ll, &disp->scr_ll, scr);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
120
src/lv_core/lv_disp.h
Normal file
120
src/lv_core/lv_disp.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* @file lv_disp.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DISP_H
|
||||
#define LV_DISP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_hal/lv_hal.h"
|
||||
#include "lv_obj.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Return with a pointer to the active screen
|
||||
* @param disp pointer to display which active screen should be get. (NULL to use the default screen)
|
||||
* @return pointer to the active screen object (loaded by 'lv_scr_load()')
|
||||
*/
|
||||
lv_obj_t * lv_disp_get_scr_act(lv_disp_t * disp);
|
||||
|
||||
/**
|
||||
* Make a screen active
|
||||
* @param scr pointer to a screen
|
||||
*/
|
||||
void lv_disp_set_scr_act(lv_obj_t * scr);
|
||||
|
||||
/**
|
||||
* Return with the top layer. (Same on every screen and it is above the normal screen layer)
|
||||
* @param disp pointer to display which top layer should be get. (NULL to use the default screen)
|
||||
* @return pointer to the top layer object (transparent screen sized lv_obj)
|
||||
*/
|
||||
lv_obj_t * lv_disp_get_layer_top(lv_disp_t * disp);
|
||||
|
||||
/**
|
||||
* Return with the sys. layer. (Same on every screen and it is above the normal screen and the top layer)
|
||||
* @param disp pointer to display which sys. layer should be get. (NULL to use the default screen)
|
||||
* @return pointer to the sys layer object (transparent screen sized lv_obj)
|
||||
*/
|
||||
lv_obj_t * lv_disp_get_layer_sys(lv_disp_t * disp);
|
||||
|
||||
/**
|
||||
* Assign a screen to a display.
|
||||
* @param disp pointer to a display where to assign the screen
|
||||
* @param scr pointer to a screen object to assign
|
||||
*/
|
||||
void lv_disp_assign_screen(lv_disp_t * disp, lv_obj_t * scr);
|
||||
|
||||
/*------------------------------------------------
|
||||
* To improve backward compatibility
|
||||
* Recommended only if you have one display
|
||||
*------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Get the active screen of the default display
|
||||
* @return pointer to the active screen
|
||||
*/
|
||||
static inline lv_obj_t * lv_scr_act(void)
|
||||
{
|
||||
return lv_disp_get_scr_act(lv_disp_get_default());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the top layer of the default display
|
||||
* @return pointer to the top layer
|
||||
*/
|
||||
static inline lv_obj_t * lv_layer_top(void)
|
||||
{
|
||||
return lv_disp_get_layer_top(lv_disp_get_default());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the active screen of the deafult display
|
||||
* @return pointer to the sys layer
|
||||
*/
|
||||
static inline lv_obj_t * lv_layer_sys(void)
|
||||
{
|
||||
return lv_disp_get_layer_sys(lv_disp_get_default());
|
||||
}
|
||||
|
||||
static inline void lv_scr_load(lv_obj_t * scr)
|
||||
{
|
||||
lv_disp_set_scr_act(scr);
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/*------------------------------------------------
|
||||
* To improve backward compatibility
|
||||
* Recommended only if you have one display
|
||||
*------------------------------------------------*/
|
||||
|
||||
#define LV_HOR_RES lv_disp_get_hor_res(lv_disp_get_default())
|
||||
#define LV_VER_RES lv_disp_get_ver_res(lv_disp_get_default())
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_TEMPL_H*/
|
||||
663
src/lv_core/lv_group.c
Normal file
663
src/lv_core/lv_group.c
Normal file
@@ -0,0 +1,663 @@
|
||||
/**
|
||||
* @file lv_group.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_group.h"
|
||||
#if LV_USE_GROUP != 0
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
#include <stddef.h>
|
||||
#include "../lv_misc/lv_gc.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void style_mod_def(lv_group_t * group, lv_style_t * style);
|
||||
static void style_mod_edit_def(lv_group_t * group, lv_style_t * style);
|
||||
static void refresh_theme(lv_group_t * g, lv_theme_t * th);
|
||||
static void focus_next_core(lv_group_t * group, void * (*begin)(const lv_ll_t *), void * (*move)(const lv_ll_t *, const void *));
|
||||
static void lv_group_refocus(lv_group_t * g);
|
||||
static void obj_to_foreground(lv_obj_t * obj);
|
||||
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Init. the group module
|
||||
*/
|
||||
void lv_group_init(void)
|
||||
{
|
||||
lv_ll_init(&LV_GC_ROOT(_lv_group_ll), sizeof(lv_group_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new object group
|
||||
* @return pointer to the new object group
|
||||
*/
|
||||
lv_group_t * lv_group_create(void)
|
||||
{
|
||||
lv_group_t * group = lv_ll_ins_head(&LV_GC_ROOT(_lv_group_ll));
|
||||
lv_mem_assert(group);
|
||||
if(group == NULL) return NULL;
|
||||
lv_ll_init(&group->obj_ll, sizeof(lv_obj_t *));
|
||||
|
||||
group->obj_focus = NULL;
|
||||
group->frozen = 0;
|
||||
group->focus_cb = NULL;
|
||||
group->click_focus = 1;
|
||||
group->editing = 0;
|
||||
group->refocus_policy = LV_GROUP_REFOCUS_POLICY_PREV;
|
||||
group->wrap = 1;
|
||||
|
||||
#if LV_USE_USER_DATA_SINGLE
|
||||
memset(&group->user_data, 0, sizeof(lv_group_user_data_t));
|
||||
#endif
|
||||
|
||||
#if LV_USE_USER_DATA_MULTI
|
||||
memset(&group->focus_user_data, 0, sizeof(lv_group_user_data_t));
|
||||
memset(&group->style_mod_user_data, 0, sizeof(lv_group_user_data_t));
|
||||
memset(&group->style_mod_edit_user_data, 0, sizeof(lv_group_user_data_t));
|
||||
#endif
|
||||
|
||||
|
||||
/*Initialize style modification callbacks from current theme*/
|
||||
refresh_theme(group, lv_theme_get_current());
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a group object
|
||||
* @param group pointer to a group
|
||||
*/
|
||||
void lv_group_del(lv_group_t * group)
|
||||
{
|
||||
/*Defocus the the currently focused object*/
|
||||
if(group->obj_focus != NULL) {
|
||||
(*group->obj_focus)->signal_cb(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
|
||||
lv_obj_invalidate(*group->obj_focus);
|
||||
}
|
||||
|
||||
/*Remove the objects from the group*/
|
||||
lv_obj_t ** obj;
|
||||
LV_LL_READ(group->obj_ll, obj) {
|
||||
(*obj)->group_p = NULL;
|
||||
}
|
||||
|
||||
lv_ll_clear(&(group->obj_ll));
|
||||
lv_mem_free(group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object to a group
|
||||
* @param group pointer to a group
|
||||
* @param obj pointer to an object to add
|
||||
*/
|
||||
void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj)
|
||||
{
|
||||
if(group == NULL) return;
|
||||
|
||||
/*Do not add the object twice*/
|
||||
lv_obj_t ** obj_i;
|
||||
LV_LL_READ(group->obj_ll, obj_i) {
|
||||
if((*obj_i) == obj) {
|
||||
LV_LOG_INFO("lv_group_add_obj: the object is already added to this group");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*If the object is already in a group and focused then defocus it*/
|
||||
if(obj->group_p) {
|
||||
if(lv_obj_is_focused(obj)) {
|
||||
lv_group_refocus(obj->group_p);
|
||||
|
||||
LV_LOG_INFO("lv_group_add_obj: assign object to an other group");
|
||||
}
|
||||
}
|
||||
|
||||
obj->group_p = group;
|
||||
lv_obj_t ** next = lv_ll_ins_tail(&group->obj_ll);
|
||||
lv_mem_assert(next);
|
||||
if(next == NULL) return;
|
||||
*next = obj;
|
||||
|
||||
/* If the head and the tail is equal then there is only one object in the linked list.
|
||||
* In this case automatically activate it*/
|
||||
if(lv_ll_get_head(&group->obj_ll) == next) {
|
||||
lv_group_refocus(group);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an object from its group
|
||||
* @param obj pointer to an object to remove
|
||||
*/
|
||||
void lv_group_remove_obj(lv_obj_t * obj)
|
||||
{
|
||||
lv_group_t * g = obj->group_p;
|
||||
if(g == NULL) return;
|
||||
if(g->obj_focus == NULL) return; /*Just to be sure (Not possible if there is at least one object in the group)*/
|
||||
|
||||
/*Focus on the next object*/
|
||||
if(*g->obj_focus == obj) {
|
||||
/*If this is the only object in the group then focus to nothing.*/
|
||||
if(lv_ll_get_head(&g->obj_ll) == g->obj_focus && lv_ll_get_tail(&g->obj_ll) == g->obj_focus) {
|
||||
(*g->obj_focus)->signal_cb(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
|
||||
}
|
||||
/*If there more objects in the group then focus to the next/prev object*/
|
||||
else {
|
||||
lv_group_refocus(g);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the focuses object is still the same then it was the only object in the group but it will be deleted.
|
||||
* Set the `obj_focus` to NULL to get back to the initial state of the group with zero objects*/
|
||||
if(*g->obj_focus == obj) {
|
||||
g->obj_focus = NULL;
|
||||
}
|
||||
|
||||
/*Search the object and remove it from its group */
|
||||
lv_obj_t ** i;
|
||||
LV_LL_READ(g->obj_ll, i) {
|
||||
if(*i == obj) {
|
||||
lv_ll_rem(&g->obj_ll, i);
|
||||
lv_mem_free(i);
|
||||
obj->group_p = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus on an object (defocus the current)
|
||||
* @param obj pointer to an object to focus on
|
||||
*/
|
||||
void lv_group_focus_obj(lv_obj_t * obj)
|
||||
{
|
||||
if(obj == NULL) return;
|
||||
lv_group_t * g = obj->group_p;
|
||||
if(g == NULL) return;
|
||||
|
||||
if(g->frozen != 0) return;
|
||||
|
||||
/*On defocus edit mode must be leaved*/
|
||||
lv_group_set_editing(g, false);
|
||||
|
||||
lv_obj_t ** i;
|
||||
LV_LL_READ(g->obj_ll, i) {
|
||||
if(*i == obj) {
|
||||
if(g->obj_focus == i) return; /*Don't focus the already focused object again*/
|
||||
if(g->obj_focus != NULL) {
|
||||
(*g->obj_focus)->signal_cb(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
|
||||
lv_res_t res = lv_obj_send_event(*g->obj_focus, LV_EVENT_DEFOCUSED);
|
||||
if(res != LV_RES_OK) return;
|
||||
lv_obj_invalidate(*g->obj_focus);
|
||||
}
|
||||
|
||||
g->obj_focus = i;
|
||||
|
||||
if(g->obj_focus != NULL) {
|
||||
(*g->obj_focus)->signal_cb(*g->obj_focus, LV_SIGNAL_FOCUS, NULL);
|
||||
if(g->focus_cb) g->focus_cb(g);
|
||||
lv_res_t res = lv_obj_send_event(*g->obj_focus, LV_EVENT_FOCUSED);
|
||||
if(res != LV_RES_OK) return;
|
||||
lv_obj_invalidate(*g->obj_focus);
|
||||
|
||||
/*If the object or its parent has `top == true` bring it to the foregorund*/
|
||||
obj_to_foreground(*g->obj_focus);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus the next object in a group (defocus the current)
|
||||
* @param group pointer to a group
|
||||
*/
|
||||
void lv_group_focus_next(lv_group_t * group)
|
||||
{
|
||||
focus_next_core(group, lv_ll_get_head, lv_ll_get_next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus the previous object in a group (defocus the current)
|
||||
* @param group pointer to a group
|
||||
*/
|
||||
void lv_group_focus_prev(lv_group_t * group)
|
||||
{
|
||||
focus_next_core(group, lv_ll_get_tail, lv_ll_get_prev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not let to change the focus from the current object
|
||||
* @param group pointer to a group
|
||||
* @param en true: freeze, false: release freezing (normal mode)
|
||||
*/
|
||||
void lv_group_focus_freeze(lv_group_t * group, bool en)
|
||||
{
|
||||
if(en == false) group->frozen = 0;
|
||||
else group->frozen = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a control character to the focuses object of a group
|
||||
* @param group pointer to a group
|
||||
* @param c a character (use LV_GROUP_KEY_.. to navigate)
|
||||
* @return result of focused object in group.
|
||||
*/
|
||||
lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c)
|
||||
{
|
||||
lv_obj_t * act = lv_group_get_focused(group);
|
||||
if(act == NULL) return LV_RES_OK;
|
||||
|
||||
return act->signal_cb(act, LV_SIGNAL_CONTROLL, &c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a function for a group which will modify the object's style if it is in focus
|
||||
* @param group pointer to a group
|
||||
* @param style_mod_func the style modifier function pointer
|
||||
*/
|
||||
void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func)
|
||||
{
|
||||
group->style_mod = style_mod_func;
|
||||
if(group->obj_focus != NULL) lv_obj_invalidate(*group->obj_focus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a function for a group which will modify the object's style if it is in focus in edit mode
|
||||
* @param group pointer to a group
|
||||
* @param style_mod_func the style modifier function pointer
|
||||
*/
|
||||
void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func)
|
||||
{
|
||||
group->style_mod_edit = style_mod_func;
|
||||
if(group->obj_focus != NULL) lv_obj_invalidate(*group->obj_focus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a function for a group which will be called when a new object is focused
|
||||
* @param group pointer to a group
|
||||
* @param focus_cb the call back function or NULL if unused
|
||||
*/
|
||||
void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb)
|
||||
{
|
||||
group->focus_cb = focus_cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set the current mode (edit or navigate).
|
||||
* @param group pointer to group
|
||||
* @param edit: true: edit mode; false: navigate mode
|
||||
*/
|
||||
void lv_group_set_editing(lv_group_t * group, bool edit)
|
||||
{
|
||||
uint8_t en_val = edit ? 1 : 0;
|
||||
|
||||
if(en_val == group->editing) return; /*Do not set the same mode again*/
|
||||
|
||||
group->editing = en_val;
|
||||
lv_obj_t * focused = lv_group_get_focused(group);
|
||||
|
||||
if(focused) {
|
||||
focused->signal_cb(focused, LV_SIGNAL_FOCUS, NULL); /*Focus again to properly leave/open edit/navigate mode*/
|
||||
lv_res_t res = lv_obj_send_event(*group->obj_focus, LV_EVENT_FOCUSED);
|
||||
if(res != LV_RES_OK) return;
|
||||
}
|
||||
|
||||
lv_obj_invalidate(focused);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked.
|
||||
* @param group pointer to group
|
||||
* @param en: true: enable `click_focus`
|
||||
*/
|
||||
void lv_group_set_click_focus(lv_group_t * group, bool en)
|
||||
{
|
||||
group->click_focus = en ? 1 : 0;
|
||||
}
|
||||
|
||||
void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy) {
|
||||
group->refocus_policy = policy & 0x01;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether focus next/prev will allow wrapping from first->last or last->first.
|
||||
* @param group pointer to group
|
||||
* @param en: true: enable `click_focus`
|
||||
*/
|
||||
void lv_group_set_wrap(lv_group_t * group, bool en)
|
||||
{
|
||||
group->wrap = en ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify a style with the set 'style_mod' function. The input style remains unchanged.
|
||||
* @param group pointer to group
|
||||
* @param style pointer to a style to modify
|
||||
* @return a copy of the input style but modified with the 'style_mod' function
|
||||
*/
|
||||
lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style)
|
||||
{
|
||||
/*Load the current style. It will be modified by the callback*/
|
||||
lv_style_copy(&group->style_tmp, style);
|
||||
|
||||
if(group->editing) {
|
||||
if(group->style_mod_edit) group->style_mod_edit(group, &group->style_tmp);
|
||||
} else {
|
||||
if(group->style_mod) group->style_mod(group, &group->style_tmp);
|
||||
}
|
||||
return &group->style_tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the focused object or NULL if there isn't one
|
||||
* @param group pointer to a group
|
||||
* @return pointer to the focused object
|
||||
*/
|
||||
lv_obj_t * lv_group_get_focused(const lv_group_t * group)
|
||||
{
|
||||
if(!group) return NULL;
|
||||
if(group->obj_focus == NULL) return NULL;
|
||||
|
||||
return *group->obj_focus;
|
||||
}
|
||||
|
||||
#if LV_USE_USER_DATA_SINGLE
|
||||
/**
|
||||
* Get a pointer to the group's user data
|
||||
* @param group pointer to an group
|
||||
* @return pointer to the user data
|
||||
*/
|
||||
lv_group_user_data_t * lv_group_get_user_data(lv_group_t * group)
|
||||
{
|
||||
return &group->user_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Get a the style modifier function of a group
|
||||
* @param group pointer to a group
|
||||
* @return pointer to the style modifier function
|
||||
*/
|
||||
lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group)
|
||||
{
|
||||
if(!group) return false;
|
||||
return group->style_mod ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a the style modifier function of a group in edit mode
|
||||
* @param group pointer to a group
|
||||
* @return pointer to the style modifier function
|
||||
*/
|
||||
lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group)
|
||||
{
|
||||
if(!group) return false;
|
||||
return group->style_mod_edit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the focus callback function of a group
|
||||
* @param group pointer to a group
|
||||
* @return the call back function or NULL if not set
|
||||
*/
|
||||
lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group)
|
||||
{
|
||||
if(!group) return false;
|
||||
return group->focus_cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current mode (edit or navigate).
|
||||
* @param group pointer to group
|
||||
* @return true: edit mode; false: navigate mode
|
||||
*/
|
||||
bool lv_group_get_editing(const lv_group_t * group)
|
||||
{
|
||||
if(!group) return false;
|
||||
return group->editing ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the `click_focus` attribute.
|
||||
* @param group pointer to group
|
||||
* @return true: `click_focus` is enabled; false: disabled
|
||||
*/
|
||||
bool lv_group_get_click_focus(const lv_group_t * group)
|
||||
{
|
||||
if(!group) return false;
|
||||
return group->click_focus ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether focus next/prev will allow wrapping from first->last or last->first object.
|
||||
* @param group pointer to group
|
||||
* @param en: true: wrapping enabled; false: wrapping disabled
|
||||
*/
|
||||
bool lv_group_get_wrap(lv_group_t * group)
|
||||
{
|
||||
if(!group) return false;
|
||||
return group->wrap ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the group that current theme changed and style modification callbacks need to be refreshed.
|
||||
* @param group pointer to group. If NULL then all groups are notified.
|
||||
*/
|
||||
void lv_group_report_style_mod(lv_group_t * group)
|
||||
{
|
||||
lv_theme_t * th = lv_theme_get_current();
|
||||
|
||||
if(group != NULL) {
|
||||
refresh_theme(group, th);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_group_t * i;
|
||||
LV_LL_READ(LV_GC_ROOT(_lv_group_ll), i) {
|
||||
refresh_theme(i, th);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void lv_group_refocus(lv_group_t *g) {
|
||||
/*Refocus must temporarily allow wrapping to work correctly*/
|
||||
uint8_t temp_wrap = g->wrap;
|
||||
g->wrap = 1;
|
||||
|
||||
if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_NEXT)
|
||||
lv_group_focus_next(g);
|
||||
else if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_PREV)
|
||||
lv_group_focus_prev(g);
|
||||
/*Restore wrap property*/
|
||||
g->wrap = temp_wrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default style modifier function
|
||||
* @param group pointer to the caller group
|
||||
* @param style pointer to a style to modify. (Typically group.style_tmp) It will be OVERWRITTEN.
|
||||
*/
|
||||
static void style_mod_def(lv_group_t * group, lv_style_t * style)
|
||||
{
|
||||
(void)group; /*Unused*/
|
||||
#if LV_COLOR_DEPTH != 1
|
||||
|
||||
/*Make the style to be a little bit orange*/
|
||||
style->body.border.opa = LV_OPA_COVER;
|
||||
style->body.border.color = LV_COLOR_ORANGE;
|
||||
|
||||
/*If not empty or has border then emphasis the border*/
|
||||
if(style->body.opa != LV_OPA_TRANSP || style->body.border.width != 0) style->body.border.width = LV_DPI / 20;
|
||||
|
||||
style->body.main_color = lv_color_mix(style->body.main_color, LV_COLOR_ORANGE, LV_OPA_70);
|
||||
style->body.grad_color = lv_color_mix(style->body.grad_color, LV_COLOR_ORANGE, LV_OPA_70);
|
||||
style->body.shadow.color = lv_color_mix(style->body.shadow.color, LV_COLOR_ORANGE, LV_OPA_60);
|
||||
|
||||
style->text.color = lv_color_mix(style->text.color, LV_COLOR_ORANGE, LV_OPA_70);
|
||||
#else
|
||||
style->body.border.opa = LV_OPA_COVER;
|
||||
style->body.border.color = LV_COLOR_BLACK;
|
||||
style->body.border.width = 2;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Default style modifier function
|
||||
* @param group pointer to the caller group
|
||||
* @param style pointer to a style to modify. (Typically group.style_tmp) It will be OVERWRITTEN.
|
||||
*/
|
||||
static void style_mod_edit_def(lv_group_t * group, lv_style_t * style)
|
||||
{
|
||||
(void)group; /*Unused*/
|
||||
#if LV_COLOR_DEPTH != 1
|
||||
|
||||
/*Make the style to be a little bit orange*/
|
||||
style->body.border.opa = LV_OPA_COVER;
|
||||
style->body.border.color = LV_COLOR_GREEN;
|
||||
|
||||
/*If not empty or has border then emphasis the border*/
|
||||
if(style->body.opa != LV_OPA_TRANSP || style->body.border.width != 0) style->body.border.width = LV_DPI / 20;
|
||||
|
||||
style->body.main_color = lv_color_mix(style->body.main_color, LV_COLOR_GREEN, LV_OPA_70);
|
||||
style->body.grad_color = lv_color_mix(style->body.grad_color, LV_COLOR_GREEN, LV_OPA_70);
|
||||
style->body.shadow.color = lv_color_mix(style->body.shadow.color, LV_COLOR_GREEN, LV_OPA_60);
|
||||
|
||||
style->text.color = lv_color_mix(style->text.color, LV_COLOR_GREEN, LV_OPA_70);
|
||||
#else
|
||||
style->body.border.opa = LV_OPA_COVER;
|
||||
style->body.border.color = LV_COLOR_BLACK;
|
||||
style->body.border.width = 3;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void refresh_theme(lv_group_t * g, lv_theme_t * th)
|
||||
{
|
||||
g->style_mod = style_mod_def;
|
||||
g->style_mod_edit = style_mod_edit_def;
|
||||
if(th) {
|
||||
if(th->group.style_mod)
|
||||
g->style_mod = th->group.style_mod;
|
||||
if(th->group.style_mod_edit)
|
||||
g->style_mod_edit = th->group.style_mod_edit;
|
||||
}
|
||||
}
|
||||
|
||||
static void focus_next_core(lv_group_t * group, void * (*begin)(const lv_ll_t *), void * (*move)(const lv_ll_t *, const void *))
|
||||
{
|
||||
if (group->frozen) return;
|
||||
|
||||
lv_obj_t ** obj_next = group->obj_focus;
|
||||
lv_obj_t ** obj_sentinel = NULL;
|
||||
bool can_move = true;
|
||||
bool can_begin = true;
|
||||
|
||||
for(;;) {
|
||||
if(obj_next == NULL) {
|
||||
if(group->wrap || obj_sentinel == NULL) {
|
||||
if(!can_begin) return;
|
||||
obj_next = begin(&group->obj_ll);
|
||||
can_move = false;
|
||||
can_begin = false;
|
||||
} else {
|
||||
/*Currently focused object is the last/first in the group, keep it that way*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(obj_sentinel == NULL) {
|
||||
obj_sentinel = obj_next;
|
||||
if(obj_sentinel == NULL) return; /*Group is empty*/
|
||||
}
|
||||
|
||||
if(can_move) {
|
||||
obj_next = move(&group->obj_ll, obj_next);
|
||||
|
||||
/*Give up if we walked the entire list and haven't found another visible object*/
|
||||
if(obj_next == obj_sentinel) return;
|
||||
}
|
||||
|
||||
can_move = true;
|
||||
|
||||
if(obj_next == NULL) continue;
|
||||
|
||||
/*Hidden objects don't receive focus*/
|
||||
if(!lv_obj_get_hidden(*obj_next)) break;
|
||||
}
|
||||
|
||||
if(obj_next == group->obj_focus) return; /*There's only one visible object and it's already focused*/
|
||||
|
||||
if(group->obj_focus) {
|
||||
(*group->obj_focus)->signal_cb(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
|
||||
lv_res_t res = lv_obj_send_event(*group->obj_focus, LV_EVENT_DEFOCUSED);
|
||||
if(res != LV_RES_OK) return;
|
||||
lv_obj_invalidate(*group->obj_focus);
|
||||
}
|
||||
|
||||
group->obj_focus = obj_next;
|
||||
|
||||
(*group->obj_focus)->signal_cb(*group->obj_focus, LV_SIGNAL_FOCUS, NULL);
|
||||
lv_res_t res = lv_obj_send_event(*group->obj_focus, LV_EVENT_FOCUSED);
|
||||
if(res != LV_RES_OK) return;
|
||||
|
||||
/*If the object or its parent has `top == true` bring it to the foregorund*/
|
||||
obj_to_foreground(*group->obj_focus);
|
||||
|
||||
lv_obj_invalidate(*group->obj_focus);
|
||||
|
||||
if(group->focus_cb) group->focus_cb(group);
|
||||
}
|
||||
|
||||
static void obj_to_foreground(lv_obj_t * obj)
|
||||
{
|
||||
/*Search for 'top' attribute*/
|
||||
lv_obj_t * i = obj;
|
||||
lv_obj_t * last_top = NULL;
|
||||
while(i != NULL) {
|
||||
if(i->top != 0) last_top = i;
|
||||
i = lv_obj_get_parent(i);
|
||||
}
|
||||
|
||||
if(last_top != NULL) {
|
||||
/*Move the last_top object to the foreground*/
|
||||
lv_obj_t * par = lv_obj_get_parent(last_top);
|
||||
/*After list change it will be the new head*/
|
||||
lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top);
|
||||
lv_obj_invalidate(last_top);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GROUP != 0*/
|
||||
281
src/lv_core/lv_group.h
Normal file
281
src/lv_core/lv_group.h
Normal file
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* @file lv_group.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GROUP_H
|
||||
#define LV_GROUP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include "lv_obj.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
/*Predefined keys to control the focused object via lv_group_send(group, c)*/
|
||||
/*For compatibility in signal function define the keys regardless to LV_GROUP*/
|
||||
#define LV_GROUP_KEY_UP 17 /*0x11*/
|
||||
#define LV_GROUP_KEY_DOWN 18 /*0x12*/
|
||||
#define LV_GROUP_KEY_RIGHT 19 /*0x13*/
|
||||
#define LV_GROUP_KEY_LEFT 20 /*0x14*/
|
||||
#define LV_GROUP_KEY_ESC 27 /*0x1B*/
|
||||
#define LV_GROUP_KEY_DEL 127 /*0x7F*/
|
||||
#define LV_GROUP_KEY_BACKSPACE 8 /*0x08*/
|
||||
#define LV_GROUP_KEY_ENTER 10 /*0x0A, '\n'*/
|
||||
#define LV_GROUP_KEY_NEXT 9 /*0x09, '\t'*/
|
||||
#define LV_GROUP_KEY_PREV 11 /*0x0B, '*/
|
||||
#define LV_GROUP_KEY_HOME 2 /*0x02, STX*/
|
||||
#define LV_GROUP_KEY_END 3 /*0x03, ETX*/
|
||||
|
||||
#if LV_USE_GROUP != 0
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
struct _lv_group_t;
|
||||
|
||||
typedef void (*lv_group_style_mod_func_t)(struct _lv_group_t *, lv_style_t *);
|
||||
typedef void (*lv_group_focus_cb_t)(struct _lv_group_t *);
|
||||
|
||||
typedef struct _lv_group_t
|
||||
{
|
||||
lv_ll_t obj_ll; /*Linked list to store the objects in the group */
|
||||
lv_obj_t ** obj_focus; /*The object in focus*/
|
||||
lv_group_style_mod_func_t style_mod; /*A function which modifies the style of the focused object*/
|
||||
lv_group_style_mod_func_t style_mod_edit;/*A function which modifies the style of the focused object*/
|
||||
lv_group_focus_cb_t focus_cb; /*A function to call when a new object is focused (optional)*/
|
||||
lv_style_t style_tmp; /*Stores the modified style of the focused object */
|
||||
#if LV_USE_USER_DATA_SINGLE
|
||||
lv_group_user_data_t user_data;
|
||||
#endif
|
||||
|
||||
#if LV_USE_USER_DATA_MULTI
|
||||
lv_group_user_data_t focus_user_data;
|
||||
lv_group_user_data_t style_mod_user_data;
|
||||
lv_group_user_data_t style_mod_edit_user_data;
|
||||
#endif
|
||||
|
||||
uint8_t frozen :1; /*1: can't focus to new object*/
|
||||
uint8_t editing :1; /*1: Edit mode, 0: Navigate mode*/
|
||||
uint8_t click_focus :1; /*1: If an object in a group is clicked by an indev then it will be focused */
|
||||
uint8_t refocus_policy :1; /*1: Focus prev if focused on deletion. 0: Focus prev if focused on deletion.*/
|
||||
uint8_t wrap :1; /*1: Focus next/prev can wrap at end of list. 0: Focus next/prev stops at end of list.*/
|
||||
} lv_group_t;
|
||||
|
||||
typedef enum _lv_group_refocus_policy_t {
|
||||
LV_GROUP_REFOCUS_POLICY_NEXT = 0,
|
||||
LV_GROUP_REFOCUS_POLICY_PREV = 1
|
||||
} lv_group_refocus_policy_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Init. the group module
|
||||
* @remarks Internal function, do not call directly.
|
||||
*/
|
||||
void lv_group_init(void);
|
||||
|
||||
/**
|
||||
* Create a new object group
|
||||
* @return pointer to the new object group
|
||||
*/
|
||||
lv_group_t * lv_group_create(void);
|
||||
|
||||
/**
|
||||
* Delete a group object
|
||||
* @param group pointer to a group
|
||||
*/
|
||||
void lv_group_del(lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Add an object to a group
|
||||
* @param group pointer to a group
|
||||
* @param obj pointer to an object to add
|
||||
*/
|
||||
void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Remove an object from its group
|
||||
* @param obj pointer to an object to remove
|
||||
*/
|
||||
void lv_group_remove_obj(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Focus on an object (defocus the current)
|
||||
* @param obj pointer to an object to focus on
|
||||
*/
|
||||
void lv_group_focus_obj(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Focus the next object in a group (defocus the current)
|
||||
* @param group pointer to a group
|
||||
*/
|
||||
void lv_group_focus_next(lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Focus the previous object in a group (defocus the current)
|
||||
* @param group pointer to a group
|
||||
*/
|
||||
void lv_group_focus_prev(lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Do not let to change the focus from the current object
|
||||
* @param group pointer to a group
|
||||
* @param en true: freeze, false: release freezing (normal mode)
|
||||
*/
|
||||
void lv_group_focus_freeze(lv_group_t * group, bool en);
|
||||
|
||||
/**
|
||||
* Send a control character to the focuses object of a group
|
||||
* @param group pointer to a group
|
||||
* @param c a character (use LV_GROUP_KEY_.. to navigate)
|
||||
* @return result of focused object in group.
|
||||
*/
|
||||
lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c);
|
||||
|
||||
/**
|
||||
* Set a function for a group which will modify the object's style if it is in focus
|
||||
* @param group pointer to a group
|
||||
* @param style_mod_func the style modifier function pointer
|
||||
*/
|
||||
void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func);
|
||||
|
||||
/**
|
||||
* Set a function for a group which will modify the object's style if it is in focus in edit mode
|
||||
* @param group pointer to a group
|
||||
* @param style_mod_func the style modifier function pointer
|
||||
*/
|
||||
void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func);
|
||||
|
||||
/**
|
||||
* Set a function for a group which will be called when a new object is focused
|
||||
* @param group pointer to a group
|
||||
* @param focus_cb the call back function or NULL if unused
|
||||
*/
|
||||
void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb);
|
||||
|
||||
/**
|
||||
* Set whether the next or previous item in a group is focused if the currently focussed obj is deleted.
|
||||
* @param group pointer to a group
|
||||
* @param new refocus policy enum
|
||||
*/
|
||||
void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy);
|
||||
|
||||
/**
|
||||
* Manually set the current mode (edit or navigate).
|
||||
* @param group pointer to group
|
||||
* @param edit: true: edit mode; false: navigate mode
|
||||
*/
|
||||
void lv_group_set_editing(lv_group_t * group, bool edit);
|
||||
|
||||
/**
|
||||
* Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked.
|
||||
* @param group pointer to group
|
||||
* @param en: true: enable `click_focus`
|
||||
*/
|
||||
void lv_group_set_click_focus(lv_group_t * group, bool en);
|
||||
|
||||
/**
|
||||
* Set whether focus next/prev will allow wrapping from first->last or last->first object.
|
||||
* @param group pointer to group
|
||||
* @param en: true: wrapping enabled; false: wrapping disabled
|
||||
*/
|
||||
void lv_group_set_wrap(lv_group_t * group, bool en);
|
||||
|
||||
/**
|
||||
* Modify a style with the set 'style_mod' function. The input style remains unchanged.
|
||||
* @param group pointer to group
|
||||
* @param style pointer to a style to modify
|
||||
* @return a copy of the input style but modified with the 'style_mod' function
|
||||
*/
|
||||
lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style);
|
||||
|
||||
/**
|
||||
* Get the focused object or NULL if there isn't one
|
||||
* @param group pointer to a group
|
||||
* @return pointer to the focused object
|
||||
*/
|
||||
lv_obj_t * lv_group_get_focused(const lv_group_t * group);
|
||||
|
||||
#if LV_USE_USER_DATA_SINGLE
|
||||
/**
|
||||
* Get a pointer to the group's user data
|
||||
* @param group pointer to an group
|
||||
* @return pointer to the user data
|
||||
*/
|
||||
lv_group_user_data_t * lv_group_get_user_data(lv_group_t * group);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get a the style modifier function of a group
|
||||
* @param group pointer to a group
|
||||
* @return pointer to the style modifier function
|
||||
*/
|
||||
lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Get a the style modifier function of a group in edit mode
|
||||
* @param group pointer to a group
|
||||
* @return pointer to the style modifier function
|
||||
*/
|
||||
lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Get the focus callback function of a group
|
||||
* @param group pointer to a group
|
||||
* @return the call back function or NULL if not set
|
||||
*/
|
||||
lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Get the current mode (edit or navigate).
|
||||
* @param group pointer to group
|
||||
* @return true: edit mode; false: navigate mode
|
||||
*/
|
||||
bool lv_group_get_editing(const lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Get the `click_focus` attribute.
|
||||
* @param group pointer to group
|
||||
* @return true: `click_focus` is enabled; false: disabled
|
||||
*/
|
||||
bool lv_group_get_click_focus(const lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Get whether focus next/prev will allow wrapping from first->last or last->first object.
|
||||
* @param group pointer to group
|
||||
* @param en: true: wrapping enabled; false: wrapping disabled
|
||||
*/
|
||||
bool lv_group_get_wrap(lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Notify the group that current theme changed and style modification callbacks need to be refreshed.
|
||||
* @param group pointer to group. If NULL then all groups are notified.
|
||||
*/
|
||||
void lv_group_report_style_mod(lv_group_t * group);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GROUP != 0*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_GROUP_H*/
|
||||
1125
src/lv_core/lv_indev.c
Normal file
1125
src/lv_core/lv_indev.c
Normal file
File diff suppressed because it is too large
Load Diff
157
src/lv_core/lv_indev.h
Normal file
157
src/lv_core/lv_indev.h
Normal file
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* @file lv_indev_proc.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_INDEV_H
|
||||
#define LV_INDEV_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj.h"
|
||||
#include "../lv_hal/lv_hal_indev.h"
|
||||
#include "../lv_core/lv_group.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the display input device subsystem
|
||||
*/
|
||||
void lv_indev_init(void);
|
||||
|
||||
/**
|
||||
* Get the currently processed input device. Can be used in action functions too.
|
||||
* @return pointer to the currently processed input device or NULL if no input device processing right now
|
||||
*/
|
||||
lv_indev_t * lv_indev_get_act(void);
|
||||
|
||||
|
||||
/**
|
||||
* Get the type of an input device
|
||||
* @param indev pointer to an input device
|
||||
* @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`)
|
||||
*/
|
||||
lv_hal_indev_type_t lv_indev_get_type(const lv_indev_t * indev);
|
||||
|
||||
/**
|
||||
* Reset one or all input devices
|
||||
* @param indev pointer to an input device to reset or NULL to reset all of them
|
||||
*/
|
||||
void lv_indev_reset(lv_indev_t * indev);
|
||||
|
||||
/**
|
||||
* Reset the long press state of an input device
|
||||
* @param indev_proc pointer to an input device
|
||||
*/
|
||||
void lv_indev_reset_long_press(lv_indev_t * indev);
|
||||
|
||||
/**
|
||||
* Enable or disable an input devices
|
||||
* @param indev pointer to an input device
|
||||
* @param en true: enable; false: disable
|
||||
*/
|
||||
void lv_indev_enable(lv_indev_t * indev, bool en);
|
||||
|
||||
/**
|
||||
* Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON)
|
||||
* @param indev pointer to an input device
|
||||
* @param cur_obj pointer to an object to be used as cursor
|
||||
*/
|
||||
void lv_indev_set_cursor(lv_indev_t *indev, lv_obj_t *cur_obj);
|
||||
|
||||
#if LV_USE_GROUP
|
||||
/**
|
||||
* Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD)
|
||||
* @param indev pointer to an input device
|
||||
* @param group point to a group
|
||||
*/
|
||||
void lv_indev_set_group(lv_indev_t *indev, lv_group_t *group);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set the an array of points for LV_INDEV_TYPE_BUTTON.
|
||||
* These points will be assigned to the buttons to press a specific point on the screen
|
||||
* @param indev pointer to an input device
|
||||
* @param group point to a group
|
||||
*/
|
||||
void lv_indev_set_button_points(lv_indev_t *indev, const lv_point_t *points);
|
||||
|
||||
/**
|
||||
* Set feedback callback for indev.
|
||||
* @param indev pointer to an input device
|
||||
* @param feedback feedback callback
|
||||
*/
|
||||
void lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback);
|
||||
|
||||
/**
|
||||
* Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
|
||||
* @param indev pointer to an input device
|
||||
* @param point pointer to a point to store the result
|
||||
*/
|
||||
void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point);
|
||||
|
||||
/**
|
||||
* Get the last pressed key of an input device (for LV_INDEV_TYPE_KEYPAD)
|
||||
* @param indev pointer to an input device
|
||||
* @return the last pressed key (0 on error)
|
||||
*/
|
||||
uint32_t lv_indev_get_key(const lv_indev_t * indev);
|
||||
|
||||
/**
|
||||
* Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
|
||||
* @param indev pointer to an input device
|
||||
* @return true: drag is in progress
|
||||
*/
|
||||
bool lv_indev_is_dragging(const lv_indev_t * indev);
|
||||
|
||||
/**
|
||||
* Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
|
||||
* @param indev pointer to an input device
|
||||
* @param point pointer to a point to store the vector
|
||||
*/
|
||||
void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point);
|
||||
/**
|
||||
* Get elapsed time since last press
|
||||
* @param indev pointer to an input device (NULL to get the overall smallest inactivity)
|
||||
* @return Elapsed ticks (milliseconds) since last press
|
||||
*/
|
||||
uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev);
|
||||
|
||||
/**
|
||||
* Get feedback callback for indev.
|
||||
* @param indev pointer to an input device
|
||||
* @return feedback callback
|
||||
*/
|
||||
lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev);
|
||||
|
||||
/**
|
||||
* Do nothing until the next release
|
||||
* @param indev pointer to an input device
|
||||
*/
|
||||
void lv_indev_wait_release(lv_indev_t * indev);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_INDEV_H*/
|
||||
2052
src/lv_core/lv_obj.c
Normal file
2052
src/lv_core/lv_obj.c
Normal file
File diff suppressed because it is too large
Load Diff
845
src/lv_core/lv_obj.h
Normal file
845
src/lv_core/lv_obj.h
Normal file
@@ -0,0 +1,845 @@
|
||||
/**
|
||||
* @file lv_obj.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_H
|
||||
#define LV_OBJ_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "lv_style.h"
|
||||
#include "../lv_misc/lv_area.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
#include "../lv_misc/lv_ll.h"
|
||||
#include "../lv_misc/lv_color.h"
|
||||
#include "../lv_misc/lv_log.h"
|
||||
#include "../lv_hal/lv_hal.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/*Error check of lv_conf.h*/
|
||||
#if LV_HOR_RES_MAX == 0 || LV_VER_RES_MAX == 0
|
||||
#error "LittlevGL: LV_HOR_RES and LV_VER_RES must be greater than 0"
|
||||
#endif
|
||||
|
||||
#if LV_ANTIALIAS > 1
|
||||
#error "LittlevGL: LV_ANTIALIAS can be only 0 or 1"
|
||||
#endif
|
||||
|
||||
#define LV_ANIM_IN 0x00 /*Animation to show an object. 'OR' it with lv_anim_builtin_t*/
|
||||
#define LV_ANIM_OUT 0x80 /*Animation to hide an object. 'OR' it with lv_anim_builtin_t*/
|
||||
#define LV_ANIM_DIR_MASK 0x80 /*ANIM_IN/ANIM_OUT mask*/
|
||||
|
||||
#define LV_MAX_ANCESTOR_NUM 8
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_obj_t;
|
||||
|
||||
enum
|
||||
{
|
||||
LV_DESIGN_DRAW_MAIN,
|
||||
LV_DESIGN_DRAW_POST,
|
||||
LV_DESIGN_COVER_CHK,
|
||||
};
|
||||
typedef uint8_t lv_design_mode_t;
|
||||
|
||||
typedef bool (* lv_design_cb_t) (struct _lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode);
|
||||
|
||||
enum
|
||||
{
|
||||
LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action function or an operation was failed*/
|
||||
LV_RES_OK, /*The object is valid (no deleted) after the action*/
|
||||
};
|
||||
typedef uint8_t lv_res_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
LV_EVENT_PRESSED, /*The object has been pressed*/
|
||||
LV_EVENT_PRESSING, /*The object is being pressed (called continuously while pressing)*/
|
||||
LV_EVENT_PRESS_LOST, /*Still pressing but slid from the objects*/
|
||||
LV_EVENT_SHORT_CLICKED, /*Released before long press time. Not called if dragged.*/
|
||||
LV_EVENT_LONG_PRESSED, /*Pressing for `LV_INDEV_LONG_PRESS_TIME` time. Not called if dragged.*/
|
||||
LV_EVENT_LONG_PRESSED_REPEAT, /*Called after `LV_INDEV_LONG_PRESS_TIME` in every `LV_INDEV_LONG_PRESS_REP_TIME` ms. Not called if dragged.*/
|
||||
LV_EVENT_CLICKED, /*Called on release if not dragged (regardless to long press)*/
|
||||
LV_EVENT_RELEASED, /*Called in every cases when the object has been released*/
|
||||
LV_EVENT_LONG_HOVER_IN, /*TODO*/
|
||||
LV_EVENT_LONG_HOVER_OUT, /*TODO*/
|
||||
LV_EVENT_DRAG_BEGIN,
|
||||
LV_EVENT_DRAG_END,
|
||||
LV_EVENT_DRAG_THROW_BEGIN,
|
||||
LV_EVENT_FOCUSED,
|
||||
LV_EVENT_DEFOCUSED,
|
||||
LV_EVENT_VALUE_CHANGED,
|
||||
LV_EVENT_REFRESH,
|
||||
LV_EVENT_APPLY, /*"Ok", "Apply" or similar specific button has clicked*/
|
||||
LV_EVENT_CANCEL, /*"Close", "Cancel" or similar specific button has clicked*/
|
||||
}lv_event_t;
|
||||
|
||||
typedef void (*lv_event_cb_t)(struct _lv_obj_t * obj, lv_event_t event);
|
||||
|
||||
enum
|
||||
{
|
||||
/*General signals*/
|
||||
LV_SIGNAL_CLEANUP,
|
||||
LV_SIGNAL_CHILD_CHG,
|
||||
LV_SIGNAL_CORD_CHG,
|
||||
LV_SIGNAL_PARENT_SIZE_CHG,
|
||||
LV_SIGNAL_STYLE_CHG,
|
||||
LV_SIGNAL_REFR_EXT_SIZE,
|
||||
LV_SIGNAL_GET_TYPE,
|
||||
|
||||
_LV_SIGNAL_FEEDBACK_SECTION_START,
|
||||
/*Input device related*/
|
||||
LV_SIGNAL_PRESSED,
|
||||
LV_SIGNAL_PRESSING,
|
||||
LV_SIGNAL_PRESS_LOST,
|
||||
LV_SIGNAL_RELEASED,
|
||||
LV_SIGNAL_LONG_PRESS,
|
||||
LV_SIGNAL_LONG_PRESS_REP,
|
||||
LV_SIGNAL_DRAG_BEGIN,
|
||||
LV_SIGNAL_DRAG_END,
|
||||
|
||||
/*Group related*/
|
||||
LV_SIGNAL_FOCUS,
|
||||
LV_SIGNAL_DEFOCUS,
|
||||
LV_SIGNAL_CONTROLL,
|
||||
_LV_SIGNAL_FEEDBACK_SECTION_END,
|
||||
LV_SIGNAL_GET_EDITABLE,
|
||||
};
|
||||
typedef uint8_t lv_signal_t;
|
||||
|
||||
typedef lv_res_t (* lv_signal_cb_t) (struct _lv_obj_t * obj, lv_signal_t sign, void * param);
|
||||
|
||||
enum
|
||||
{
|
||||
LV_ALIGN_CENTER = 0,
|
||||
LV_ALIGN_IN_TOP_LEFT,
|
||||
LV_ALIGN_IN_TOP_MID,
|
||||
LV_ALIGN_IN_TOP_RIGHT,
|
||||
LV_ALIGN_IN_BOTTOM_LEFT,
|
||||
LV_ALIGN_IN_BOTTOM_MID,
|
||||
LV_ALIGN_IN_BOTTOM_RIGHT,
|
||||
LV_ALIGN_IN_LEFT_MID,
|
||||
LV_ALIGN_IN_RIGHT_MID,
|
||||
LV_ALIGN_OUT_TOP_LEFT,
|
||||
LV_ALIGN_OUT_TOP_MID,
|
||||
LV_ALIGN_OUT_TOP_RIGHT,
|
||||
LV_ALIGN_OUT_BOTTOM_LEFT,
|
||||
LV_ALIGN_OUT_BOTTOM_MID,
|
||||
LV_ALIGN_OUT_BOTTOM_RIGHT,
|
||||
LV_ALIGN_OUT_LEFT_TOP,
|
||||
LV_ALIGN_OUT_LEFT_MID,
|
||||
LV_ALIGN_OUT_LEFT_BOTTOM,
|
||||
LV_ALIGN_OUT_RIGHT_TOP,
|
||||
LV_ALIGN_OUT_RIGHT_MID,
|
||||
LV_ALIGN_OUT_RIGHT_BOTTOM,
|
||||
};
|
||||
typedef uint8_t lv_align_t;
|
||||
|
||||
#if LV_OBJ_REALIGN
|
||||
typedef struct {
|
||||
const struct _lv_obj_t * base;
|
||||
lv_coord_t xofs;
|
||||
lv_coord_t yofs;
|
||||
lv_align_t align;
|
||||
uint8_t auto_realign :1;
|
||||
uint8_t origo_align :1; /*1: the oigo (center of the object) was aligned with `lv_obj_align_origo`*/
|
||||
}lv_reailgn_t;
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct _lv_obj_t
|
||||
{
|
||||
struct _lv_obj_t * par; /*Pointer to the parent object*/
|
||||
lv_ll_t child_ll; /*Linked list to store the children objects*/
|
||||
|
||||
lv_area_t coords; /*Coordinates of the object (x1, y1, x2, y2)*/
|
||||
|
||||
lv_event_cb_t event_cb;
|
||||
lv_signal_cb_t signal_cb; /*Object type specific signal function*/
|
||||
lv_design_cb_t design_cb; /*Object type specific design function*/
|
||||
|
||||
void * ext_attr; /*Object type specific extended data*/
|
||||
lv_style_t * style_p; /*Pointer to the object's style*/
|
||||
|
||||
#if LV_USE_GROUP != 0
|
||||
void * group_p; /*Pointer to the group of the object*/
|
||||
#endif
|
||||
/*Attributes and states*/
|
||||
uint8_t click :1; /*1: Can be pressed by an input device*/
|
||||
uint8_t drag :1; /*1: Enable the dragging*/
|
||||
uint8_t drag_throw :1; /*1: Enable throwing with drag*/
|
||||
uint8_t drag_parent :1; /*1: Parent will be dragged instead*/
|
||||
uint8_t hidden :1; /*1: Object is hidden*/
|
||||
uint8_t top :1; /*1: If the object or its children is clicked it goes to the foreground*/
|
||||
uint8_t opa_scale_en :1; /*1: opa_scale is set*/
|
||||
uint8_t parent_event :1; /*1: Send the object's events to the parent too. */
|
||||
uint8_t protect; /*Automatically happening actions can be prevented. 'OR'ed values from `lv_protect_t`*/
|
||||
lv_opa_t opa_scale; /*Scale down the opacity by this factor. Effects all children as well*/
|
||||
|
||||
lv_coord_t ext_size; /*EXTtend the size of the object in every direction. E.g. for shadow drawing*/
|
||||
#if LV_OBJ_REALIGN
|
||||
lv_reailgn_t realign;
|
||||
#endif
|
||||
|
||||
#if LV_USE_USER_DATA_SINGLE
|
||||
lv_obj_user_data_t user_data;
|
||||
#endif
|
||||
|
||||
#if LV_USE_USER_DATA_MULTI
|
||||
lv_obj_user_data_t event_user_data;
|
||||
lv_obj_user_data_t signal_user_data;
|
||||
lv_obj_user_data_t design_user_data;
|
||||
#endif
|
||||
|
||||
} lv_obj_t;
|
||||
|
||||
/*Protect some attributes (max. 8 bit)*/
|
||||
enum
|
||||
{
|
||||
LV_PROTECT_NONE = 0x00,
|
||||
LV_PROTECT_CHILD_CHG = 0x01, /*Disable the child change signal. Used by the library*/
|
||||
LV_PROTECT_PARENT = 0x02, /*Prevent automatic parent change (e.g. in lv_page)*/
|
||||
LV_PROTECT_POS = 0x04, /*Prevent automatic positioning (e.g. in lv_cont layout)*/
|
||||
LV_PROTECT_FOLLOW = 0x08, /*Prevent the object be followed in automatic ordering (e.g. in lv_cont PRETTY layout)*/
|
||||
LV_PROTECT_PRESS_LOST= 0x10, /*If the `indev` was pressing this object but swiped out while pressing do not search other object.*/
|
||||
LV_PROTECT_CLICK_FOCUS= 0x20,/*Prevent focusing the object by clicking on it*/
|
||||
};
|
||||
typedef uint8_t lv_protect_t;
|
||||
|
||||
|
||||
/*Used by `lv_obj_get_type()`. The object's and its ancestor types are stored here*/
|
||||
typedef struct {
|
||||
const char * type[LV_MAX_ANCESTOR_NUM]; /*[0]: the actual type, [1]: ancestor, [2] #1's ancestor ... [x]: "lv_obj" */
|
||||
} lv_obj_type_t;
|
||||
|
||||
enum
|
||||
{
|
||||
LV_ANIM_NONE = 0,
|
||||
LV_ANIM_FLOAT_TOP, /*Float from/to the top*/
|
||||
LV_ANIM_FLOAT_LEFT, /*Float from/to the left*/
|
||||
LV_ANIM_FLOAT_BOTTOM, /*Float from/to the bottom*/
|
||||
LV_ANIM_FLOAT_RIGHT, /*Float from/to the right*/
|
||||
LV_ANIM_GROW_H, /*Grow/shrink horizontally*/
|
||||
LV_ANIM_GROW_V, /*Grow/shrink vertically*/
|
||||
};
|
||||
typedef uint8_t lv_anim_builtin_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Init. the 'lv' library.
|
||||
*/
|
||||
void lv_init(void);
|
||||
|
||||
/*--------------------
|
||||
* Create and delete
|
||||
*-------------------*/
|
||||
|
||||
/**
|
||||
* Create a basic object
|
||||
* @param parent pointer to a parent object.
|
||||
* If NULL then a screen will be created
|
||||
* @param copy pointer to a base object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the new object
|
||||
*/
|
||||
lv_obj_t * lv_obj_create(lv_obj_t * parent,const lv_obj_t * copy);
|
||||
|
||||
/**
|
||||
* Delete 'obj' and all of its children
|
||||
* @param obj pointer to an object to delete
|
||||
* @return LV_RES_INV because the object is deleted
|
||||
*/
|
||||
lv_res_t lv_obj_del(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Delete all children of an object
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_clean(lv_obj_t *obj);
|
||||
|
||||
/**
|
||||
* Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task'
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_invalidate(const lv_obj_t * obj);
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/*--------------------
|
||||
* Parent/children set
|
||||
*--------------------*/
|
||||
|
||||
/**
|
||||
* Set a new parent for an object. Its relative position will be the same.
|
||||
* @param obj pointer to an object. Can't be a screen.
|
||||
* @param parent pointer to the new parent object. (Can't be NULL)
|
||||
*/
|
||||
void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent);
|
||||
|
||||
/*--------------------
|
||||
* Coordinate set
|
||||
* ------------------*/
|
||||
|
||||
/**
|
||||
* Set relative the position of an object (relative to the parent)
|
||||
* @param obj pointer to an object
|
||||
* @param x new distance from the left side of the parent
|
||||
* @param y new distance from the top of the parent
|
||||
*/
|
||||
void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y);
|
||||
|
||||
/**
|
||||
* Set the x coordinate of a object
|
||||
* @param obj pointer to an object
|
||||
* @param x new distance from the left side from the parent
|
||||
*/
|
||||
void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x);
|
||||
|
||||
/**
|
||||
* Set the y coordinate of a object
|
||||
* @param obj pointer to an object
|
||||
* @param y new distance from the top of the parent
|
||||
*/
|
||||
void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y);
|
||||
|
||||
/**
|
||||
* Set the size of an object
|
||||
* @param obj pointer to an object
|
||||
* @param w new width
|
||||
* @param h new height
|
||||
*/
|
||||
void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h);
|
||||
|
||||
/**
|
||||
* Set the width of an object
|
||||
* @param obj pointer to an object
|
||||
* @param w new width
|
||||
*/
|
||||
void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w);
|
||||
|
||||
/**
|
||||
* Set the height of an object
|
||||
* @param obj pointer to an object
|
||||
* @param h new height
|
||||
*/
|
||||
void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h);
|
||||
|
||||
/**
|
||||
* Align an object to an other object.
|
||||
* @param obj pointer to an object to align
|
||||
* @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.
|
||||
* @param align type of alignment (see 'lv_align_t' enum)
|
||||
* @param x_mod x coordinate shift after alignment
|
||||
* @param y_mod y coordinate shift after alignment
|
||||
*/
|
||||
void lv_obj_align(lv_obj_t * obj,const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod);
|
||||
|
||||
/**
|
||||
* Align an object to an other object.
|
||||
* @param obj pointer to an object to align
|
||||
* @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.
|
||||
* @param align type of alignment (see 'lv_align_t' enum)
|
||||
* @param x_mod x coordinate shift after alignment
|
||||
* @param y_mod y coordinate shift after alignment
|
||||
*/
|
||||
void lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod);
|
||||
|
||||
/**
|
||||
* Realign the object based on the last `lv_obj_align` parameters.
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_realign(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Enable the automatic realign of the object when its size has changed based on the last `lv_obj_align` parameters.
|
||||
* @param obj pointer to an object
|
||||
* @param en true: enable auto realign; false: disable auto realign
|
||||
*/
|
||||
void lv_obj_set_auto_realign(lv_obj_t * obj, bool en);
|
||||
|
||||
/*---------------------
|
||||
* Appearance set
|
||||
*--------------------*/
|
||||
|
||||
/**
|
||||
* Set a new style for an object
|
||||
* @param obj pointer to an object
|
||||
* @param style_p pointer to the new style
|
||||
*/
|
||||
void lv_obj_set_style(lv_obj_t * obj, lv_style_t * style);
|
||||
|
||||
/**
|
||||
* Notify an object about its style is modified
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_refresh_style(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Notify all object if a style is modified
|
||||
* @param style pointer to a style. Only the objects with this style will be notified
|
||||
* (NULL to notify all objects)
|
||||
*/
|
||||
void lv_obj_report_style_mod(lv_style_t * style);
|
||||
|
||||
/*-----------------
|
||||
* Attribute set
|
||||
*----------------*/
|
||||
|
||||
/**
|
||||
* Hide an object. It won't be visible and clickable.
|
||||
* @param obj pointer to an object
|
||||
* @param en true: hide the object
|
||||
*/
|
||||
void lv_obj_set_hidden(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Enable or disable the clicking of an object
|
||||
* @param obj pointer to an object
|
||||
* @param en true: make the object clickable
|
||||
*/
|
||||
void lv_obj_set_click(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Enable to bring this object to the foreground if it
|
||||
* or any of its children is clicked
|
||||
* @param obj pointer to an object
|
||||
* @param en true: enable the auto top feature
|
||||
*/
|
||||
void lv_obj_set_top(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Enable the dragging of an object
|
||||
* @param obj pointer to an object
|
||||
* @param en true: make the object dragable
|
||||
*/
|
||||
void lv_obj_set_drag(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Enable the throwing of an object after is is dragged
|
||||
* @param obj pointer to an object
|
||||
* @param en true: enable the drag throw
|
||||
*/
|
||||
void lv_obj_set_drag_throw(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Enable to use parent for drag related operations.
|
||||
* If trying to drag the object the parent will be moved instead
|
||||
* @param obj pointer to an object
|
||||
* @param en true: enable the 'drag parent' for the object
|
||||
*/
|
||||
void lv_obj_set_drag_parent(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Propagate the events to the parent too
|
||||
* @param obj pointer to an object
|
||||
* @param en true: enable the event propagation
|
||||
*/
|
||||
void lv_obj_set_parent_event(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`)
|
||||
* @param obj pointer to an object
|
||||
* @param en true: opa scaling is enabled for this object and all children; false: no opa scaling
|
||||
*/
|
||||
void lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Set the opa scale of an object
|
||||
* @param obj pointer to an object
|
||||
* @param opa_scale a factor to scale down opacity [0..255]
|
||||
*/
|
||||
void lv_obj_set_opa_scale(lv_obj_t * obj, lv_opa_t opa_scale);
|
||||
|
||||
/**
|
||||
* Set a bit or bits in the protect filed
|
||||
* @param obj pointer to an object
|
||||
* @param prot 'OR'-ed values from `lv_protect_t`
|
||||
*/
|
||||
void lv_obj_set_protect(lv_obj_t * obj, uint8_t prot);
|
||||
|
||||
/**
|
||||
* Clear a bit or bits in the protect filed
|
||||
* @param obj pointer to an object
|
||||
* @param prot 'OR'-ed values from `lv_protect_t`
|
||||
*/
|
||||
void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot);
|
||||
|
||||
/**
|
||||
* Set a an event handler function for an object.
|
||||
* Used by the user to react on event which happens with the object.
|
||||
* @param obj pointer to an object
|
||||
* @param cb the new event function
|
||||
*/
|
||||
void lv_obj_set_event_cb(lv_obj_t * obj, lv_event_cb_t cb);
|
||||
|
||||
/**
|
||||
* Send an event to the object
|
||||
* @param obj pointer to an object
|
||||
* @param event the type of the event from `lv_event_t`.
|
||||
* @return LV_RES_OK: `obj` was not deleted in the event; LV_RES_INV: `obj` was deleted in the event
|
||||
*/
|
||||
lv_res_t lv_obj_send_event(lv_obj_t * obj, lv_event_t event);
|
||||
|
||||
/**
|
||||
* Set the a signal function of an object. Used internally by the library.
|
||||
* Always call the previous signal function in the new.
|
||||
* @param obj pointer to an object
|
||||
* @param cb the new signal function
|
||||
*/
|
||||
void lv_obj_set_signal_cb(lv_obj_t * obj, lv_signal_cb_t cb);
|
||||
|
||||
/**
|
||||
* Send an event to the object
|
||||
* @param obj pointer to an object
|
||||
* @param event the type of the event from `lv_event_t`.
|
||||
*/
|
||||
void lv_obj_send_signal(lv_obj_t * obj, lv_signal_t signal, void * param);
|
||||
|
||||
/**
|
||||
* Set a new design function for an object
|
||||
* @param obj pointer to an object
|
||||
* @param cb the new design function
|
||||
*/
|
||||
void lv_obj_set_design_cb(lv_obj_t * obj, lv_design_cb_t cb);
|
||||
|
||||
/*----------------
|
||||
* Other set
|
||||
*--------------*/
|
||||
|
||||
/**
|
||||
* Allocate a new ext. data for an object
|
||||
* @param obj pointer to an object
|
||||
* @param ext_size the size of the new ext. data
|
||||
* @return pointer to the allocated ext
|
||||
*/
|
||||
void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size);
|
||||
|
||||
/**
|
||||
* Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_refresh_ext_size(lv_obj_t * obj);
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
/**
|
||||
* Animate an object
|
||||
* @param obj pointer to an object to animate
|
||||
* @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT
|
||||
* @param time time of animation in milliseconds
|
||||
* @param delay delay before the animation in milliseconds
|
||||
* @param cb a function to call when the animation is ready
|
||||
*/
|
||||
void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay, void (*cb) (lv_obj_t *));
|
||||
#endif
|
||||
|
||||
/*=======================
|
||||
* Getter functions
|
||||
*======================*/
|
||||
|
||||
/**
|
||||
* Return with the screen of an object
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to a screen
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the display of an object
|
||||
* @param scr pointer to an object
|
||||
* @return pointer the object's display
|
||||
*/
|
||||
lv_disp_t * lv_obj_get_disp(const lv_obj_t * obj);
|
||||
|
||||
/*---------------------
|
||||
* Parent/children get
|
||||
*--------------------*/
|
||||
|
||||
/**
|
||||
* Returns with the parent of an object
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to the parent of 'obj'
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Iterate through the children of an object (start from the "youngest, lastly created")
|
||||
* @param obj pointer to an object
|
||||
* @param child NULL at first call to get the next children
|
||||
* and the previous return value later
|
||||
* @return the child after 'act_child' or NULL if no more child
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child);
|
||||
|
||||
/**
|
||||
* Iterate through the children of an object (start from the "oldest", firstly created)
|
||||
* @param obj pointer to an object
|
||||
* @param child NULL at first call to get the next children
|
||||
* and the previous return value later
|
||||
* @return the child after 'act_child' or NULL if no more child
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child);
|
||||
|
||||
/**
|
||||
* Count the children of an object (only children directly on 'obj')
|
||||
* @param obj pointer to an object
|
||||
* @return children number of 'obj'
|
||||
*/
|
||||
uint16_t lv_obj_count_children(const lv_obj_t * obj);
|
||||
|
||||
/*---------------------
|
||||
* Coordinate get
|
||||
*--------------------*/
|
||||
|
||||
/**
|
||||
* Copy the coordinates of an object to an area
|
||||
* @param obj pointer to an object
|
||||
* @param cords_p pointer to an area to store the coordinates
|
||||
*/
|
||||
void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p);
|
||||
|
||||
/**
|
||||
* Get the x coordinate of object
|
||||
* @param obj pointer to an object
|
||||
* @return distance of 'obj' from the left side of its parent
|
||||
*/
|
||||
lv_coord_t lv_obj_get_x(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the y coordinate of object
|
||||
* @param obj pointer to an object
|
||||
* @return distance of 'obj' from the top of its parent
|
||||
*/
|
||||
lv_coord_t lv_obj_get_y(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the width of an object
|
||||
* @param obj pointer to an object
|
||||
* @return the width
|
||||
*/
|
||||
lv_coord_t lv_obj_get_width(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the height of an object
|
||||
* @param obj pointer to an object
|
||||
* @return the height
|
||||
*/
|
||||
lv_coord_t lv_obj_get_height(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get that width reduced by the left and right padding.
|
||||
* @param obj pointer to an object
|
||||
* @return the width which still fits into the container
|
||||
*/
|
||||
lv_coord_t lv_obj_get_width_fit(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get that height reduced by the top an bottom padding.
|
||||
* @param obj pointer to an object
|
||||
* @return the height which still fits into the container
|
||||
*/
|
||||
lv_coord_t lv_obj_get_height_fit(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the extended size attribute of an object
|
||||
* @param obj pointer to an object
|
||||
* @return the extended size attribute
|
||||
*/
|
||||
lv_coord_t lv_obj_get_ext_size(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the automatic realign property of the object.
|
||||
* @param obj pointer to an object
|
||||
* @return true: auto realign is enabled; false: auto realign is disabled
|
||||
*/
|
||||
bool lv_obj_get_auto_realign(lv_obj_t * obj);
|
||||
|
||||
/*-----------------
|
||||
* Appearance get
|
||||
*---------------*/
|
||||
|
||||
/**
|
||||
* Get the style pointer of an object (if NULL get style of the parent)
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to a style
|
||||
*/
|
||||
lv_style_t * lv_obj_get_style(const lv_obj_t * obj);
|
||||
|
||||
/*-----------------
|
||||
* Attribute get
|
||||
*----------------*/
|
||||
|
||||
/**
|
||||
* Get the hidden attribute of an object
|
||||
* @param obj pointer to an object
|
||||
* @return true: the object is hidden
|
||||
*/
|
||||
bool lv_obj_get_hidden(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the click enable attribute of an object
|
||||
* @param obj pointer to an object
|
||||
* @return true: the object is clickable
|
||||
*/
|
||||
bool lv_obj_get_click(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the top enable attribute of an object
|
||||
* @param obj pointer to an object
|
||||
* @return true: the auto top feature is enabled
|
||||
*/
|
||||
bool lv_obj_get_top(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the drag enable attribute of an object
|
||||
* @param obj pointer to an object
|
||||
* @return true: the object is dragable
|
||||
*/
|
||||
bool lv_obj_get_drag(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the drag throw enable attribute of an object
|
||||
* @param obj pointer to an object
|
||||
* @return true: drag throw is enabled
|
||||
*/
|
||||
bool lv_obj_get_drag_throw(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the drag parent attribute of an object
|
||||
* @param obj pointer to an object
|
||||
* @return true: drag parent is enabled
|
||||
*/
|
||||
bool lv_obj_get_drag_parent(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the drag parent attribute of an object
|
||||
* @param obj pointer to an object
|
||||
* @return true: drag parent is enabled
|
||||
*/
|
||||
bool lv_obj_get_parent_event(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the opa scale enable parameter
|
||||
* @param obj pointer to an object
|
||||
* @return true: opa scaling is enabled for this object and all children; false: no opa scaling
|
||||
*/
|
||||
lv_opa_t lv_obj_get_opa_scale_enable(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the opa scale parameter of an object
|
||||
* @param obj pointer to an object
|
||||
* @return opa scale [0..255]
|
||||
*/
|
||||
lv_opa_t lv_obj_get_opa_scale(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the protect field of an object
|
||||
* @param obj pointer to an object
|
||||
* @return protect field ('OR'ed values of `lv_protect_t`)
|
||||
*/
|
||||
uint8_t lv_obj_get_protect(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Check at least one bit of a given protect bitfield is set
|
||||
* @param obj pointer to an object
|
||||
* @param prot protect bits to test ('OR'ed values of `lv_protect_t`)
|
||||
* @return false: none of the given bits are set, true: at least one bit is set
|
||||
*/
|
||||
bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot);
|
||||
|
||||
/**
|
||||
* Get the signal function of an object
|
||||
* @param obj pointer to an object
|
||||
* @return the signal function
|
||||
*/
|
||||
lv_signal_cb_t lv_obj_get_signal_func(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the design function of an object
|
||||
* @param obj pointer to an object
|
||||
* @return the design function
|
||||
*/
|
||||
lv_design_cb_t lv_obj_get_design_func(const lv_obj_t * obj);
|
||||
|
||||
/*------------------
|
||||
* Other get
|
||||
*-----------------*/
|
||||
|
||||
/**
|
||||
* Get the ext pointer
|
||||
* @param obj pointer to an object
|
||||
* @return the ext pointer but not the dynamic version
|
||||
* Use it as ext->data1, and NOT da(ext)->data1
|
||||
*/
|
||||
void * lv_obj_get_ext_attr(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get object's and its ancestors type. Put their name in `type_buf` starting with the current type.
|
||||
* E.g. buf.type[0]="lv_btn", buf.type[1]="lv_cont", buf.type[2]="lv_obj"
|
||||
* @param obj pointer to an object which type should be get
|
||||
* @param buf pointer to an `lv_obj_type_t` buffer to store the types
|
||||
*/
|
||||
void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf);
|
||||
|
||||
|
||||
#if LV_USE_USER_DATA_SINGLE
|
||||
/**
|
||||
* Get a pointer to the object's user data
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to the user data
|
||||
*/
|
||||
lv_obj_user_data_t * lv_obj_get_user_data(lv_obj_t * obj);
|
||||
#endif
|
||||
|
||||
#if LV_USE_GROUP
|
||||
/**
|
||||
* Get the group of the object
|
||||
* @param obj pointer to an object
|
||||
* @return the pointer to group of the object
|
||||
*/
|
||||
void * lv_obj_get_group(const lv_obj_t * obj);
|
||||
|
||||
|
||||
/**
|
||||
* Tell whether the object is the focused object of a group or not.
|
||||
* @param obj pointer to an object
|
||||
* @return true: the object is focused, false: the object is not focused or not in a group
|
||||
*/
|
||||
bool lv_obj_is_focused(const lv_obj_t * obj);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_H*/
|
||||
554
src/lv_core/lv_refr.c
Normal file
554
src/lv_core/lv_refr.c
Normal file
@@ -0,0 +1,554 @@
|
||||
/**
|
||||
* @file lv_refr.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stddef.h>
|
||||
#include "lv_refr.h"
|
||||
#include "lv_disp.h"
|
||||
#include "../lv_hal/lv_hal_tick.h"
|
||||
#include "../lv_hal/lv_hal_disp.h"
|
||||
#include "../lv_misc/lv_task.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
#include "../lv_misc/lv_gc.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void lv_refr_task(void * param);
|
||||
static void lv_refr_join_area(void);
|
||||
static void lv_refr_areas(void);
|
||||
static void lv_refr_area(const lv_area_t * area_p);
|
||||
static void lv_refr_area_part(const lv_area_t * area_p);
|
||||
static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj);
|
||||
static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p);
|
||||
static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p);
|
||||
static void lv_refr_vdb_flush(void);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static uint32_t px_num;
|
||||
static lv_disp_t * disp_refr; /*Display being refreshed*/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the screen refresh subsystem
|
||||
*/
|
||||
void lv_refr_init(void)
|
||||
{
|
||||
lv_task_t * task;
|
||||
task = lv_task_create(lv_refr_task, LV_REFR_PERIOD, LV_TASK_PRIO_MID, NULL);
|
||||
lv_task_ready(task); /*Be sure the screen will be refreshed immediately on start up*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Redraw the invalidated areas now.
|
||||
* Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process can
|
||||
* prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar)
|
||||
* this function can be called when the screen should be updated.
|
||||
*/
|
||||
void lv_refr_now(void)
|
||||
{
|
||||
lv_refr_task(NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invalidate an area on display to redraw it
|
||||
* @param area_p pointer to area which should be invalidated (NULL: delete the invalidated areas)
|
||||
* @param disp pointer to display where the area should be invalidated (NULL can be used if there is only one display)
|
||||
*/
|
||||
void lv_inv_area(lv_disp_t * disp, const lv_area_t * area_p)
|
||||
{
|
||||
if(!disp) disp = lv_disp_get_default();
|
||||
if(!disp) return;
|
||||
|
||||
/*Clear the invalidate buffer if the parameter is NULL*/
|
||||
if(area_p == NULL) {
|
||||
disp->inv_p = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_area_t scr_area;
|
||||
scr_area.x1 = 0;
|
||||
scr_area.y1 = 0;
|
||||
scr_area.x2 = disp->driver.hor_res - 1;
|
||||
scr_area.y2 = disp->driver.ver_res - 1;
|
||||
|
||||
lv_area_t com_area;
|
||||
bool suc;
|
||||
|
||||
suc = lv_area_intersect(&com_area, area_p, &scr_area);
|
||||
|
||||
/*The area is truncated to the screen*/
|
||||
if(suc != false) {
|
||||
if(disp->driver.rounder_cb) disp->driver.rounder_cb(&disp_refr->driver, &com_area);
|
||||
|
||||
/*Save only if this area is not in one of the saved areas*/
|
||||
uint16_t i;
|
||||
for(i = 0; i < disp->inv_p; i++) {
|
||||
if(lv_area_is_in(&com_area, &disp->inv_areas[i]) != false) return;
|
||||
}
|
||||
|
||||
/*Save the area*/
|
||||
if(disp->inv_p < LV_INV_BUF_SIZE) {
|
||||
lv_area_copy(&disp->inv_areas[disp->inv_p], &com_area);
|
||||
} else {/*If no place for the area add the screen*/
|
||||
disp->inv_p = 0;
|
||||
lv_area_copy(&disp->inv_areas[disp->inv_p], &scr_area);
|
||||
}
|
||||
disp->inv_p ++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the display which is being refreshed
|
||||
* @return the display being refreshed
|
||||
*/
|
||||
lv_disp_t * lv_refr_get_disp_refreshing(void)
|
||||
{
|
||||
return disp_refr;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Called periodically to handle the refreshing
|
||||
* @param param unused
|
||||
*/
|
||||
static void lv_refr_task(void * param)
|
||||
{
|
||||
(void)param;
|
||||
|
||||
LV_LOG_TRACE("lv_refr_task: started");
|
||||
|
||||
uint32_t start = lv_tick_get();
|
||||
|
||||
LV_LL_READ(LV_GC_ROOT(_lv_disp_ll), disp_refr) {
|
||||
LV_LOG_TRACE("lv_refr_task: refreshing a display");
|
||||
|
||||
lv_refr_join_area();
|
||||
|
||||
lv_refr_areas();
|
||||
|
||||
/*If refresh happened ...*/
|
||||
if(disp_refr->inv_p != 0) {
|
||||
/*In true double buffered mode copy the refreshed areas to the new VDB to keep it up to date*/
|
||||
if(lv_disp_is_true_double_buf(disp_refr)) {
|
||||
lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr);
|
||||
|
||||
/*Flush the content of the VDB*/
|
||||
lv_refr_vdb_flush();
|
||||
|
||||
/* With true double buffering the flushing should be only the address change of the current frame buffer.
|
||||
* Wait until the address change is ready and copy the changed content to the other frame buffer (new active VDB)
|
||||
* to keep the buffers synchronized*/
|
||||
while(vdb->flushing);
|
||||
|
||||
uint8_t * buf_act = (uint8_t *) vdb->buf_act;
|
||||
uint8_t * buf_ina = (uint8_t *) vdb->buf_act == vdb->buf1 ? vdb->buf2 : vdb->buf1;
|
||||
|
||||
lv_coord_t hres = lv_disp_get_hor_res(disp_refr);
|
||||
uint16_t a;
|
||||
for(a = 0; a < disp_refr->inv_p; a++) {
|
||||
if(disp_refr->inv_area_joined[a] == 0) {
|
||||
lv_coord_t y;
|
||||
uint32_t start_offs = (hres * disp_refr->inv_areas[a].y1 + disp_refr->inv_areas[a].x1) * sizeof(lv_color_t);
|
||||
uint32_t line_length = lv_area_get_width(&disp_refr->inv_areas[a]) * sizeof(lv_color_t);
|
||||
|
||||
for(y = disp_refr->inv_areas[a].y1; y <= disp_refr->inv_areas[a].y2; y++) {
|
||||
memcpy(buf_act + start_offs, buf_ina + start_offs, line_length);
|
||||
start_offs += hres * sizeof(lv_color_t);
|
||||
}
|
||||
}
|
||||
}
|
||||
} /*End of true double buffer handling*/
|
||||
|
||||
/*Clean up*/
|
||||
memset(disp_refr->inv_areas, 0, sizeof(disp_refr->inv_areas));
|
||||
memset(disp_refr->inv_area_joined, 0, sizeof(disp_refr->inv_area_joined));
|
||||
disp_refr->inv_p = 0;
|
||||
|
||||
/*Call monitor cb if present*/
|
||||
if(disp_refr->driver.monitor_cb) {
|
||||
disp_refr->driver.monitor_cb(&disp_refr->driver, lv_tick_elaps(start), px_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LV_LOG_TRACE("lv_refr_task: ready");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Join the areas which has got common parts
|
||||
*/
|
||||
static void lv_refr_join_area(void)
|
||||
{
|
||||
uint32_t join_from;
|
||||
uint32_t join_in;
|
||||
lv_area_t joined_area;
|
||||
for(join_in = 0; join_in < disp_refr->inv_p; join_in++) {
|
||||
if(disp_refr->inv_area_joined[join_in] != 0) continue;
|
||||
|
||||
/*Check all areas to join them in 'join_in'*/
|
||||
for(join_from = 0; join_from < disp_refr->inv_p; join_from++) {
|
||||
/*Handle only unjoined areas and ignore itself*/
|
||||
if(disp_refr->inv_area_joined[join_from] != 0 || join_in == join_from) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*Check if the areas are on each other*/
|
||||
if(lv_area_is_on(&disp_refr->inv_areas[join_in],
|
||||
&disp_refr->inv_areas[join_from]) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lv_area_join(&joined_area, &disp_refr->inv_areas[join_in],
|
||||
&disp_refr->inv_areas[join_from]);
|
||||
|
||||
/*Join two area only if the joined area size is smaller*/
|
||||
if(lv_area_get_size(&joined_area) <
|
||||
(lv_area_get_size(&disp_refr->inv_areas[join_in]) + lv_area_get_size(&disp_refr->inv_areas[join_from]))) {
|
||||
lv_area_copy(&disp_refr->inv_areas[join_in], &joined_area);
|
||||
|
||||
/*Mark 'join_form' is joined into 'join_in'*/
|
||||
disp_refr->inv_area_joined[join_from] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the joined areas
|
||||
*/
|
||||
static void lv_refr_areas(void)
|
||||
{
|
||||
px_num = 0;
|
||||
uint32_t i;
|
||||
|
||||
for(i = 0; i < disp_refr->inv_p; i++) {
|
||||
/*Refresh the unjoined areas*/
|
||||
if(disp_refr->inv_area_joined[i] == 0) {
|
||||
|
||||
lv_refr_area(&disp_refr->inv_areas[i]);
|
||||
|
||||
if(disp_refr->driver.monitor_cb) px_num += lv_area_get_size(&disp_refr->inv_areas[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh an area if there is Virtual Display Buffer
|
||||
* @param area_p pointer to an area to refresh
|
||||
*/
|
||||
static void lv_refr_area(const lv_area_t * area_p)
|
||||
{
|
||||
/*True double buffering: there are two screen sized buffers. Just redraw directly into a buffer*/
|
||||
if(lv_disp_is_true_double_buf(disp_refr)) {
|
||||
lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr);
|
||||
vdb->area.x1 = 0;
|
||||
vdb->area.x2 = lv_disp_get_hor_res(disp_refr) - 1;
|
||||
vdb->area.y1 = 0;
|
||||
vdb->area.y2 = lv_disp_get_ver_res(disp_refr) - 1;
|
||||
lv_refr_area_part(area_p);
|
||||
}
|
||||
/*The buffer is smaller: refresh the area in parts*/
|
||||
else {
|
||||
lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr);
|
||||
/*Calculate the max row num*/
|
||||
lv_coord_t w = lv_area_get_width(area_p);
|
||||
lv_coord_t h = lv_area_get_height(area_p);
|
||||
lv_coord_t y2 = area_p->y2 >= lv_disp_get_ver_res(disp_refr) ? y2 = lv_disp_get_ver_res(disp_refr) - 1 : area_p->y2;
|
||||
|
||||
int32_t max_row = (uint32_t) vdb->size / w;
|
||||
|
||||
if(max_row > h) max_row = h;
|
||||
|
||||
/*Round down the lines of VDB if rounding is added*/
|
||||
if(disp_refr->driver.rounder_cb) {
|
||||
lv_area_t tmp;
|
||||
tmp.x1 = 0;
|
||||
tmp.x2 = 0;
|
||||
tmp.y1 = 0;
|
||||
tmp.y2 = max_row;
|
||||
|
||||
lv_coord_t y_tmp = max_row;
|
||||
do {
|
||||
tmp.y2 = y_tmp;
|
||||
disp_refr->driver.rounder_cb(&disp_refr->driver, &tmp);
|
||||
y_tmp --; /*Decrement the number of line until it is rounded to a smaller (or equal) value then the original. */
|
||||
} while(lv_area_get_height(&tmp) > max_row && y_tmp != 0);
|
||||
|
||||
if(y_tmp == 0) {
|
||||
LV_LOG_WARN("Can't set VDB height using the round function. (Wrong round_cb or to small VDB)");
|
||||
return;
|
||||
} else {
|
||||
max_row = tmp.y2 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*Always use the full row*/
|
||||
lv_coord_t row;
|
||||
lv_coord_t row_last = 0;
|
||||
for(row = area_p->y1; row + max_row - 1 <= y2; row += max_row) {
|
||||
/*Calc. the next y coordinates of VDB*/
|
||||
vdb->area.x1 = area_p->x1;
|
||||
vdb->area.x2 = area_p->x2;
|
||||
vdb->area.y1 = row;
|
||||
vdb->area.y2 = row + max_row - 1;
|
||||
if(vdb->area.y2 > y2) vdb->area.y2 = y2;
|
||||
row_last = vdb->area.y2;
|
||||
lv_refr_area_part(area_p);
|
||||
}
|
||||
|
||||
/*If the last y coordinates are not handled yet ...*/
|
||||
if(y2 != row_last) {
|
||||
/*Calc. the next y coordinates of VDB*/
|
||||
vdb->area.x1 = area_p->x1;
|
||||
vdb->area.x2 = area_p->x2;
|
||||
vdb->area.y1 = row;
|
||||
vdb->area.y2 = y2;
|
||||
|
||||
/*Refresh this part too*/
|
||||
lv_refr_area_part(area_p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh a part of an area which is on the actual Virtual Display Buffer
|
||||
* @param area_p pointer to an area to refresh
|
||||
*/
|
||||
static void lv_refr_area_part(const lv_area_t * area_p)
|
||||
{
|
||||
|
||||
lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr);
|
||||
|
||||
/*In non double buffered mode, before rendering the next part wait until the previous image is flushed*/
|
||||
if(lv_disp_is_double_buf(disp_refr) == false) {
|
||||
while(vdb->flushing);
|
||||
}
|
||||
|
||||
lv_obj_t * top_p;
|
||||
|
||||
/*Get the new mask from the original area and the act. VDB
|
||||
It will be a part of 'area_p'*/
|
||||
lv_area_t start_mask;
|
||||
lv_area_intersect(&start_mask, area_p, &vdb->area);
|
||||
|
||||
/*Get the most top object which is not covered by others*/
|
||||
top_p = lv_refr_get_top_obj(&start_mask, lv_disp_get_scr_act(disp_refr));
|
||||
|
||||
/*Do the refreshing from the top object*/
|
||||
lv_refr_obj_and_children(top_p, &start_mask);
|
||||
|
||||
/*Also refresh top and sys layer unconditionally*/
|
||||
lv_refr_obj_and_children(lv_disp_get_layer_top(disp_refr), &start_mask);
|
||||
lv_refr_obj_and_children(lv_disp_get_layer_sys(disp_refr), &start_mask);
|
||||
|
||||
/* In true double buffered mode flush only once when all areas were rendered.
|
||||
* In normal mode flush after every area */
|
||||
if(lv_disp_is_true_double_buf(disp_refr) == false) {
|
||||
lv_refr_vdb_flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the most top object which fully covers an area
|
||||
* @param area_p pointer to an area
|
||||
* @param obj the first object to start the searching (typically a screen)
|
||||
* @return
|
||||
*/
|
||||
static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj)
|
||||
{
|
||||
lv_obj_t * i;
|
||||
lv_obj_t * found_p = NULL;
|
||||
|
||||
/*If this object is fully cover the draw area check the children too */
|
||||
if(lv_area_is_in(area_p, &obj->coords) && obj->hidden == 0) {
|
||||
LV_LL_READ(obj->child_ll, i) {
|
||||
found_p = lv_refr_get_top_obj(area_p, i);
|
||||
|
||||
/*If a children is ok then break*/
|
||||
if(found_p != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*If no better children check this object*/
|
||||
if(found_p == NULL) {
|
||||
lv_style_t * style = lv_obj_get_style(obj);
|
||||
if(style->body.opa == LV_OPA_COVER &&
|
||||
obj->design_cb(obj, area_p, LV_DESIGN_COVER_CHK) != false &&
|
||||
lv_obj_get_opa_scale(obj) == LV_OPA_COVER) {
|
||||
found_p = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found_p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the refreshing from an object. Draw all its children and the youngers too.
|
||||
* @param top_p pointer to an objects. Start the drawing from it.
|
||||
* @param mask_p pointer to an area, the objects will be drawn only here
|
||||
*/
|
||||
static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p)
|
||||
{
|
||||
/* Normally always will be a top_obj (at least the screen)
|
||||
* but in special cases (e.g. if the screen has alpha) it won't.
|
||||
* In this case use the screen directly */
|
||||
if(top_p == NULL) top_p = lv_disp_get_scr_act(disp_refr);
|
||||
|
||||
/*Refresh the top object and its children*/
|
||||
lv_refr_obj(top_p, mask_p);
|
||||
|
||||
/*Draw the 'younger' sibling objects because they can be on top_obj */
|
||||
lv_obj_t * par;
|
||||
lv_obj_t * i;
|
||||
lv_obj_t * border_p = top_p;
|
||||
|
||||
par = lv_obj_get_parent(top_p);
|
||||
|
||||
/*Do until not reach the screen*/
|
||||
while(par != NULL) {
|
||||
/*object before border_p has to be redrawn*/
|
||||
i = lv_ll_get_prev(&(par->child_ll), border_p);
|
||||
|
||||
while(i != NULL) {
|
||||
/*Refresh the objects*/
|
||||
lv_refr_obj(i, mask_p);
|
||||
i = lv_ll_get_prev(&(par->child_ll), i);
|
||||
}
|
||||
|
||||
/*The new border will be there last parents,
|
||||
*so the 'younger' brothers of parent will be refreshed*/
|
||||
border_p = par;
|
||||
/*Go a level deeper*/
|
||||
par = lv_obj_get_parent(par);
|
||||
}
|
||||
|
||||
/*Call the post draw design function of the parents of the to object*/
|
||||
par = lv_obj_get_parent(top_p);
|
||||
while(par != NULL) {
|
||||
par->design_cb(par, mask_p, LV_DESIGN_DRAW_POST);
|
||||
par = lv_obj_get_parent(par);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh an object an all of its children. (Called recursively)
|
||||
* @param obj pointer to an object to refresh
|
||||
* @param mask_ori_p pointer to an area, the objects will be drawn only here
|
||||
*/
|
||||
static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p)
|
||||
{
|
||||
/*Do not refresh hidden objects*/
|
||||
if(obj->hidden != 0) return;
|
||||
|
||||
bool union_ok; /* Store the return value of area_union */
|
||||
/* Truncate the original mask to the coordinates of the parent
|
||||
* because the parent and its children are visible only here */
|
||||
lv_area_t obj_mask;
|
||||
lv_area_t obj_ext_mask;
|
||||
lv_area_t obj_area;
|
||||
lv_coord_t ext_size = obj->ext_size;
|
||||
lv_obj_get_coords(obj, &obj_area);
|
||||
obj_area.x1 -= ext_size;
|
||||
obj_area.y1 -= ext_size;
|
||||
obj_area.x2 += ext_size;
|
||||
obj_area.y2 += ext_size;
|
||||
union_ok = lv_area_intersect(&obj_ext_mask, mask_ori_p, &obj_area);
|
||||
|
||||
/*Draw the parent and its children only if they ore on 'mask_parent'*/
|
||||
if(union_ok != false) {
|
||||
|
||||
/* Redraw the object */
|
||||
obj->design_cb(obj, &obj_ext_mask, LV_DESIGN_DRAW_MAIN);
|
||||
//usleep(5 * 1000); /*DEBUG: Wait after every object draw to see the order of drawing*/
|
||||
|
||||
|
||||
/*Create a new 'obj_mask' without 'ext_size' because the children can't be visible there*/
|
||||
lv_obj_get_coords(obj, &obj_area);
|
||||
union_ok = lv_area_intersect(&obj_mask, mask_ori_p, &obj_area);
|
||||
if(union_ok != false) {
|
||||
lv_area_t mask_child; /*Mask from obj and its child*/
|
||||
lv_obj_t * child_p;
|
||||
lv_area_t child_area;
|
||||
LV_LL_READ_BACK(obj->child_ll, child_p) {
|
||||
lv_obj_get_coords(child_p, &child_area);
|
||||
ext_size = child_p->ext_size;
|
||||
child_area.x1 -= ext_size;
|
||||
child_area.y1 -= ext_size;
|
||||
child_area.x2 += ext_size;
|
||||
child_area.y2 += ext_size;
|
||||
/* Get the union (common parts) of original mask (from obj)
|
||||
* and its child */
|
||||
union_ok = lv_area_intersect(&mask_child, &obj_mask, &child_area);
|
||||
|
||||
/*If the parent and the child has common area then refresh the child */
|
||||
if(union_ok) {
|
||||
/*Refresh the next children*/
|
||||
lv_refr_obj(child_p, &mask_child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If all the children are redrawn make 'post draw' design */
|
||||
obj->design_cb(obj, &obj_ext_mask, LV_DESIGN_DRAW_POST);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the content of the VDB
|
||||
*/
|
||||
static void lv_refr_vdb_flush(void)
|
||||
{
|
||||
lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr);
|
||||
|
||||
/*In double buffered mode wait until the other buffer is flushed before flushing the current one*/
|
||||
if(lv_disp_is_double_buf(disp_refr)) {
|
||||
while(vdb->flushing);
|
||||
}
|
||||
|
||||
vdb->flushing = 1;
|
||||
|
||||
/*Flush the rendered content to the display*/
|
||||
lv_disp_t * disp = lv_refr_get_disp_refreshing();
|
||||
if(disp->driver.flush_cb) disp->driver.flush_cb(&disp->driver, &vdb->area, vdb->buf_act);
|
||||
|
||||
|
||||
if(vdb->buf1 && vdb->buf2) {
|
||||
if(vdb->buf_act == vdb->buf1) vdb->buf_act = vdb->buf2;
|
||||
else vdb->buf_act = vdb->buf1;
|
||||
|
||||
/*If the screen is transparent initialize it when the new VDB is selected*/
|
||||
# if LV_COLOR_SCREEN_TRANSP
|
||||
memset(vdb[vdb_active].buf, 0x00, LV_VDB_SIZE_IN_BYTES);
|
||||
# endif /*LV_COLOR_SCREEN_TRANSP*/
|
||||
}
|
||||
}
|
||||
90
src/lv_core/lv_refr.h
Normal file
90
src/lv_core/lv_refr.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @file lv_refr.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_REFR_H
|
||||
#define LV_REFR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the screen refresh subsystem
|
||||
*/
|
||||
void lv_refr_init(void);
|
||||
|
||||
/**
|
||||
* Redraw the invalidated areas now.
|
||||
* Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process can
|
||||
* prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar)
|
||||
* this function can be called when the screen should be updated.
|
||||
*/
|
||||
void lv_refr_now(void);
|
||||
|
||||
/**
|
||||
* Invalidate an area on display to redraw it
|
||||
* @param area_p pointer to area which should be invalidated (NULL: delete the invalidated areas)
|
||||
* @param disp pointer to display where the area should be invalidated (NULL can be used if there is only one display)
|
||||
*/
|
||||
void lv_inv_area(lv_disp_t * disp, const lv_area_t * area_p);
|
||||
|
||||
/**
|
||||
* Get the number of areas in the buffer
|
||||
* @return number of invalid areas
|
||||
*/
|
||||
uint16_t lv_refr_get_buf_size(void);
|
||||
|
||||
/**
|
||||
* Pop (delete) the last 'num' invalidated areas from the buffer
|
||||
* @param num number of areas to delete
|
||||
*/
|
||||
void lv_refr_pop_from_buf(uint16_t num);
|
||||
|
||||
/**
|
||||
* Get the display which is being refreshed
|
||||
* @return the display being refreshed
|
||||
*/
|
||||
lv_disp_t * lv_refr_get_disp_refreshing(void);
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_REFR_H*/
|
||||
356
src/lv_core/lv_style.c
Normal file
356
src/lv_core/lv_style.c
Normal file
@@ -0,0 +1,356 @@
|
||||
/**
|
||||
* @file lv_style.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define STYLE_MIX_MAX 256
|
||||
#define STYLE_MIX_SHIFT 8 /*log2(STYLE_MIX_MAX)*/
|
||||
|
||||
#define VAL_PROP(v1, v2, r) v1 + (((v2-v1) * r) >> STYLE_MIX_SHIFT)
|
||||
#define STYLE_ATTR_MIX(attr, r) if(start->attr != end->attr) {res->attr = VAL_PROP(start->attr, end->attr, r);} else {res->attr = start->attr;}
|
||||
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
#if LV_USE_ANIMATION
|
||||
typedef struct {
|
||||
lv_style_t style_start; /*Save not only pointers because can be same as 'style_anim' then it will be modified too*/
|
||||
lv_style_t style_end;
|
||||
lv_style_t * style_anim;
|
||||
void (*end_cb)(void *);
|
||||
} lv_style_anim_dsc_t;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
#if LV_USE_ANIMATION
|
||||
static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val);
|
||||
static void style_animation_common_end_cb(void * ptr);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
lv_style_t lv_style_scr;
|
||||
lv_style_t lv_style_transp;
|
||||
lv_style_t lv_style_transp_fit;
|
||||
lv_style_t lv_style_transp_tight;
|
||||
lv_style_t lv_style_plain;
|
||||
lv_style_t lv_style_plain_color;
|
||||
lv_style_t lv_style_pretty;
|
||||
lv_style_t lv_style_pretty_color;
|
||||
lv_style_t lv_style_btn_rel;
|
||||
lv_style_t lv_style_btn_pr;
|
||||
lv_style_t lv_style_btn_tgl_rel;
|
||||
lv_style_t lv_style_btn_tgl_pr;
|
||||
lv_style_t lv_style_btn_ina;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Init the basic styles
|
||||
*/
|
||||
void lv_style_init(void)
|
||||
{
|
||||
/* Not White/Black/Gray colors are created by HSV model with
|
||||
* HUE = 210*/
|
||||
|
||||
/*Screen style*/
|
||||
lv_style_scr.glass = 0;
|
||||
lv_style_scr.body.opa = LV_OPA_COVER;
|
||||
lv_style_scr.body.main_color = LV_COLOR_WHITE;
|
||||
lv_style_scr.body.grad_color = LV_COLOR_WHITE;
|
||||
lv_style_scr.body.radius = 0;
|
||||
lv_style_scr.body.padding.left = 0;
|
||||
lv_style_scr.body.padding.right = 0;
|
||||
lv_style_scr.body.padding.top = 0;
|
||||
lv_style_scr.body.padding.bottom = 0;
|
||||
lv_style_scr.body.padding.inner = LV_DPI / 12;
|
||||
|
||||
lv_style_scr.body.border.color = LV_COLOR_BLACK;
|
||||
lv_style_scr.body.border.opa = LV_OPA_COVER;
|
||||
lv_style_scr.body.border.width = 0;
|
||||
lv_style_scr.body.border.part = LV_BORDER_FULL;
|
||||
|
||||
lv_style_scr.body.shadow.color = LV_COLOR_GRAY;
|
||||
lv_style_scr.body.shadow.type = LV_SHADOW_FULL;
|
||||
lv_style_scr.body.shadow.width = 0;
|
||||
|
||||
lv_style_scr.text.opa = LV_OPA_COVER;
|
||||
lv_style_scr.text.color = lv_color_make(0x30, 0x30, 0x30);
|
||||
lv_style_scr.text.font = LV_FONT_DEFAULT;
|
||||
lv_style_scr.text.letter_space = 2;
|
||||
lv_style_scr.text.line_space = 2;
|
||||
|
||||
lv_style_scr.image.opa = LV_OPA_COVER;
|
||||
lv_style_scr.image.color = lv_color_make(0x20, 0x20, 0x20);
|
||||
lv_style_scr.image.intense = LV_OPA_TRANSP;
|
||||
|
||||
lv_style_scr.line.opa = LV_OPA_COVER;
|
||||
lv_style_scr.line.color = lv_color_make(0x20, 0x20, 0x20);
|
||||
lv_style_scr.line.width = 2;
|
||||
lv_style_scr.line.rounded = 0;
|
||||
|
||||
/*Plain style (by default near the same as the screen style)*/
|
||||
memcpy(&lv_style_plain, &lv_style_scr, sizeof(lv_style_t));
|
||||
lv_style_plain.body.padding.left = LV_DPI / 12;
|
||||
lv_style_plain.body.padding.right = LV_DPI / 12;
|
||||
lv_style_plain.body.padding.top = LV_DPI / 12;
|
||||
lv_style_plain.body.padding.bottom = LV_DPI / 12;
|
||||
|
||||
/*Plain color style*/
|
||||
memcpy(&lv_style_plain_color, &lv_style_plain, sizeof(lv_style_t));
|
||||
lv_style_plain_color.text.color = lv_color_make(0xf0, 0xf0, 0xf0);
|
||||
lv_style_plain_color.image.color = lv_color_make(0xf0, 0xf0, 0xf0);
|
||||
lv_style_plain_color.line.color = lv_color_make(0xf0, 0xf0, 0xf0);
|
||||
lv_style_plain_color.body.main_color = lv_color_make(0x55, 0x96, 0xd8);
|
||||
lv_style_plain_color.body.grad_color = lv_style_plain_color.body.main_color;
|
||||
|
||||
/*Pretty style */
|
||||
memcpy(&lv_style_pretty, &lv_style_plain, sizeof(lv_style_t));
|
||||
lv_style_pretty.text.color = lv_color_make(0x20, 0x20, 0x20);
|
||||
lv_style_pretty.image.color = lv_color_make(0x20, 0x20, 0x20);
|
||||
lv_style_pretty.line.color = lv_color_make(0x20, 0x20, 0x20);
|
||||
lv_style_pretty.body.main_color = LV_COLOR_WHITE;
|
||||
lv_style_pretty.body.grad_color = LV_COLOR_SILVER;
|
||||
lv_style_pretty.body.radius = LV_DPI / 15;
|
||||
lv_style_pretty.body.border.color = lv_color_make(0x40, 0x40, 0x40);
|
||||
lv_style_pretty.body.border.width = LV_DPI / 50 >= 1 ? LV_DPI / 50 : 1;
|
||||
lv_style_pretty.body.border.opa = LV_OPA_30;
|
||||
|
||||
/*Pretty color style*/
|
||||
memcpy(&lv_style_pretty_color, &lv_style_pretty, sizeof(lv_style_t));
|
||||
lv_style_pretty_color.text.color = lv_color_make(0xe0, 0xe0, 0xe0);
|
||||
lv_style_pretty_color.image.color = lv_color_make(0xe0, 0xe0, 0xe0);
|
||||
lv_style_pretty_color.line.color = lv_color_make(0xc0, 0xc0, 0xc0);
|
||||
lv_style_pretty_color.body.main_color = lv_color_make(0x6b, 0x9a, 0xc7);
|
||||
lv_style_pretty_color.body.grad_color = lv_color_make(0x2b, 0x59, 0x8b);
|
||||
lv_style_pretty_color.body.border.color = lv_color_make(0x15, 0x2c, 0x42);
|
||||
|
||||
/*Transparent style*/
|
||||
memcpy(&lv_style_transp, &lv_style_plain, sizeof(lv_style_t));
|
||||
lv_style_transp.glass = 1;
|
||||
lv_style_transp.body.border.width = 0;
|
||||
lv_style_transp.body.opa = LV_OPA_TRANSP;
|
||||
|
||||
/*Transparent fitting size*/
|
||||
memcpy(&lv_style_transp_fit, &lv_style_transp, sizeof(lv_style_t));
|
||||
lv_style_transp_fit.body.padding.left = 0;
|
||||
lv_style_transp_fit.body.padding.right = 0;
|
||||
lv_style_transp_fit.body.padding.top = 0;
|
||||
lv_style_transp_fit.body.padding.bottom = 0;
|
||||
|
||||
/*Transparent tight style*/
|
||||
memcpy(&lv_style_transp_tight, &lv_style_transp_fit, sizeof(lv_style_t));
|
||||
lv_style_transp_tight.body.padding.inner = 0;
|
||||
|
||||
/*Button released style*/
|
||||
memcpy(&lv_style_btn_rel, &lv_style_plain, sizeof(lv_style_t));
|
||||
lv_style_btn_rel.body.main_color = lv_color_make(0x76, 0xa2, 0xd0);
|
||||
lv_style_btn_rel.body.grad_color = lv_color_make(0x19, 0x3a, 0x5d);
|
||||
lv_style_btn_rel.body.radius = LV_DPI / 15;
|
||||
lv_style_btn_rel.body.padding.left= LV_DPI / 4;
|
||||
lv_style_btn_rel.body.padding.right = LV_DPI / 4;
|
||||
lv_style_btn_rel.body.padding.top = LV_DPI / 6;
|
||||
lv_style_btn_rel.body.padding.bottom = LV_DPI / 6;
|
||||
lv_style_btn_rel.body.padding.inner = LV_DPI / 10;
|
||||
lv_style_btn_rel.body.border.color = lv_color_make(0x0b, 0x19, 0x28);
|
||||
lv_style_btn_rel.body.border.width = LV_DPI / 50 >= 1 ? LV_DPI / 50 : 1;
|
||||
lv_style_btn_rel.body.border.opa = LV_OPA_70;
|
||||
lv_style_btn_rel.body.shadow.color = LV_COLOR_GRAY;
|
||||
lv_style_btn_rel.body.shadow.width = 0;
|
||||
lv_style_btn_rel.text.color = lv_color_make(0xff, 0xff, 0xff);
|
||||
lv_style_btn_rel.image.color = lv_color_make(0xff, 0xff, 0xff);
|
||||
|
||||
/*Button pressed style*/
|
||||
memcpy(&lv_style_btn_pr, &lv_style_btn_rel, sizeof(lv_style_t));
|
||||
lv_style_btn_pr.body.main_color = lv_color_make(0x33, 0x62, 0x94);
|
||||
lv_style_btn_pr.body.grad_color = lv_color_make(0x10, 0x26, 0x3c);
|
||||
lv_style_btn_pr.text.color = lv_color_make(0xa4, 0xb5, 0xc6);
|
||||
lv_style_btn_pr.image.color = lv_color_make(0xa4, 0xb5, 0xc6);
|
||||
lv_style_btn_pr.line.color = lv_color_make(0xa4, 0xb5, 0xc6);
|
||||
|
||||
/*Button toggle released style*/
|
||||
memcpy(&lv_style_btn_tgl_rel, &lv_style_btn_rel, sizeof(lv_style_t));
|
||||
lv_style_btn_tgl_rel.body.main_color = lv_color_make(0x0a, 0x11, 0x22);
|
||||
lv_style_btn_tgl_rel.body.grad_color = lv_color_make(0x37, 0x62, 0x90);
|
||||
lv_style_btn_tgl_rel.body.border.color = lv_color_make(0x01, 0x07, 0x0d);
|
||||
lv_style_btn_tgl_rel.text.color = lv_color_make(0xc8, 0xdd, 0xf4);
|
||||
lv_style_btn_tgl_rel.image.color = lv_color_make(0xc8, 0xdd, 0xf4);
|
||||
lv_style_btn_tgl_rel.line.color = lv_color_make(0xc8, 0xdd, 0xf4);
|
||||
|
||||
/*Button toggle pressed style*/
|
||||
memcpy(&lv_style_btn_tgl_pr, &lv_style_btn_tgl_rel, sizeof(lv_style_t));
|
||||
lv_style_btn_tgl_pr.body.main_color = lv_color_make(0x02, 0x14, 0x27);
|
||||
lv_style_btn_tgl_pr.body.grad_color = lv_color_make(0x2b, 0x4c, 0x70);
|
||||
lv_style_btn_tgl_pr.text.color = lv_color_make(0xa4, 0xb5, 0xc6);
|
||||
lv_style_btn_tgl_pr.image.color = lv_color_make(0xa4, 0xb5, 0xc6);
|
||||
lv_style_btn_tgl_pr.line.color = lv_color_make(0xa4, 0xb5, 0xc6);
|
||||
|
||||
/*Button inactive style*/
|
||||
memcpy(&lv_style_btn_ina, &lv_style_btn_rel, sizeof(lv_style_t));
|
||||
lv_style_btn_ina.body.main_color = lv_color_make(0xd8, 0xd8, 0xd8);
|
||||
lv_style_btn_ina.body.grad_color = lv_color_make(0xd8, 0xd8, 0xd8);
|
||||
lv_style_btn_ina.body.border.color = lv_color_make(0x90, 0x90, 0x90);
|
||||
lv_style_btn_ina.text.color = lv_color_make(0x70, 0x70, 0x70);
|
||||
lv_style_btn_ina.image.color = lv_color_make(0x70, 0x70, 0x70);
|
||||
lv_style_btn_ina.line.color = lv_color_make(0x70, 0x70, 0x70);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy a style to an other
|
||||
* @param dest pointer to the destination style
|
||||
* @param src pointer to the source style
|
||||
*/
|
||||
void lv_style_copy(lv_style_t * dest, const lv_style_t * src)
|
||||
{
|
||||
memcpy(dest, src, sizeof(lv_style_t));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mix two styles according to a given ratio
|
||||
* @param start start style
|
||||
* @param end end style
|
||||
* @param res store the result style here
|
||||
* @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style
|
||||
*/
|
||||
void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio)
|
||||
{
|
||||
STYLE_ATTR_MIX(body.opa, ratio);
|
||||
STYLE_ATTR_MIX(body.radius, ratio);
|
||||
STYLE_ATTR_MIX(body.border.width, ratio);
|
||||
STYLE_ATTR_MIX(body.border.opa, ratio);
|
||||
STYLE_ATTR_MIX(body.shadow.width, ratio);
|
||||
STYLE_ATTR_MIX(body.padding.left, ratio);
|
||||
STYLE_ATTR_MIX(body.padding.right, ratio);
|
||||
STYLE_ATTR_MIX(body.padding.top, ratio);
|
||||
STYLE_ATTR_MIX(body.padding.bottom, ratio);
|
||||
STYLE_ATTR_MIX(body.padding.inner, ratio);
|
||||
STYLE_ATTR_MIX(text.line_space, ratio);
|
||||
STYLE_ATTR_MIX(text.letter_space, ratio);
|
||||
STYLE_ATTR_MIX(text.opa, ratio);
|
||||
STYLE_ATTR_MIX(line.width, ratio);
|
||||
STYLE_ATTR_MIX(line.opa, ratio);
|
||||
STYLE_ATTR_MIX(image.intense, ratio);
|
||||
STYLE_ATTR_MIX(image.opa, ratio);
|
||||
|
||||
lv_opa_t opa = ratio == STYLE_MIX_MAX ? LV_OPA_COVER : ratio;
|
||||
|
||||
res->body.main_color = lv_color_mix(end->body.main_color, start->body.main_color, opa);
|
||||
res->body.grad_color = lv_color_mix(end->body.grad_color, start->body.grad_color, opa);
|
||||
res->body.border.color = lv_color_mix(end->body.border.color, start->body.border.color, opa);
|
||||
res->body.shadow.color = lv_color_mix(end->body.shadow.color, start->body.shadow.color, opa);
|
||||
res->text.color = lv_color_mix(end->text.color, start->text.color, opa);
|
||||
res->image.color = lv_color_mix(end->image.color, start->image.color, opa);
|
||||
res->line.color = lv_color_mix(end->line.color, start->line.color, opa);
|
||||
|
||||
if(ratio < (STYLE_MIX_MAX >> 1)) {
|
||||
res->body.border.part = start->body.border.part;
|
||||
res->glass = start->glass;
|
||||
res->text.font = start->text.font;
|
||||
res->body.shadow.type = start->body.shadow.type;
|
||||
res->line.rounded = start->line.rounded;
|
||||
} else {
|
||||
res->body.border.part = end->body.border.part;
|
||||
res->glass = end->glass;
|
||||
res->text.font = end->text.font;
|
||||
res->body.shadow.type = end->body.shadow.type;
|
||||
res->line.rounded = end->line.rounded;
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
|
||||
/**
|
||||
* Create an animation from a pre-configured 'lv_style_anim_t' variable
|
||||
* @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied)
|
||||
* @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`)
|
||||
*/
|
||||
void * lv_style_anim_create(lv_style_anim_t * anim)
|
||||
{
|
||||
lv_style_anim_dsc_t * dsc;
|
||||
dsc = lv_mem_alloc(sizeof(lv_style_anim_dsc_t));
|
||||
lv_mem_assert(dsc);
|
||||
if(dsc == NULL) return NULL;
|
||||
|
||||
dsc->style_anim = anim->style_anim;
|
||||
memcpy(&dsc->style_start, anim->style_start, sizeof(lv_style_t));
|
||||
memcpy(&dsc->style_end, anim->style_end, sizeof(lv_style_t));
|
||||
memcpy(dsc->style_anim, anim->style_start, sizeof(lv_style_t));
|
||||
dsc->end_cb = anim->end_cb;
|
||||
|
||||
|
||||
lv_anim_t a;
|
||||
a.var = (void *)dsc;
|
||||
a.start = 0;
|
||||
a.end = STYLE_MIX_MAX;
|
||||
a.fp = (lv_anim_fp_t)style_animator;
|
||||
a.path = lv_anim_path_linear;
|
||||
a.end_cb = style_animation_common_end_cb;
|
||||
a.act_time = anim->act_time;
|
||||
a.time = anim->time;
|
||||
a.playback = anim->playback;
|
||||
a.playback_pause = anim->playback_pause;
|
||||
a.repeat = anim->repeat;
|
||||
a.repeat_pause = anim->repeat_pause;
|
||||
|
||||
lv_anim_create(&a);
|
||||
|
||||
return dsc;
|
||||
}
|
||||
|
||||
#endif
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
#if LV_USE_ANIMATION
|
||||
/**
|
||||
* Used by the style animations to set the values of a style according to start and end style.
|
||||
* @param dsc the 'animated variable' set by lv_style_anim_create()
|
||||
* @param val the current state of the animation between 0 and LV_STYLE_ANIM_RES
|
||||
*/
|
||||
static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val)
|
||||
{
|
||||
const lv_style_t * start = &dsc->style_start;
|
||||
const lv_style_t * end = &dsc->style_end;
|
||||
lv_style_t * act = dsc->style_anim;
|
||||
|
||||
lv_style_mix(start, end, act, val);
|
||||
|
||||
lv_obj_report_style_mod(dsc->style_anim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a style animation is ready
|
||||
* It called the user defined call back and free the allocated memories
|
||||
* @param ptr the 'animated variable' set by lv_style_anim_create()
|
||||
*/
|
||||
static void style_animation_common_end_cb(void * ptr)
|
||||
{
|
||||
lv_style_anim_dsc_t * dsc = ptr; /*To avoid casting*/
|
||||
|
||||
if(dsc->end_cb) dsc->end_cb(dsc);
|
||||
|
||||
lv_mem_free(dsc);
|
||||
}
|
||||
|
||||
#endif
|
||||
199
src/lv_core/lv_style.h
Normal file
199
src/lv_core/lv_style.h
Normal file
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* @file lv_style.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_STYLE_H
|
||||
#define LV_STYLE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdbool.h>
|
||||
#include "../lv_misc/lv_color.h"
|
||||
#include "../lv_misc/lv_area.h"
|
||||
#include "../lv_misc/lv_font.h"
|
||||
#include "../lv_misc/lv_anim.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_RADIUS_CIRCLE (LV_COORD_MAX) /*A very big radius to always draw as circle*/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/*Border types (Use 'OR'ed values)*/
|
||||
enum
|
||||
{
|
||||
LV_BORDER_NONE = 0x00,
|
||||
LV_BORDER_BOTTOM = 0x01,
|
||||
LV_BORDER_TOP = 0x02,
|
||||
LV_BORDER_LEFT = 0x04,
|
||||
LV_BORDER_RIGHT = 0x08,
|
||||
LV_BORDER_FULL = 0x0F,
|
||||
LV_BORDER_INTERNAL = 0x10, /*FOR matrix-like objects (e.g. Button matrix)*/
|
||||
};
|
||||
typedef uint8_t lv_border_part_t;
|
||||
|
||||
/*Shadow types*/
|
||||
enum
|
||||
{
|
||||
LV_SHADOW_BOTTOM = 0,
|
||||
LV_SHADOW_FULL,
|
||||
};
|
||||
typedef uint8_t lv_shadow_type_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t glass :1; /*1: Do not inherit this style*/
|
||||
|
||||
struct {
|
||||
lv_color_t main_color;
|
||||
lv_color_t grad_color; /*`grad_color` will be removed in v6.0, use `aux_color` instead*/
|
||||
lv_coord_t radius;
|
||||
lv_opa_t opa;
|
||||
|
||||
struct {
|
||||
lv_color_t color;
|
||||
lv_coord_t width;
|
||||
lv_border_part_t part;
|
||||
lv_opa_t opa;
|
||||
} border;
|
||||
|
||||
struct {
|
||||
lv_color_t color;
|
||||
lv_coord_t width;
|
||||
lv_shadow_type_t type;
|
||||
} shadow;
|
||||
|
||||
struct {
|
||||
lv_coord_t top;
|
||||
lv_coord_t bottom;
|
||||
lv_coord_t left;
|
||||
lv_coord_t right;
|
||||
lv_coord_t inner;
|
||||
} padding;
|
||||
} body;
|
||||
|
||||
|
||||
struct {
|
||||
lv_color_t color;
|
||||
const lv_font_t * font;
|
||||
lv_coord_t letter_space;
|
||||
lv_coord_t line_space;
|
||||
lv_opa_t opa;
|
||||
} text;
|
||||
|
||||
struct {
|
||||
lv_color_t color;
|
||||
lv_opa_t intense;
|
||||
lv_opa_t opa;
|
||||
} image;
|
||||
|
||||
struct {
|
||||
lv_color_t color;
|
||||
lv_coord_t width;
|
||||
lv_opa_t opa;
|
||||
uint8_t rounded :1; /*1: rounded line endings*/
|
||||
} line;
|
||||
} lv_style_t;
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
typedef struct {
|
||||
const lv_style_t * style_start; /*Pointer to the starting style*/
|
||||
const lv_style_t * style_end; /*Pointer to the destination style*/
|
||||
lv_style_t * style_anim; /*Pointer to a style to animate*/
|
||||
lv_anim_cb_t end_cb; /*Call it when the animation is ready (NULL if unused)*/
|
||||
int16_t time; /*Animation time in ms*/
|
||||
int16_t act_time; /*Current time in animation. Set to negative to make delay.*/
|
||||
uint16_t playback_pause; /*Wait before play back*/
|
||||
uint16_t repeat_pause; /*Wait before repeat*/
|
||||
uint8_t playback :1; /*When the animation is ready play it back*/
|
||||
uint8_t repeat :1; /*Repeat the animation infinitely*/
|
||||
} lv_style_anim_t;
|
||||
|
||||
/* Example initialization
|
||||
lv_style_anim_t a;
|
||||
a.style_anim = &style_to_anim;
|
||||
a.style_start = &style_1;
|
||||
a.style_end = &style_2;
|
||||
a.act_time = 0;
|
||||
a.time = 1000;
|
||||
a.playback = 0;
|
||||
a.playback_pause = 0;
|
||||
a.repeat = 0;
|
||||
a.repeat_pause = 0;
|
||||
a.end_cb = NULL;
|
||||
lv_style_anim_create(&a);
|
||||
*/
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Init the basic styles
|
||||
*/
|
||||
void lv_style_init (void);
|
||||
|
||||
/**
|
||||
* Copy a style to an other
|
||||
* @param dest pointer to the destination style
|
||||
* @param src pointer to the source style
|
||||
*/
|
||||
void lv_style_copy(lv_style_t * dest, const lv_style_t * src);
|
||||
|
||||
|
||||
/**
|
||||
* Mix two styles according to a given ratio
|
||||
* @param start start style
|
||||
* @param end end style
|
||||
* @param res store the result style here
|
||||
* @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style
|
||||
*/
|
||||
void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio);
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
|
||||
/**
|
||||
* Create an animation from a pre-configured 'lv_style_anim_t' variable
|
||||
* @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied)
|
||||
* @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`)
|
||||
*/
|
||||
void * lv_style_anim_create(lv_style_anim_t * anim);
|
||||
#endif
|
||||
|
||||
/*************************
|
||||
* GLOBAL VARIABLES
|
||||
*************************/
|
||||
extern lv_style_t lv_style_scr;
|
||||
extern lv_style_t lv_style_transp;
|
||||
extern lv_style_t lv_style_transp_fit;
|
||||
extern lv_style_t lv_style_transp_tight;
|
||||
extern lv_style_t lv_style_plain;
|
||||
extern lv_style_t lv_style_plain_color;
|
||||
extern lv_style_t lv_style_pretty;
|
||||
extern lv_style_t lv_style_pretty_color;
|
||||
extern lv_style_t lv_style_btn_rel;
|
||||
extern lv_style_t lv_style_btn_pr;
|
||||
extern lv_style_t lv_style_btn_tgl_rel;
|
||||
extern lv_style_t lv_style_btn_tgl_pr;
|
||||
extern lv_style_t lv_style_btn_ina;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_STYLE_H*/
|
||||
143
src/lv_draw/lv_draw.c
Normal file
143
src/lv_draw/lv_draw.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* @file lv_draw.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "lv_draw.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#if LV_ANTIALIAS != 0
|
||||
|
||||
/**
|
||||
* Get the opacity of a pixel based it's position in a line segment
|
||||
* @param seg segment length
|
||||
* @param px_id position of of a pixel which opacity should be get [0..seg-1]
|
||||
* @param base_opa the base opacity
|
||||
* @return the opacity of the given pixel
|
||||
*/
|
||||
lv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa)
|
||||
{
|
||||
/* How to calculate the opacity of pixels on the edges which makes the anti-aliasing?
|
||||
* For example we have a line like this (y = -0.5 * x):
|
||||
*
|
||||
* | _ _
|
||||
* * * |
|
||||
*
|
||||
* Anti-aliased pixels come to the '*' characters
|
||||
* Calculate what percentage of the pixels should be covered if real line (not rasterized) would be drawn:
|
||||
* 1. A real line should start on (0;0) and end on (2;1)
|
||||
* 2. So the line intersection coordinates on the first pixel: (0;0) (1;0.5) -> 25% covered pixel in average
|
||||
* 3. For the second pixel: (1;0.5) (2;1) -> 75% covered pixel in average
|
||||
* 4. The equation: (px_id * 2 + 1) / (segment_width * 2)
|
||||
* segment_width: the line segment which is being anti-aliased (was 2 in the example)
|
||||
* px_id: pixel ID from 0 to (segment_width - 1)
|
||||
* result: [0..1] coverage of the pixel
|
||||
*/
|
||||
|
||||
/*Accelerate the common segment sizes to avoid division*/
|
||||
static const lv_opa_t seg1[1] = {128};
|
||||
static const lv_opa_t seg2[2] = {64, 192};
|
||||
static const lv_opa_t seg3[3] = {42, 128, 212};
|
||||
static const lv_opa_t seg4[4] = {32, 96, 159, 223};
|
||||
static const lv_opa_t seg5[5] = {26, 76, 128, 178, 230};
|
||||
static const lv_opa_t seg6[6] = {21, 64, 106, 148, 191, 234};
|
||||
static const lv_opa_t seg7[7] = {18, 55, 91, 128, 164, 200, 237};
|
||||
static const lv_opa_t seg8[8] = {16, 48, 80, 112, 143, 175, 207, 239};
|
||||
|
||||
static const lv_opa_t * seg_map[] = {seg1, seg2, seg3, seg4,
|
||||
seg5, seg6, seg7, seg8
|
||||
};
|
||||
|
||||
if(seg == 0) return LV_OPA_TRANSP;
|
||||
else if(seg < 8) return (uint32_t)((uint32_t)seg_map[seg - 1][px_id] * base_opa) >> 8;
|
||||
else {
|
||||
return ((px_id * 2 + 1) * base_opa) / (2 * seg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a vertical anti-aliasing segment (pixels with decreasing opacity)
|
||||
* @param x start point x coordinate
|
||||
* @param y start point y coordinate
|
||||
* @param length length of segment (negative value to start from 0 opacity)
|
||||
* @param mask draw only in this area
|
||||
* @param color color of pixels
|
||||
* @param opa maximum opacity
|
||||
*/
|
||||
void lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
bool aa_inv = false;
|
||||
if(length < 0) {
|
||||
aa_inv = true;
|
||||
length = -length;
|
||||
}
|
||||
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < length; i++) {
|
||||
lv_opa_t px_opa = lv_draw_aa_get_opa(length, i, opa);
|
||||
if(aa_inv) px_opa = opa - px_opa;
|
||||
lv_draw_px(x, y + i, mask, color, px_opa);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a horizontal anti-aliasing segment (pixels with decreasing opacity)
|
||||
* @param x start point x coordinate
|
||||
* @param y start point y coordinate
|
||||
* @param length length of segment (negative value to start from 0 opacity)
|
||||
* @param mask draw only in this area
|
||||
* @param color color of pixels
|
||||
* @param opa maximum opacity
|
||||
*/
|
||||
void lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
bool aa_inv = false;
|
||||
if(length < 0) {
|
||||
aa_inv = true;
|
||||
length = -length;
|
||||
}
|
||||
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < length; i++) {
|
||||
lv_opa_t px_opa = lv_draw_aa_get_opa(length, i, opa);
|
||||
if(aa_inv) px_opa = opa - px_opa;
|
||||
lv_draw_px(x + i, y, mask, color, px_opa);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
110
src/lv_draw/lv_draw.h
Normal file
110
src/lv_draw/lv_draw.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* @file lv_draw.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_H
|
||||
#define LV_DRAW_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include "../lv_core/lv_style.h"
|
||||
#include "../lv_misc/lv_txt.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
/*If image pixels contains alpha we need to know how much byte is a pixel*/
|
||||
#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
|
||||
# define LV_IMG_PX_SIZE_ALPHA_BYTE 2
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
# define LV_IMG_PX_SIZE_ALPHA_BYTE 3
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
# define LV_IMG_PX_SIZE_ALPHA_BYTE 4
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
enum {
|
||||
LV_IMG_SRC_VARIABLE,
|
||||
LV_IMG_SRC_FILE,
|
||||
LV_IMG_SRC_SYMBOL,
|
||||
LV_IMG_SRC_UNKNOWN,
|
||||
};
|
||||
typedef uint8_t lv_img_src_t;
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
#if LV_ANTIALIAS != 0
|
||||
|
||||
/**
|
||||
* Get the opacity of a pixel based it's position in a line segment
|
||||
* @param seg segment length
|
||||
* @param px_id position of of a pixel which opacity should be get [0..seg-1]
|
||||
* @param base_opa the base opacity
|
||||
* @return the opacity of the given pixel
|
||||
*/
|
||||
lv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa);
|
||||
|
||||
/**
|
||||
* Add a vertical anti-aliasing segment (pixels with decreasing opacity)
|
||||
* @param x start point x coordinate
|
||||
* @param y start point y coordinate
|
||||
* @param length length of segment (negative value to start from 0 opacity)
|
||||
* @param mask draw only in this area
|
||||
* @param color color of pixels
|
||||
* @param opa maximum opacity
|
||||
*/
|
||||
void lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);
|
||||
|
||||
/**
|
||||
* Add a horizontal anti-aliasing segment (pixels with decreasing opacity)
|
||||
* @param x start point x coordinate
|
||||
* @param y start point y coordinate
|
||||
* @param length length of segment (negative value to start from 0 opacity)
|
||||
* @param mask draw only in this area
|
||||
* @param color color of pixels
|
||||
* @param opa maximum opacity
|
||||
*/
|
||||
void lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* POST INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_basic.h"
|
||||
#include "lv_draw_rect.h"
|
||||
#include "lv_draw_label.h"
|
||||
#include "lv_draw_img.h"
|
||||
#include "lv_draw_line.h"
|
||||
#include "lv_draw_triangle.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_H*/
|
||||
13
src/lv_draw/lv_draw.mk
Normal file
13
src/lv_draw/lv_draw.mk
Normal file
@@ -0,0 +1,13 @@
|
||||
CSRCS += lv_draw_basic.c
|
||||
CSRCS += lv_draw.c
|
||||
CSRCS += lv_draw_rect.c
|
||||
CSRCS += lv_draw_label.c
|
||||
CSRCS += lv_draw_line.c
|
||||
CSRCS += lv_draw_img.c
|
||||
CSRCS += lv_draw_arc.c
|
||||
CSRCS += lv_draw_triangle.c
|
||||
|
||||
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/src/lv_draw
|
||||
VPATH += :$(LVGL_DIR)/lvgl/src/lv_draw
|
||||
|
||||
CFLAGS += "-I$(LVGL_DIR)lvgl/src/lv_draw"
|
||||
264
src/lv_draw/lv_draw_arc.c
Normal file
264
src/lv_draw/lv_draw_arc.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* @file lv_draw_arc.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_arc.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static uint16_t fast_atan2(int x, int y);
|
||||
static void ver_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa);
|
||||
static void hor_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa);
|
||||
static bool deg_test_norm(uint16_t deg, uint16_t start, uint16_t end);
|
||||
static bool deg_test_inv(uint16_t deg, uint16_t start, uint16_t end);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw an arc. (Can draw pie too with great thickness.)
|
||||
* @param center_x the x coordinate of the center of the arc
|
||||
* @param center_y the y coordinate of the center of the arc
|
||||
* @param radius the radius of the arc
|
||||
* @param mask the arc will be drawn only in this mask
|
||||
* @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right)
|
||||
* @param end_angle the end angle of the arc
|
||||
* @param style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used)
|
||||
* @param opa_scale scale down all opacities by the factor
|
||||
*/
|
||||
void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask,
|
||||
uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale)
|
||||
{
|
||||
lv_coord_t thickness = style->line.width;
|
||||
if(thickness > radius) thickness = radius;
|
||||
|
||||
lv_coord_t r_out = radius;
|
||||
lv_coord_t r_in = r_out - thickness;
|
||||
int16_t deg_base;
|
||||
int16_t deg;
|
||||
lv_coord_t x_start[4];
|
||||
lv_coord_t x_end[4];
|
||||
|
||||
lv_color_t color = style->line.color;
|
||||
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8;
|
||||
|
||||
|
||||
bool (*deg_test)(uint16_t, uint16_t, uint16_t);
|
||||
if(start_angle <= end_angle) deg_test = deg_test_norm;
|
||||
else deg_test = deg_test_inv;
|
||||
|
||||
if(deg_test(270, start_angle, end_angle)) hor_line(center_x - r_out + 1, center_y, mask, thickness - 1, color, opa); // Left Middle
|
||||
if(deg_test(90, start_angle, end_angle)) hor_line(center_x + r_in, center_y, mask, thickness - 1, color, opa); // Right Middle
|
||||
if(deg_test(180, start_angle, end_angle)) ver_line(center_x, center_y - r_out + 1, mask, thickness - 1, color, opa); // Top Middle
|
||||
if(deg_test(0, start_angle, end_angle)) ver_line(center_x, center_y + r_in, mask, thickness - 1, color, opa); // Bottom middle
|
||||
|
||||
uint32_t r_out_sqr = r_out * r_out;
|
||||
uint32_t r_in_sqr = r_in * r_in;
|
||||
int16_t xi;
|
||||
int16_t yi;
|
||||
for(yi = -r_out; yi < 0; yi++) {
|
||||
x_start[0] = LV_COORD_MIN;
|
||||
x_start[1] = LV_COORD_MIN;
|
||||
x_start[2] = LV_COORD_MIN;
|
||||
x_start[3] = LV_COORD_MIN;
|
||||
x_end[0] = LV_COORD_MIN;
|
||||
x_end[1] = LV_COORD_MIN;
|
||||
x_end[2] = LV_COORD_MIN;
|
||||
x_end[3] = LV_COORD_MIN;
|
||||
for(xi = -r_out; xi < 0; xi++) {
|
||||
|
||||
uint32_t r_act_sqr = xi * xi + yi * yi;
|
||||
if(r_act_sqr > r_out_sqr) continue;
|
||||
|
||||
deg_base = fast_atan2(xi, yi) - 180;
|
||||
|
||||
deg = 180 + deg_base;
|
||||
if(deg_test(deg, start_angle, end_angle)) {
|
||||
if(x_start[0] == LV_COORD_MIN) x_start[0] = xi;
|
||||
} else if(x_start[0] != LV_COORD_MIN && x_end[0] == LV_COORD_MIN) {
|
||||
x_end[0] = xi - 1;
|
||||
}
|
||||
|
||||
deg = 360 - deg_base;
|
||||
if(deg_test(deg, start_angle, end_angle)) {
|
||||
if(x_start[1] == LV_COORD_MIN) x_start[1] = xi;
|
||||
} else if(x_start[1] != LV_COORD_MIN && x_end[1] == LV_COORD_MIN) {
|
||||
x_end[1] = xi - 1;
|
||||
}
|
||||
|
||||
deg = 180 - deg_base;
|
||||
if(deg_test(deg, start_angle, end_angle)) {
|
||||
if(x_start[2] == LV_COORD_MIN) x_start[2] = xi;
|
||||
} else if(x_start[2] != LV_COORD_MIN && x_end[2] == LV_COORD_MIN) {
|
||||
x_end[2] = xi - 1;
|
||||
}
|
||||
|
||||
deg = deg_base;
|
||||
if(deg_test(deg, start_angle, end_angle)) {
|
||||
if(x_start[3] == LV_COORD_MIN) x_start[3] = xi;
|
||||
} else if(x_start[3] != LV_COORD_MIN && x_end[3] == LV_COORD_MIN) {
|
||||
x_end[3] = xi - 1;
|
||||
}
|
||||
|
||||
if(r_act_sqr < r_in_sqr) break; /*No need to continue the iteration in x once we found the inner edge of the arc*/
|
||||
}
|
||||
|
||||
|
||||
if(x_start[0] != LV_COORD_MIN) {
|
||||
if(x_end[0] == LV_COORD_MIN) x_end[0] = xi - 1;
|
||||
hor_line(center_x + x_start[0], center_y + yi, mask, x_end[0] - x_start[0], color, opa);
|
||||
}
|
||||
|
||||
if(x_start[1] != LV_COORD_MIN) {
|
||||
if(x_end[1] == LV_COORD_MIN) x_end[1] = xi - 1;
|
||||
hor_line(center_x + x_start[1], center_y - yi, mask, x_end[1] - x_start[1], color, opa);
|
||||
}
|
||||
|
||||
if(x_start[2] != LV_COORD_MIN) {
|
||||
if(x_end[2] == LV_COORD_MIN) x_end[2] = xi - 1;
|
||||
hor_line(center_x - x_end[2], center_y + yi, mask, LV_MATH_ABS(x_end[2] - x_start[2]), color, opa);
|
||||
}
|
||||
|
||||
if(x_start[3] != LV_COORD_MIN) {
|
||||
if(x_end[3] == LV_COORD_MIN) x_end[3] = xi - 1;
|
||||
hor_line(center_x - x_end[3], center_y - yi, mask, LV_MATH_ABS(x_end[3] - x_start[3]), color, opa);
|
||||
}
|
||||
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
/*TODO*/
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t fast_atan2(int x, int y)
|
||||
{
|
||||
// Fast XY vector to integer degree algorithm - Jan 2011 www.RomanBlack.com
|
||||
// Converts any XY values including 0 to a degree value that should be
|
||||
// within +/- 1 degree of the accurate value without needing
|
||||
// large slow trig functions like ArcTan() or ArcCos().
|
||||
// NOTE! at least one of the X or Y values must be non-zero!
|
||||
// This is the full version, for all 4 quadrants and will generate
|
||||
// the angle in integer degrees from 0-360.
|
||||
// Any values of X and Y are usable including negative values provided
|
||||
// they are between -1456 and 1456 so the 16bit multiply does not overflow.
|
||||
|
||||
unsigned char negflag;
|
||||
unsigned char tempdegree;
|
||||
unsigned char comp;
|
||||
unsigned int degree; // this will hold the result
|
||||
//signed int x; // these hold the XY vector at the start
|
||||
//signed int y; // (and they will be destroyed)
|
||||
unsigned int ux;
|
||||
unsigned int uy;
|
||||
|
||||
// Save the sign flags then remove signs and get XY as unsigned ints
|
||||
negflag = 0;
|
||||
if(x < 0) {
|
||||
negflag += 0x01; // x flag bit
|
||||
x = (0 - x); // is now +
|
||||
}
|
||||
ux = x; // copy to unsigned var before multiply
|
||||
if(y < 0) {
|
||||
negflag += 0x02; // y flag bit
|
||||
y = (0 - y); // is now +
|
||||
}
|
||||
uy = y; // copy to unsigned var before multiply
|
||||
|
||||
// 1. Calc the scaled "degrees"
|
||||
if(ux > uy) {
|
||||
degree = (uy * 45) / ux; // degree result will be 0-45 range
|
||||
negflag += 0x10; // octant flag bit
|
||||
} else {
|
||||
degree = (ux * 45) / uy; // degree result will be 0-45 range
|
||||
}
|
||||
|
||||
// 2. Compensate for the 4 degree error curve
|
||||
comp = 0;
|
||||
tempdegree = degree; // use an unsigned char for speed!
|
||||
if(tempdegree > 22) { // if top half of range
|
||||
if(tempdegree <= 44) comp++;
|
||||
if(tempdegree <= 41) comp++;
|
||||
if(tempdegree <= 37) comp++;
|
||||
if(tempdegree <= 32) comp++; // max is 4 degrees compensated
|
||||
} else { // else is lower half of range
|
||||
if(tempdegree >= 2) comp++;
|
||||
if(tempdegree >= 6) comp++;
|
||||
if(tempdegree >= 10) comp++;
|
||||
if(tempdegree >= 15) comp++; // max is 4 degrees compensated
|
||||
}
|
||||
degree += comp; // degree is now accurate to +/- 1 degree!
|
||||
|
||||
// Invert degree if it was X>Y octant, makes 0-45 into 90-45
|
||||
if(negflag & 0x10) degree = (90 - degree);
|
||||
|
||||
// 3. Degree is now 0-90 range for this quadrant,
|
||||
// need to invert it for whichever quadrant it was in
|
||||
if(negflag & 0x02) { // if -Y
|
||||
if(negflag & 0x01) // if -Y -X
|
||||
degree = (180 + degree);
|
||||
else // else is -Y +X
|
||||
degree = (180 - degree);
|
||||
} else { // else is +Y
|
||||
if(negflag & 0x01) // if +Y -X
|
||||
degree = (360 - degree);
|
||||
}
|
||||
return degree;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
static void ver_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
lv_area_t area;
|
||||
lv_area_set(&area, x, y, x, y + len);
|
||||
|
||||
lv_draw_fill(&area, mask, color, opa);
|
||||
}
|
||||
|
||||
static void hor_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
lv_area_t area;
|
||||
lv_area_set(&area, x, y, x + len, y);
|
||||
|
||||
lv_draw_fill(&area, mask, color, opa);
|
||||
}
|
||||
|
||||
static bool deg_test_norm(uint16_t deg, uint16_t start, uint16_t end)
|
||||
{
|
||||
if(deg >= start && deg <= end) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
static bool deg_test_inv(uint16_t deg, uint16_t start, uint16_t end)
|
||||
{
|
||||
if(deg >= start || deg <= end) {
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
53
src/lv_draw/lv_draw_arc.h
Normal file
53
src/lv_draw/lv_draw_arc.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @file lv_draw_arc.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_ARC_H
|
||||
#define LV_DRAW_ARC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw an arc. (Can draw pie too with great thickness.)
|
||||
* @param center_x the x coordinate of the center of the arc
|
||||
* @param center_y the y coordinate of the center of the arc
|
||||
* @param radius the radius of the arc
|
||||
* @param mask the arc will be drawn only in this mask
|
||||
* @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right)
|
||||
* @param end_angle the end angle of the arc
|
||||
* @param style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used)
|
||||
* @param opa_scale scale down all opacities by the factor
|
||||
*/
|
||||
void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask,
|
||||
uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_ARC*/
|
||||
675
src/lv_draw/lv_draw_basic.c
Normal file
675
src/lv_draw/lv_draw_basic.c
Normal file
@@ -0,0 +1,675 @@
|
||||
/**
|
||||
* @file lv_draw_basic.c
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lv_draw_basic.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../lv_core/lv_refr.h"
|
||||
#include "../lv_hal/lv_hal.h"
|
||||
#include "../lv_misc/lv_area.h"
|
||||
#include "../lv_misc/lv_font.h"
|
||||
#include "../lv_misc/lv_color.h"
|
||||
#include "../lv_misc/lv_log.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include "lv_draw.h"
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define VFILL_HW_ACC_SIZE_LIMIT 50 /*Always fill < 50 px with 'sw_color_fill' because of the hw. init overhead*/
|
||||
|
||||
#ifndef LV_ATTRIBUTE_MEM_ALIGN
|
||||
#define LV_ATTRIBUTE_MEM_ALIGN
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);
|
||||
static void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa);
|
||||
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
static inline lv_color_t color_mix_2_alpha(lv_color_t bg_color, lv_opa_t bg_opa, lv_color_t fg_color, lv_opa_t fg_opa);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Put a pixel in the Virtual Display Buffer
|
||||
* @param x pixel x coordinate
|
||||
* @param y pixel y coordinate
|
||||
* @param mask_p fill only on this mask (truncated to VDB area)
|
||||
* @param color pixel color
|
||||
* @param opa opacity of the area (0..255)
|
||||
*/
|
||||
void lv_draw_px(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
if(opa < LV_OPA_MIN) return;
|
||||
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
|
||||
|
||||
|
||||
/*Pixel out of the mask*/
|
||||
if(x < mask_p->x1 || x > mask_p->x2 ||
|
||||
y < mask_p->y1 || y > mask_p->y2) {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_disp_t * disp = lv_refr_get_disp_refreshing();
|
||||
lv_disp_buf_t * vdb = lv_disp_get_buf(disp);
|
||||
uint32_t vdb_width = lv_area_get_width(&vdb->area);
|
||||
|
||||
/*Make the coordinates relative to VDB*/
|
||||
x -= vdb->area.x1;
|
||||
y -= vdb->area.y1;
|
||||
|
||||
if(disp->driver.set_px_cb) {
|
||||
disp->driver.set_px_cb(&disp->driver, (uint8_t *)vdb->buf_act, vdb_width, x, y, color, opa);
|
||||
} else {
|
||||
lv_color_t * vdb_px_p = vdb->buf_act;
|
||||
vdb_px_p += y * vdb_width + x;
|
||||
#if LV_COLOR_SCREEN_TRANSP == 0
|
||||
if(opa == LV_OPA_COVER) {
|
||||
*vdb_px_p = color;
|
||||
} else {
|
||||
*vdb_px_p = lv_color_mix(color, *vdb_px_p, opa);
|
||||
}
|
||||
#else
|
||||
*vdb_px_p = color_mix_2_alpha(*vdb_px_p, (*vdb_px_p).alpha, color, opa);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fill an area in the Virtual Display Buffer
|
||||
* @param cords_p coordinates of the area to fill
|
||||
* @param mask_p fill only o this mask (truncated to VDB area)
|
||||
* @param color fill color
|
||||
* @param opa opacity of the area (0..255)
|
||||
*/
|
||||
void lv_draw_fill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
if(opa < LV_OPA_MIN) return;
|
||||
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
|
||||
|
||||
lv_area_t res_a;
|
||||
bool union_ok;
|
||||
|
||||
/*Get the union of cord and mask*/
|
||||
/* The mask is already truncated to the vdb size
|
||||
* in 'lv_refr_area_with_vdb' function */
|
||||
union_ok = lv_area_intersect(&res_a, cords_p, mask_p);
|
||||
|
||||
/*If there are common part of the three area then draw to the vdb*/
|
||||
if(union_ok == false) return;
|
||||
|
||||
lv_disp_t * disp = lv_refr_get_disp_refreshing();
|
||||
lv_disp_buf_t * vdb = lv_disp_get_buf(disp);
|
||||
|
||||
lv_area_t vdb_rel_a; /*Stores relative coordinates on vdb*/
|
||||
vdb_rel_a.x1 = res_a.x1 - vdb->area.x1;
|
||||
vdb_rel_a.y1 = res_a.y1 - vdb->area.y1;
|
||||
vdb_rel_a.x2 = res_a.x2 - vdb->area.x1;
|
||||
vdb_rel_a.y2 = res_a.y2 - vdb->area.y1;
|
||||
|
||||
lv_color_t * vdb_buf_tmp = vdb->buf_act;
|
||||
uint32_t vdb_width = lv_area_get_width(&vdb->area);
|
||||
/*Move the vdb_tmp to the first row*/
|
||||
vdb_buf_tmp += vdb_width * vdb_rel_a.y1;
|
||||
|
||||
|
||||
#if LV_USE_GPU
|
||||
static LV_ATTRIBUTE_MEM_ALIGN lv_color_t color_array_tmp[LV_HOR_RES_MAX]; /*Used by 'lv_disp_mem_blend'*/
|
||||
static lv_coord_t last_width = -1;
|
||||
|
||||
lv_coord_t w = lv_area_get_width(&vdb_rel_a);
|
||||
/*Don't use hw. acc. for every small fill (because of the init overhead)*/
|
||||
if(w < VFILL_HW_ACC_SIZE_LIMIT) {
|
||||
sw_color_fill(&vdb->area, vdb->buf_act, &vdb_rel_a, color, opa);
|
||||
}
|
||||
/*Not opaque fill*/
|
||||
else if(opa == LV_OPA_COVER) {
|
||||
/*Use hw fill if present*/
|
||||
if(disp->driver.mem_fill) {
|
||||
lv_coord_t row;
|
||||
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
|
||||
disp->driver.mem_fill(&vdb_buf_tmp[vdb_rel_a.x1], w, color);
|
||||
vdb_buf_tmp += vdb_width;
|
||||
}
|
||||
}
|
||||
/*Use hw blend if present and the area is not too small*/
|
||||
else if(lv_area_get_height(&vdb_rel_a) > VFILL_HW_ACC_SIZE_LIMIT &&
|
||||
disp->driver.mem_blend) {
|
||||
/*Fill a one line sized buffer with a color and blend this later*/
|
||||
if(color_array_tmp[0].full != color.full || last_width != w) {
|
||||
uint16_t i;
|
||||
for(i = 0; i < w; i++) {
|
||||
color_array_tmp[i].full = color.full;
|
||||
}
|
||||
last_width = w;
|
||||
}
|
||||
|
||||
/*Blend the filled line to every line VDB line-by-line*/
|
||||
lv_coord_t row;
|
||||
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
|
||||
disp->driver.mem_blend(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa);
|
||||
vdb_buf_tmp += vdb_width;
|
||||
}
|
||||
|
||||
}
|
||||
/*Else use sw fill if no better option*/
|
||||
else {
|
||||
sw_color_fill(&vdb->area, vdb->buf_act, &vdb_rel_a, color, opa);
|
||||
}
|
||||
|
||||
}
|
||||
/*Fill with opacity*/
|
||||
else {
|
||||
/*Use hw blend if present*/
|
||||
if(disp->driver.mem_blend) {
|
||||
if(color_array_tmp[0].full != color.full || last_width != w) {
|
||||
uint16_t i;
|
||||
for(i = 0; i < w; i++) {
|
||||
color_array_tmp[i].full = color.full;
|
||||
}
|
||||
|
||||
last_width = w;
|
||||
}
|
||||
lv_coord_t row;
|
||||
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
|
||||
disp->driver.mem_blend(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa);
|
||||
vdb_buf_tmp += vdb_width;
|
||||
}
|
||||
|
||||
}
|
||||
/*Use sw fill with opa if no better option*/
|
||||
else {
|
||||
sw_color_fill(&vdb->area, vdb->buf_act, &vdb_rel_a, color, opa);
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
sw_color_fill(&vdb->area, vdb->buf_act, &vdb_rel_a, color, opa);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a letter in the Virtual Display Buffer
|
||||
* @param pos_p left-top coordinate of the latter
|
||||
* @param mask_p the letter will be drawn only on this area (truncated to VDB area)
|
||||
* @param font_p pointer to font
|
||||
* @param letter a letter to draw
|
||||
* @param color color of letter
|
||||
* @param opa opacity of letter (0..255)
|
||||
*/
|
||||
void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p,
|
||||
const lv_font_t * font_p, uint32_t letter,
|
||||
lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
const uint8_t bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
|
||||
const uint8_t bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
|
||||
const uint8_t bpp4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
|
||||
68, 85, 102, 119,
|
||||
136, 153, 170, 187,
|
||||
204, 221, 238, 255
|
||||
};
|
||||
if(opa < LV_OPA_MIN) return;
|
||||
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
|
||||
|
||||
if(font_p == NULL) {
|
||||
LV_LOG_WARN("Font: character's bitmap not found");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_coord_t pos_x = pos_p->x;
|
||||
lv_coord_t pos_y = pos_p->y;
|
||||
uint8_t letter_w = lv_font_get_real_width(font_p, letter);
|
||||
uint8_t letter_h = lv_font_get_height(font_p);
|
||||
uint8_t bpp = lv_font_get_bpp(font_p, letter); /*Bit per pixel (1,2, 4 or 8)*/
|
||||
const uint8_t * bpp_opa_table;
|
||||
uint8_t mask_init;
|
||||
uint8_t mask;
|
||||
|
||||
if(lv_font_is_monospace(font_p, letter)) {
|
||||
pos_x += (lv_font_get_width(font_p, letter) - letter_w) / 2;
|
||||
}
|
||||
|
||||
|
||||
switch(bpp) {
|
||||
case 1:
|
||||
bpp_opa_table = bpp1_opa_table;
|
||||
mask_init = 0x80;
|
||||
break;
|
||||
case 2:
|
||||
bpp_opa_table = bpp2_opa_table;
|
||||
mask_init = 0xC0;
|
||||
break;
|
||||
case 4:
|
||||
bpp_opa_table = bpp4_opa_table;
|
||||
mask_init = 0xF0;
|
||||
break;
|
||||
case 8:
|
||||
bpp_opa_table = NULL;
|
||||
mask_init = 0xFF;
|
||||
break; /*No opa table, pixel value will be used directly*/
|
||||
default:
|
||||
return; /*Invalid bpp. Can't render the letter*/
|
||||
}
|
||||
|
||||
const uint8_t * map_p = lv_font_get_bitmap(font_p, letter);
|
||||
|
||||
if(map_p == NULL) return;
|
||||
|
||||
/*If the letter is completely out of mask don't draw it */
|
||||
if(pos_x + letter_w < mask_p->x1 || pos_x > mask_p->x2 ||
|
||||
pos_y + letter_h < mask_p->y1 || pos_y > mask_p->y2) return;
|
||||
|
||||
lv_disp_t * disp = lv_refr_get_disp_refreshing();
|
||||
lv_disp_buf_t * vdb = lv_disp_get_buf(disp);
|
||||
|
||||
lv_coord_t vdb_width = lv_area_get_width(&vdb->area);
|
||||
lv_color_t * vdb_buf_tmp = vdb->buf_act;
|
||||
lv_coord_t col, row;
|
||||
uint8_t col_bit;
|
||||
uint8_t col_byte_cnt;
|
||||
uint8_t width_byte_scr = letter_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/
|
||||
if(letter_w & 0x7) width_byte_scr++;
|
||||
uint8_t width_byte_bpp = (letter_w * bpp) >> 3; /*Letter width in byte. Real width in the font*/
|
||||
if((letter_w * bpp) & 0x7) width_byte_bpp++;
|
||||
|
||||
/* Calculate the col/row start/end on the map*/
|
||||
lv_coord_t col_start = pos_x >= mask_p->x1 ? 0 : mask_p->x1 - pos_x;
|
||||
lv_coord_t col_end = pos_x + letter_w <= mask_p->x2 ? letter_w : mask_p->x2 - pos_x + 1;
|
||||
lv_coord_t row_start = pos_y >= mask_p->y1 ? 0 : mask_p->y1 - pos_y;
|
||||
lv_coord_t row_end = pos_y + letter_h <= mask_p->y2 ? letter_h : mask_p->y2 - pos_y + 1;
|
||||
|
||||
/*Set a pointer on VDB to the first pixel of the letter*/
|
||||
vdb_buf_tmp += ((pos_y - vdb->area.y1) * vdb_width)
|
||||
+ pos_x - vdb->area.x1;
|
||||
|
||||
/*If the letter is partially out of mask the move there on VDB*/
|
||||
vdb_buf_tmp += (row_start * vdb_width) + col_start;
|
||||
|
||||
/*Move on the map too*/
|
||||
map_p += (row_start * width_byte_bpp) + ((col_start * bpp) >> 3);
|
||||
|
||||
uint8_t letter_px;
|
||||
lv_opa_t px_opa;
|
||||
for(row = row_start; row < row_end; row ++) {
|
||||
col_byte_cnt = 0;
|
||||
col_bit = (col_start * bpp) % 8;
|
||||
mask = mask_init >> col_bit;
|
||||
for(col = col_start; col < col_end; col ++) {
|
||||
letter_px = (*map_p & mask) >> (8 - col_bit - bpp);
|
||||
if(letter_px != 0) {
|
||||
if(opa == LV_OPA_COVER) {
|
||||
px_opa = bpp == 8 ? letter_px : bpp_opa_table[letter_px];
|
||||
} else {
|
||||
px_opa = bpp == 8 ?
|
||||
(uint16_t)((uint16_t)letter_px * opa) >> 8 :
|
||||
(uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8;
|
||||
}
|
||||
|
||||
if(disp->driver.set_px_cb) {
|
||||
disp->driver.set_px_cb(&disp->driver, (uint8_t *)vdb->buf_act, vdb_width,
|
||||
(col + pos_x) - vdb->area.x1, (row + pos_y) - vdb->area.y1,
|
||||
color, px_opa);
|
||||
} else {
|
||||
#if LV_COLOR_SCREEN_TRANSP == 0
|
||||
*vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, px_opa);
|
||||
#else
|
||||
*vdb_buf_tmp = color_mix_2_alpha(*vdb_buf_tmp, (*vdb_buf_tmp).alpha, color, px_opa);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
vdb_buf_tmp++;
|
||||
|
||||
if(col_bit < 8 - bpp) {
|
||||
col_bit += bpp;
|
||||
mask = mask >> bpp;
|
||||
} else {
|
||||
col_bit = 0;
|
||||
col_byte_cnt ++;
|
||||
mask = mask_init;
|
||||
map_p ++;
|
||||
}
|
||||
}
|
||||
|
||||
map_p += (width_byte_bpp) - col_byte_cnt;
|
||||
vdb_buf_tmp += vdb_width - (col_end - col_start); /*Next row in VDB*/
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a color map to the display (image)
|
||||
* @param cords_p coordinates the color map
|
||||
* @param mask_p the map will drawn only on this area (truncated to VDB area)
|
||||
* @param map_p pointer to a lv_color_t array
|
||||
* @param opa opacity of the map
|
||||
* @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels
|
||||
* @param alpha_byte true: extra alpha byte is inserted for every pixel
|
||||
* @param recolor mix the pixels with this color
|
||||
* @param recolor_opa the intense of recoloring
|
||||
*/
|
||||
void lv_draw_map(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,
|
||||
lv_color_t recolor, lv_opa_t recolor_opa)
|
||||
{
|
||||
|
||||
if(opa < LV_OPA_MIN) return;
|
||||
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
|
||||
|
||||
lv_area_t masked_a;
|
||||
bool union_ok;
|
||||
|
||||
/*Get the union of map size and mask*/
|
||||
/* The mask is already truncated to the vdb size
|
||||
* in 'lv_refr_area_with_vdb' function */
|
||||
union_ok = lv_area_intersect(&masked_a, cords_p, mask_p);
|
||||
|
||||
/*If there are common part of the three area then draw to the vdb*/
|
||||
if(union_ok == false) return;
|
||||
|
||||
/*The pixel size in byte is different if an alpha byte is added too*/
|
||||
uint8_t px_size_byte = alpha_byte ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t);
|
||||
|
||||
/*If the map starts OUT of the masked area then calc. the first pixel*/
|
||||
lv_coord_t map_width = lv_area_get_width(cords_p);
|
||||
if(cords_p->y1 < masked_a.y1) {
|
||||
map_p += (uint32_t) map_width * ((masked_a.y1 - cords_p->y1)) * px_size_byte;
|
||||
}
|
||||
if(cords_p->x1 < masked_a.x1) {
|
||||
map_p += (masked_a.x1 - cords_p->x1) * px_size_byte;
|
||||
}
|
||||
|
||||
lv_disp_t * disp = lv_refr_get_disp_refreshing();
|
||||
lv_disp_buf_t * vdb = lv_disp_get_buf(disp);
|
||||
|
||||
/*Stores coordinates relative to the current VDB*/
|
||||
masked_a.x1 = masked_a.x1 - vdb->area.x1;
|
||||
masked_a.y1 = masked_a.y1 - vdb->area.y1;
|
||||
masked_a.x2 = masked_a.x2 - vdb->area.x1;
|
||||
masked_a.y2 = masked_a.y2 - vdb->area.y1;
|
||||
|
||||
lv_coord_t vdb_width = lv_area_get_width(&vdb->area);
|
||||
lv_color_t * vdb_buf_tmp = vdb->buf_act;
|
||||
vdb_buf_tmp += (uint32_t) vdb_width * masked_a.y1; /*Move to the first row*/
|
||||
vdb_buf_tmp += (uint32_t) masked_a.x1; /*Move to the first col*/
|
||||
|
||||
lv_coord_t row;
|
||||
lv_coord_t map_useful_w = lv_area_get_width(&masked_a);
|
||||
|
||||
/*The simplest case just copy the pixels into the VDB*/
|
||||
if(chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && recolor_opa == LV_OPA_TRANSP) {
|
||||
|
||||
/*Use the custom VDB write function is exists*/
|
||||
if(disp->driver.set_px_cb) {
|
||||
lv_coord_t col;
|
||||
for(row = masked_a.y1; row <= masked_a.y2; row++) {
|
||||
for(col = 0; col < map_useful_w; col++) {
|
||||
lv_color_t px_color = *((lv_color_t *)&map_p[(uint32_t)col * px_size_byte]);
|
||||
disp->driver.set_px_cb(&disp->driver, (uint8_t *)vdb->buf_act, vdb_width, col + masked_a.x1, row, px_color, opa);
|
||||
}
|
||||
map_p += map_width * px_size_byte; /*Next row on the map*/
|
||||
}
|
||||
}
|
||||
/*Normal native VDB*/
|
||||
else {
|
||||
for(row = masked_a.y1; row <= masked_a.y2; row++) {
|
||||
#if LV_USE_GPU
|
||||
if(disp->driver.mem_blend == false) {
|
||||
sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
|
||||
} else {
|
||||
disp->driver.mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
|
||||
}
|
||||
#else
|
||||
sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
|
||||
#endif
|
||||
map_p += map_width * px_size_byte; /*Next row on the map*/
|
||||
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*In the other cases every pixel need to be checked one-by-one*/
|
||||
else {
|
||||
lv_color_t chroma_key_color = LV_COLOR_TRANSP;
|
||||
lv_coord_t col;
|
||||
lv_color_t last_img_px = LV_COLOR_BLACK;
|
||||
lv_color_t recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa);
|
||||
for(row = masked_a.y1; row <= masked_a.y2; row++) {
|
||||
for(col = 0; col < map_useful_w; col++) {
|
||||
lv_opa_t opa_result = opa;
|
||||
uint8_t * px_color_p = (uint8_t *) &map_p[(uint32_t)col * px_size_byte];
|
||||
lv_color_t px_color;
|
||||
|
||||
/*Calculate with the pixel level alpha*/
|
||||
if(alpha_byte) {
|
||||
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
|
||||
px_color.full = px_color_p[0];
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
/*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
|
||||
px_color.full = px_color_p[0] + (px_color_p[1] << 8);
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
px_color = *((lv_color_t *)px_color_p);
|
||||
#endif
|
||||
lv_opa_t px_opa = *(px_color_p + LV_IMG_PX_SIZE_ALPHA_BYTE - 1);
|
||||
if(px_opa == LV_OPA_TRANSP) continue;
|
||||
else if(px_opa != LV_OPA_COVER) opa_result = (uint32_t)((uint32_t)px_opa * opa_result) >> 8;
|
||||
} else {
|
||||
px_color = *((lv_color_t *)px_color_p);
|
||||
}
|
||||
|
||||
/*Handle chroma key*/
|
||||
if(chroma_key && px_color.full == chroma_key_color.full) continue;
|
||||
|
||||
/*Re-color the pixel if required*/
|
||||
if(recolor_opa != LV_OPA_TRANSP) {
|
||||
if(last_img_px.full != px_color.full) { /*Minor acceleration: calculate only for new colors (save the last)*/
|
||||
last_img_px = px_color;
|
||||
recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa);
|
||||
}
|
||||
/*Handle custom VDB write is present*/
|
||||
if(disp->driver.set_px_cb) {
|
||||
disp->driver.set_px_cb(&disp->driver, (uint8_t *)vdb->buf_act, vdb_width, col + masked_a.x1, row, recolored_px, opa_result);
|
||||
}
|
||||
/*Normal native VDB write*/
|
||||
else {
|
||||
if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col].full = recolored_px.full;
|
||||
else vdb_buf_tmp[col] = lv_color_mix(recolored_px, vdb_buf_tmp[col], opa_result);
|
||||
}
|
||||
} else {
|
||||
/*Handle custom VDB write is present*/
|
||||
if(disp->driver.set_px_cb) {
|
||||
disp->driver.set_px_cb(&disp->driver, (uint8_t *)vdb->buf_act, vdb_width, col + masked_a.x1, row, px_color, opa_result);
|
||||
}
|
||||
/*Normal native VDB write*/
|
||||
else {
|
||||
if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col] = px_color;
|
||||
else {
|
||||
#if LV_COLOR_SCREEN_TRANSP == 0
|
||||
vdb_buf_tmp[col] = lv_color_mix(px_color, vdb_buf_tmp[col], opa_result);
|
||||
#else
|
||||
vdb_buf_tmp[col] = color_mix_2_alpha(vdb_buf_tmp[col], vdb_buf_tmp[col].alpha, px_color, opa_result);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map_p += map_width * px_size_byte; /*Next row on the map*/
|
||||
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Blend pixels to destination memory using opacity
|
||||
* @param dest a memory address. Copy 'src' here.
|
||||
* @param src pointer to pixel map. Copy it to 'dest'.
|
||||
* @param length number of pixels in 'src'
|
||||
* @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover)
|
||||
*/
|
||||
static void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa)
|
||||
{
|
||||
if(opa == LV_OPA_COVER) {
|
||||
memcpy(dest, src, length * sizeof(lv_color_t));
|
||||
} else {
|
||||
uint32_t col;
|
||||
for(col = 0; col < length; col++) {
|
||||
dest[col] = lv_color_mix(src[col], dest[col], opa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mem_area coordinates of 'mem' memory area
|
||||
* @param mem a memory address. Considered to a rectangular window according to 'mem_area'
|
||||
* @param fill_area coordinates of an area to fill. Relative to 'mem_area'.
|
||||
* @param color fill color
|
||||
* @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover)
|
||||
*/
|
||||
static void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
/*Set all row in vdb to the given color*/
|
||||
lv_coord_t row;
|
||||
lv_coord_t col;
|
||||
lv_coord_t mem_width = lv_area_get_width(mem_area);
|
||||
|
||||
lv_disp_t * disp = lv_refr_get_disp_refreshing();
|
||||
if(disp->driver.set_px_cb) {
|
||||
for(col = fill_area->x1; col <= fill_area->x2; col++) {
|
||||
for(row = fill_area->y1; row <= fill_area->y2; row++) {
|
||||
disp->driver.set_px_cb(&disp->driver, (uint8_t *)mem, mem_width, col, row, color, opa);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mem += fill_area->y1 * mem_width; /*Go to the first row*/
|
||||
|
||||
/*Run simpler function without opacity*/
|
||||
if(opa == LV_OPA_COVER) {
|
||||
|
||||
/*Fill the first row with 'color'*/
|
||||
for(col = fill_area->x1; col <= fill_area->x2; col++) {
|
||||
mem[col] = color;
|
||||
}
|
||||
|
||||
/*Copy the first row to all other rows*/
|
||||
lv_color_t * mem_first = &mem[fill_area->x1];
|
||||
lv_coord_t copy_size = (fill_area->x2 - fill_area->x1 + 1) * sizeof(lv_color_t);
|
||||
mem += mem_width;
|
||||
|
||||
for(row = fill_area->y1 + 1; row <= fill_area->y2; row++) {
|
||||
memcpy(&mem[fill_area->x1], mem_first, copy_size);
|
||||
mem += mem_width;
|
||||
}
|
||||
}
|
||||
/*Calculate with alpha too*/
|
||||
else {
|
||||
|
||||
#if LV_COLOR_SCREEN_TRANSP == 0
|
||||
lv_color_t bg_tmp = LV_COLOR_BLACK;
|
||||
lv_color_t opa_tmp = lv_color_mix(color, bg_tmp, opa);
|
||||
#endif
|
||||
for(row = fill_area->y1; row <= fill_area->y2; row++) {
|
||||
for(col = fill_area->x1; col <= fill_area->x2; col++) {
|
||||
#if LV_COLOR_SCREEN_TRANSP == 0
|
||||
/*If the bg color changed recalculate the result color*/
|
||||
if(mem[col].full != bg_tmp.full) {
|
||||
bg_tmp = mem[col];
|
||||
opa_tmp = lv_color_mix(color, bg_tmp, opa);
|
||||
}
|
||||
|
||||
mem[col] = opa_tmp;
|
||||
|
||||
#else
|
||||
mem[col] = color_mix_2_alpha(mem[col], mem[col].alpha, color, opa);
|
||||
#endif
|
||||
}
|
||||
mem += mem_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
|
||||
/**
|
||||
* Mix two colors. Both color can have alpha value. It requires ARGB888 colors.
|
||||
* @param bg_color background color
|
||||
* @param bg_opa alpha of the background color
|
||||
* @param fg_color foreground color
|
||||
* @param fg_opa alpha of the foreground color
|
||||
* @return the mixed color. the alpha channel (color.alpha) contains the result alpha
|
||||
*/
|
||||
static inline lv_color_t color_mix_2_alpha(lv_color_t bg_color, lv_opa_t bg_opa, lv_color_t fg_color, lv_opa_t fg_opa)
|
||||
{
|
||||
/* Pick the foreground if it's fully opaque or the Background is fully transparent*/
|
||||
if(fg_opa == LV_OPA_COVER && bg_opa <= LV_OPA_MIN) {
|
||||
fg_color.alpha = fg_opa;
|
||||
return fg_color;
|
||||
}
|
||||
/*Transparent foreground: use the Background*/
|
||||
else if(fg_opa <= LV_OPA_MIN) {
|
||||
return bg_color;
|
||||
}
|
||||
/*Opaque background: use simple mix*/
|
||||
else if(bg_opa >= LV_OPA_MAX) {
|
||||
return lv_color_mix(fg_color, bg_color, fg_opa);
|
||||
}
|
||||
/*Both colors have alpha. Expensive calculation need to be applied*/
|
||||
else {
|
||||
/*Save the parameters and the result. If they will be asked again don't compute again*/
|
||||
static lv_opa_t fg_opa_save = 0;
|
||||
static lv_opa_t bg_opa_save = 0;
|
||||
static lv_color_t c = {{0}};
|
||||
|
||||
if(fg_opa != fg_opa_save || bg_opa != bg_opa_save) {
|
||||
fg_opa_save = fg_opa;
|
||||
bg_opa_save = bg_opa;
|
||||
/*Info: https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator*/
|
||||
lv_opa_t alpha_res = 255 - ((uint16_t)((uint16_t)(255 - fg_opa) * (255 - bg_opa)) >> 8);
|
||||
if(alpha_res == 0) {
|
||||
while(1);
|
||||
}
|
||||
lv_opa_t ratio = (uint16_t)((uint16_t) fg_opa * 255) / alpha_res;
|
||||
c = lv_color_mix(fg_color, bg_color, ratio);
|
||||
c.alpha = alpha_res;
|
||||
}
|
||||
return c;
|
||||
|
||||
}
|
||||
}
|
||||
#endif /*LV_COLOR_SCREEN_TRANSP*/
|
||||
|
||||
85
src/lv_draw/lv_draw_basic.h
Normal file
85
src/lv_draw/lv_draw_basic.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @file lv_draw_basic.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_BASIC_H
|
||||
#define LV_DRAW_BASIC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include "../lv_misc/lv_color.h"
|
||||
#include "../lv_misc/lv_area.h"
|
||||
#include "../lv_misc/lv_font.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_px(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa);
|
||||
/**
|
||||
* Fill an area in the Virtual Display Buffer
|
||||
* @param cords_p coordinates of the area to fill
|
||||
* @param mask_p fill only o this mask
|
||||
* @param color fill color
|
||||
* @param opa opacity of the area (0..255)
|
||||
*/
|
||||
void lv_draw_fill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
lv_color_t color, lv_opa_t opa);
|
||||
|
||||
/**
|
||||
* Draw a letter in the Virtual Display Buffer
|
||||
* @param pos_p left-top coordinate of the latter
|
||||
* @param mask_p the letter will be drawn only on this area
|
||||
* @param font_p pointer to font
|
||||
* @param letter a letter to draw
|
||||
* @param color color of letter
|
||||
* @param opa opacity of letter (0..255)
|
||||
*/
|
||||
void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p,
|
||||
const lv_font_t * font_p, uint32_t letter,
|
||||
lv_color_t color, lv_opa_t opa);
|
||||
|
||||
/**
|
||||
* Draw a color map to the display (image)
|
||||
* @param cords_p coordinates the color map
|
||||
* @param mask_p the map will drawn only on this area (truncated to VDB area)
|
||||
* @param map_p pointer to a lv_color_t array
|
||||
* @param opa opacity of the map
|
||||
* @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels
|
||||
* @param alpha_byte true: extra alpha byte is inserted for every pixel
|
||||
* @param recolor mix the pixels with this color
|
||||
* @param recolor_opa the intense of recoloring
|
||||
*/
|
||||
void lv_draw_map(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,
|
||||
lv_color_t recolor, lv_opa_t recolor_opa);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_BASIC_H*/
|
||||
759
src/lv_draw/lv_draw_img.c
Normal file
759
src/lv_draw/lv_draw_img.c
Normal file
@@ -0,0 +1,759 @@
|
||||
/**
|
||||
* @file lv_draw_img.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_img.h"
|
||||
#include "../lv_misc/lv_fs.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask,
|
||||
const void * src, const lv_style_t * style, lv_opa_t opa_scale);
|
||||
|
||||
static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style);
|
||||
static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
|
||||
static void lv_img_decoder_close(void);
|
||||
static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
|
||||
static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static bool decoder_custom;
|
||||
static const void * decoder_src;
|
||||
static lv_img_src_t decoder_src_type;
|
||||
static lv_img_header_t decoder_header;
|
||||
static const lv_style_t * decoder_style;
|
||||
#if LV_USE_FILESYSTEM
|
||||
static lv_fs_file_t decoder_file;
|
||||
#endif
|
||||
#if LV_IMG_CF_INDEXED
|
||||
static lv_color_t decoder_index_map[256];
|
||||
#endif
|
||||
|
||||
static lv_img_decoder_info_f_t lv_img_decoder_info_custom;
|
||||
static lv_img_decoder_open_f_t lv_img_decoder_open_custom;
|
||||
static lv_img_decoder_read_line_f_t lv_img_decoder_read_line_custom;
|
||||
static lv_img_decoder_close_f_t lv_img_decoder_close_custom;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw an image
|
||||
* @param coords the coordinates of the image
|
||||
* @param mask the image will be drawn only in this area
|
||||
* @param src pointer to a lv_color_t array which contains the pixels of the image
|
||||
* @param style style of the image
|
||||
* @param opa_scale scale down all opacities by the factor
|
||||
*/
|
||||
void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask,
|
||||
const void * src, const lv_style_t * style, lv_opa_t opa_scale)
|
||||
{
|
||||
if(src == NULL) {
|
||||
LV_LOG_WARN("Image draw: src is NULL");
|
||||
lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER);
|
||||
lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, "No\ndata", LV_TXT_FLAG_NONE, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_res_t res;
|
||||
res = lv_img_draw_core(coords, mask, src, style, opa_scale);
|
||||
|
||||
if(res == LV_RES_INV) {
|
||||
LV_LOG_WARN("Image draw error");
|
||||
lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER);
|
||||
lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, "No\ndata", LV_TXT_FLAG_NONE, NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param src
|
||||
* @param header
|
||||
* @param style
|
||||
* @return
|
||||
*/
|
||||
lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header)
|
||||
{
|
||||
header->always_zero = 0;
|
||||
/*Try to get info with the custom functions first*/
|
||||
if(lv_img_decoder_info_custom) {
|
||||
lv_res_t custom_res;
|
||||
custom_res = lv_img_decoder_info_custom(src, header);
|
||||
if(custom_res == LV_RES_OK) return LV_RES_OK; /*Custom info has supported this source*/
|
||||
}
|
||||
|
||||
lv_img_src_t src_type = lv_img_src_get_type(src);
|
||||
if(src_type == LV_IMG_SRC_VARIABLE) {
|
||||
header->w = ((lv_img_dsc_t *)src)->header.w;
|
||||
header->h = ((lv_img_dsc_t *)src)->header.h;
|
||||
header->cf = ((lv_img_dsc_t *)src)->header.cf;
|
||||
}
|
||||
#if LV_USE_FILESYSTEM
|
||||
else if(src_type == LV_IMG_SRC_FILE) {
|
||||
lv_fs_file_t file;
|
||||
lv_fs_res_t res;
|
||||
uint32_t rn;
|
||||
res = lv_fs_open(&file, src, LV_FS_MODE_RD);
|
||||
if(res == LV_FS_RES_OK) {
|
||||
res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn);
|
||||
}
|
||||
|
||||
/*Create a dummy header on fs error*/
|
||||
if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) {
|
||||
header->w = LV_DPI;
|
||||
header->h = LV_DPI;
|
||||
header->cf = LV_IMG_CF_UNKNOWN;
|
||||
}
|
||||
|
||||
lv_fs_close(&file);
|
||||
}
|
||||
#endif
|
||||
else if(src_type == LV_IMG_SRC_SYMBOL) {
|
||||
/*The size depend on the font but it is unknown here. It should be handled outside of the function*/
|
||||
header->w = 1;
|
||||
header->h = 1;
|
||||
/* Symbols always have transparent parts. Important because of cover check in the design function.
|
||||
* The actual value doesn't matter because lv_draw_label will draw it*/
|
||||
header->cf = LV_IMG_CF_ALPHA_1BIT;
|
||||
} else {
|
||||
LV_LOG_WARN("Image get info found unknown src type");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf)
|
||||
{
|
||||
uint8_t px_size = 0;
|
||||
|
||||
switch(cf) {
|
||||
case LV_IMG_CF_UNKNOWN:
|
||||
case LV_IMG_CF_RAW:
|
||||
px_size = 0;
|
||||
break;
|
||||
case LV_IMG_CF_TRUE_COLOR:
|
||||
case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
|
||||
px_size = LV_COLOR_SIZE;
|
||||
break;
|
||||
case LV_IMG_CF_TRUE_COLOR_ALPHA:
|
||||
px_size = LV_IMG_PX_SIZE_ALPHA_BYTE << 3;
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_1BIT:
|
||||
case LV_IMG_CF_ALPHA_1BIT:
|
||||
px_size = 1;
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_2BIT:
|
||||
case LV_IMG_CF_ALPHA_2BIT:
|
||||
px_size = 2;
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_4BIT:
|
||||
case LV_IMG_CF_ALPHA_4BIT:
|
||||
px_size = 4;
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_8BIT:
|
||||
case LV_IMG_CF_ALPHA_8BIT:
|
||||
px_size = 8;
|
||||
break;
|
||||
default:
|
||||
px_size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return px_size;
|
||||
}
|
||||
|
||||
bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf)
|
||||
{
|
||||
bool is_chroma_keyed = false;
|
||||
|
||||
switch(cf) {
|
||||
case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
|
||||
case LV_IMG_CF_RAW_CHROMA_KEYED:
|
||||
case LV_IMG_CF_INDEXED_1BIT:
|
||||
case LV_IMG_CF_INDEXED_2BIT:
|
||||
case LV_IMG_CF_INDEXED_4BIT:
|
||||
case LV_IMG_CF_INDEXED_8BIT:
|
||||
is_chroma_keyed = true;
|
||||
break;
|
||||
default:
|
||||
is_chroma_keyed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return is_chroma_keyed;
|
||||
}
|
||||
|
||||
|
||||
bool lv_img_color_format_has_alpha(lv_img_cf_t cf)
|
||||
{
|
||||
bool has_alpha = false;
|
||||
|
||||
switch(cf) {
|
||||
case LV_IMG_CF_TRUE_COLOR_ALPHA:
|
||||
case LV_IMG_CF_RAW_ALPHA:
|
||||
case LV_IMG_CF_ALPHA_1BIT:
|
||||
case LV_IMG_CF_ALPHA_2BIT:
|
||||
case LV_IMG_CF_ALPHA_4BIT:
|
||||
case LV_IMG_CF_ALPHA_8BIT:
|
||||
has_alpha = true;
|
||||
break;
|
||||
default:
|
||||
has_alpha = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return has_alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of an image source
|
||||
* @param src pointer to an image source:
|
||||
* - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code)
|
||||
* - a path to a file (e.g. "S:/folder/image.bin")
|
||||
* - or a symbol (e.g. LV_SYMBOL_CLOSE)
|
||||
* @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKNOWN
|
||||
*/
|
||||
lv_img_src_t lv_img_src_get_type(const void * src)
|
||||
{
|
||||
lv_img_src_t img_src_type = LV_IMG_SRC_UNKNOWN;
|
||||
|
||||
if(src == NULL) return img_src_type;
|
||||
const uint8_t * u8_p = src;
|
||||
|
||||
/*The first byte shows the type of the image source*/
|
||||
if(u8_p[0] >= 0x20 && u8_p[0] <= 0x7F) {
|
||||
img_src_type = LV_IMG_SRC_FILE; /*If it's an ASCII character then it's file name*/
|
||||
} else if(u8_p[0] >= 0x80) {
|
||||
img_src_type = LV_IMG_SRC_SYMBOL; /*Symbols begins after 0x7F*/
|
||||
} else {
|
||||
img_src_type = LV_IMG_SRC_VARIABLE; /*`lv_img_dsc_t` is design to the first byte < 0x20*/
|
||||
}
|
||||
|
||||
if (LV_IMG_SRC_UNKNOWN == img_src_type) {
|
||||
LV_LOG_WARN("lv_img_src_get_type: unknown image type");
|
||||
}
|
||||
|
||||
return img_src_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom decoder functions. See the typdefs of the function typed above for more info about them
|
||||
* @param info_fp info get function
|
||||
* @param open_fp open function
|
||||
* @param read_fp read line function
|
||||
* @param close_fp clode function
|
||||
*/
|
||||
void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp,
|
||||
lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp)
|
||||
{
|
||||
lv_img_decoder_info_custom = info_fp;
|
||||
lv_img_decoder_open_custom = open_fp;
|
||||
lv_img_decoder_read_line_custom = read_fp;
|
||||
lv_img_decoder_close_custom = close_fp;
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask,
|
||||
const void * src, const lv_style_t * style, lv_opa_t opa_scale)
|
||||
{
|
||||
|
||||
lv_area_t mask_com; /*Common area of mask and coords*/
|
||||
bool union_ok;
|
||||
union_ok = lv_area_intersect(&mask_com, mask, coords);
|
||||
if(union_ok == false) {
|
||||
return LV_RES_OK; /*Out of mask. There is nothing to draw so the image is drawn successfully.*/
|
||||
}
|
||||
|
||||
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->image.opa : (uint16_t)((uint16_t) style->image.opa * opa_scale) >> 8;
|
||||
|
||||
lv_img_header_t header;
|
||||
lv_res_t header_res;
|
||||
header_res = lv_img_dsc_get_info(src, &header);
|
||||
if(header_res != LV_RES_OK) {
|
||||
LV_LOG_WARN("Image draw can't get image info");
|
||||
lv_img_decoder_close();
|
||||
return LV_RES_INV;
|
||||
}
|
||||
|
||||
bool chroma_keyed = lv_img_color_format_is_chroma_keyed(header.cf);
|
||||
bool alpha_byte = lv_img_color_format_has_alpha(header.cf);
|
||||
|
||||
const uint8_t * img_data = lv_img_decoder_open(src, style);
|
||||
if(img_data == LV_IMG_DECODER_OPEN_FAIL) {
|
||||
LV_LOG_WARN("Image draw cannot open the image resource");
|
||||
lv_img_decoder_close();
|
||||
return LV_RES_INV;
|
||||
}
|
||||
|
||||
/* The decoder open could open the image and gave the entire uncompressed image.
|
||||
* Just draw it!*/
|
||||
if(img_data) {
|
||||
lv_draw_map(coords, mask, img_data, opa, chroma_keyed, alpha_byte, style->image.color, style->image.intense);
|
||||
}
|
||||
/* The whole uncompressed image is not available. Try to read it line-by-line*/
|
||||
else {
|
||||
lv_coord_t width = lv_area_get_width(&mask_com);
|
||||
|
||||
#if LV_COMPILER_VLA_SUPPORTED
|
||||
uint8_t buf[(lv_area_get_width(&mask_com) * ((LV_COLOR_DEPTH >> 3) + 1))];
|
||||
#else
|
||||
uint8_t buf[LV_HOR_RES_MAX * ((LV_COLOR_DEPTH >> 3) + 1)]; /*+1 because of the possible alpha byte*/
|
||||
#endif
|
||||
lv_area_t line;
|
||||
lv_area_copy(&line, &mask_com);
|
||||
lv_area_set_height(&line, 1);
|
||||
lv_coord_t x = mask_com.x1 - coords->x1;
|
||||
lv_coord_t y = mask_com.y1 - coords->y1;
|
||||
lv_coord_t row;
|
||||
lv_res_t read_res;
|
||||
for(row = mask_com.y1; row <= mask_com.y2; row++) {
|
||||
read_res = lv_img_decoder_read_line(x, y, width, buf);
|
||||
if(read_res != LV_RES_OK) {
|
||||
lv_img_decoder_close();
|
||||
LV_LOG_WARN("Image draw can't read the line");
|
||||
return LV_RES_INV;
|
||||
}
|
||||
lv_draw_map(&line, mask, buf, opa, chroma_keyed, alpha_byte, style->image.color, style->image.intense);
|
||||
line.y1++;
|
||||
line.y2++;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
lv_img_decoder_close();
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
|
||||
static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style)
|
||||
{
|
||||
decoder_custom = false;
|
||||
|
||||
/*Try to open with the custom functions first*/
|
||||
if(lv_img_decoder_open_custom) {
|
||||
const uint8_t * custom_res;
|
||||
custom_res = lv_img_decoder_open_custom(src, style);
|
||||
if(custom_res != LV_IMG_DECODER_OPEN_FAIL) {
|
||||
decoder_custom = true; /*Mark that custom decoder function should be used for this img source.*/
|
||||
return custom_res; /*Custom open supported this source*/
|
||||
}
|
||||
}
|
||||
|
||||
decoder_src = src;
|
||||
decoder_style = style;
|
||||
decoder_src_type = lv_img_src_get_type(src);
|
||||
|
||||
lv_res_t header_res;
|
||||
header_res = lv_img_dsc_get_info(src, &decoder_header);
|
||||
if(header_res == LV_RES_INV) {
|
||||
decoder_src = NULL;
|
||||
decoder_src_type = LV_IMG_SRC_UNKNOWN;
|
||||
LV_LOG_WARN("Built-in image decoder can't get the header info");
|
||||
return LV_IMG_DECODER_OPEN_FAIL;
|
||||
}
|
||||
|
||||
/*Open the file if it's a file*/
|
||||
if(decoder_src_type == LV_IMG_SRC_FILE) {
|
||||
#if LV_USE_FILESYSTEM
|
||||
lv_fs_res_t res = lv_fs_open(&decoder_file, src, LV_FS_MODE_RD);
|
||||
if(res != LV_FS_RES_OK) {
|
||||
LV_LOG_WARN("Built-in image decoder can't open the file");
|
||||
return LV_IMG_DECODER_OPEN_FAIL;
|
||||
}
|
||||
#else
|
||||
LV_LOG_WARN("Image built-in decoder can read file because LV_USE_FILESYSTEM = 0");
|
||||
return LV_IMG_DECODER_OPEN_FAIL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*Process the different color formats*/
|
||||
lv_img_cf_t cf = decoder_header.cf;
|
||||
if(cf == LV_IMG_CF_TRUE_COLOR ||
|
||||
cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
|
||||
cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
|
||||
if(decoder_src_type == LV_IMG_SRC_VARIABLE) {
|
||||
/*In case of uncompressed formats if the image stored in the ROM/RAM simply give it's pointer*/
|
||||
return ((lv_img_dsc_t *)decoder_src)->data;
|
||||
} else {
|
||||
/*If it's file it need to be read line by line later*/
|
||||
return NULL;
|
||||
}
|
||||
} else if(cf == LV_IMG_CF_INDEXED_1BIT ||
|
||||
cf == LV_IMG_CF_INDEXED_2BIT ||
|
||||
cf == LV_IMG_CF_INDEXED_4BIT ||
|
||||
cf == LV_IMG_CF_INDEXED_8BIT) {
|
||||
|
||||
#if LV_IMG_CF_INDEXED
|
||||
#if LV_USE_FILESYSTEM
|
||||
lv_color32_t palette_file[256];
|
||||
#endif
|
||||
|
||||
lv_color32_t * palette_p = NULL;
|
||||
uint8_t px_size = lv_img_color_format_get_px_size(cf);
|
||||
uint32_t palette_size = 1 << px_size;
|
||||
|
||||
if(decoder_src_type == LV_IMG_SRC_FILE) {
|
||||
/*Read the palette from file*/
|
||||
#if LV_USE_FILESYSTEM
|
||||
lv_fs_seek(&decoder_file, 4); /*Skip the header*/
|
||||
lv_fs_read(&decoder_file, palette_file, palette_size * sizeof(lv_color32_t), NULL);
|
||||
palette_p = palette_file;
|
||||
#else
|
||||
LV_LOG_WARN("Image built-in decoder can read the palette because LV_USE_FILESYSTEM = 0");
|
||||
return LV_IMG_DECODER_OPEN_FAIL;
|
||||
#endif
|
||||
} else {
|
||||
/*The palette begins in the beginning of the image data. Just point to it.*/
|
||||
palette_p = (lv_color32_t *)((lv_img_dsc_t *)decoder_src)->data;
|
||||
}
|
||||
|
||||
uint32_t i;
|
||||
for(i = 0; i < palette_size; i++) {
|
||||
decoder_index_map[i] = lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue);
|
||||
}
|
||||
return NULL;
|
||||
#else
|
||||
LV_LOG_WARN("Indexed (palette) images are not enabled in lv_conf.h. See LV_IMG_CF_INDEXED");
|
||||
return LV_IMG_DECODER_OPEN_FAIL;
|
||||
#endif
|
||||
} else if(cf == LV_IMG_CF_ALPHA_1BIT ||
|
||||
cf == LV_IMG_CF_ALPHA_2BIT ||
|
||||
cf == LV_IMG_CF_ALPHA_4BIT ||
|
||||
cf == LV_IMG_CF_ALPHA_8BIT) {
|
||||
#if LV_IMG_CF_ALPHA
|
||||
return NULL; /*Nothing to process*/
|
||||
#else
|
||||
LV_LOG_WARN("Alpha indexed images are not enabled in lv_conf.h. See LV_IMG_CF_ALPHA");
|
||||
return LV_IMG_DECODER_OPEN_FAIL;
|
||||
#endif
|
||||
} else {
|
||||
LV_LOG_WARN("Image decoder open: unknown color format")
|
||||
return LV_IMG_DECODER_OPEN_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
|
||||
{
|
||||
/*Try to read the line with the custom functions*/
|
||||
if(decoder_custom) {
|
||||
if(lv_img_decoder_read_line_custom) {
|
||||
lv_res_t custom_res;
|
||||
custom_res = lv_img_decoder_read_line_custom(x, y, len, buf);
|
||||
return custom_res;
|
||||
} else {
|
||||
LV_LOG_WARN("Image open with custom decoder but read not supported")
|
||||
}
|
||||
return LV_RES_INV; /*It"s an error if not returned earlier*/
|
||||
}
|
||||
|
||||
if(decoder_src_type == LV_IMG_SRC_FILE) {
|
||||
#if LV_USE_FILESYSTEM
|
||||
uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf);
|
||||
|
||||
lv_fs_res_t res;
|
||||
|
||||
if(decoder_header.cf == LV_IMG_CF_TRUE_COLOR ||
|
||||
decoder_header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
|
||||
decoder_header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
|
||||
uint32_t pos = ((y * decoder_header.w + x) * px_size) >> 3;
|
||||
pos += 4; /*Skip the header*/
|
||||
res = lv_fs_seek(&decoder_file, pos);
|
||||
if(res != LV_FS_RES_OK) {
|
||||
LV_LOG_WARN("Built-in image decoder seek failed");
|
||||
return false;
|
||||
}
|
||||
uint32_t btr = len * (px_size >> 3);
|
||||
uint32_t br = 0;
|
||||
lv_fs_read(&decoder_file, buf, btr, &br);
|
||||
if(res != LV_FS_RES_OK || btr != br) {
|
||||
LV_LOG_WARN("Built-in image decoder read failed");
|
||||
return false;
|
||||
}
|
||||
} else if(decoder_header.cf == LV_IMG_CF_ALPHA_1BIT ||
|
||||
decoder_header.cf == LV_IMG_CF_ALPHA_2BIT ||
|
||||
decoder_header.cf == LV_IMG_CF_ALPHA_4BIT ||
|
||||
decoder_header.cf == LV_IMG_CF_ALPHA_8BIT) {
|
||||
|
||||
lv_img_built_in_decoder_line_alpha(x, y, len, buf);
|
||||
} else if(decoder_header.cf == LV_IMG_CF_INDEXED_1BIT ||
|
||||
decoder_header.cf == LV_IMG_CF_INDEXED_2BIT ||
|
||||
decoder_header.cf == LV_IMG_CF_INDEXED_4BIT ||
|
||||
decoder_header.cf == LV_IMG_CF_INDEXED_8BIT) {
|
||||
lv_img_built_in_decoder_line_indexed(x, y, len, buf);
|
||||
} else {
|
||||
LV_LOG_WARN("Built-in image decoder read not supports the color format");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
LV_LOG_WARN("Image built-in decoder can't read file because LV_USE_FILESYSTEM = 0");
|
||||
return false;
|
||||
#endif
|
||||
} else if(decoder_src_type == LV_IMG_SRC_VARIABLE) {
|
||||
const lv_img_dsc_t * img_dsc = decoder_src;
|
||||
|
||||
if(img_dsc->header.cf == LV_IMG_CF_ALPHA_1BIT ||
|
||||
img_dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||
|
||||
img_dsc->header.cf == LV_IMG_CF_ALPHA_4BIT ||
|
||||
img_dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
|
||||
lv_img_built_in_decoder_line_alpha(x, y, len, buf);
|
||||
} else if(img_dsc->header.cf == LV_IMG_CF_INDEXED_1BIT ||
|
||||
img_dsc->header.cf == LV_IMG_CF_INDEXED_2BIT ||
|
||||
img_dsc->header.cf == LV_IMG_CF_INDEXED_4BIT ||
|
||||
img_dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
|
||||
lv_img_built_in_decoder_line_indexed(x, y, len, buf);
|
||||
} else {
|
||||
LV_LOG_WARN("Built-in image decoder not supports the color format");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void lv_img_decoder_close(void)
|
||||
{
|
||||
/*Try to close with the custom functions*/
|
||||
if(decoder_custom) {
|
||||
if(lv_img_decoder_close_custom) lv_img_decoder_close_custom();
|
||||
return;
|
||||
}
|
||||
|
||||
/*It was opened with built-in decoder*/
|
||||
if(decoder_src) {
|
||||
#if LV_USE_FILESYSTEM
|
||||
if(decoder_src_type == LV_IMG_SRC_FILE) {
|
||||
lv_fs_close(&decoder_file);
|
||||
}
|
||||
#endif
|
||||
decoder_src_type = LV_IMG_SRC_UNKNOWN;
|
||||
decoder_src = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
|
||||
{
|
||||
|
||||
#if LV_IMG_CF_ALPHA
|
||||
const lv_opa_t alpha1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
|
||||
const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
|
||||
const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
|
||||
68, 85, 102, 119,
|
||||
136, 153, 170, 187,
|
||||
204, 221, 238, 255
|
||||
};
|
||||
|
||||
/*Simply fill the buffer with the color. Later only the alpha value will be modified.*/
|
||||
lv_color_t bg_color = decoder_style->image.color;
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < len; i++) {
|
||||
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
/*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF;
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF;
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
*((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full;
|
||||
#else
|
||||
#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
const lv_opa_t * opa_table = NULL;
|
||||
uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf);
|
||||
uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
|
||||
|
||||
lv_coord_t w = 0;
|
||||
uint32_t ofs = 0;
|
||||
int8_t pos = 0;
|
||||
switch(decoder_header.cf) {
|
||||
case LV_IMG_CF_ALPHA_1BIT:
|
||||
w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/
|
||||
if(decoder_header.w & 0x7) w++;
|
||||
ofs += w * y + (x >> 3); /*First pixel*/
|
||||
pos = 7 - (x & 0x7);
|
||||
opa_table = alpha1_opa_table;
|
||||
break;
|
||||
case LV_IMG_CF_ALPHA_2BIT:
|
||||
w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
|
||||
if(decoder_header.w & 0x3) w++;
|
||||
ofs += w * y + (x >> 2); /*First pixel*/
|
||||
pos = 6 - ((x & 0x3) * 2);
|
||||
opa_table = alpha2_opa_table;
|
||||
break;
|
||||
case LV_IMG_CF_ALPHA_4BIT:
|
||||
w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
|
||||
if(decoder_header.w & 0x1) w++;
|
||||
ofs += w * y + (x >> 1); /*First pixel*/
|
||||
pos = 4 - ((x & 0x1) * 4);
|
||||
opa_table = alpha4_opa_table;
|
||||
break;
|
||||
case LV_IMG_CF_ALPHA_8BIT:
|
||||
w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
|
||||
ofs += w * y + x; /*First pixel*/
|
||||
pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
#if LV_USE_FILESYSTEM
|
||||
# if LV_COMPILER_VLA_SUPPORTED
|
||||
uint8_t fs_buf[w];
|
||||
# else
|
||||
uint8_t fs_buf[LV_HOR_RES];
|
||||
# endif
|
||||
#endif
|
||||
const uint8_t * data_tmp = NULL;
|
||||
if(decoder_src_type == LV_IMG_SRC_VARIABLE) {
|
||||
const lv_img_dsc_t * img_dsc = decoder_src;
|
||||
data_tmp = img_dsc->data + ofs;
|
||||
} else {
|
||||
#if LV_USE_FILESYSTEM
|
||||
lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/
|
||||
lv_fs_read(&decoder_file, fs_buf, w, NULL);
|
||||
data_tmp = fs_buf;
|
||||
#else
|
||||
LV_LOG_WARN("Image built-in alpha line reader can't read file because LV_USE_FILESYSTEM = 0");
|
||||
data_tmp = NULL; /*To avoid warnings*/
|
||||
return LV_RES_INV;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint8_t byte_act = 0;
|
||||
uint8_t val_act;
|
||||
for(i = 0; i < len; i ++) {
|
||||
val_act = (data_tmp[byte_act] & (mask << pos)) >> pos;
|
||||
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] =
|
||||
decoder_header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act];
|
||||
|
||||
pos -= px_size;
|
||||
if(pos < 0) {
|
||||
pos = 8 - px_size;
|
||||
data_tmp++;
|
||||
}
|
||||
}
|
||||
|
||||
return LV_RES_OK;
|
||||
|
||||
#else
|
||||
LV_LOG_WARN("Image built-in alpha line reader failed because LV_IMG_CF_ALPHA is 0 in lv_conf.h");
|
||||
return LV_RES_INV;
|
||||
#endif
|
||||
}
|
||||
|
||||
static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
|
||||
{
|
||||
|
||||
#if LV_IMG_CF_INDEXED
|
||||
uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf);
|
||||
uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
|
||||
|
||||
lv_coord_t w = 0;
|
||||
int8_t pos = 0;
|
||||
uint32_t ofs = 0;
|
||||
switch(decoder_header.cf) {
|
||||
case LV_IMG_CF_INDEXED_1BIT:
|
||||
w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/
|
||||
if(decoder_header.w & 0x7) w++;
|
||||
ofs += w * y + (x >> 3); /*First pixel*/
|
||||
ofs += 8; /*Skip the palette*/
|
||||
pos = 7 - (x & 0x7);
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_2BIT:
|
||||
w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
|
||||
if(decoder_header.w & 0x3) w++;
|
||||
ofs += w * y + (x >> 2); /*First pixel*/
|
||||
ofs += 16; /*Skip the palette*/
|
||||
pos = 6 - ((x & 0x3) * 2);
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_4BIT:
|
||||
w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
|
||||
if(decoder_header.w & 0x1) w++;
|
||||
ofs += w * y + (x >> 1); /*First pixel*/
|
||||
ofs += 64; /*Skip the palette*/
|
||||
pos = 4 - ((x & 0x1) * 4);
|
||||
break;
|
||||
case LV_IMG_CF_INDEXED_8BIT:
|
||||
w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
|
||||
ofs += w * y + x; /*First pixel*/
|
||||
ofs += 1024; /*Skip the palette*/
|
||||
pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
#if LV_USE_FILESYSTEM
|
||||
# if LV_COMPILER_VLA_SUPPORTED
|
||||
uint8_t fs_buf[w];
|
||||
# else
|
||||
uint8_t fs_buf[LV_HOR_RES];
|
||||
# endif
|
||||
#endif
|
||||
const uint8_t * data_tmp = NULL;
|
||||
if(decoder_src_type == LV_IMG_SRC_VARIABLE) {
|
||||
const lv_img_dsc_t * img_dsc = decoder_src;
|
||||
data_tmp = img_dsc->data + ofs;
|
||||
} else {
|
||||
#if LV_USE_FILESYSTEM
|
||||
lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/
|
||||
lv_fs_read(&decoder_file, fs_buf, w, NULL);
|
||||
data_tmp = fs_buf;
|
||||
#else
|
||||
LV_LOG_WARN("Image built-in indexed line reader can't read file because LV_USE_FILESYSTEM = 0");
|
||||
data_tmp = NULL; /*To avoid warnings*/
|
||||
return LV_RES_INV;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t byte_act = 0;
|
||||
uint8_t val_act;
|
||||
lv_coord_t i;
|
||||
lv_color_t * cbuf = (lv_color_t *) buf;
|
||||
for(i = 0; i < len; i ++) {
|
||||
val_act = (data_tmp[byte_act] & (mask << pos)) >> pos;
|
||||
cbuf[i] = decoder_index_map[val_act];
|
||||
|
||||
pos -= px_size;
|
||||
if(pos < 0) {
|
||||
pos = 8 - px_size;
|
||||
data_tmp++;
|
||||
}
|
||||
}
|
||||
|
||||
return LV_RES_OK;
|
||||
#else
|
||||
LV_LOG_WARN("Image built-in indexed line reader failed because LV_IMG_CF_INDEXED is 0 in lv_conf.h");
|
||||
return LV_RES_INV;
|
||||
#endif
|
||||
}
|
||||
167
src/lv_draw/lv_draw_img.h
Normal file
167
src/lv_draw/lv_draw_img.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* @file lv_draw_img.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_IMG_H
|
||||
#define LV_DRAW_IMG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw.h"
|
||||
#include "../lv_core/lv_obj.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_IMG_DECODER_OPEN_FAIL ((void*)(-1))
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
struct _lv_img_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
/* The first 8 bit is very important to distinguish the different source types.
|
||||
* For more info see `lv_img_get_src_type()` in lv_img.c */
|
||||
uint32_t cf :5; /* Color format: See `lv_img_color_format_t`*/
|
||||
uint32_t always_zero :3; /*It the upper bits of the first byte. Always zero to look like a non-printable character*/
|
||||
|
||||
uint32_t reserved :2; /*Reserved to be used later*/
|
||||
|
||||
uint32_t w:11; /*Width of the image map*/
|
||||
uint32_t h:11; /*Height of the image map*/
|
||||
} lv_img_header_t;
|
||||
|
||||
/*Image color format*/
|
||||
enum {
|
||||
LV_IMG_CF_UNKNOWN = 0,
|
||||
|
||||
LV_IMG_CF_RAW, /*Contains the file as it is. Needs custom decoder function*/
|
||||
LV_IMG_CF_RAW_ALPHA, /*Contains the file as it is. The image has alpha. Needs custom decoder function*/
|
||||
LV_IMG_CF_RAW_CHROMA_KEYED, /*Contains the file as it is. The image is chroma keyed. Needs custom decoder function*/
|
||||
|
||||
LV_IMG_CF_TRUE_COLOR, /*Color format and depth should match with LV_COLOR settings*/
|
||||
LV_IMG_CF_TRUE_COLOR_ALPHA, /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/
|
||||
LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels will be transparent*/
|
||||
|
||||
LV_IMG_CF_INDEXED_1BIT, /*Can have 2 different colors in a palette (always chroma keyed)*/
|
||||
LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/
|
||||
LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/
|
||||
LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always chroma keyed)*/
|
||||
|
||||
LV_IMG_CF_ALPHA_1BIT, /*Can have one color and it can be drawn or not*/
|
||||
LV_IMG_CF_ALPHA_2BIT, /*Can have one color but 4 different alpha value*/
|
||||
LV_IMG_CF_ALPHA_4BIT, /*Can have one color but 16 different alpha value*/
|
||||
LV_IMG_CF_ALPHA_8BIT, /*Can have one color but 256 different alpha value*/
|
||||
};
|
||||
typedef uint8_t lv_img_cf_t;
|
||||
|
||||
/* Image header it is compatible with
|
||||
* the result image converter utility*/
|
||||
typedef struct
|
||||
{
|
||||
lv_img_header_t header;
|
||||
uint32_t data_size;
|
||||
const uint8_t * data;
|
||||
} lv_img_dsc_t;
|
||||
|
||||
/* Decoder function definitions */
|
||||
|
||||
|
||||
/**
|
||||
* Get info from an image and store in the `header`
|
||||
* @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type)
|
||||
* @param header store the info here
|
||||
* @return LV_RES_OK: info written correctly; LV_RES_INV: failed
|
||||
*/
|
||||
typedef lv_res_t (*lv_img_decoder_info_f_t)(const void * src, lv_img_header_t * header);
|
||||
|
||||
/**
|
||||
* Open an image for decoding. Prepare it as it is required to read it later
|
||||
* @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type)
|
||||
* @param style the style of image (maybe it will be required to determine a color or something)
|
||||
* @return there are 3 possible return values:
|
||||
* 1) buffer with the decoded image
|
||||
* 2) if can decode the whole image NULL. decoder_read_line will be called to read the image line-by-line
|
||||
* 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an error occurred
|
||||
*/
|
||||
typedef const uint8_t * (*lv_img_decoder_open_f_t)(const void * src, const lv_style_t * style);
|
||||
|
||||
/**
|
||||
* Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
|
||||
* Required only if the "open" function can't return with the whole decoded pixel array.
|
||||
* @param x start x coordinate
|
||||
* @param y startt y coordinate
|
||||
* @param len number of pixels to decode
|
||||
* @param buf a buffer to store the decoded pixels
|
||||
* @return LV_RES_OK: ok; LV_RES_INV: failed
|
||||
*/
|
||||
typedef lv_res_t (*lv_img_decoder_read_line_f_t)(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
|
||||
|
||||
/**
|
||||
* Close the pending decoding. Free resources etc.
|
||||
*/
|
||||
typedef void (*lv_img_decoder_close_f_t)(void);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw an image
|
||||
* @param coords the coordinates of the image
|
||||
* @param mask the image will be drawn only in this area
|
||||
* @param src pointer to a lv_color_t array which contains the pixels of the image
|
||||
* @param style style of the image
|
||||
* @param opa_scale scale down all opacities by the factor
|
||||
*/
|
||||
void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask,
|
||||
const void * src, const lv_style_t * style, lv_opa_t opa_scale);
|
||||
|
||||
|
||||
/**
|
||||
* Get the type of an image source
|
||||
* @param src pointer to an image source:
|
||||
* - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code)
|
||||
* - a path to a file (e.g. "S:/folder/image.bin")
|
||||
* - or a symbol (e.g. LV_SYMBOL_CLOSE)
|
||||
* @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKNOWN
|
||||
*/
|
||||
lv_img_src_t lv_img_src_get_type(const void * src);
|
||||
|
||||
/**
|
||||
* Set custom decoder functions. See the typdefs of the function typed above for more info about them
|
||||
* @param info_fp info get function
|
||||
* @param open_fp open function
|
||||
* @param read_fp read line function
|
||||
* @param close_fp clode function
|
||||
*/
|
||||
void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp,
|
||||
lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp);
|
||||
|
||||
lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header);
|
||||
|
||||
uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf);
|
||||
|
||||
bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf);
|
||||
|
||||
bool lv_img_color_format_has_alpha(lv_img_cf_t cf);
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_TEMPL_H*/
|
||||
257
src/lv_draw/lv_draw_label.c
Normal file
257
src/lv_draw/lv_draw_label.c
Normal file
@@ -0,0 +1,257 @@
|
||||
/**
|
||||
* @file lv_draw_label.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_label.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LABEL_RECOLOR_PAR_LENGTH 6
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
enum {
|
||||
CMD_STATE_WAIT,
|
||||
CMD_STATE_PAR,
|
||||
CMD_STATE_IN,
|
||||
};
|
||||
typedef uint8_t cmd_state_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static uint8_t hex_char_to_num(char hex);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Write a text
|
||||
* @param coords coordinates of the label
|
||||
* @param mask the label will be drawn only in this area
|
||||
* @param style pointer to a style
|
||||
* @param opa_scale scale down all opacities by the factor
|
||||
* @param txt 0 terminated text to write
|
||||
* @param flag settings for the text from 'txt_flag_t' enum
|
||||
* @param offset text offset in x and y direction (NULL if unused)
|
||||
*
|
||||
*/
|
||||
void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale,
|
||||
const char * txt, lv_txt_flag_t flag, lv_point_t * offset)
|
||||
{
|
||||
const lv_font_t * font = style->text.font;
|
||||
lv_coord_t w;
|
||||
if((flag & LV_TXT_FLAG_EXPAND) == 0) {
|
||||
/*Normally use the label's width as width*/
|
||||
w = lv_area_get_width(coords);
|
||||
} else {
|
||||
/*If EXAPND is enabled then not limit the text's width to the object's width*/
|
||||
lv_point_t p;
|
||||
lv_txt_get_size(&p, txt, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, flag);
|
||||
w = p.x;
|
||||
}
|
||||
|
||||
lv_coord_t line_height = lv_font_get_height(font) + style->text.line_space;
|
||||
|
||||
|
||||
/*Init variables for the first line*/
|
||||
lv_coord_t line_width = 0;
|
||||
lv_point_t pos;
|
||||
pos.x = coords->x1;
|
||||
pos.y = coords->y1;
|
||||
|
||||
lv_coord_t x_ofs = 0;
|
||||
lv_coord_t y_ofs = 0;
|
||||
if(offset != NULL) {
|
||||
x_ofs = offset->x;
|
||||
y_ofs = offset->y;
|
||||
pos.y += y_ofs;
|
||||
}
|
||||
|
||||
uint32_t line_start = 0;
|
||||
uint32_t line_end = lv_txt_get_next_line(txt, font, style->text.letter_space, w, flag);
|
||||
|
||||
/*Go the first visible line*/
|
||||
while(pos.y + line_height < mask->y1) {
|
||||
/*Go to next line*/
|
||||
line_start = line_end;
|
||||
line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag);
|
||||
pos.y += line_height;
|
||||
|
||||
if(txt[line_start] == '\0') return;
|
||||
}
|
||||
|
||||
/*Align to middle*/
|
||||
if(flag & LV_TXT_FLAG_CENTER) {
|
||||
line_width = lv_txt_get_width(&txt[line_start], line_end - line_start,
|
||||
font, style->text.letter_space, flag);
|
||||
|
||||
pos.x += (lv_area_get_width(coords) - line_width) / 2;
|
||||
|
||||
}
|
||||
/*Align to the right*/
|
||||
else if(flag & LV_TXT_FLAG_RIGHT) {
|
||||
line_width = lv_txt_get_width(&txt[line_start], line_end - line_start,
|
||||
font, style->text.letter_space, flag);
|
||||
pos.x += lv_area_get_width(coords) - line_width;
|
||||
}
|
||||
|
||||
|
||||
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->text.opa : (uint16_t)((uint16_t) style->text.opa * opa_scale) >> 8;
|
||||
|
||||
cmd_state_t cmd_state = CMD_STATE_WAIT;
|
||||
uint32_t i;
|
||||
uint16_t par_start = 0;
|
||||
lv_color_t recolor;
|
||||
lv_coord_t letter_w;
|
||||
|
||||
/*Write out all lines*/
|
||||
while(txt[line_start] != '\0') {
|
||||
if(offset != NULL) {
|
||||
pos.x += x_ofs;
|
||||
}
|
||||
/*Write all letter of a line*/
|
||||
cmd_state = CMD_STATE_WAIT;
|
||||
i = line_start;
|
||||
uint32_t letter;
|
||||
while(i < line_end) {
|
||||
letter = lv_txt_encoded_next(txt, &i);
|
||||
|
||||
/*Handle the re-color command*/
|
||||
if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
|
||||
if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) {
|
||||
if(cmd_state == CMD_STATE_WAIT) { /*Start char*/
|
||||
par_start = i;
|
||||
cmd_state = CMD_STATE_PAR;
|
||||
continue;
|
||||
} else if(cmd_state == CMD_STATE_PAR) { /*Other start char in parameter escaped cmd. char */
|
||||
cmd_state = CMD_STATE_WAIT;
|
||||
} else if(cmd_state == CMD_STATE_IN) { /*Command end */
|
||||
cmd_state = CMD_STATE_WAIT;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*Skip the color parameter and wait the space after it*/
|
||||
if(cmd_state == CMD_STATE_PAR) {
|
||||
if(letter == ' ') {
|
||||
/*Get the parameter*/
|
||||
if(i - par_start == LABEL_RECOLOR_PAR_LENGTH + 1) {
|
||||
char buf[LABEL_RECOLOR_PAR_LENGTH + 1];
|
||||
memcpy(buf, &txt[par_start], LABEL_RECOLOR_PAR_LENGTH);
|
||||
buf[LABEL_RECOLOR_PAR_LENGTH] = '\0';
|
||||
int r, g, b;
|
||||
r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]);
|
||||
g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]);
|
||||
b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]);
|
||||
recolor = lv_color_make(r, g, b);
|
||||
} else {
|
||||
recolor.full = style->text.color.full;
|
||||
}
|
||||
cmd_state = CMD_STATE_IN; /*After the parameter the text is in the command*/
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
lv_color_t color = style->text.color;
|
||||
|
||||
if(cmd_state == CMD_STATE_IN) color = recolor;
|
||||
|
||||
lv_draw_letter(&pos, mask, font, letter, color, opa);
|
||||
letter_w = lv_font_get_width(font, letter);
|
||||
|
||||
if(letter_w > 0){
|
||||
pos.x += letter_w + style->text.letter_space;
|
||||
}
|
||||
}
|
||||
/*Go to next line*/
|
||||
line_start = line_end;
|
||||
line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag);
|
||||
|
||||
pos.x = coords->x1;
|
||||
/*Align to middle*/
|
||||
if(flag & LV_TXT_FLAG_CENTER) {
|
||||
line_width = lv_txt_get_width(&txt[line_start], line_end - line_start,
|
||||
font, style->text.letter_space, flag);
|
||||
|
||||
pos.x += (lv_area_get_width(coords) - line_width) / 2;
|
||||
|
||||
}
|
||||
/*Align to the right*/
|
||||
else if(flag & LV_TXT_FLAG_RIGHT) {
|
||||
line_width = lv_txt_get_width(&txt[line_start], line_end - line_start,
|
||||
font, style->text.letter_space, flag);
|
||||
pos.x += lv_area_get_width(coords) - line_width;
|
||||
}
|
||||
|
||||
/*Go the next line position*/
|
||||
pos.y += line_height;
|
||||
|
||||
if(pos.y > mask->y2) return;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Convert a hexadecimal characters to a number (0..15)
|
||||
* @param hex Pointer to a hexadecimal character (0..9, A..F)
|
||||
* @return the numerical value of `hex` or 0 on error
|
||||
*/
|
||||
static uint8_t hex_char_to_num(char hex)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
|
||||
if(hex >= '0' && hex <= '9') {
|
||||
result = hex - '0';
|
||||
}
|
||||
else {
|
||||
if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/
|
||||
|
||||
switch(hex) {
|
||||
case 'A':
|
||||
result = 10;
|
||||
break;
|
||||
case 'B':
|
||||
result = 11;
|
||||
break;
|
||||
case 'C':
|
||||
result = 12;
|
||||
break;
|
||||
case 'D':
|
||||
result = 13;
|
||||
break;
|
||||
case 'E':
|
||||
result = 14;
|
||||
break;
|
||||
case 'F':
|
||||
result = 15;
|
||||
break;
|
||||
default:
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
53
src/lv_draw/lv_draw_label.h
Normal file
53
src/lv_draw/lv_draw_label.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @file lv_draw_label.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_LABEL_H
|
||||
#define LV_DRAW_LABEL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Write a text
|
||||
* @param coords coordinates of the label
|
||||
* @param mask the label will be drawn only in this area
|
||||
* @param style pointer to a style
|
||||
* @param opa_scale scale down all opacities by the factor
|
||||
* @param txt 0 terminated text to write
|
||||
* @param flag settings for the text from 'txt_flag_t' enum
|
||||
* @param offset text offset in x and y direction (NULL if unused)
|
||||
*
|
||||
*/
|
||||
void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale,
|
||||
const char * txt, lv_txt_flag_t flag, lv_point_t * offset);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_LABEL_H*/
|
||||
608
src/lv_draw/lv_draw_line.c
Normal file
608
src/lv_draw/lv_draw_line.c
Normal file
@@ -0,0 +1,608 @@
|
||||
/**
|
||||
* @file lv_draw_line.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "lv_draw.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#if LV_COMPILER_VLA_SUPPORTED == 0
|
||||
#define LINE_MAX_WIDTH 64
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
lv_point_t p_act;
|
||||
lv_coord_t dx;
|
||||
lv_coord_t sx; /*-1: x1 < x2; 1: x2 >= x1*/
|
||||
lv_coord_t dy;
|
||||
lv_coord_t sy; /*-1: y1 < y2; 1: y2 >= y1*/
|
||||
lv_coord_t err;
|
||||
lv_coord_t e2;
|
||||
bool hor; /*Rather horizontal or vertical*/
|
||||
} line_draw_t;
|
||||
|
||||
typedef struct {
|
||||
lv_coord_t width;
|
||||
lv_coord_t width_1;
|
||||
lv_coord_t width_half;
|
||||
} line_width_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
|
||||
static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
|
||||
static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
|
||||
static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2);
|
||||
static bool line_next(line_draw_t * line);
|
||||
static bool line_next_y(line_draw_t * line);
|
||||
static bool line_next_x(line_draw_t * line);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw a line
|
||||
* @param point1 first point of the line
|
||||
* @param point2 second point of the line
|
||||
* @param mask the line will be drawn only on this area
|
||||
* @param style pointer to a line's style
|
||||
* @param opa_scale scale down all opacities by the factor
|
||||
*/
|
||||
void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask,
|
||||
const lv_style_t * style, lv_opa_t opa_scale)
|
||||
{
|
||||
|
||||
if(style->line.width == 0) return;
|
||||
if(point1->x == point2->x && point1->y == point2->y) return;
|
||||
|
||||
line_draw_t main_line;
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
|
||||
/*If the line if rather vertical then be sure y1 < y2 else x1 < x2*/
|
||||
|
||||
if(LV_MATH_ABS(point1->x - point2->x) > LV_MATH_ABS(point1->y - point2->y)) {
|
||||
|
||||
/*Steps less in y then x -> rather horizontal*/
|
||||
if(point1->x < point2->x) {
|
||||
p1.x = point1->x;
|
||||
p1.y = point1->y;
|
||||
p2.x = point2->x;
|
||||
p2.y = point2->y;
|
||||
} else {
|
||||
p1.x = point2->x;
|
||||
p1.y = point2->y;
|
||||
p2.x = point1->x;
|
||||
p2.y = point1->y;
|
||||
}
|
||||
} else {
|
||||
/*Steps less in x then y -> rather vertical*/
|
||||
if(point1->y < point2->y) {
|
||||
p1.x = point1->x;
|
||||
p1.y = point1->y;
|
||||
p2.x = point2->x;
|
||||
p2.y = point2->y;
|
||||
} else {
|
||||
p1.x = point2->x;
|
||||
p1.y = point2->y;
|
||||
p2.x = point1->x;
|
||||
p2.y = point1->y;
|
||||
}
|
||||
}
|
||||
|
||||
line_init(&main_line, &p1, &p2);
|
||||
|
||||
|
||||
/*Special case draw a horizontal line*/
|
||||
if(main_line.p1.y == main_line.p2.y) {
|
||||
line_draw_hor(&main_line, mask, style, opa_scale);
|
||||
}
|
||||
/*Special case draw a vertical line*/
|
||||
else if(main_line.p1.x == main_line.p2.x) {
|
||||
line_draw_ver(&main_line, mask, style, opa_scale);
|
||||
}
|
||||
/*Arbitrary skew line*/
|
||||
else {
|
||||
bool dir_ori = false;
|
||||
#if LV_ANTIALIAS
|
||||
lv_point_t p_tmp;
|
||||
|
||||
if(main_line.hor) {
|
||||
if(main_line.p1.y < main_line.p2.y) {
|
||||
dir_ori = true;
|
||||
p_tmp.x = main_line.p2.x;
|
||||
p_tmp.y = main_line.p2.y - 1;
|
||||
line_init(&main_line, &p1, &p_tmp);
|
||||
main_line.sy = LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/
|
||||
}
|
||||
else if(main_line.p1.y > main_line.p2.y) {
|
||||
dir_ori = false;
|
||||
p_tmp.x = main_line.p2.x;
|
||||
p_tmp.y = main_line.p2.y + 1;
|
||||
line_init(&main_line, &p1, &p_tmp);
|
||||
main_line.sy = -LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(main_line.p1.x < main_line.p2.x) {
|
||||
dir_ori = true;
|
||||
p_tmp.x = main_line.p2.x - 1;
|
||||
p_tmp.y = main_line.p2.y;
|
||||
line_init(&main_line, &p1, &p_tmp);
|
||||
main_line.sx = LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/
|
||||
}
|
||||
else if(main_line.p1.x > main_line.p2.x) {
|
||||
dir_ori = false;
|
||||
p_tmp.x = main_line.p2.x + 1;
|
||||
p_tmp.y = main_line.p2.y;
|
||||
line_init(&main_line, &p1, &p_tmp);
|
||||
main_line.sx = -LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/
|
||||
}
|
||||
}
|
||||
#endif
|
||||
line_draw_skew(&main_line, dir_ori, mask, style, opa_scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
|
||||
{
|
||||
lv_coord_t width = style->line.width - 1;
|
||||
lv_coord_t width_half = width >> 1;
|
||||
lv_coord_t width_1 = width & 0x1;
|
||||
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8;
|
||||
|
||||
lv_area_t act_area;
|
||||
act_area.x1 = main_line->p1.x;
|
||||
act_area.x2 = main_line->p2.x;
|
||||
act_area.y1 = main_line->p1.y - width_half - width_1;
|
||||
act_area.y2 = main_line->p2.y + width_half ;
|
||||
|
||||
lv_area_t draw_area;
|
||||
draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);
|
||||
draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);
|
||||
draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);
|
||||
draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);
|
||||
lv_draw_fill(&draw_area, mask, style->line.color, opa);
|
||||
}
|
||||
|
||||
static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
|
||||
{
|
||||
lv_coord_t width = style->line.width - 1;
|
||||
lv_coord_t width_half = width >> 1;
|
||||
lv_coord_t width_1 = width & 0x1;
|
||||
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8;
|
||||
|
||||
|
||||
lv_area_t act_area;
|
||||
act_area.x1 = main_line->p1.x - width_half;
|
||||
act_area.x2 = main_line->p2.x + width_half + width_1;
|
||||
act_area.y1 = main_line->p1.y;
|
||||
act_area.y2 = main_line->p2.y;
|
||||
|
||||
lv_area_t draw_area;
|
||||
draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);
|
||||
draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);
|
||||
draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);
|
||||
draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);
|
||||
lv_draw_fill(&draw_area, mask, style->line.color, opa);
|
||||
}
|
||||
|
||||
static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
|
||||
{
|
||||
|
||||
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8;
|
||||
|
||||
lv_point_t vect_main, vect_norm;
|
||||
vect_main.x = main_line->p2.x - main_line->p1.x;
|
||||
vect_main.y = main_line->p2.y - main_line->p1.y;
|
||||
|
||||
if(main_line->hor) {
|
||||
if(main_line->p1.y < main_line->p2.y + dir_ori) {
|
||||
vect_norm.x = - vect_main.y;
|
||||
vect_norm.y = vect_main.x;
|
||||
} else {
|
||||
vect_norm.x = vect_main.y;
|
||||
vect_norm.y = -vect_main.x;
|
||||
}
|
||||
} else {
|
||||
if(main_line->p1.x < main_line->p2.x + dir_ori) {
|
||||
vect_norm.x = vect_main.y;
|
||||
vect_norm.y = - vect_main.x;
|
||||
} else {
|
||||
vect_norm.x = - vect_main.y;
|
||||
vect_norm.y = vect_main.x;
|
||||
}
|
||||
}
|
||||
|
||||
/* In case of a short but tick line the perpendicular ending is longer then the real line.
|
||||
* it would break the calculations so make the normal vector larger*/
|
||||
vect_norm.x = vect_norm.x << 4;
|
||||
vect_norm.y = vect_norm.y << 4;
|
||||
|
||||
lv_coord_t width;
|
||||
width = style->line.width;
|
||||
|
||||
/* The pattern stores the points of the line ending. It has the good direction and length.
|
||||
* The worth case is the 45° line where pattern can have 1.41 x `width` points*/
|
||||
#if LV_COMPILER_VLA_SUPPORTED
|
||||
lv_point_t pattern[width * 2];
|
||||
#else
|
||||
lv_point_t pattern[LINE_MAX_WIDTH];
|
||||
#endif
|
||||
lv_coord_t i = 0;
|
||||
|
||||
/*Create a perpendicular pattern (a small line)*/
|
||||
if(width != 0) {
|
||||
line_draw_t pattern_line;
|
||||
lv_point_t p0 = {0, 0};
|
||||
line_init(&pattern_line, &p0, &vect_norm);
|
||||
|
||||
uint32_t width_sqr = width * width;
|
||||
/* Run for a lot of times. Meanwhile the real width will be determined as well */
|
||||
for(i = 0; i < (lv_coord_t)sizeof(pattern); i ++) {
|
||||
pattern[i].x = pattern_line.p_act.x;
|
||||
pattern[i].y = pattern_line.p_act.y;
|
||||
|
||||
/*Finish the pattern line if it's length equal to the desired width (Use Pythagoras theorem)*/
|
||||
uint32_t sqr = pattern_line.p_act.x * pattern_line.p_act.x + pattern_line.p_act.y * pattern_line.p_act.y;
|
||||
if(sqr >= width_sqr) {
|
||||
width = i;
|
||||
#if LV_ANTIALIAS
|
||||
width--;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
line_next(&pattern_line);
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
lv_coord_t width_safe = width;
|
||||
if(width == 0) width_safe = 1;
|
||||
|
||||
lv_coord_t aa_last_corner;
|
||||
aa_last_corner = 0;
|
||||
#endif
|
||||
|
||||
lv_coord_t x_center_ofs = 0;
|
||||
lv_coord_t y_center_ofs = 0;
|
||||
|
||||
if(width != 0) {
|
||||
x_center_ofs = pattern[width - 1].x / 2;
|
||||
y_center_ofs = pattern[width - 1].y / 2;
|
||||
}
|
||||
else {
|
||||
if(main_line->hor && main_line->p1.y >= main_line->p2.y + dir_ori) pattern[0].y --;
|
||||
if(!main_line->hor && main_line->p1.x >= main_line->p2.x + dir_ori) pattern[0].x --;
|
||||
}
|
||||
|
||||
/* Make the coordinates relative to the center */
|
||||
for(i = 0; i < width; i++) {
|
||||
pattern[i].x -= x_center_ofs;
|
||||
pattern[i].y -= y_center_ofs;
|
||||
#if LV_ANTIALIAS
|
||||
if(i != 0) {
|
||||
if(main_line->hor) {
|
||||
if(pattern[i - 1].x != pattern[i].x) {
|
||||
lv_coord_t seg_w = pattern[i].y - pattern[aa_last_corner].y;
|
||||
if(main_line->sy < 0) {
|
||||
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y + seg_w + 1,
|
||||
seg_w, mask, style->line.color, opa);
|
||||
|
||||
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y + seg_w + 1,
|
||||
-seg_w, mask, style->line.color, opa);
|
||||
} else {
|
||||
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y,
|
||||
seg_w, mask, style->line.color, opa);
|
||||
|
||||
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y,
|
||||
-seg_w, mask, style->line.color, opa);
|
||||
}
|
||||
aa_last_corner = i;
|
||||
}
|
||||
} else {
|
||||
if(pattern[i - 1].y != pattern[i].y) {
|
||||
lv_coord_t seg_w = pattern[i].x - pattern[aa_last_corner].x;
|
||||
if(main_line->sx < 0) {
|
||||
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w + 1, main_line->p1.y + pattern[aa_last_corner].y - 1,
|
||||
seg_w, mask, style->line.color, opa);
|
||||
|
||||
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w + 1, main_line->p2.y + pattern[aa_last_corner].y + 1,
|
||||
-seg_w, mask, style->line.color, opa);
|
||||
} else {
|
||||
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x, main_line->p1.y + pattern[aa_last_corner].y - 1,
|
||||
seg_w, mask, style->line.color, opa);
|
||||
|
||||
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x, main_line->p2.y + pattern[aa_last_corner].y + 1,
|
||||
-seg_w, mask, style->line.color, opa);
|
||||
}
|
||||
aa_last_corner = i;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
/*Add the last part of anti-aliasing for the perpendicular ending*/
|
||||
if(width != 0) { /*Due to rounding error with very thin lines it looks ugly*/
|
||||
if(main_line->hor) {
|
||||
lv_coord_t seg_w = pattern[width_safe - 1].y - pattern[aa_last_corner].y;
|
||||
if(main_line->sy < 0) {
|
||||
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y + seg_w,
|
||||
seg_w + main_line->sy, mask, style->line.color, opa);
|
||||
|
||||
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y + seg_w,
|
||||
-(seg_w + main_line->sy), mask, style->line.color, opa);
|
||||
|
||||
} else {
|
||||
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y,
|
||||
seg_w + main_line->sy, mask, style->line.color, opa);
|
||||
|
||||
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y,
|
||||
-(seg_w + main_line->sy), mask, style->line.color, opa);
|
||||
}
|
||||
} else {
|
||||
lv_coord_t seg_w = pattern[width_safe - 1].x - pattern[aa_last_corner].x;
|
||||
if(main_line->sx < 0) {
|
||||
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w, main_line->p1.y + pattern[aa_last_corner].y - 1,
|
||||
seg_w + main_line->sx, mask, style->line.color, opa);
|
||||
|
||||
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w, main_line->p2.y + pattern[aa_last_corner].y + 1,
|
||||
-(seg_w + main_line->sx), mask, style->line.color, opa);
|
||||
|
||||
} else {
|
||||
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x, main_line->p1.y + pattern[aa_last_corner].y - 1,
|
||||
seg_w + main_line->sx, mask, style->line.color, opa);
|
||||
|
||||
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x, main_line->p2.y + pattern[aa_last_corner].y + 1,
|
||||
-(seg_w + main_line->sx), mask, style->line.color, opa);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
|
||||
/*Shift the anti aliasing on the edges (-1, 1 or 0 (zero only in case width == 0))*/
|
||||
lv_coord_t aa_shift1;
|
||||
lv_coord_t aa_shift2;
|
||||
|
||||
if(main_line->hor == false) {
|
||||
if(main_line->sx < 0) {
|
||||
aa_shift1 = -1;
|
||||
aa_shift2 = width == 0 ? 0 : aa_shift1;
|
||||
} else {
|
||||
aa_shift2 = 1;
|
||||
aa_shift1 = width == 0 ? 0 : aa_shift2;
|
||||
}
|
||||
} else {
|
||||
if(main_line->sy < 0) {
|
||||
aa_shift1 = -1;
|
||||
aa_shift2 = width == 0 ? 0 : aa_shift1;
|
||||
} else {
|
||||
aa_shift2 = 1;
|
||||
aa_shift1 = width == 0 ? 0 : aa_shift2;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
volatile lv_point_t prev_p;
|
||||
prev_p.x = main_line->p1.x;
|
||||
prev_p.y = main_line->p1.y;
|
||||
lv_area_t draw_area;
|
||||
bool first_run = true;
|
||||
|
||||
if(main_line->hor) {
|
||||
while(line_next_y(main_line)) {
|
||||
for(i = 0; i < width; i++) {
|
||||
draw_area.x1 = prev_p.x + pattern[i].x;
|
||||
draw_area.y1 = prev_p.y + pattern[i].y;
|
||||
draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x - 1;
|
||||
draw_area.y2 = draw_area.y1;
|
||||
lv_draw_fill(&draw_area, mask, style->line.color, opa);
|
||||
|
||||
/* Fill the gaps
|
||||
* When stepping in y one pixel remains empty on every corner (don't do this on the first segment ) */
|
||||
if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) {
|
||||
lv_draw_px(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa);
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1,
|
||||
-(main_line->p_act.x - prev_p.x), mask, style->line.color, opa);
|
||||
lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2,
|
||||
main_line->p_act.x - prev_p.x, mask, style->line.color, opa);
|
||||
#endif
|
||||
|
||||
first_run = false;
|
||||
|
||||
prev_p.x = main_line->p_act.x;
|
||||
prev_p.y = main_line->p_act.y;
|
||||
}
|
||||
|
||||
for(i = 0; i < width; i++) {
|
||||
draw_area.x1 = prev_p.x + pattern[i].x;
|
||||
draw_area.y1 = prev_p.y + pattern[i].y;
|
||||
draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x;
|
||||
draw_area.y2 = draw_area.y1;
|
||||
lv_draw_fill(&draw_area, mask, style->line.color, opa);
|
||||
|
||||
/* Fill the gaps
|
||||
* When stepping in y one pixel remains empty on every corner */
|
||||
if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) {
|
||||
lv_draw_px(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa);
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1,
|
||||
-(main_line->p_act.x - prev_p.x + 1), mask, style->line.color, opa);
|
||||
lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2,
|
||||
main_line->p_act.x - prev_p.x + 1, mask, style->line.color, opa);
|
||||
#endif
|
||||
}
|
||||
/*Rather a vertical line*/
|
||||
else {
|
||||
|
||||
while(line_next_x(main_line)) {
|
||||
for(i = 0; i < width; i++) {
|
||||
draw_area.x1 = prev_p.x + pattern[i].x;
|
||||
draw_area.y1 = prev_p.y + pattern[i].y;
|
||||
draw_area.x2 = draw_area.x1;
|
||||
draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y - 1;
|
||||
|
||||
lv_draw_fill(&draw_area, mask, style->line.color, opa);
|
||||
|
||||
/* Fill the gaps
|
||||
* When stepping in x one pixel remains empty on every corner (don't do this on the first segment ) */
|
||||
if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) {
|
||||
lv_draw_px(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y,
|
||||
-(main_line->p_act.y - prev_p.y), mask, style->line.color, opa);
|
||||
lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y,
|
||||
main_line->p_act.y - prev_p.y, mask, style->line.color, opa);
|
||||
#endif
|
||||
|
||||
first_run = false;
|
||||
|
||||
prev_p.x = main_line->p_act.x;
|
||||
prev_p.y = main_line->p_act.y;
|
||||
}
|
||||
|
||||
/*Draw the last part*/
|
||||
for(i = 0; i < width; i++) {
|
||||
draw_area.x1 = prev_p.x + pattern[i].x;
|
||||
draw_area.y1 = prev_p.y + pattern[i].y;
|
||||
draw_area.x2 = draw_area.x1;
|
||||
draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y;
|
||||
|
||||
lv_draw_fill(&draw_area, mask, style->line.color, opa);
|
||||
|
||||
/* Fill the gaps
|
||||
* When stepping in x one pixel remains empty on every corner */
|
||||
if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) {
|
||||
lv_draw_px(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa);
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y,
|
||||
-(main_line->p_act.y - prev_p.y + 1), mask, style->line.color, opa);
|
||||
lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y,
|
||||
main_line->p_act.y - prev_p.y + 1, mask, style->line.color, opa);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2)
|
||||
{
|
||||
line->p1.x = p1->x;
|
||||
line->p1.y = p1->y;
|
||||
line->p2.x = p2->x;
|
||||
line->p2.y = p2->y;
|
||||
|
||||
line->dx = LV_MATH_ABS(line->p2.x - line->p1.x);
|
||||
line->sx = line->p1.x < line->p2.x ? 1 : -1;
|
||||
line->dy = LV_MATH_ABS(line->p2.y - line->p1.y);
|
||||
line->sy = line->p1.y < line->p2.y ? 1 : -1;
|
||||
line->err = (line->dx > line->dy ? line->dx : -line->dy) / 2;
|
||||
line->e2 = 0;
|
||||
line->hor = line->dx > line->dy ? true : false; /*Rather horizontal or vertical*/
|
||||
|
||||
line->p_act.x = line->p1.x;
|
||||
line->p_act.y = line->p1.y;
|
||||
}
|
||||
|
||||
static bool line_next(line_draw_t * line)
|
||||
{
|
||||
if(line->p_act.x == line->p2.x && line->p_act.y == line->p2.y) return false;
|
||||
line->e2 = line->err;
|
||||
if(line->e2 > -line->dx) {
|
||||
line->err -= line->dy;
|
||||
line->p_act.x += line->sx;
|
||||
}
|
||||
if(line->e2 < line->dy) {
|
||||
line->err += line->dx;
|
||||
line->p_act.y += line->sy;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate until step one in y direction.
|
||||
* @param line
|
||||
* @return
|
||||
*/
|
||||
static bool line_next_y(line_draw_t * line)
|
||||
{
|
||||
lv_coord_t last_y = line->p_act.y;
|
||||
|
||||
do {
|
||||
if(!line_next(line)) return false;
|
||||
} while(last_y == line->p_act.y);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate until step one in x direction.
|
||||
* @param line
|
||||
* @return
|
||||
*/
|
||||
static bool line_next_x(line_draw_t * line)
|
||||
{
|
||||
lv_coord_t last_x = line->p_act.x;
|
||||
|
||||
do {
|
||||
if(!line_next(line)) return false;
|
||||
} while(last_x == line->p_act.x);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
49
src/lv_draw/lv_draw_line.h
Normal file
49
src/lv_draw/lv_draw_line.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @file lv_draw_line.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_LINE_H
|
||||
#define LV_DRAW_LINE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw a line
|
||||
* @param point1 first point of the line
|
||||
* @param point2 second point of the line
|
||||
* @param mask the line will be drawn only on this area
|
||||
* @param style pointer to a line's style
|
||||
* @param opa_scale scale down all opacities by the factor
|
||||
*/
|
||||
void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask,
|
||||
const lv_style_t * style, lv_opa_t opa_scale);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_LINE_H*/
|
||||
1435
src/lv_draw/lv_draw_rect.c
Normal file
1435
src/lv_draw/lv_draw_rect.c
Normal file
File diff suppressed because it is too large
Load Diff
48
src/lv_draw/lv_draw_rect.h
Normal file
48
src/lv_draw/lv_draw_rect.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @file lv_draw_rect.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_RECT_H
|
||||
#define LV_DRAW_RECT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw a rectangle
|
||||
* @param coords the coordinates of the rectangle
|
||||
* @param mask the rectangle will be drawn only in this mask
|
||||
* @param style pointer to a style
|
||||
* @param opa_scale scale down all opacities by the factor
|
||||
*/
|
||||
void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_RECT_H*/
|
||||
164
src/lv_draw/lv_draw_triangle.c
Normal file
164
src/lv_draw/lv_draw_triangle.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @file lv_draw_triangle.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_triangle.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static void point_swap(lv_point_t * p1, lv_point_t * p2);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
/**
|
||||
*
|
||||
* @param points pointer to an array with 3 points
|
||||
* @param mask the triangle will be drawn only in this mask
|
||||
* @param color color of the triangle
|
||||
* @param opa_scale scale down all opacities by the factor
|
||||
*/
|
||||
void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color, lv_opa_t opa_scale)
|
||||
{
|
||||
lv_point_t tri[3];
|
||||
|
||||
memcpy(tri, points, sizeof(tri));
|
||||
|
||||
/*Sort the vertices according to their y coordinate (0: y max, 1: y mid, 2:y min)*/
|
||||
if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]);
|
||||
if(tri[2].y < tri[1].y) point_swap(&tri[2], &tri[1]);
|
||||
if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]);
|
||||
|
||||
/*Return is the triangle is degenerated*/
|
||||
if(tri[0].x == tri[1].x && tri[0].y == tri[1].y) return;
|
||||
if(tri[1].x == tri[2].x && tri[1].y == tri[2].y) return;
|
||||
if(tri[0].x == tri[2].x && tri[0].y == tri[2].y) return;
|
||||
|
||||
if(tri[0].x == tri[1].x && tri[1].x == tri[2].x) return;
|
||||
if(tri[0].y == tri[1].y && tri[1].y == tri[2].y) return;
|
||||
|
||||
/*Draw the triangle*/
|
||||
lv_point_t edge1;
|
||||
lv_coord_t dx1 = LV_MATH_ABS(tri[0].x - tri[1].x);
|
||||
lv_coord_t sx1 = tri[0].x < tri[1].x ? 1 : -1;
|
||||
lv_coord_t dy1 = LV_MATH_ABS(tri[0].y - tri[1].y);
|
||||
lv_coord_t sy1 = tri[0].y < tri[1].y ? 1 : -1;
|
||||
lv_coord_t err1 = (dx1 > dy1 ? dx1 : -dy1) / 2;
|
||||
lv_coord_t err_tmp1;
|
||||
|
||||
lv_point_t edge2;
|
||||
lv_coord_t dx2 = LV_MATH_ABS(tri[0].x - tri[2].x);
|
||||
lv_coord_t sx2 = tri[0].x < tri[2].x ? 1 : -1;
|
||||
lv_coord_t dy2 = LV_MATH_ABS(tri[0].y - tri[2].y);
|
||||
lv_coord_t sy2 = tri[0].y < tri[2].y ? 1 : -1;
|
||||
lv_coord_t err2 = (dx1 > dy2 ? dx2 : -dy2) / 2;
|
||||
lv_coord_t err_tmp2;
|
||||
|
||||
lv_coord_t y1_tmp;
|
||||
lv_coord_t y2_tmp;
|
||||
|
||||
edge1.x = tri[0].x;
|
||||
edge1.y = tri[0].y;
|
||||
edge2.x = tri[0].x;
|
||||
edge2.y = tri[0].y;
|
||||
lv_area_t act_area;
|
||||
lv_area_t draw_area;
|
||||
|
||||
while(1) {
|
||||
act_area.x1 = edge1.x;
|
||||
act_area.x2 = edge2.x ;
|
||||
act_area.y1 = edge1.y;
|
||||
act_area.y2 = edge2.y ;
|
||||
|
||||
|
||||
draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);
|
||||
draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);
|
||||
draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);
|
||||
draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);
|
||||
draw_area.x2--; /*Do not draw most right pixel because it will be drawn by the adjacent triangle*/
|
||||
lv_draw_fill(&draw_area, mask, color, LV_OPA_COVER);
|
||||
|
||||
/*Calc. the next point of edge1*/
|
||||
y1_tmp = edge1.y;
|
||||
do {
|
||||
if(edge1.x == tri[1].x && edge1.y == tri[1].y) {
|
||||
|
||||
dx1 = LV_MATH_ABS(tri[1].x - tri[2].x);
|
||||
sx1 = tri[1].x < tri[2].x ? 1 : -1;
|
||||
dy1 = LV_MATH_ABS(tri[1].y - tri[2].y);
|
||||
sy1 = tri[1].y < tri[2].y ? 1 : -1;
|
||||
err1 = (dx1 > dy1 ? dx1 : -dy1) / 2;
|
||||
} else if(edge1.x == tri[2].x && edge1.y == tri[2].y) return;
|
||||
err_tmp1 = err1;
|
||||
if(err_tmp1 > -dx1) {
|
||||
err1 -= dy1;
|
||||
edge1.x += sx1;
|
||||
}
|
||||
if(err_tmp1 < dy1) {
|
||||
err1 += dx1;
|
||||
edge1.y += sy1;
|
||||
}
|
||||
} while(edge1.y == y1_tmp);
|
||||
|
||||
/*Calc. the next point of edge2*/
|
||||
y2_tmp = edge2.y;
|
||||
do {
|
||||
if(edge2.x == tri[2].x && edge2.y == tri[2].y) return;
|
||||
err_tmp2 = err2;
|
||||
if(err_tmp2 > -dx2) {
|
||||
err2 -= dy2;
|
||||
edge2.x += sx2;
|
||||
}
|
||||
if(err_tmp2 < dy2) {
|
||||
err2 += dx2;
|
||||
edge2.y += sy2;
|
||||
}
|
||||
} while(edge2.y == y2_tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
/**
|
||||
* Swap two points
|
||||
* p1 pointer to the first point
|
||||
* p2 pointer to the second point
|
||||
*/
|
||||
static void point_swap(lv_point_t * p1, lv_point_t * p2)
|
||||
{
|
||||
lv_point_t tmp;
|
||||
tmp.x = p1->x;
|
||||
tmp.y = p1->y;
|
||||
|
||||
p1->x = p2->x;
|
||||
p1->y = p2->y;
|
||||
|
||||
p2->x = tmp.x;
|
||||
p2->y = tmp.y;
|
||||
|
||||
}
|
||||
48
src/lv_draw/lv_draw_triangle.h
Normal file
48
src/lv_draw/lv_draw_triangle.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @file lv_draw_triangle.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_TRIANGLE_H
|
||||
#define LV_DRAW_TRIANGLE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param points pointer to an array with 3 points
|
||||
* @param mask the triangle will be drawn only in this mask
|
||||
* @param color color of the triangle
|
||||
* @param opa_scale scale down all opacities by the factor
|
||||
*/
|
||||
void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color, lv_opa_t opa_scale);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_TRIANGLE_H*/
|
||||
165
src/lv_fonts/lv_font_builtin.c
Normal file
165
src/lv_fonts/lv_font_builtin.c
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* @file lv_font_built_in.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_font_builtin.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the built-in fonts
|
||||
*/
|
||||
void lv_font_builtin_init(void)
|
||||
{
|
||||
/*DEJAVU 10*/
|
||||
#if LV_USE_FONT_DEJAVU_10 != 0
|
||||
lv_font_add(&lv_font_dejavu_10, NULL);
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_10_LATIN_SUP != 0
|
||||
#if LV_USE_FONT_DEJAVU_10 != 0
|
||||
lv_font_add(&lv_font_dejavu_10_latin_sup, &lv_font_dejavu_10);
|
||||
#else
|
||||
lv_font_add(&lv_font_dejavu_10_latin_sup, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_10_CYRILLIC != 0
|
||||
#if LV_USE_FONT_DEJAVU_10 != 0
|
||||
lv_font_add(&lv_font_dejavu_10_cyrillic, &lv_font_dejavu_10);
|
||||
#else
|
||||
lv_font_add(&lv_font_dejavu_10_cyrillic, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*SYMBOL 10*/
|
||||
#if LV_USE_FONT_SYMBOL_10 != 0
|
||||
#if LV_USE_FONT_DEJAVU_10 != 0
|
||||
lv_font_add(&lv_font_symbol_10, &lv_font_dejavu_10);
|
||||
#else
|
||||
lv_font_add(&lv_font_symbol_10, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*DEJAVU 20*/
|
||||
#if LV_USE_FONT_DEJAVU_20 != 0
|
||||
lv_font_add(&lv_font_dejavu_20, NULL);
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_20_LATIN_SUP != 0
|
||||
#if LV_USE_FONT_DEJAVU_20 != 0
|
||||
lv_font_add(&lv_font_dejavu_20_latin_sup, &lv_font_dejavu_20);
|
||||
#else
|
||||
lv_font_add(&lv_font_symbol_20_latin_sup, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_20_CYRILLIC != 0
|
||||
#if LV_USE_FONT_DEJAVU_20 != 0
|
||||
lv_font_add(&lv_font_dejavu_20_cyrillic, &lv_font_dejavu_20);
|
||||
#else
|
||||
lv_font_add(&lv_font_dejavu_20_cyrillic, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*SYMBOL 20*/
|
||||
#if LV_USE_FONT_SYMBOL_20 != 0
|
||||
#if LV_USE_FONT_DEJAVU_20 != 0
|
||||
lv_font_add(&lv_font_symbol_20, &lv_font_dejavu_20);
|
||||
#else
|
||||
lv_font_add(&lv_font_symbol_20, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*DEJAVU 30*/
|
||||
#if LV_USE_FONT_DEJAVU_30 != 0
|
||||
lv_font_add(&lv_font_dejavu_30, NULL);
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_30_LATIN_SUP != 0
|
||||
#if LV_USE_FONT_DEJAVU_30 != 0
|
||||
lv_font_add(&lv_font_dejavu_30_latin_sup, &lv_font_dejavu_30);
|
||||
#else
|
||||
lv_font_add(&lv_font_dejavu_30_latin_sup, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_30_CYRILLIC != 0
|
||||
#if LV_USE_FONT_DEJAVU_30 != 0
|
||||
lv_font_add(&lv_font_dejavu_30_cyrillic, &lv_font_dejavu_30);
|
||||
#else
|
||||
lv_font_add(&lv_font_dejavu_30_cyrillic, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*SYMBOL 30*/
|
||||
#if LV_USE_FONT_SYMBOL_30 != 0
|
||||
#if LV_USE_FONT_DEJAVU_30 != 0
|
||||
lv_font_add(&lv_font_symbol_30, &lv_font_dejavu_30);
|
||||
#else
|
||||
lv_font_add(&lv_font_symbol_30_basic, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*DEJAVU 40*/
|
||||
#if LV_USE_FONT_DEJAVU_40 != 0
|
||||
lv_font_add(&lv_font_dejavu_40, NULL);
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_40_LATIN_SUP != 0
|
||||
#if LV_USE_FONT_DEJAVU_40 != 0
|
||||
lv_font_add(&lv_font_dejavu_40_latin_sup, &lv_font_dejavu_40);
|
||||
#else
|
||||
lv_font_add(&lv_font_dejavu_40_latin_sup, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_40_CYRILLIC != 0
|
||||
#if LV_USE_FONT_DEJAVU_40 != 0
|
||||
lv_font_add(&lv_font_dejavu_40_cyrillic, &lv_font_dejavu_40);
|
||||
#else
|
||||
lv_font_add(&lv_font_dejavu_40_cyrillic, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*SYMBOL 40*/
|
||||
#if LV_USE_FONT_SYMBOL_40 != 0
|
||||
#if LV_USE_FONT_DEJAVU_40 != 0
|
||||
lv_font_add(&lv_font_symbol_40, &lv_font_dejavu_40);
|
||||
#else
|
||||
lv_font_add(&lv_font_symbol_40, NULL);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
125
src/lv_fonts/lv_font_builtin.h
Normal file
125
src/lv_fonts/lv_font_builtin.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* @file lv_font_builtin.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_FONT_BUILTIN_H
|
||||
#define LV_FONT_BUILTIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include "../lv_misc/lv_font.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the built-in fonts
|
||||
*/
|
||||
void lv_font_builtin_init(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* FONT DECLARATIONS
|
||||
**********************/
|
||||
|
||||
/*10 px */
|
||||
#if LV_USE_FONT_DEJAVU_10
|
||||
LV_FONT_DECLARE(lv_font_dejavu_10)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_10_LATIN_SUP
|
||||
LV_FONT_DECLARE(lv_font_dejavu_10_latin_sup)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_10_CYRILLIC
|
||||
LV_FONT_DECLARE(lv_font_dejavu_10_cyrillic)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_SYMBOL_10
|
||||
LV_FONT_DECLARE(lv_font_symbol_10)
|
||||
#endif
|
||||
|
||||
/*20 px */
|
||||
#if LV_USE_FONT_DEJAVU_20
|
||||
LV_FONT_DECLARE(lv_font_dejavu_20)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_20_LATIN_SUP
|
||||
LV_FONT_DECLARE(lv_font_dejavu_20_latin_sup)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_20_CYRILLIC
|
||||
LV_FONT_DECLARE(lv_font_dejavu_20_cyrillic)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_SYMBOL_20
|
||||
LV_FONT_DECLARE(lv_font_symbol_20)
|
||||
#endif
|
||||
|
||||
/*30 px */
|
||||
#if LV_USE_FONT_DEJAVU_30
|
||||
LV_FONT_DECLARE(lv_font_dejavu_30)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_30_LATIN_SUP
|
||||
LV_FONT_DECLARE(lv_font_dejavu_30_latin_sup)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_30_CYRILLIC
|
||||
LV_FONT_DECLARE(lv_font_dejavu_30_cyrillic)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_SYMBOL_30
|
||||
LV_FONT_DECLARE(lv_font_symbol_30)
|
||||
#endif
|
||||
|
||||
/*40 px */
|
||||
#if LV_USE_FONT_DEJAVU_40
|
||||
LV_FONT_DECLARE(lv_font_dejavu_40)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_40_LATIN_SUP
|
||||
LV_FONT_DECLARE(lv_font_dejavu_40_latin_sup)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_DEJAVU_40_CYRILLIC
|
||||
LV_FONT_DECLARE(lv_font_dejavu_40_cyrillic)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_SYMBOL_40
|
||||
LV_FONT_DECLARE(lv_font_symbol_40)
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_MONOSPACE_8
|
||||
LV_FONT_DECLARE(lv_font_monospace_8)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_FONT_BUILTIN_H*/
|
||||
5380
src/lv_fonts/lv_font_dejavu_10.c
Normal file
5380
src/lv_fonts/lv_font_dejavu_10.c
Normal file
File diff suppressed because it is too large
Load Diff
3644
src/lv_fonts/lv_font_dejavu_10_cyrillic.c
Normal file
3644
src/lv_fonts/lv_font_dejavu_10_cyrillic.c
Normal file
File diff suppressed because it is too large
Load Diff
5436
src/lv_fonts/lv_font_dejavu_10_latin_sup.c
Normal file
5436
src/lv_fonts/lv_font_dejavu_10_latin_sup.c
Normal file
File diff suppressed because it is too large
Load Diff
9180
src/lv_fonts/lv_font_dejavu_20.c
Normal file
9180
src/lv_fonts/lv_font_dejavu_20.c
Normal file
File diff suppressed because it is too large
Load Diff
6204
src/lv_fonts/lv_font_dejavu_20_cyrillic.c
Normal file
6204
src/lv_fonts/lv_font_dejavu_20_cyrillic.c
Normal file
File diff suppressed because it is too large
Load Diff
9276
src/lv_fonts/lv_font_dejavu_20_latin_sup.c
Normal file
9276
src/lv_fonts/lv_font_dejavu_20_latin_sup.c
Normal file
File diff suppressed because it is too large
Load Diff
12980
src/lv_fonts/lv_font_dejavu_30.c
Normal file
12980
src/lv_fonts/lv_font_dejavu_30.c
Normal file
File diff suppressed because it is too large
Load Diff
8764
src/lv_fonts/lv_font_dejavu_30_cyrillic.c
Normal file
8764
src/lv_fonts/lv_font_dejavu_30_cyrillic.c
Normal file
File diff suppressed because it is too large
Load Diff
13116
src/lv_fonts/lv_font_dejavu_30_latin_sup.c
Normal file
13116
src/lv_fonts/lv_font_dejavu_30_latin_sup.c
Normal file
File diff suppressed because it is too large
Load Diff
16780
src/lv_fonts/lv_font_dejavu_40.c
Normal file
16780
src/lv_fonts/lv_font_dejavu_40.c
Normal file
File diff suppressed because it is too large
Load Diff
11323
src/lv_fonts/lv_font_dejavu_40_cyrillic.c
Normal file
11323
src/lv_fonts/lv_font_dejavu_40_cyrillic.c
Normal file
File diff suppressed because it is too large
Load Diff
16956
src/lv_fonts/lv_font_dejavu_40_latin_sup.c
Normal file
16956
src/lv_fonts/lv_font_dejavu_40_latin_sup.c
Normal file
File diff suppressed because it is too large
Load Diff
4619
src/lv_fonts/lv_font_monospace_8.c
Normal file
4619
src/lv_fonts/lv_font_monospace_8.c
Normal file
File diff suppressed because it is too large
Load Diff
2861
src/lv_fonts/lv_font_symbol_10.c
Normal file
2861
src/lv_fonts/lv_font_symbol_10.c
Normal file
File diff suppressed because it is too large
Load Diff
4861
src/lv_fonts/lv_font_symbol_20.c
Normal file
4861
src/lv_fonts/lv_font_symbol_20.c
Normal file
File diff suppressed because it is too large
Load Diff
6860
src/lv_fonts/lv_font_symbol_30.c
Normal file
6860
src/lv_fonts/lv_font_symbol_30.c
Normal file
File diff suppressed because it is too large
Load Diff
8861
src/lv_fonts/lv_font_symbol_40.c
Normal file
8861
src/lv_fonts/lv_font_symbol_40.c
Normal file
File diff suppressed because it is too large
Load Diff
23
src/lv_fonts/lv_fonts.mk
Normal file
23
src/lv_fonts/lv_fonts.mk
Normal file
@@ -0,0 +1,23 @@
|
||||
CSRCS += lv_font_builtin.c
|
||||
CSRCS += lv_font_dejavu_10.c
|
||||
CSRCS += lv_font_dejavu_20.c
|
||||
CSRCS += lv_font_dejavu_30.c
|
||||
CSRCS += lv_font_dejavu_40.c
|
||||
CSRCS += lv_font_dejavu_10_cyrillic.c
|
||||
CSRCS += lv_font_dejavu_20_cyrillic.c
|
||||
CSRCS += lv_font_dejavu_30_cyrillic.c
|
||||
CSRCS += lv_font_dejavu_40_cyrillic.c
|
||||
CSRCS += lv_font_dejavu_10_latin_sup.c
|
||||
CSRCS += lv_font_dejavu_20_latin_sup.c
|
||||
CSRCS += lv_font_dejavu_30_latin_sup.c
|
||||
CSRCS += lv_font_dejavu_40_latin_sup.c
|
||||
CSRCS += lv_font_symbol_10.c
|
||||
CSRCS += lv_font_symbol_20.c
|
||||
CSRCS += lv_font_symbol_30.c
|
||||
CSRCS += lv_font_symbol_40.c
|
||||
CSRCS += lv_font_monospace_8.c
|
||||
|
||||
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/src/lv_fonts
|
||||
VPATH += :$(LVGL_DIR)/lvgl/src/lv_fonts
|
||||
|
||||
CFLAGS += "-I$(LVGL_DIR)/lvgl/src/lv_fonts"
|
||||
40
src/lv_hal/lv_hal.h
Normal file
40
src/lv_hal/lv_hal.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @file lv_hal.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_HAL_H
|
||||
#define LV_HAL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_hal_disp.h"
|
||||
#include "lv_hal_indev.h"
|
||||
#include "lv_hal_tick.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
8
src/lv_hal/lv_hal.mk
Normal file
8
src/lv_hal/lv_hal.mk
Normal file
@@ -0,0 +1,8 @@
|
||||
CSRCS += lv_hal_disp.c
|
||||
CSRCS += lv_hal_indev.c
|
||||
CSRCS += lv_hal_tick.c
|
||||
|
||||
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/src/lv_hal
|
||||
VPATH += :$(LVGL_DIR)/lvgl/src/lv_hal
|
||||
|
||||
CFLAGS += "-I$(LVGL_DIR)/lvgl/src/lv_hal"
|
||||
296
src/lv_hal/lv_hal_disp.c
Normal file
296
src/lv_hal/lv_hal_disp.c
Normal file
@@ -0,0 +1,296 @@
|
||||
|
||||
/**
|
||||
* @file hal_disp.c
|
||||
*
|
||||
* @description HAL layer for display driver
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "lv_hal.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
#include "../lv_core/lv_obj.h"
|
||||
#include "../lv_misc/lv_gc.h"
|
||||
|
||||
#if defined(LV_GC_INCLUDE)
|
||||
# include LV_GC_INCLUDE
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_disp_t * disp_def;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize a display driver with default values.
|
||||
* It is used to surly have known values in the fields ant not memory junk.
|
||||
* After it you can set the fields.
|
||||
* @param driver pointer to driver variable to initialize
|
||||
*/
|
||||
void lv_disp_drv_init(lv_disp_drv_t * driver)
|
||||
{
|
||||
memset(driver, 0, sizeof(lv_disp_drv_t));
|
||||
|
||||
driver->flush_cb = NULL;
|
||||
driver->hor_res = LV_HOR_RES_MAX;
|
||||
driver->ver_res = LV_VER_RES_MAX;
|
||||
driver->buffer = NULL;
|
||||
|
||||
#if LV_USE_GPU
|
||||
driver->mem_blend = NULL;
|
||||
driver->mem_fill = NULL;
|
||||
#endif
|
||||
|
||||
driver->set_px_cb = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a display buffer
|
||||
* @param disp_buf pointer `lv_disp_buf_t` variable to initialize
|
||||
* @param buf1 A buffer to be used by LittlevGL to draw the image.
|
||||
* Always has to specified and can't be NULL.
|
||||
* Can be an array allocated by the user. E.g. `static lv_color_t disp_buf1[1024 * 10]`
|
||||
* Or a memory address e.g. in external SRAM
|
||||
* @param buf2 Optionally specify a second buffer to make image rendering and image flushing
|
||||
* (sending to the display) parallel.
|
||||
* In the `disp_drv->flush` you should use DMA or similar hardware to send
|
||||
* the image to the display in the background.
|
||||
* It lets LittlevGL to render next frame into the other buffer while previous is being sent.
|
||||
* Set to `NULL` if unused.
|
||||
* @param size size of the `buf1` and `buf2` in pixel count.
|
||||
*/
|
||||
void lv_disp_buf_init(lv_disp_buf_t * disp_buf, void * buf1, void * buf2, uint32_t size)
|
||||
{
|
||||
memset(disp_buf, 0, sizeof(lv_disp_buf_t));
|
||||
|
||||
disp_buf->buf1 = buf1;
|
||||
disp_buf->buf2 = buf2;
|
||||
disp_buf->buf_act = disp_buf->buf1;
|
||||
disp_buf->size = size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register an initialized display driver.
|
||||
* Automatically set the first display as active.
|
||||
* @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable)
|
||||
* @return pointer to the new display or NULL on error
|
||||
*/
|
||||
lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver)
|
||||
{
|
||||
lv_disp_t * disp = lv_ll_ins_head(&LV_GC_ROOT(_lv_disp_ll));
|
||||
if(!disp) {
|
||||
lv_mem_assert(disp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&disp->driver, driver, sizeof(lv_disp_drv_t));
|
||||
memset(&disp->inv_area_joined, 0, sizeof(disp->inv_area_joined));
|
||||
memset(&disp->inv_areas, 0, sizeof(disp->inv_areas));
|
||||
lv_ll_init(&disp->scr_ll, sizeof(lv_obj_t));
|
||||
|
||||
if(disp_def == NULL) disp_def = disp;
|
||||
|
||||
lv_disp_t * disp_def_tmp = disp_def;
|
||||
disp_def = disp; /*Temporarily change the default screen to create the default screens on the new display*/
|
||||
|
||||
disp->act_scr = lv_obj_create(NULL, NULL); /*Create a default screen on the display*/
|
||||
disp->top_layer = lv_obj_create(NULL, NULL); /*Create top layer on the display*/
|
||||
disp->sys_layer = lv_obj_create(NULL, NULL); /*Create top layer on the display*/
|
||||
lv_obj_set_style(disp->top_layer, &lv_style_transp);
|
||||
lv_obj_set_style(disp->sys_layer, &lv_style_transp);
|
||||
|
||||
disp->inv_p = 0;
|
||||
|
||||
lv_obj_invalidate(disp->act_scr);
|
||||
|
||||
disp_def = disp_def_tmp; /*Revert the default display*/
|
||||
|
||||
|
||||
return disp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a display
|
||||
* @param disp pointer to display
|
||||
*/
|
||||
void lv_disp_remove(lv_disp_t * disp)
|
||||
{
|
||||
bool was_default = false;
|
||||
if(disp == lv_disp_get_default()) was_default = true;
|
||||
|
||||
/*Detach the input devices */
|
||||
lv_indev_t * indev;
|
||||
indev = lv_indev_next(NULL);
|
||||
while(indev) {
|
||||
if(indev->driver.disp == disp) {
|
||||
indev->driver.disp = NULL;
|
||||
}
|
||||
indev = lv_indev_next(indev);
|
||||
}
|
||||
|
||||
lv_ll_rem(&LV_GC_ROOT(_lv_disp_ll), disp);
|
||||
lv_mem_free(disp);
|
||||
|
||||
if(was_default) lv_disp_set_default(lv_ll_get_head(&LV_GC_ROOT(_lv_disp_ll)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a default screen. The new screens will be created on it by default.
|
||||
* @param disp pointer to a display
|
||||
*/
|
||||
void lv_disp_set_default(lv_disp_t * disp)
|
||||
{
|
||||
disp_def = disp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default display
|
||||
* @return pointer to the default display
|
||||
*/
|
||||
lv_disp_t * lv_disp_get_default(void)
|
||||
{
|
||||
return disp_def;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the horizontal resolution of a display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the horizontal resolution of the display
|
||||
*/
|
||||
lv_coord_t lv_disp_get_hor_res(lv_disp_t * disp)
|
||||
{
|
||||
if(disp == NULL) disp = lv_disp_get_default();
|
||||
|
||||
if(disp == NULL) return LV_HOR_RES_MAX;
|
||||
else return disp->driver.hor_res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the vertical resolution of a display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the vertical resolution of the display
|
||||
*/
|
||||
lv_coord_t lv_disp_get_ver_res(lv_disp_t * disp)
|
||||
{
|
||||
if(disp == NULL) disp = lv_disp_get_default();
|
||||
|
||||
if(disp == NULL) return LV_VER_RES_MAX;
|
||||
else return disp->driver.ver_res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call in the display driver's `flush_cb` function when the flushing is finished
|
||||
* @param disp_drv pointer to display driver in `flush_cb` where this function is called
|
||||
*/
|
||||
LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_drv_t * disp_drv)
|
||||
{
|
||||
disp_drv->buffer->flushing = 0;
|
||||
|
||||
/*If the screen is transparent initialize it when the flushing is ready*/
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
memset(vdb_buf, 0x00, LV_VDB_SIZE_IN_BYTES);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next display.
|
||||
* @param disp pointer to the current display. NULL to initialize.
|
||||
* @return the next display or NULL if no more. Give the first display when the parameter is NULL
|
||||
*/
|
||||
lv_disp_t * lv_disp_get_next(lv_disp_t * disp)
|
||||
{
|
||||
if(disp == NULL) return lv_ll_get_head(&LV_GC_ROOT(_lv_disp_ll));
|
||||
else return lv_ll_get_next(&LV_GC_ROOT(_lv_disp_ll), disp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internal buffer of a display
|
||||
* @param disp pointer to a display
|
||||
* @return pointer to the internal buffers
|
||||
*/
|
||||
lv_disp_buf_t * lv_disp_get_buf(lv_disp_t * disp)
|
||||
{
|
||||
return disp->driver.buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of areas in the buffer
|
||||
* @return number of invalid areas
|
||||
*/
|
||||
uint16_t lv_disp_get_inv_buf_size(lv_disp_t * disp)
|
||||
{
|
||||
return disp->inv_p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop (delete) the last 'num' invalidated areas from the buffer
|
||||
* @param num number of areas to delete
|
||||
*/
|
||||
void lv_disp_pop_from_inv_buf(lv_disp_t * disp, uint16_t num)
|
||||
{
|
||||
|
||||
if(disp->inv_p < num) disp->inv_p = 0;
|
||||
else disp->inv_p -= num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the driver configuration if it's double buffered (both `buf1` and `buf2` are set)
|
||||
* @param disp pointer to to display to check
|
||||
* @return true: double buffered; false: not double buffered
|
||||
*/
|
||||
bool lv_disp_is_double_buf(lv_disp_t * disp)
|
||||
{
|
||||
if(disp->driver.buffer->buf1 && disp->driver.buffer->buf2) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the driver configuration if it's TRUE double buffered (both `buf1` and `buf2` are set and `size` is screen sized)
|
||||
* @param disp pointer to to display to check
|
||||
* @return true: double buffered; false: not double buffered
|
||||
*/
|
||||
bool lv_disp_is_true_double_buf(lv_disp_t * disp)
|
||||
{
|
||||
uint32_t scr_size = disp->driver.hor_res * disp->driver.ver_res;
|
||||
|
||||
if(lv_disp_is_double_buf(disp) &&
|
||||
disp->driver.buffer->size == scr_size) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
250
src/lv_hal/lv_hal_disp.h
Normal file
250
src/lv_hal/lv_hal_disp.h
Normal file
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* @file lv_hal_disp.h
|
||||
*
|
||||
* @description Display Driver HAL interface header file
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_HAL_DISP_H
|
||||
#define LV_HAL_DISP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "lv_hal.h"
|
||||
#include "../lv_misc/lv_color.h"
|
||||
#include "../lv_misc/lv_area.h"
|
||||
#include "../lv_misc/lv_ll.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#ifndef LV_INV_BUF_SIZE
|
||||
#define LV_INV_BUF_SIZE 32 /*Buffer size for invalid areas */
|
||||
#endif
|
||||
|
||||
#ifndef LV_ATTRIBUTE_FLUSH_READY
|
||||
# define LV_ATTRIBUTE_FLUSH_READY
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _disp_t;
|
||||
struct _disp_drv_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void * buf1;
|
||||
void * buf2;
|
||||
|
||||
/*Used by the library*/
|
||||
void * buf_act;
|
||||
uint32_t size; /*In pixel count*/
|
||||
lv_area_t area;
|
||||
volatile uint32_t flushing :1;
|
||||
}lv_disp_buf_t;
|
||||
|
||||
|
||||
/**
|
||||
* Display Driver structure to be registered by HAL
|
||||
*/
|
||||
typedef struct _disp_drv_t {
|
||||
|
||||
/*Horizontal and vertical resolution*/
|
||||
lv_coord_t hor_res;
|
||||
lv_coord_t ver_res;
|
||||
|
||||
/* Pointer to a buffer initialized with `lv_disp_buf_init()`.
|
||||
* LittlevGL will use this buffer(s) to draw the screens contents */
|
||||
lv_disp_buf_t * buffer;
|
||||
|
||||
/* MANDATORY: Write the internal buffer (VDB) to the display. 'lv_flush_ready()' has to be called when finished */
|
||||
void (*flush_cb)(struct _disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||
|
||||
/* OPTIONAL: Extend the invalidated areas to match with the display drivers requirements
|
||||
* E.g. round `y` to, 8, 16 ..) on a monochrome display*/
|
||||
void (*rounder_cb)(struct _disp_drv_t * disp_drv, lv_area_t * area);
|
||||
|
||||
/* OPTIONAL: Set a pixel in a buffer according to the special requirements of the display
|
||||
* Can be used for color format not supported in LittelvGL. E.g. 2 bit -> 4 gray scales
|
||||
* Note: Much slower then drawing with supported color formats. */
|
||||
void (*set_px_cb)(struct _disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
|
||||
|
||||
/* OPTIONAL: Called after every refresh cycle to tell the rendering and flushing time + the number of flushed pixels */
|
||||
void (*monitor_cb)(struct _disp_drv_t * disp_drv, uint32_t time, uint32_t px);
|
||||
|
||||
|
||||
#if LV_USE_USER_DATA_SINGLE
|
||||
lv_disp_drv_user_data_t user_data;
|
||||
#endif
|
||||
|
||||
#if LV_USE_USER_DATA_MULTI
|
||||
lv_disp_drv_user_data_t flush_user_data;
|
||||
lv_disp_drv_user_data_t rounder_user_data;
|
||||
lv_disp_drv_user_data_t set_px_user_data;
|
||||
lv_disp_drv_user_data_t monitor_user_data;
|
||||
#endif
|
||||
|
||||
#if LV_USE_GPU
|
||||
/*OPTIONAL: Blend two memories using opacity (GPU only)*/
|
||||
void (*mem_blend)(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);
|
||||
|
||||
/*OPTIONAL: Fill a memory with a color (GPU only)*/
|
||||
void (*mem_fill)(lv_color_t * dest, uint32_t length, lv_color_t color);
|
||||
#endif
|
||||
|
||||
} lv_disp_drv_t;
|
||||
|
||||
struct _lv_obj_t;
|
||||
|
||||
typedef struct _disp_t {
|
||||
/*Driver to the display*/
|
||||
lv_disp_drv_t driver;
|
||||
|
||||
/*Screens of the display*/
|
||||
lv_ll_t scr_ll;
|
||||
struct _lv_obj_t * act_scr;
|
||||
struct _lv_obj_t * top_layer;
|
||||
struct _lv_obj_t * sys_layer;
|
||||
|
||||
/*Invalidated (marked to redraw) areas*/
|
||||
lv_area_t inv_areas[LV_INV_BUF_SIZE];
|
||||
uint8_t inv_area_joined[LV_INV_BUF_SIZE];
|
||||
uint32_t inv_p :10;
|
||||
} lv_disp_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize a display driver with default values.
|
||||
* It is used to surly have known values in the fields ant not memory junk.
|
||||
* After it you can set the fields.
|
||||
* @param driver pointer to driver variable to initialize
|
||||
*/
|
||||
void lv_disp_drv_init(lv_disp_drv_t * driver);
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a display buffer
|
||||
* @param disp_buf pointer `lv_disp_buf_t` variable to initialize
|
||||
* @param buf1 A buffer to be used by LittlevGL to draw the image.
|
||||
* Always has to specified and can't be NULL.
|
||||
* Can be an array allocated by the user. E.g. `static lv_color_t disp_buf1[1024 * 10]`
|
||||
* Or a memory address e.g. in external SRAM
|
||||
* @param buf2 Optionally specify a second buffer to make image rendering and image flushing
|
||||
* (sending to the display) parallel.
|
||||
* In the `disp_drv->flush` you should use DMA or similar hardware to send
|
||||
* the image to the display in the background.
|
||||
* It lets LittlevGL to render next frame into the other buffer while previous is being sent.
|
||||
* Set to `NULL` if unused.
|
||||
* @param size size of the `buf1` and `buf2` in pixel count.
|
||||
*/
|
||||
void lv_disp_buf_init(lv_disp_buf_t * disp_buf, void * buf1, void * buf2, uint32_t size);
|
||||
|
||||
/**
|
||||
* Register an initialized display driver.
|
||||
* Automatically set the first display as active.
|
||||
* @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable)
|
||||
* @return pointer to the new display or NULL on error
|
||||
*/
|
||||
lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver);
|
||||
|
||||
/**
|
||||
* Remove a display
|
||||
* @param disp pointer to display
|
||||
*/
|
||||
void lv_disp_remove(lv_disp_t * disp);
|
||||
|
||||
/**
|
||||
* Set a default screen. The new screens will be created on it by default.
|
||||
* @param disp pointer to a display
|
||||
*/
|
||||
void lv_disp_set_default(lv_disp_t * disp);
|
||||
|
||||
/**
|
||||
* Get the default display
|
||||
* @return pointer to the default display
|
||||
*/
|
||||
lv_disp_t * lv_disp_get_default(void);
|
||||
|
||||
/**
|
||||
* Get the horizontal resolution of a display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the horizontal resolution of the display
|
||||
*/
|
||||
lv_coord_t lv_disp_get_hor_res(lv_disp_t * disp);
|
||||
|
||||
/**
|
||||
* Get the vertical resolution of a display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the vertical resolution of the display
|
||||
*/
|
||||
lv_coord_t lv_disp_get_ver_res(lv_disp_t * disp);
|
||||
|
||||
/**
|
||||
* Call in the display driver's `flush_cb` function when the flushing is finished
|
||||
* @param disp_drv pointer to display driver in `flush_cb` where this function is called
|
||||
*/
|
||||
LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_drv_t * disp_drv);
|
||||
|
||||
|
||||
/**
|
||||
* Get the next display.
|
||||
* @param disp pointer to the current display. NULL to initialize.
|
||||
* @return the next display or NULL if no more. Give the first display when the parameter is NULL
|
||||
*/
|
||||
lv_disp_t * lv_disp_get_next(lv_disp_t * disp);
|
||||
|
||||
/**
|
||||
* Get the internal buffer of a display
|
||||
* @param disp pointer to a display
|
||||
* @return pointer to the internal buffers
|
||||
*/
|
||||
lv_disp_buf_t * lv_disp_get_buf(lv_disp_t * disp);
|
||||
|
||||
/**
|
||||
* Get the number of areas in the buffer
|
||||
* @return number of invalid areas
|
||||
*/
|
||||
uint16_t lv_disp_get_inv_buf_size(lv_disp_t * disp);
|
||||
|
||||
/**
|
||||
* Pop (delete) the last 'num' invalidated areas from the buffer
|
||||
* @param num number of areas to delete
|
||||
*/
|
||||
void lv_disp_pop_from_inv_buf(lv_disp_t * disp, uint16_t num);
|
||||
|
||||
/**
|
||||
* Check the driver configuration if it's double buffered (both `buf1` and `buf2` are set)
|
||||
* @param disp pointer to to display to check
|
||||
* @return true: double buffered; false: not double buffered
|
||||
*/
|
||||
bool lv_disp_is_double_buf(lv_disp_t * disp);
|
||||
|
||||
/**
|
||||
* Check the driver configuration if it's TRUE double buffered (both `buf1` and `buf2` are set and `size` is screen sized)
|
||||
* @param disp pointer to to display to check
|
||||
* @return true: double buffered; false: not double buffered
|
||||
*/
|
||||
bool lv_disp_is_true_double_buf(lv_disp_t * disp);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
137
src/lv_hal/lv_hal_indev.c
Normal file
137
src/lv_hal/lv_hal_indev.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* @file hal_indev.c
|
||||
*
|
||||
* @description Input device HAL interface
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_hal/lv_hal_indev.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
#include "../lv_misc/lv_gc.h"
|
||||
#include "lv_hal_disp.h"
|
||||
|
||||
#if defined(LV_GC_INCLUDE)
|
||||
# include LV_GC_INCLUDE
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize an input device driver with default values.
|
||||
* It is used to surly have known values in the fields ant not memory junk.
|
||||
* After it you can set the fields.
|
||||
* @param driver pointer to driver variable to initialize
|
||||
*/
|
||||
void lv_indev_drv_init(lv_indev_drv_t * driver)
|
||||
{
|
||||
memset(driver, 0, sizeof(lv_indev_drv_t));
|
||||
|
||||
driver->type = LV_INDEV_TYPE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an initialized input device driver.
|
||||
* @param driver pointer to an initialized 'lv_indev_drv_t' variable (can be local variable)
|
||||
* @return pointer to the new input device or NULL on error
|
||||
*/
|
||||
lv_indev_t * lv_indev_drv_register(lv_indev_drv_t * driver)
|
||||
{
|
||||
|
||||
if(driver->disp == NULL) driver->disp = lv_disp_get_default();
|
||||
|
||||
if(driver->disp == NULL) {
|
||||
LV_LOG_WARN("lv_indev_drv_register: no display registered hence can't attache the indev to a display");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_indev_t * node = lv_ll_ins_head(&LV_GC_ROOT(_lv_indev_ll));
|
||||
if(!node) {
|
||||
lv_mem_assert(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(node, 0, sizeof(lv_indev_t));
|
||||
memcpy(&node->driver, driver, sizeof(lv_indev_drv_t));
|
||||
|
||||
node->proc.reset_query = 1;
|
||||
node->cursor = NULL;
|
||||
node->group = NULL;
|
||||
node->btn_points = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next input device.
|
||||
* @param indev pointer to the current input device. NULL to initialize.
|
||||
* @return the next input devise or NULL if no more. Give the first input device when the parameter is NULL
|
||||
*/
|
||||
lv_indev_t * lv_indev_next(lv_indev_t * indev)
|
||||
{
|
||||
if(indev == NULL) return lv_ll_get_head(LV_GC_ROOT(&_lv_indev_ll));
|
||||
else return lv_ll_get_next(LV_GC_ROOT(&_lv_indev_ll), indev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data from an input device.
|
||||
* @param indev pointer to an input device
|
||||
* @param data input device will write its data here
|
||||
* @return false: no more data; true: there more data to read (buffered)
|
||||
*/
|
||||
bool lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
{
|
||||
bool cont = false;
|
||||
|
||||
memset(data, 0, sizeof(lv_indev_data_t));
|
||||
|
||||
/* For touchpad sometimes users don't the last pressed coordinate on release.
|
||||
* So be sure a coordinates are initialized to the last point */
|
||||
if(indev->driver.type == LV_INDEV_TYPE_POINTER) {
|
||||
data->point.x = indev->proc.types.pointer.act_point.x;
|
||||
data->point.y = indev->proc.types.pointer.act_point.y;
|
||||
}
|
||||
/*Similarly set at least the last key in case of the the user doesn't set it on release*/
|
||||
else if(indev->driver.type == LV_INDEV_TYPE_KEYPAD) {
|
||||
data->key = indev->proc.types.keypad.last_key;
|
||||
}
|
||||
|
||||
if(indev->driver.read_cb) {
|
||||
LV_LOG_TRACE("idnev read started");
|
||||
cont = indev->driver.read_cb(&indev->driver, data);
|
||||
LV_LOG_TRACE("idnev read finished");
|
||||
} else {
|
||||
LV_LOG_WARN("indev function registered");
|
||||
}
|
||||
|
||||
return cont;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
177
src/lv_hal/lv_hal_indev.h
Normal file
177
src/lv_hal/lv_hal_indev.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* @file lv_hal_indev.h
|
||||
*
|
||||
* @description Input Device HAL interface layer header file
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_HAL_INDEV_H
|
||||
#define LV_HAL_INDEV_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "../lv_misc/lv_area.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_obj_t;
|
||||
struct _disp_t;
|
||||
struct _lv_indev_t;
|
||||
struct _lv_indev_drv_t;
|
||||
|
||||
/*Possible input device types*/
|
||||
enum {
|
||||
LV_INDEV_TYPE_NONE, /*Show uninitialized state*/
|
||||
LV_INDEV_TYPE_POINTER, /*Touch pad, mouse, external button*/
|
||||
LV_INDEV_TYPE_KEYPAD, /*Keypad or keyboard*/
|
||||
LV_INDEV_TYPE_BUTTON, /*External (hardware button) which is assinged to a specific point of the screen*/
|
||||
LV_INDEV_TYPE_ENCODER, /*Encoder with only Left, Right turn and a Button*/
|
||||
};
|
||||
typedef uint8_t lv_hal_indev_type_t;
|
||||
|
||||
/*States for input devices*/
|
||||
enum {
|
||||
LV_INDEV_STATE_REL = 0,
|
||||
LV_INDEV_STATE_PR
|
||||
};
|
||||
typedef uint8_t lv_indev_state_t;
|
||||
|
||||
/*Data type when an input device is read */
|
||||
typedef struct {
|
||||
lv_point_t point; /*For LV_INDEV_TYPE_POINTER the currently pressed point*/
|
||||
uint32_t key; /*For LV_INDEV_TYPE_KEYPAD the currently pressed key*/
|
||||
uint32_t btn_id; /*For LV_INDEV_TYPE_BUTTON the currently pressed button*/
|
||||
int16_t enc_diff; /*For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/
|
||||
|
||||
lv_indev_state_t state; /*LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/
|
||||
|
||||
} lv_indev_data_t;
|
||||
|
||||
/*Initialized by the user and registered by 'lv_indev_add()'*/
|
||||
typedef struct _lv_indev_drv_t {
|
||||
lv_hal_indev_type_t type; /*Input device type*/
|
||||
bool (*read_cb)(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t *data); /*Function pointer to read_cb data. Return 'true' if there is still data to be read_cb (buffered)*/
|
||||
|
||||
#if LV_USE_USER_DATA_MULTI
|
||||
lv_indev_drv_user_data_t read_user_data; /*Pointer to user defined data, passed in 'lv_indev_data_t' on read*/
|
||||
#endif
|
||||
|
||||
#if LV_USE_USER_DATA_SINGLE
|
||||
lv_indev_drv_user_data_t user_data;
|
||||
#endif
|
||||
struct _disp_t * disp; /*Pointer to the assigned display*/
|
||||
} lv_indev_drv_t;
|
||||
|
||||
|
||||
/*Run time data of input devices*/
|
||||
typedef struct _lv_indev_proc_t {
|
||||
lv_indev_state_t state;
|
||||
union {
|
||||
struct { /*Pointer and button data*/
|
||||
lv_point_t act_point;
|
||||
lv_point_t last_point;
|
||||
lv_point_t vect;
|
||||
lv_point_t drag_sum; /*Count the dragged pixels to check LV_INDEV_DRAG_LIMIT*/
|
||||
lv_point_t drag_throw_vect;
|
||||
struct _lv_obj_t * act_obj; /*The object being pressed*/
|
||||
struct _lv_obj_t * last_obj; /*The last obejct which was pressed (used by dragthrow and other post-release event)*/
|
||||
struct _lv_obj_t * last_pressed; /*The lastly pressed object*/
|
||||
|
||||
/*Flags*/
|
||||
uint8_t drag_limit_out :1;
|
||||
uint8_t drag_in_prog :1;
|
||||
uint8_t wait_until_release :1;
|
||||
}pointer;
|
||||
struct { /*Keypad data*/
|
||||
lv_indev_state_t last_state;
|
||||
uint32_t last_key;
|
||||
}keypad;
|
||||
}types;
|
||||
|
||||
uint32_t pr_timestamp; /*Pressed time stamp*/
|
||||
uint32_t longpr_rep_timestamp; /*Long press repeat time stamp*/
|
||||
|
||||
/*Flags*/
|
||||
uint8_t long_pr_sent :1;
|
||||
uint8_t reset_query :1;
|
||||
uint8_t disabled :1;
|
||||
} lv_indev_proc_t;
|
||||
|
||||
typedef void (*lv_indev_feedback_t)(struct _lv_indev_t *, uint8_t);
|
||||
|
||||
struct _lv_obj_t;
|
||||
struct _lv_group_t;
|
||||
|
||||
/*The main input device descriptor with driver, runtime data ('proc') and some additional information*/
|
||||
typedef struct _lv_indev_t {
|
||||
lv_indev_drv_t driver;
|
||||
lv_indev_proc_t proc;
|
||||
lv_indev_feedback_t feedback;
|
||||
uint32_t last_activity_time;
|
||||
struct _lv_obj_t *cursor; /*Cursor for LV_INPUT_TYPE_POINTER*/
|
||||
struct _lv_group_t *group; /*Keypad destination group*/
|
||||
const lv_point_t * btn_points; /*Array points assigned to the button ()screen will be pressed here by the buttons*/
|
||||
} lv_indev_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize an input device driver with default values.
|
||||
* It is used to surly have known values in the fields ant not memory junk.
|
||||
* After it you can set the fields.
|
||||
* @param driver pointer to driver variable to initialize
|
||||
*/
|
||||
void lv_indev_drv_init(lv_indev_drv_t *driver);
|
||||
|
||||
/**
|
||||
* Register an initialized input device driver.
|
||||
* @param driver pointer to an initialized 'lv_indev_drv_t' variable (can be local variable)
|
||||
* @return pointer to the new input device or NULL on error
|
||||
*/
|
||||
lv_indev_t * lv_indev_drv_register(lv_indev_drv_t *driver);
|
||||
|
||||
/**
|
||||
* Get the next input device.
|
||||
* @param indev pointer to the current input device. NULL to initialize.
|
||||
* @return the next input devise or NULL if no more. Give the first input device when the parameter is NULL
|
||||
*/
|
||||
lv_indev_t * lv_indev_next(lv_indev_t * indev);
|
||||
|
||||
/**
|
||||
* Read data from an input device.
|
||||
* @param indev pointer to an input device
|
||||
* @param data input device will write its data here
|
||||
* @return false: no more data; true: there more data to read (buffered)
|
||||
*/
|
||||
bool lv_indev_read(lv_indev_t * indev, lv_indev_data_t *data);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
100
src/lv_hal/lv_hal_tick.c
Normal file
100
src/lv_hal/lv_hal_tick.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @file systick.c
|
||||
* Provide access to the system tick with 1 millisecond resolution
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include "lv_hal_tick.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#if LV_TICK_CUSTOM == 1
|
||||
#include LV_TICK_CUSTOM_INCLUDE
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static uint32_t sys_time = 0;
|
||||
static volatile uint8_t tick_irq_flag;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* You have to call this function periodically
|
||||
* @param tick_period the call period of this function in milliseconds
|
||||
*/
|
||||
LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period)
|
||||
{
|
||||
tick_irq_flag = 0;
|
||||
sys_time += tick_period;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the elapsed milliseconds since start up
|
||||
* @return the elapsed milliseconds
|
||||
*/
|
||||
uint32_t lv_tick_get(void)
|
||||
{
|
||||
#if LV_TICK_CUSTOM == 0
|
||||
uint32_t result;
|
||||
do {
|
||||
tick_irq_flag = 1;
|
||||
result = sys_time;
|
||||
} while(!tick_irq_flag); /*'lv_tick_inc()' clears this flag which can be in an interrupt. Continue until make a non interrupted cycle */
|
||||
|
||||
return result;
|
||||
#else
|
||||
return LV_TICK_CUSTOM_SYS_TIME_EXPR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the elapsed milliseconds since a previous time stamp
|
||||
* @param prev_tick a previous time stamp (return value of systick_get() )
|
||||
* @return the elapsed milliseconds since 'prev_tick'
|
||||
*/
|
||||
uint32_t lv_tick_elaps(uint32_t prev_tick)
|
||||
{
|
||||
uint32_t act_time = lv_tick_get();
|
||||
|
||||
/*If there is no overflow in sys_time simple subtract*/
|
||||
if(act_time >= prev_tick) {
|
||||
prev_tick = act_time - prev_tick;
|
||||
} else {
|
||||
prev_tick = UINT32_MAX - prev_tick + 1;
|
||||
prev_tick += act_time;
|
||||
}
|
||||
|
||||
return prev_tick;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
66
src/lv_hal/lv_hal_tick.h
Normal file
66
src/lv_hal/lv_hal_tick.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @file lv_hal_tick.h
|
||||
* Provide access to the system tick with 1 millisecond resolution
|
||||
*/
|
||||
|
||||
#ifndef LV_HAL_TICK_H
|
||||
#define LV_HAL_TICK_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#ifndef LV_ATTRIBUTE_TICK_INC
|
||||
#define LV_ATTRIBUTE_TICK_INC
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* You have to call this function periodically
|
||||
* @param tick_period the call period of this function in milliseconds
|
||||
*/
|
||||
LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period);
|
||||
|
||||
/**
|
||||
* Get the elapsed milliseconds since start up
|
||||
* @return the elapsed milliseconds
|
||||
*/
|
||||
uint32_t lv_tick_get(void);
|
||||
|
||||
/**
|
||||
* Get the elapsed milliseconds since a previous time stamp
|
||||
* @param prev_tick a previous time stamp (return value of systick_get() )
|
||||
* @return the elapsed milliseconds since 'prev_tick'
|
||||
*/
|
||||
uint32_t lv_tick_elaps(uint32_t prev_tick);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_HAL_TICK_H*/
|
||||
445
src/lv_misc/lv_anim.c
Normal file
445
src/lv_misc/lv_anim.c
Normal file
@@ -0,0 +1,445 @@
|
||||
/**
|
||||
* @file anim.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_anim.h"
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "../lv_hal/lv_hal_tick.h"
|
||||
#include "lv_task.h"
|
||||
#include "lv_math.h"
|
||||
#include "lv_gc.h"
|
||||
|
||||
#if defined(LV_GC_INCLUDE)
|
||||
# include LV_GC_INCLUDE
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_ANIM_RESOLUTION 1024
|
||||
#define LV_ANIM_RES_SHIFT 10
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void anim_task(void * param);
|
||||
static bool anim_ready_handler(lv_anim_t * a);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static uint32_t last_task_run;
|
||||
static bool anim_list_changed;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Init. the animation module
|
||||
*/
|
||||
void lv_anim_init(void)
|
||||
{
|
||||
lv_ll_init(&LV_GC_ROOT(_lv_anim_ll), sizeof(lv_anim_t));
|
||||
last_task_run = lv_tick_get();
|
||||
lv_task_create(anim_task, LV_REFR_PERIOD, LV_TASK_PRIO_MID, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an animation
|
||||
* @param anim_p an initialized 'anim_t' variable. Not required after call.
|
||||
*/
|
||||
void lv_anim_create(lv_anim_t * anim_p)
|
||||
{
|
||||
LV_LOG_TRACE("animation create started")
|
||||
/* Do not let two animations for the same 'var' with the same 'fp'*/
|
||||
if(anim_p->fp != NULL) lv_anim_del(anim_p->var, anim_p->fp); /*fp == NULL would delete all animations of var*/
|
||||
|
||||
/*Add the new animation to the animation linked list*/
|
||||
lv_anim_t * new_anim = lv_ll_ins_head(&LV_GC_ROOT(_lv_anim_ll));
|
||||
lv_mem_assert(new_anim);
|
||||
if(new_anim == NULL) return;
|
||||
|
||||
/*Initialize the animation descriptor*/
|
||||
anim_p->playback_now = 0;
|
||||
memcpy(new_anim, anim_p, sizeof(lv_anim_t));
|
||||
|
||||
/*Set the start value*/
|
||||
if(new_anim->fp != NULL) new_anim->fp(new_anim->var, new_anim->start);
|
||||
|
||||
/* Creating an animation changed the linked list.
|
||||
* It's important if it happens in a ready callback. (see `anim_task`)*/
|
||||
anim_list_changed = true;
|
||||
|
||||
LV_LOG_TRACE("animation created")
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an animation for a variable with a given animator function
|
||||
* @param var pointer to variable
|
||||
* @param fp a function pointer which is animating 'var',
|
||||
* or NULL to delete all animations of 'var'
|
||||
* @return true: at least 1 animation is deleted, false: no animation is deleted
|
||||
*/
|
||||
bool lv_anim_del(void * var, lv_anim_fp_t fp)
|
||||
{
|
||||
lv_anim_t * a;
|
||||
lv_anim_t * a_next;
|
||||
bool del = false;
|
||||
a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll));
|
||||
while(a != NULL) {
|
||||
/*'a' might be deleted, so get the next object while 'a' is valid*/
|
||||
a_next = lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a);
|
||||
|
||||
if(a->var == var && (a->fp == fp || fp == NULL)) {
|
||||
lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a);
|
||||
lv_mem_free(a);
|
||||
anim_list_changed = true; /*Read by `anim_task`. It need to know if a delete occurred in the linked list*/
|
||||
del = true;
|
||||
}
|
||||
|
||||
a = a_next;
|
||||
}
|
||||
|
||||
return del;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of currently running animations
|
||||
* @return the number of running animations
|
||||
*/
|
||||
uint16_t lv_anim_count_running(void)
|
||||
{
|
||||
uint16_t cnt = 0;
|
||||
lv_anim_t * a;
|
||||
LV_LL_READ(LV_GC_ROOT(_lv_anim_ll), a) cnt++;
|
||||
|
||||
return cnt++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the time of an animation with a given speed and the start and end values
|
||||
* @param speed speed of animation in unit/sec
|
||||
* @param start start value of the animation
|
||||
* @param end end value of the animation
|
||||
* @return the required time [ms] for the animation with the given parameters
|
||||
*/
|
||||
uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end)
|
||||
{
|
||||
int32_t d = LV_MATH_ABS((int32_t) start - end);
|
||||
uint32_t time = (int32_t)((int32_t)(d * 1000) / speed);
|
||||
|
||||
if(time > UINT16_MAX) time = UINT16_MAX;
|
||||
|
||||
if(time == 0) {
|
||||
time++;
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation applying linear characteristic
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_linear(const lv_anim_t * a)
|
||||
{
|
||||
/*Calculate the current step*/
|
||||
uint16_t step;
|
||||
if(a->time == a->act_time) step = LV_ANIM_RESOLUTION; /*Use the last value if the time fully elapsed*/
|
||||
else step = (a->act_time * LV_ANIM_RESOLUTION) / a->time;
|
||||
|
||||
/* Get the new value which will be proportional to `step`
|
||||
* and the `start` and `end` values*/
|
||||
int32_t new_value;
|
||||
new_value = (int32_t) step * (a->end - a->start);
|
||||
new_value = new_value >> LV_ANIM_RES_SHIFT;
|
||||
new_value += a->start;
|
||||
|
||||
return new_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation slowing down the start phase
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_ease_in(const lv_anim_t * a)
|
||||
{
|
||||
/*Calculate the current step*/
|
||||
uint32_t t;
|
||||
if(a->time == a->act_time) t = 1024;
|
||||
else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time;
|
||||
|
||||
int32_t step = lv_bezier3(t, 0, 1, 1, 1024);
|
||||
|
||||
int32_t new_value;
|
||||
new_value = (int32_t) step * (a->end - a->start);
|
||||
new_value = new_value >> 10;
|
||||
new_value += a->start;
|
||||
|
||||
|
||||
return new_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation slowing down the end phase
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_ease_out(const lv_anim_t * a)
|
||||
{
|
||||
/*Calculate the current step*/
|
||||
|
||||
uint32_t t;
|
||||
if(a->time == a->act_time) t = 1024;
|
||||
else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time;
|
||||
|
||||
int32_t step = lv_bezier3(t, 0, 1023, 1023, 1024);
|
||||
|
||||
int32_t new_value;
|
||||
new_value = (int32_t) step * (a->end - a->start);
|
||||
new_value = new_value >> 10;
|
||||
new_value += a->start;
|
||||
|
||||
|
||||
return new_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation applying an "S" characteristic (cosine)
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_ease_in_out(const lv_anim_t * a)
|
||||
{
|
||||
/*Calculate the current step*/
|
||||
|
||||
uint32_t t;
|
||||
if(a->time == a->act_time) t = 1024;
|
||||
else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time;
|
||||
|
||||
int32_t step = lv_bezier3(t, 0, 100, 924, 1024);
|
||||
|
||||
int32_t new_value;
|
||||
new_value = (int32_t) step * (a->end - a->start);
|
||||
new_value = new_value >> 10;
|
||||
new_value += a->start;
|
||||
|
||||
|
||||
return new_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation with overshoot at the end
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_overshoot(const lv_anim_t * a)
|
||||
{
|
||||
/*Calculate the current step*/
|
||||
|
||||
uint32_t t;
|
||||
if(a->time == a->act_time) t = 1024;
|
||||
else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time;
|
||||
|
||||
int32_t step = lv_bezier3(t, 0, 600, 1300, 1024);
|
||||
|
||||
int32_t new_value;
|
||||
new_value = (int32_t) step * (a->end - a->start);
|
||||
new_value = new_value >> 10;
|
||||
new_value += a->start;
|
||||
|
||||
|
||||
return new_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation with 3 bounces
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_bounce(const lv_anim_t * a)
|
||||
{
|
||||
/*Calculate the current step*/
|
||||
uint32_t t;
|
||||
if(a->time == a->act_time) t = 1024;
|
||||
else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time;
|
||||
|
||||
int32_t diff = (a->end - a->start);
|
||||
|
||||
/*3 bounces has 5 parts: 3 down and 2 up. One part is t / 5 long*/
|
||||
|
||||
if(t < 408){
|
||||
/*Go down*/
|
||||
t = (t * 2500) >> 10; /*[0..1024] range*/
|
||||
}
|
||||
else if(t >= 408 && t < 614) {
|
||||
/*First bounce back*/
|
||||
t -= 408;
|
||||
t = t * 5; /*to [0..1024] range*/
|
||||
t = 1024 - t;
|
||||
diff = diff / 6;
|
||||
}
|
||||
else if(t >= 614 && t < 819) {
|
||||
/*Fall back*/
|
||||
t -= 614;
|
||||
t = t * 5; /*to [0..1024] range*/
|
||||
diff = diff / 6;
|
||||
}
|
||||
else if(t >= 819 && t < 921) {
|
||||
/*Second bounce back*/
|
||||
t -= 819;
|
||||
t = t * 10; /*to [0..1024] range*/
|
||||
t = 1024 - t;
|
||||
diff = diff / 16;
|
||||
}
|
||||
else if(t >= 921 && t <= 1024) {
|
||||
/*Fall back*/
|
||||
t -= 921;
|
||||
t = t * 10; /*to [0..1024] range*/
|
||||
diff = diff / 16;
|
||||
}
|
||||
|
||||
if(t > 1024) t = 1024;
|
||||
|
||||
int32_t step = lv_bezier3(t, 1024, 1024, 800, 0);
|
||||
|
||||
int32_t new_value;
|
||||
|
||||
new_value = (int32_t) step * diff;
|
||||
new_value = new_value >> 10;
|
||||
new_value = a->end - new_value;
|
||||
|
||||
|
||||
return new_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation applying step characteristic.
|
||||
* (Set end value on the end of the animation)
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_step(const lv_anim_t * a)
|
||||
{
|
||||
if(a->act_time >= a->time) return a->end;
|
||||
else return a->start;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Periodically handle the animations.
|
||||
* @param param unused
|
||||
*/
|
||||
static void anim_task(void * param)
|
||||
{
|
||||
(void)param;
|
||||
|
||||
lv_anim_t * a;
|
||||
LV_LL_READ(LV_GC_ROOT(_lv_anim_ll), a) {
|
||||
a->has_run = 0;
|
||||
}
|
||||
|
||||
uint32_t elaps = lv_tick_elaps(last_task_run);
|
||||
a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll));
|
||||
|
||||
while(a != NULL) {
|
||||
/*It can be set by `lv_anim_del()` typically in `end_cb`. If set then an animation delete happened in `anim_ready_handler`
|
||||
* which could make this linked list reading corrupt because the list is changed meanwhile
|
||||
*/
|
||||
anim_list_changed = false;
|
||||
|
||||
if(!a->has_run) {
|
||||
a->has_run = 1; /*The list readying might be reseted so need to know which anim has run already*/
|
||||
a->act_time += elaps;
|
||||
if(a->act_time >= 0) {
|
||||
if(a->act_time > a->time) a->act_time = a->time;
|
||||
|
||||
int32_t new_value;
|
||||
new_value = a->path(a);
|
||||
|
||||
if(a->fp != NULL) a->fp(a->var, new_value); /*Apply the calculated value*/
|
||||
|
||||
/*If the time is elapsed the animation is ready*/
|
||||
if(a->act_time >= a->time) {
|
||||
anim_ready_handler(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the linked list changed due to anim. delete then it's not safe to continue
|
||||
* the reading of the list from here -> start from the head*/
|
||||
if(anim_list_changed) a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll));
|
||||
else a = lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a);
|
||||
}
|
||||
|
||||
last_task_run = lv_tick_get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an animation is ready to do the necessary thinks
|
||||
* e.g. repeat, play back, delete etc.
|
||||
* @param a pointer to an animation descriptor
|
||||
* @return true: animation delete occurred nnd the `LV_GC_ROOT(_lv_anim_ll)` has changed
|
||||
* */
|
||||
static bool anim_ready_handler(lv_anim_t * a)
|
||||
{
|
||||
|
||||
/*Delete the animation if
|
||||
* - no repeat and no play back (simple one shot animation)
|
||||
* - no repeat, play back is enabled and play back is ready */
|
||||
if((a->repeat == 0 && a->playback == 0) ||
|
||||
(a->repeat == 0 && a->playback == 1 && a->playback_now == 1)) {
|
||||
void (*cb)(void *) = a->end_cb;
|
||||
void * p = a->var;
|
||||
lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a);
|
||||
lv_mem_free(a);
|
||||
anim_list_changed = true;
|
||||
|
||||
/* Call the callback function at the end*/
|
||||
/* Check if an animation is deleted in the cb function
|
||||
* if yes then the caller function has to know this*/
|
||||
if(cb != NULL) cb(p);
|
||||
}
|
||||
/*If the animation is not deleted then restart it*/
|
||||
else {
|
||||
a->act_time = - a->repeat_pause; /*Restart the animation*/
|
||||
/*Swap the start and end values in play back mode*/
|
||||
if(a->playback != 0) {
|
||||
/*If now turning back use the 'playback_pause*/
|
||||
if(a->playback_now == 0) a->act_time = - a->playback_pause;
|
||||
|
||||
/*Toggle the play back state*/
|
||||
a->playback_now = a->playback_now == 0 ? 1 : 0;
|
||||
/*Swap the start and end values*/
|
||||
int32_t tmp;
|
||||
tmp = a->start;
|
||||
a->start = a->end;
|
||||
a->end = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return anim_list_changed;
|
||||
}
|
||||
#endif
|
||||
177
src/lv_misc/lv_anim.h
Normal file
177
src/lv_misc/lv_anim.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* @file anim.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANIM_H
|
||||
#define ANIM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_anim_t;
|
||||
|
||||
typedef int32_t(*lv_anim_path_t)(const struct _lv_anim_t*);
|
||||
|
||||
typedef void (*lv_anim_fp_t)(void *, int32_t);
|
||||
typedef void (*lv_anim_cb_t)(void *);
|
||||
|
||||
typedef struct _lv_anim_t
|
||||
{
|
||||
void * var; /*Variable to animate*/
|
||||
lv_anim_fp_t fp; /*Animator function*/
|
||||
lv_anim_cb_t end_cb; /*Call it when the animation is ready*/
|
||||
lv_anim_path_t path; /*An array with the steps of animations*/
|
||||
int32_t start; /*Start value*/
|
||||
int32_t end; /*End value*/
|
||||
uint16_t time; /*Animation time in ms*/
|
||||
int16_t act_time; /*Current time in animation. Set to negative to make delay.*/
|
||||
uint16_t playback_pause; /*Wait before play back*/
|
||||
uint16_t repeat_pause; /*Wait before repeat*/
|
||||
uint8_t playback :1; /*When the animation is ready play it back*/
|
||||
uint8_t repeat :1; /*Repeat the animation infinitely*/
|
||||
/*Animation system use these - user shouldn't set*/
|
||||
uint8_t playback_now :1; /*Play back is in progress*/
|
||||
uint32_t has_run :1; /*Indicates the animation has run it this round*/
|
||||
} lv_anim_t;
|
||||
|
||||
/*Example initialization
|
||||
lv_anim_t a;
|
||||
a.var = obj;
|
||||
a.start = lv_obj_get_height(obj);
|
||||
a.end = new_height;
|
||||
a.fp = (lv_anim_fp_t)lv_obj_set_height;
|
||||
a.path = lv_anim_path_linear;
|
||||
a.end_cb = NULL;
|
||||
a.act_time = 0;
|
||||
a.time = 200;
|
||||
a.playback = 0;
|
||||
a.playback_pause = 0;
|
||||
a.repeat = 0;
|
||||
a.repeat_pause = 0;
|
||||
lv_anim_create(&a);
|
||||
*/
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Init. the animation module
|
||||
*/
|
||||
void lv_anim_init(void);
|
||||
|
||||
/**
|
||||
* Create an animation
|
||||
* @param anim_p an initialized 'anim_t' variable. Not required after call.
|
||||
*/
|
||||
void lv_anim_create(lv_anim_t * anim_p);
|
||||
|
||||
/**
|
||||
* Delete an animation for a variable with a given animatior function
|
||||
* @param var pointer to variable
|
||||
* @param fp a function pointer which is animating 'var',
|
||||
* or NULL to ignore it and delete all animation with 'var
|
||||
* @return true: at least 1 animation is deleted, false: no animation is deleted
|
||||
*/
|
||||
bool lv_anim_del(void * var, lv_anim_fp_t fp);
|
||||
|
||||
/**
|
||||
* Get the number of currently running animations
|
||||
* @return the number of running animations
|
||||
*/
|
||||
uint16_t lv_anim_count_running(void);
|
||||
|
||||
/**
|
||||
* Calculate the time of an animation with a given speed and the start and end values
|
||||
* @param speed speed of animation in unit/sec
|
||||
* @param start start value of the animation
|
||||
* @param end end value of the animation
|
||||
* @return the required time [ms] for the animation with the given parameters
|
||||
*/
|
||||
uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end);
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation applying linear characteristic
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_linear(const lv_anim_t *a);
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation slowing down the start phase
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_ease_in(const lv_anim_t * a);
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation slowing down the end phase
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_ease_out(const lv_anim_t * a);
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation applying an "S" characteristic (cosine)
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_ease_in_out(const lv_anim_t *a);
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation with overshoot at the end
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_overshoot(const lv_anim_t * a);
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation with 3 bounces
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_bounce(const lv_anim_t * a);
|
||||
|
||||
/**
|
||||
* Calculate the current value of an animation applying step characteristic.
|
||||
* (Set end value on the end of the animation)
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_step(const lv_anim_t *a);
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_ANIMATION == 0*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_ANIM_H*/
|
||||
|
||||
200
src/lv_misc/lv_area.c
Normal file
200
src/lv_misc/lv_area.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* @file lv_area.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_area.h"
|
||||
#include "lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize an area
|
||||
* @param area_p pointer to an area
|
||||
* @param x1 left coordinate of the area
|
||||
* @param y1 top coordinate of the area
|
||||
* @param x2 right coordinate of the area
|
||||
* @param y2 bottom coordinate of the area
|
||||
*/
|
||||
void lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2)
|
||||
{
|
||||
area_p->x1 = x1;
|
||||
area_p->y1 = y1;
|
||||
area_p->x2 = x2;
|
||||
area_p->y2 = y2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width of an area
|
||||
* @param area_p pointer to an area
|
||||
* @param w the new width of the area (w == 1 makes x1 == x2)
|
||||
*/
|
||||
void lv_area_set_width(lv_area_t * area_p, lv_coord_t w)
|
||||
{
|
||||
area_p->x2 = area_p->x1 + w - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the height of an area
|
||||
* @param area_p pointer to an area
|
||||
* @param h the new height of the area (h == 1 makes y1 == y2)
|
||||
*/
|
||||
void lv_area_set_height(lv_area_t * area_p, lv_coord_t h)
|
||||
{
|
||||
area_p->y2 = area_p->y1 + h - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the position of an area (width and height will be kept)
|
||||
* @param area_p pointer to an area
|
||||
* @param x the new x coordinate of the area
|
||||
* @param y the new y coordinate of the area
|
||||
*/
|
||||
void lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y)
|
||||
{
|
||||
lv_coord_t w = lv_area_get_width(area_p);
|
||||
lv_coord_t h = lv_area_get_height(area_p);
|
||||
area_p->x1 = x;
|
||||
area_p->y1 = y;
|
||||
lv_area_set_width(area_p, w);
|
||||
lv_area_set_height(area_p, h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with area of an area (x * y)
|
||||
* @param area_p pointer to an area
|
||||
* @return size of area
|
||||
*/
|
||||
uint32_t lv_area_get_size(const lv_area_t * area_p)
|
||||
{
|
||||
uint32_t size;
|
||||
|
||||
size = (uint32_t)(area_p->x2 - area_p->x1 + 1) *
|
||||
(area_p->y2 - area_p->y1 + 1);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the common parts of two areas
|
||||
* @param res_p pointer to an area, the result will be stored here
|
||||
* @param a1_p pointer to the first area
|
||||
* @param a2_p pointer to the second area
|
||||
* @return false: the two area has NO common parts, res_p is invalid
|
||||
*/
|
||||
bool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p)
|
||||
{
|
||||
/* Get the smaller area from 'a1_p' and 'a2_p' */
|
||||
res_p->x1 = LV_MATH_MAX(a1_p->x1, a2_p->x1);
|
||||
res_p->y1 = LV_MATH_MAX(a1_p->y1, a2_p->y1);
|
||||
res_p->x2 = LV_MATH_MIN(a1_p->x2, a2_p->x2);
|
||||
res_p->y2 = LV_MATH_MIN(a1_p->y2, a2_p->y2);
|
||||
|
||||
/*If x1 or y1 greater then x2 or y2 then the areas union is empty*/
|
||||
bool union_ok = true;
|
||||
if((res_p->x1 > res_p->x2) ||
|
||||
(res_p->y1 > res_p->y2)) {
|
||||
union_ok = false;
|
||||
}
|
||||
|
||||
return union_ok;
|
||||
}
|
||||
/**
|
||||
* Join two areas into a third which involves the other two
|
||||
* @param res_p pointer to an area, the result will be stored here
|
||||
* @param a1_p pointer to the first area
|
||||
* @param a2_p pointer to the second area
|
||||
*/
|
||||
void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p)
|
||||
{
|
||||
a_res_p->x1 = LV_MATH_MIN(a1_p->x1, a2_p->x1);
|
||||
a_res_p->y1 = LV_MATH_MIN(a1_p->y1, a2_p->y1);
|
||||
a_res_p->x2 = LV_MATH_MAX(a1_p->x2, a2_p->x2);
|
||||
a_res_p->y2 = LV_MATH_MAX(a1_p->y2, a2_p->y2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a point is on an area
|
||||
* @param a_p pointer to an area
|
||||
* @param p_p pointer to a point
|
||||
* @return false:the point is out of the area
|
||||
*/
|
||||
bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p)
|
||||
{
|
||||
bool is_on = false;
|
||||
|
||||
if((p_p->x >= a_p->x1 && p_p->x <= a_p->x2) &&
|
||||
((p_p->y >= a_p->y1 && p_p->y <= a_p->y2))) {
|
||||
is_on = true;
|
||||
}
|
||||
|
||||
return is_on;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two area has common parts
|
||||
* @param a1_p pointer to an area.
|
||||
* @param a2_p pointer to an other area
|
||||
* @return false: a1_p and a2_p has no common parts
|
||||
*/
|
||||
bool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p)
|
||||
{
|
||||
if((a1_p->x1 <= a2_p->x2) &&
|
||||
(a1_p->x2 >= a2_p->x1) &&
|
||||
(a1_p->y1 <= a2_p->y2) &&
|
||||
(a1_p->y2 >= a2_p->y1)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an area is fully on an other
|
||||
* @param ain_p pointer to an area which could be in 'aholder_p'
|
||||
* @param aholder pointer to an area which could involve 'ain_p'
|
||||
* @return
|
||||
*/
|
||||
bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p)
|
||||
{
|
||||
bool is_in = false;
|
||||
|
||||
if(ain_p->x1 >= aholder_p->x1 &&
|
||||
ain_p->y1 >= aholder_p->y1 &&
|
||||
ain_p->x2 <= aholder_p->x2 &&
|
||||
ain_p->y2 <= aholder_p->y2) {
|
||||
is_in = true;
|
||||
}
|
||||
|
||||
return is_in;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
169
src/lv_misc/lv_area.h
Normal file
169
src/lv_misc/lv_area.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* @file lv_area.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_AREA_H
|
||||
#define LV_AREA_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_COORD_MAX (16383) /*To avoid overflow don't let the max [-32,32k] range */
|
||||
#define LV_COORD_MIN (-16384)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef int16_t lv_coord_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
lv_coord_t x;
|
||||
lv_coord_t y;
|
||||
} lv_point_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
lv_coord_t x1;
|
||||
lv_coord_t y1;
|
||||
lv_coord_t x2;
|
||||
lv_coord_t y2;
|
||||
} lv_area_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize an area
|
||||
* @param area_p pointer to an area
|
||||
* @param x1 left coordinate of the area
|
||||
* @param y1 top coordinate of the area
|
||||
* @param x2 right coordinate of the area
|
||||
* @param y2 bottom coordinate of the area
|
||||
*/
|
||||
void lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2);
|
||||
|
||||
/**
|
||||
* Copy an area
|
||||
* @param dest pointer to the destination area
|
||||
* @param src pointer to the source area
|
||||
*/
|
||||
inline static void lv_area_copy(lv_area_t * dest, const lv_area_t * src)
|
||||
{
|
||||
memcpy(dest, src, sizeof(lv_area_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of an area
|
||||
* @param area_p pointer to an area
|
||||
* @return the width of the area (if x1 == x2 -> width = 1)
|
||||
*/
|
||||
static inline lv_coord_t lv_area_get_width(const lv_area_t * area_p)
|
||||
{
|
||||
return area_p->x2 - area_p->x1 + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of an area
|
||||
* @param area_p pointer to an area
|
||||
* @return the height of the area (if y1 == y2 -> height = 1)
|
||||
*/
|
||||
static inline lv_coord_t lv_area_get_height(const lv_area_t * area_p)
|
||||
{
|
||||
return area_p->y2 - area_p->y1 + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width of an area
|
||||
* @param area_p pointer to an area
|
||||
* @param w the new width of the area (w == 1 makes x1 == x2)
|
||||
*/
|
||||
void lv_area_set_width(lv_area_t * area_p, lv_coord_t w);
|
||||
|
||||
/**
|
||||
* Set the height of an area
|
||||
* @param area_p pointer to an area
|
||||
* @param h the new height of the area (h == 1 makes y1 == y2)
|
||||
*/
|
||||
void lv_area_set_height(lv_area_t * area_p, lv_coord_t h);
|
||||
|
||||
/**
|
||||
* Set the position of an area (width and height will be kept)
|
||||
* @param area_p pointer to an area
|
||||
* @param x the new x coordinate of the area
|
||||
* @param y the new y coordinate of the area
|
||||
*/
|
||||
void lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y);
|
||||
|
||||
/**
|
||||
* Return with area of an area (x * y)
|
||||
* @param area_p pointer to an area
|
||||
* @return size of area
|
||||
*/
|
||||
uint32_t lv_area_get_size(const lv_area_t * area_p);
|
||||
|
||||
/**
|
||||
* Get the common parts of two areas
|
||||
* @param res_p pointer to an area, the result will be stored her
|
||||
* @param a1_p pointer to the first area
|
||||
* @param a2_p pointer to the second area
|
||||
* @return false: the two area has NO common parts, res_p is invalid
|
||||
*/
|
||||
bool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p);
|
||||
|
||||
/**
|
||||
* Join two areas into a third which involves the other two
|
||||
* @param res_p pointer to an area, the result will be stored here
|
||||
* @param a1_p pointer to the first area
|
||||
* @param a2_p pointer to the second area
|
||||
*/
|
||||
void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p);
|
||||
|
||||
/**
|
||||
* Check if a point is on an area
|
||||
* @param a_p pointer to an area
|
||||
* @param p_p pointer to a point
|
||||
* @return false:the point is out of the area
|
||||
*/
|
||||
bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p);
|
||||
|
||||
/**
|
||||
* Check if two area has common parts
|
||||
* @param a1_p pointer to an area.
|
||||
* @param a2_p pointer to an other area
|
||||
* @return false: a1_p and a2_p has no common parts
|
||||
*/
|
||||
bool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p);
|
||||
|
||||
/**
|
||||
* Check if an area is fully on an other
|
||||
* @param ain_p pointer to an area which could be on aholder_p
|
||||
* @param aholder pointer to an area which could involve ain_p
|
||||
* @return
|
||||
*/
|
||||
bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
79
src/lv_misc/lv_circ.c
Normal file
79
src/lv_misc/lv_circ.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @file lv_circ.c
|
||||
* Circle drawing algorithm (with Bresenham)
|
||||
* Only a 1/8 circle is calculated. Use CIRC_OCT1_X, CIRC_OCT1_Y macros to get
|
||||
* the other octets.
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_circ.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the circle drawing
|
||||
* @param c pointer to a point. The coordinates will be calculated here
|
||||
* @param tmp point to a variable. It will store temporary data
|
||||
* @param radius radius of the circle
|
||||
*/
|
||||
void lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius)
|
||||
{
|
||||
c->x = radius;
|
||||
c->y = 0;
|
||||
*tmp = 1 - radius;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the circle drawing is ready or not
|
||||
* @param c same as in circ_init
|
||||
* @return true if the circle is not ready yet
|
||||
*/
|
||||
bool lv_circ_cont(lv_point_t * c)
|
||||
{
|
||||
return c->y <= c->x ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next point from the circle
|
||||
* @param c same as in circ_init. The next point stored here.
|
||||
* @param tmp same as in circ_init.
|
||||
*/
|
||||
void lv_circ_next(lv_point_t * c, lv_coord_t * tmp)
|
||||
{
|
||||
c->y++;
|
||||
|
||||
if(*tmp <= 0) {
|
||||
(*tmp) += 2 * c->y + 1; // Change in decision criterion for y -> y+1
|
||||
} else {
|
||||
c->x--;
|
||||
(*tmp) += 2 * (c->y - c->x) + 1; // Change for y -> y+1, x -> x-1
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
79
src/lv_misc/lv_circ.h
Normal file
79
src/lv_misc/lv_circ.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @file lv_circ.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_CIRC_H
|
||||
#define LV_CIRC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stddef.h>
|
||||
#include "lv_area.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_CIRC_OCT1_X(p) (p.x)
|
||||
#define LV_CIRC_OCT1_Y(p) (p.y)
|
||||
#define LV_CIRC_OCT2_X(p) (p.y)
|
||||
#define LV_CIRC_OCT2_Y(p) (p.x)
|
||||
#define LV_CIRC_OCT3_X(p) (-p.y)
|
||||
#define LV_CIRC_OCT3_Y(p) (p.x)
|
||||
#define LV_CIRC_OCT4_X(p) (-p.x)
|
||||
#define LV_CIRC_OCT4_Y(p) (p.y)
|
||||
#define LV_CIRC_OCT5_X(p) (-p.x)
|
||||
#define LV_CIRC_OCT5_Y(p) (-p.y)
|
||||
#define LV_CIRC_OCT6_X(p) (-p.y)
|
||||
#define LV_CIRC_OCT6_Y(p) (-p.x)
|
||||
#define LV_CIRC_OCT7_X(p) (p.y)
|
||||
#define LV_CIRC_OCT7_Y(p) (-p.x)
|
||||
#define LV_CIRC_OCT8_X(p) (p.x)
|
||||
#define LV_CIRC_OCT8_Y(p) (-p.y)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the circle drawing
|
||||
* @param c pointer to a point. The coordinates will be calculated here
|
||||
* @param tmp point to a variable. It will store temporary data
|
||||
* @param radius radius of the circle
|
||||
*/
|
||||
void lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius);
|
||||
|
||||
/**
|
||||
* Test the circle drawing is ready or not
|
||||
* @param c same as in circ_init
|
||||
* @return true if the circle is not ready yet
|
||||
*/
|
||||
bool lv_circ_cont(lv_point_t * c);
|
||||
|
||||
/**
|
||||
* Get the next point from the circle
|
||||
* @param c same as in circ_init. The next point stored here.
|
||||
* @param tmp same as in circ_init.
|
||||
*/
|
||||
void lv_circ_next(lv_point_t * c, lv_coord_t * tmp);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
143
src/lv_misc/lv_color.c
Normal file
143
src/lv_misc/lv_color.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* @file lv_color.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_color.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Convert a HSV color to RGB
|
||||
* @param h hue [0..359]
|
||||
* @param s saturation [0..100]
|
||||
* @param v value [0..100]
|
||||
* @return the given RGB color in RGB (with LV_COLOR_DEPTH depth)
|
||||
*/
|
||||
lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v)
|
||||
{
|
||||
h = (uint32_t)((uint32_t)h * 255) / 360;
|
||||
s = (uint16_t)((uint16_t)s * 255) / 100;
|
||||
v = (uint16_t)((uint16_t)v * 255) / 100;
|
||||
|
||||
uint8_t r, g, b;
|
||||
|
||||
uint8_t region, remainder, p, q, t;
|
||||
|
||||
if(s == 0) {
|
||||
r = v;
|
||||
g = v;
|
||||
b = v;
|
||||
return lv_color_make(v, v, v);
|
||||
}
|
||||
|
||||
region = h / 43;
|
||||
remainder = (h - (region * 43)) * 6;
|
||||
|
||||
p = (v * (255 - s)) >> 8;
|
||||
q = (v * (255 - ((s * remainder) >> 8))) >> 8;
|
||||
t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
|
||||
|
||||
switch(region) {
|
||||
case 0:
|
||||
r = v;
|
||||
g = t;
|
||||
b = p;
|
||||
break;
|
||||
case 1:
|
||||
r = q;
|
||||
g = v;
|
||||
b = p;
|
||||
break;
|
||||
case 2:
|
||||
r = p;
|
||||
g = v;
|
||||
b = t;
|
||||
break;
|
||||
case 3:
|
||||
r = p;
|
||||
g = q;
|
||||
b = v;
|
||||
break;
|
||||
case 4:
|
||||
r = t;
|
||||
g = p;
|
||||
b = v;
|
||||
break;
|
||||
default:
|
||||
r = v;
|
||||
g = p;
|
||||
b = q;
|
||||
break;
|
||||
}
|
||||
|
||||
lv_color_t result = lv_color_make(r, g, b);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an RGB color to HSV
|
||||
* @param r red
|
||||
* @param g green
|
||||
* @param b blue
|
||||
* @return the given RGB color n HSV
|
||||
*/
|
||||
lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
lv_color_hsv_t hsv;
|
||||
uint8_t rgbMin, rgbMax;
|
||||
|
||||
rgbMin = r < g ? (r < b ? r : b) : (g < b ? g : b);
|
||||
rgbMax = r > g ? (r > b ? r : b) : (g > b ? g : b);
|
||||
|
||||
hsv.v = rgbMax;
|
||||
if(hsv.v == 0) {
|
||||
hsv.h = 0;
|
||||
hsv.s = 0;
|
||||
return hsv;
|
||||
}
|
||||
|
||||
hsv.s = 255 * (long)(rgbMax - rgbMin) / hsv.v;
|
||||
if(hsv.s == 0) {
|
||||
hsv.h = 0;
|
||||
return hsv;
|
||||
}
|
||||
|
||||
if(rgbMax == r)
|
||||
hsv.h = 0 + 43 * (g - b) / (rgbMax - rgbMin);
|
||||
else if(rgbMax == g)
|
||||
hsv.h = 85 + 43 * (b - r) / (rgbMax - rgbMin);
|
||||
else
|
||||
hsv.h = 171 + 43 * (r - g) / (rgbMax - rgbMin);
|
||||
|
||||
return hsv;
|
||||
}
|
||||
456
src/lv_misc/lv_color.h
Normal file
456
src/lv_misc/lv_color.h
Normal file
@@ -0,0 +1,456 @@
|
||||
/**
|
||||
* @file lv_color.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_COLOR_H
|
||||
#define LV_COLOR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
/*Error checking*/
|
||||
#if LV_COLOR_DEPTH == 24
|
||||
#error "LV_COLOR_DEPTH 24 is deprecated. Use LV_COLOR_DEPTH 32 instead (lv_conf.h)"
|
||||
#endif
|
||||
|
||||
#if LV_COLOR_DEPTH != 32 && LV_COLOR_SCREEN_TRANSP != 0
|
||||
#error "LV_COLOR_SCREEN_TRANSP requires LV_COLOR_DEPTH == 32. Set it in lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if LV_COLOR_DEPTH != 16 && LV_COLOR_16_SWAP != 0
|
||||
#error "LV_COLOR_16_SWAP requires LV_COLOR_DEPTH == 16. Set it in lv_conf.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_COLOR_WHITE LV_COLOR_MAKE(0xFF,0xFF,0xFF)
|
||||
#define LV_COLOR_SILVER LV_COLOR_MAKE(0xC0,0xC0,0xC0)
|
||||
#define LV_COLOR_GRAY LV_COLOR_MAKE(0x80,0x80,0x80)
|
||||
#define LV_COLOR_BLACK LV_COLOR_MAKE(0x00,0x00,0x00)
|
||||
#define LV_COLOR_RED LV_COLOR_MAKE(0xFF,0x00,0x00)
|
||||
#define LV_COLOR_MAROON LV_COLOR_MAKE(0x80,0x00,0x00)
|
||||
#define LV_COLOR_YELLOW LV_COLOR_MAKE(0xFF,0xFF,0x00)
|
||||
#define LV_COLOR_OLIVE LV_COLOR_MAKE(0x80,0x80,0x00)
|
||||
#define LV_COLOR_LIME LV_COLOR_MAKE(0x00,0xFF,0x00)
|
||||
#define LV_COLOR_GREEN LV_COLOR_MAKE(0x00,0x80,0x00)
|
||||
#define LV_COLOR_CYAN LV_COLOR_MAKE(0x00,0xFF,0xFF)
|
||||
#define LV_COLOR_AQUA LV_COLOR_CYAN
|
||||
#define LV_COLOR_TEAL LV_COLOR_MAKE(0x00,0x80,0x80)
|
||||
#define LV_COLOR_BLUE LV_COLOR_MAKE(0x00,0x00,0xFF)
|
||||
#define LV_COLOR_NAVY LV_COLOR_MAKE(0x00,0x00,0x80)
|
||||
#define LV_COLOR_MAGENTA LV_COLOR_MAKE(0xFF,0x00,0xFF)
|
||||
#define LV_COLOR_PURPLE LV_COLOR_MAKE(0x80,0x00,0x80)
|
||||
#define LV_COLOR_ORANGE LV_COLOR_MAKE(0xFF,0xA5,0x00)
|
||||
|
||||
enum {
|
||||
LV_OPA_TRANSP = 0,
|
||||
LV_OPA_0 = 0,
|
||||
LV_OPA_10 = 25,
|
||||
LV_OPA_20 = 51,
|
||||
LV_OPA_30 = 76,
|
||||
LV_OPA_40 = 102,
|
||||
LV_OPA_50 = 127,
|
||||
LV_OPA_60 = 153,
|
||||
LV_OPA_70 = 178,
|
||||
LV_OPA_80 = 204,
|
||||
LV_OPA_90 = 229,
|
||||
LV_OPA_100 = 255,
|
||||
LV_OPA_COVER = 255,
|
||||
};
|
||||
|
||||
#define LV_OPA_MIN 16 /*Opacities below this will be transparent*/
|
||||
#define LV_OPA_MAX 251 /*Opacities above this will fully cover*/
|
||||
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
#define LV_COLOR_SIZE 8
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
#define LV_COLOR_SIZE 8
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
#define LV_COLOR_SIZE 16
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
#define LV_COLOR_SIZE 32
|
||||
#else
|
||||
#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!"
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef union
|
||||
{
|
||||
uint8_t blue :1;
|
||||
uint8_t green :1;
|
||||
uint8_t red :1;
|
||||
uint8_t full :1;
|
||||
} lv_color1_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t blue :2;
|
||||
uint8_t green :3;
|
||||
uint8_t red :3;
|
||||
}ch;
|
||||
uint8_t full;
|
||||
} lv_color8_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
#if LV_COLOR_16_SWAP == 0
|
||||
uint16_t blue :5;
|
||||
uint16_t green :6;
|
||||
uint16_t red :5;
|
||||
#else
|
||||
uint16_t green_h :3;
|
||||
uint16_t red :5;
|
||||
uint16_t blue :5;
|
||||
uint16_t green_l :3;
|
||||
#endif
|
||||
}ch;
|
||||
uint16_t full;
|
||||
} lv_color16_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t blue;
|
||||
uint8_t green;
|
||||
uint8_t red;
|
||||
uint8_t alpha;
|
||||
}ch;
|
||||
uint32_t full;
|
||||
} lv_color32_t;
|
||||
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
typedef uint8_t lv_color_int_t;
|
||||
typedef lv_color1_t lv_color_t;
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
typedef uint8_t lv_color_int_t;
|
||||
typedef lv_color8_t lv_color_t;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
typedef uint16_t lv_color_int_t;
|
||||
typedef lv_color16_t lv_color_t;
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
typedef uint32_t lv_color_int_t;
|
||||
typedef lv_color32_t lv_color_t;
|
||||
#else
|
||||
#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!"
|
||||
#endif
|
||||
|
||||
typedef uint8_t lv_opa_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t h;
|
||||
uint8_t s;
|
||||
uint8_t v;
|
||||
} lv_color_hsv_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/*In color conversations:
|
||||
* - When converting to bigger color type the LSB weight of 1 LSB is calculated
|
||||
* E.g. 16 bit Red has 5 bits
|
||||
* 8 bit Red has 2 bits
|
||||
* ----------------------
|
||||
* 8 bit red LSB = (2^5 - 1) / (2^2 - 1) = 31 / 3 = 10
|
||||
*
|
||||
* - When calculating to smaller color type simply shift out the LSBs
|
||||
* E.g. 8 bit Red has 2 bits
|
||||
* 16 bit Red has 5 bits
|
||||
* ----------------------
|
||||
* Shift right with 5 - 3 = 2
|
||||
*/
|
||||
|
||||
static inline uint8_t lv_color_to1(lv_color_t color)
|
||||
{
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
return color.full;
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
if((color.ch.red & 0x4) ||
|
||||
(color.ch.green & 0x4) ||
|
||||
(color.ch.blue & 0x2)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
if((color.ch.red & 0x10) ||
|
||||
(color.ch.green & 0x20) ||
|
||||
(color.ch.blue & 0x10)) {
|
||||
return 1;
|
||||
# else
|
||||
if((color.ch.red & 0x10) ||
|
||||
(color.ch.green_h & 0x20) ||
|
||||
(color.ch.blue & 0x10)) {
|
||||
return 1;
|
||||
# endif
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
if((color.ch.red & 0x80) ||
|
||||
(color.ch.green & 0x80) ||
|
||||
(color.ch.blue & 0x80)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint8_t lv_color_to8(lv_color_t color)
|
||||
{
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
if(color.full == 0) return 0;
|
||||
else return 0xFF;
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
return color.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
lv_color8_t ret;
|
||||
ret.ch.red = color.ch.red >> 2; /* 5 - 3 = 2*/
|
||||
ret.ch.green = color.ch.green >> 3; /* 6 - 3 = 3*/
|
||||
ret.ch.blue = color.ch.blue >> 3; /* 5 - 2 = 3*/
|
||||
return ret.full;
|
||||
# else
|
||||
lv_color8_t ret;
|
||||
ret.ch.red = color.ch.red >> 2; /* 5 - 3 = 2*/
|
||||
ret.ch.green = color.ch.green_h; /* 6 - 3 = 3*/
|
||||
ret.ch.blue = color.ch.blue >> 3; /* 5 - 2 = 3*/
|
||||
return ret.full;
|
||||
# endif
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
lv_color8_t ret;
|
||||
ret.ch.red = color.ch.red >> 5; /* 8 - 3 = 5*/
|
||||
ret.ch.green = color.ch.green >> 5; /* 8 - 3 = 5*/
|
||||
ret.ch.blue = color.ch.blue >> 6; /* 8 - 2 = 6*/
|
||||
return ret.full;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint16_t lv_color_to16(lv_color_t color)
|
||||
{
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
if(color.full == 0) return 0;
|
||||
else return 0xFFFF;
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
lv_color16_t ret;
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
ret.ch.red = color.ch.red * 4; /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/
|
||||
ret.ch.green = color.ch.green * 9; /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/
|
||||
ret.ch.blue = color.ch.blue * 10; /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/
|
||||
# else
|
||||
ret.red = color.ch.red * 4;
|
||||
uint8_t g_tmp = color.ch.green * 9;
|
||||
ret.ch.green_h = (g_tmp & 0x1F) >> 3;
|
||||
ret.ch.green_l = g_tmp & 0x07;
|
||||
ret.ch.blue = color.ch.blue * 10;
|
||||
# endif
|
||||
return ret.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
return color.full;
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
lv_color16_t ret;
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
ret.ch.red = color.ch.red >> 3; /* 8 - 5 = 3*/
|
||||
ret.ch.green = color.ch.green >> 2; /* 8 - 6 = 2*/
|
||||
ret.ch.blue = color.ch.blue >> 3; /* 8 - 5 = 3*/
|
||||
# else
|
||||
ret.ch.red = color.ch.red >> 3;
|
||||
ret.ch.green_h = (color.ch.green & 0xE0) >> 5;
|
||||
ret.ch.green_l = (color.ch.green & 0x1C) >> 2;
|
||||
ret.ch.blue = color.ch.blue >> 3;
|
||||
# endif
|
||||
return ret.full;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t lv_color_to32(lv_color_t color)
|
||||
{
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
if(color.full == 0) return 0;
|
||||
else return 0xFFFFFFFF;
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
lv_color32_t ret;
|
||||
ret.ch.red = color.ch.red * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/
|
||||
ret.ch.green = color.ch.green * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/
|
||||
ret.ch.blue = color.ch.blue * 85; /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/
|
||||
ret.ch.alpha = 0xFF;
|
||||
return ret.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
lv_color32_t ret;
|
||||
ret.ch.red = color.ch.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
|
||||
ret.ch.green = color.ch.green * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/
|
||||
ret.ch.blue = color.ch.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
|
||||
ret.ch.alpha = 0xFF;
|
||||
return ret.full;
|
||||
# else
|
||||
lv_color32_t ret;
|
||||
ret.ch.red = color.ch.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
|
||||
ret.ch.green = ((color.ch.green_h << 3) + color.ch.green_l) * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/
|
||||
ret.ch.blue = color.ch.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
|
||||
ret.ch.alpha = 0xFF;
|
||||
return ret.full;
|
||||
# endif
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
return color.full;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix)
|
||||
{
|
||||
lv_color_t ret;
|
||||
#if LV_COLOR_DEPTH != 1
|
||||
/*LV_COLOR_DEPTH == 8, 16 or 32*/
|
||||
ret.ch.red = (uint16_t)((uint16_t) c1.ch.red * mix + (c2.ch.red * (255 - mix))) >> 8;
|
||||
# if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP
|
||||
/*If swapped Green is in 2 parts*/
|
||||
uint16_t g_1 = (c1.ch.green_h << 3) + c1.ch.green_l;
|
||||
uint16_t g_2 = (c2.ch.green_h << 3) + c2.ch.green_l;
|
||||
uint16_t g_out = (uint16_t)((uint16_t) g_1 * mix + (g_2 * (255 - mix))) >> 8;
|
||||
ret.ch.green_h = g_out >> 3;
|
||||
ret.ch.green_l = g_out & 0x7;
|
||||
# else
|
||||
ret.ch.green = (uint16_t)((uint16_t) c1.ch.green * mix + (c2.ch.green * (255 - mix))) >> 8;
|
||||
# endif
|
||||
ret.ch.blue = (uint16_t)((uint16_t) c1.ch.blue * mix + (c2.ch.blue * (255 - mix))) >> 8;
|
||||
# if LV_COLOR_DEPTH == 32
|
||||
ret.ch.alpha = 0xFF;
|
||||
# endif
|
||||
#else
|
||||
/*LV_COLOR_DEPTH == 1*/
|
||||
ret.full = mix > LV_OPA_50 ? c1.full : c2.full;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the brightness of a color
|
||||
* @param color a color
|
||||
* @return the brightness [0..255]
|
||||
*/
|
||||
static inline uint8_t lv_color_brightness(lv_color_t color)
|
||||
{
|
||||
lv_color32_t c32;
|
||||
c32.full = lv_color_to32(color);
|
||||
uint16_t bright = 3 * c32.ch.red + c32.ch.blue + 4 * c32.ch.green;
|
||||
return (uint16_t) bright >> 3;
|
||||
}
|
||||
|
||||
/* The most simple macro to create a color from R,G and B values */
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(b8 >> 7 | g8 >> 7 | r8 >> 7)})
|
||||
static inline lv_color_t lv_color_make(int r8, int g8, int b8){
|
||||
lv_color_t color;
|
||||
color.full = (b8 >> 7 | g8 >> 7 | r8 >> 7);
|
||||
return color;
|
||||
}
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 6, g8 >> 5, r8 >> 5}})
|
||||
static inline lv_color_t lv_color_make(uint8_t r8, int g8, int b8){
|
||||
lv_color_t color;
|
||||
color.ch.blue = b8 >> 6;
|
||||
color.ch.green = g8 >> 5;
|
||||
color.ch.red = r8 >> 5;
|
||||
return color;
|
||||
}
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 3, g8 >> 2, r8 >> 3}})
|
||||
static inline lv_color_t lv_color_make(uint8_t r8, uint8_t g8, uint8_t b8){
|
||||
lv_color_t color;
|
||||
color.ch.blue = (uint16_t)(b8 >> 3);
|
||||
color.ch.green = (uint16_t)(g8 >> 2);
|
||||
color.ch.red = (uint16_t)(r8 >> 3);
|
||||
return color;
|
||||
}
|
||||
# else
|
||||
# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{g8 >> 5, r8 >> 3, b8 >> 3, (g8 >> 2) & 0x7}})
|
||||
static inline lv_color_t lv_color_make(uint8_t r8, uint8_t g8, uint8_t b8){
|
||||
lv_color_t color;
|
||||
color.ch.green_h = (uint16_t)(g8 >> 5);
|
||||
color.ch.red = (uint16_t)(r8 >> 3);
|
||||
color.ch.blue = (uint16_t)(b8 >> 3);
|
||||
color.ch.green_l = (uint16_t)((g8 >> 2) & 0x7);
|
||||
return color;
|
||||
}
|
||||
# endif
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8, g8, r8, 0xff}}) /*Fix 0xff alpha*/
|
||||
static inline lv_color_t lv_color_make(uint8_t r8, uint8_t g8, uint8_t b8){
|
||||
lv_color_t color;
|
||||
color.ch.blue = b8;
|
||||
color.ch.green = g8;
|
||||
color.ch.red = r8;
|
||||
color.ch.alpha = 0xff;
|
||||
return color;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline lv_color_t lv_color_hex(uint32_t c) {
|
||||
return lv_color_make((uint8_t) ((c >> 16) & 0xFF),
|
||||
(uint8_t) ((c >> 8) & 0xFF),
|
||||
(uint8_t) (c & 0xFF));
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_color_hex3(uint32_t c) {
|
||||
return lv_color_make((uint8_t) (((c >> 4) & 0xF0) | ((c >> 8) & 0xF)),
|
||||
(uint8_t) ((c & 0xF0) | ((c & 0xF0) >> 4)),
|
||||
(uint8_t) ((c & 0xF) | ((c & 0xF) << 4)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a HSV color to RGB
|
||||
* @param h hue [0..359]
|
||||
* @param s saturation [0..100]
|
||||
* @param v value [0..100]
|
||||
* @return the given RGB color in RGB (with LV_COLOR_DEPTH depth)
|
||||
*/
|
||||
lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v);
|
||||
|
||||
/**
|
||||
* Convert an RGB color to HSV
|
||||
* @param r red
|
||||
* @param g green
|
||||
* @param b blue
|
||||
* @return the given RGB color n HSV
|
||||
*/
|
||||
lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*USE_COLOR*/
|
||||
269
src/lv_misc/lv_font.c
Normal file
269
src/lv_misc/lv_font.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/**
|
||||
* @file lv_font.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stddef.h>
|
||||
#include "lv_font.h"
|
||||
#include "lv_log.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the fonts
|
||||
*/
|
||||
void lv_font_init(void)
|
||||
{
|
||||
lv_font_builtin_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a font to an other to extend the character set.
|
||||
* @param child the font to add
|
||||
* @param parent this font will be extended. Using it later will contain the characters from `child`
|
||||
*/
|
||||
void lv_font_add(lv_font_t * child, lv_font_t * parent)
|
||||
{
|
||||
if(parent == NULL) return;
|
||||
|
||||
while(parent->next_page != NULL) {
|
||||
parent = parent->next_page; /*Got to the last page and add the new font there*/
|
||||
}
|
||||
|
||||
parent->next_page = child;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a font from a character set.
|
||||
* @param child the font to remove
|
||||
* @param parent remove `child` from here
|
||||
*/
|
||||
void lv_font_remove(lv_font_t * child, lv_font_t * parent)
|
||||
{
|
||||
if(parent == NULL) return;
|
||||
if(child == NULL) return;
|
||||
|
||||
while(parent->next_page != child) {
|
||||
parent = parent->next_page; /*Got to the last page and add the new font there*/
|
||||
}
|
||||
|
||||
parent->next_page = child->next_page;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tells if font which contains `letter` is monospace or not
|
||||
* @param font_p point to font
|
||||
* @param letter an UNICODE character code
|
||||
* @return true: the letter is monospace; false not monospace
|
||||
*/
|
||||
bool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter)
|
||||
{
|
||||
const lv_font_t * font_i = font_p;
|
||||
int16_t w;
|
||||
while(font_i != NULL) {
|
||||
w = font_i->get_width(font_i, letter);
|
||||
if(w >= 0) {
|
||||
/*Glyph found*/
|
||||
if(font_i->monospace) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
font_i = font_i->next_page;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with the bitmap of a font.
|
||||
* @param font_p pointer to a font
|
||||
* @param letter an UNICODE character code
|
||||
* @return pointer to the bitmap of the letter
|
||||
*/
|
||||
const uint8_t * lv_font_get_bitmap(const lv_font_t * font_p, uint32_t letter)
|
||||
{
|
||||
const lv_font_t * font_i = font_p;
|
||||
while(font_i != NULL) {
|
||||
const uint8_t * bitmap = font_i->get_bitmap(font_i, letter);
|
||||
if(bitmap) return bitmap;
|
||||
|
||||
font_i = font_i->next_page;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of a letter in a font. If `monospace` is set then return with it.
|
||||
* @param font_p pointer to a font
|
||||
* @param letter an UNICODE character code
|
||||
* @return the width of a letter
|
||||
*/
|
||||
uint8_t lv_font_get_width(const lv_font_t * font_p, uint32_t letter)
|
||||
{
|
||||
const lv_font_t * font_i = font_p;
|
||||
int16_t w;
|
||||
while(font_i != NULL) {
|
||||
w = font_i->get_width(font_i, letter);
|
||||
if(w >= 0) {
|
||||
/*Glyph found*/
|
||||
uint8_t m = font_i->monospace;
|
||||
if(m) w = m;
|
||||
return w;
|
||||
}
|
||||
|
||||
font_i = font_i->next_page;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of the letter without overwriting it with the `monospace` attribute
|
||||
* @param font_p pointer to a font
|
||||
* @param letter an UNICODE character code
|
||||
* @return the width of a letter
|
||||
*/
|
||||
uint8_t lv_font_get_real_width(const lv_font_t * font_p, uint32_t letter)
|
||||
{
|
||||
const lv_font_t * font_i = font_p;
|
||||
int16_t w;
|
||||
while(font_i != NULL) {
|
||||
w = font_i->get_width(font_i, letter);
|
||||
if(w >= 0) return w;
|
||||
|
||||
font_i = font_i->next_page;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bit-per-pixel of font
|
||||
* @param font pointer to font
|
||||
* @param letter a letter from font (font extensions can have different bpp)
|
||||
* @return bpp of the font (or font extension)
|
||||
*/
|
||||
uint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter)
|
||||
{
|
||||
const lv_font_t * font_i = font;
|
||||
while(font_i != NULL) {
|
||||
if(letter >= font_i->unicode_first && letter <= font_i->unicode_last) {
|
||||
return font_i->bpp;
|
||||
}
|
||||
font_i = font_i->next_page;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in the range
|
||||
* @param font pointer to font
|
||||
* @param unicode_letter an unicode letter which bitmap should be get
|
||||
* @return pointer to the bitmap or NULL if not found
|
||||
*/
|
||||
const uint8_t * lv_font_get_bitmap_continuous(const lv_font_t * font, uint32_t unicode_letter)
|
||||
{
|
||||
/*Check the range*/
|
||||
if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return NULL;
|
||||
|
||||
uint32_t index = (unicode_letter - font->unicode_first);
|
||||
return &font->glyph_bitmap[font->glyph_dsc[index].glyph_index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic bitmap get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse)
|
||||
* @param font pointer to font
|
||||
* @param unicode_letter an unicode letter which bitmap should be get
|
||||
* @return pointer to the bitmap or NULL if not found
|
||||
*/
|
||||
const uint8_t * lv_font_get_bitmap_sparse(const lv_font_t * font, uint32_t unicode_letter)
|
||||
{
|
||||
/*Check the range*/
|
||||
if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return NULL;
|
||||
|
||||
uint32_t i;
|
||||
for(i = 0; font->unicode_list[i] != 0; i++) {
|
||||
if(font->unicode_list[i] == unicode_letter) {
|
||||
return &font->glyph_bitmap[font->glyph_dsc[i].glyph_index];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic glyph width get function used in 'font->get_width' when the font contains all characters in the range
|
||||
* @param font pointer to font
|
||||
* @param unicode_letter an unicode letter which width should be get
|
||||
* @return width of the gylph or -1 if not found
|
||||
*/
|
||||
int16_t lv_font_get_width_continuous(const lv_font_t * font, uint32_t unicode_letter)
|
||||
{
|
||||
/*Check the range*/
|
||||
if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t index = (unicode_letter - font->unicode_first);
|
||||
return font->glyph_dsc[index].w_px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic glyph width get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse)
|
||||
* @param font pointer to font
|
||||
* @param unicode_letter an unicode letter which width should be get
|
||||
* @return width of the glyph or -1 if not found
|
||||
*/
|
||||
int16_t lv_font_get_width_sparse(const lv_font_t * font, uint32_t unicode_letter)
|
||||
{
|
||||
/*Check the range*/
|
||||
if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return -1;
|
||||
|
||||
uint32_t i;
|
||||
for(i = 0; font->unicode_list[i] != 0; i++) {
|
||||
if(font->unicode_list[i] == unicode_letter) {
|
||||
return font->glyph_dsc[i].w_px;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
192
src/lv_misc/lv_font.h
Normal file
192
src/lv_misc/lv_font.h
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* @file lv_font.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_FONT_H
|
||||
#define LV_FONT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "lv_symbol_def.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t w_px :8;
|
||||
uint32_t glyph_index :24;
|
||||
} lv_font_glyph_dsc_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t unicode :21;
|
||||
uint32_t glyph_dsc_index :11;
|
||||
} lv_font_unicode_map_t;
|
||||
|
||||
typedef struct _lv_font_struct
|
||||
{
|
||||
uint32_t unicode_first;
|
||||
uint32_t unicode_last;
|
||||
const uint8_t * glyph_bitmap;
|
||||
const lv_font_glyph_dsc_t * glyph_dsc;
|
||||
const uint32_t * unicode_list;
|
||||
const uint8_t * (*get_bitmap)(const struct _lv_font_struct *,uint32_t); /*Get a glyph's bitmap from a font*/
|
||||
int16_t (*get_width)(const struct _lv_font_struct *,uint32_t); /*Get a glyph's with with a given font*/
|
||||
struct _lv_font_struct * next_page; /*Pointer to a font extension*/
|
||||
uint32_t h_px :8;
|
||||
uint32_t bpp :4; /*Bit per pixel: 1, 2 or 4*/
|
||||
uint32_t monospace :8; /*Fix width (0: normal width)*/
|
||||
uint16_t glyph_cnt; /*Number of glyphs (letters) in the font*/
|
||||
} lv_font_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the fonts
|
||||
*/
|
||||
void lv_font_init(void);
|
||||
|
||||
/**
|
||||
* Add a font to an other to extend the character set.
|
||||
* @param child the font to add
|
||||
* @param parent this font will be extended. Using it later will contain the characters from `child`
|
||||
*/
|
||||
void lv_font_add(lv_font_t *child, lv_font_t *parent);
|
||||
|
||||
/**
|
||||
* Remove a font from a character set.
|
||||
* @param child the font to remove
|
||||
* @param parent remove `child` from here
|
||||
*/
|
||||
void lv_font_remove(lv_font_t * child, lv_font_t * parent);
|
||||
|
||||
/**
|
||||
* Tells if font which contains `letter` is monospace or not
|
||||
* @param font_p point to font
|
||||
* @param letter an UNICODE character code
|
||||
* @return true: the letter is monospace; false not monospace
|
||||
*/
|
||||
bool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter);
|
||||
|
||||
/**
|
||||
* Return with the bitmap of a font.
|
||||
* @param font_p pointer to a font
|
||||
* @param letter an UNICODE character code
|
||||
* @return pointer to the bitmap of the letter
|
||||
*/
|
||||
const uint8_t * lv_font_get_bitmap(const lv_font_t * font_p, uint32_t letter);
|
||||
|
||||
/**
|
||||
* Get the width of a letter in a font. If `monospace` is set then return with it.
|
||||
* @param font_p pointer to a font
|
||||
* @param letter an UNICODE character code
|
||||
* @return the width of a letter
|
||||
*/
|
||||
uint8_t lv_font_get_width(const lv_font_t * font_p, uint32_t letter);
|
||||
|
||||
|
||||
/**
|
||||
* Get the width of the letter without overwriting it with the `monospace` attribute
|
||||
* @param font_p pointer to a font
|
||||
* @param letter an UNICODE character code
|
||||
* @return the width of a letter
|
||||
*/
|
||||
uint8_t lv_font_get_real_width(const lv_font_t * font_p, uint32_t letter);
|
||||
|
||||
/**
|
||||
* Get the height of a font
|
||||
* @param font_p pointer to a font
|
||||
* @return the height of a font
|
||||
*/
|
||||
static inline uint8_t lv_font_get_height(const lv_font_t * font_p)
|
||||
{
|
||||
return font_p->h_px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bit-per-pixel of font
|
||||
* @param font pointer to font
|
||||
* @param letter a letter from font (font extensions can have different bpp)
|
||||
* @return bpp of the font (or font extension)
|
||||
*/
|
||||
uint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter);
|
||||
|
||||
/**
|
||||
* Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in the range
|
||||
* @param font pointer to font
|
||||
* @param unicode_letter an unicode letter which bitmap should be get
|
||||
* @return pointer to the bitmap or NULL if not found
|
||||
*/
|
||||
const uint8_t * lv_font_get_bitmap_continuous(const lv_font_t * font, uint32_t unicode_letter);
|
||||
|
||||
/**
|
||||
* Generic bitmap get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse)
|
||||
* @param font pointer to font
|
||||
* @param unicode_letter an unicode letter which bitmap should be get
|
||||
* @return pointer to the bitmap or NULL if not found
|
||||
*/
|
||||
const uint8_t * lv_font_get_bitmap_sparse(const lv_font_t * font, uint32_t unicode_letter);
|
||||
/**
|
||||
* Generic glyph width get function used in 'font->get_width' when the font contains all characters in the range
|
||||
* @param font pointer to font
|
||||
* @param unicode_letter an unicode letter which width should be get
|
||||
* @return width of the gylph or -1 if not found
|
||||
*/
|
||||
int16_t lv_font_get_width_continuous(const lv_font_t * font, uint32_t unicode_letter);
|
||||
|
||||
/**
|
||||
* Generic glyph width get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse)
|
||||
* @param font pointer to font
|
||||
* @param unicode_letter an unicode letter which width should be get
|
||||
* @return width of the glyph or -1 if not found
|
||||
*/
|
||||
int16_t lv_font_get_width_sparse(const lv_font_t * font, uint32_t unicode_letter);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#define LV_FONT_DECLARE(font_name) extern lv_font_t font_name;
|
||||
|
||||
|
||||
/**********************
|
||||
* ADD BUILT IN FONTS
|
||||
**********************/
|
||||
#include "../lv_fonts/lv_font_builtin.h"
|
||||
|
||||
/*Declare the custom (user defined) fonts*/
|
||||
#ifdef LV_FONT_CUSTOM_DECLARE
|
||||
LV_FONT_CUSTOM_DECLARE
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*USE_FONT*/
|
||||
|
||||
627
src/lv_misc/lv_fs.c
Normal file
627
src/lv_misc/lv_fs.c
Normal file
@@ -0,0 +1,627 @@
|
||||
/**
|
||||
* @file lv_fs.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_fs.h"
|
||||
#if LV_USE_FILESYSTEM
|
||||
|
||||
#include "lv_ll.h"
|
||||
#include <string.h>
|
||||
#include "lv_gc.h"
|
||||
|
||||
#if defined(LV_GC_INCLUDE)
|
||||
# include LV_GC_INCLUDE
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/* "free" is used as a function pointer (in lv_fs_drv_t).
|
||||
* We must make sure "free" was not defined to a platform specific
|
||||
* free function, otherwise compilation would fail.
|
||||
*/
|
||||
#ifdef free
|
||||
#undef free
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static const char * lv_fs_get_real_path(const char * path);
|
||||
static lv_fs_drv_t * lv_fs_get_drv(char letter);
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the File system interface
|
||||
*/
|
||||
void lv_fs_init(void)
|
||||
{
|
||||
lv_ll_init(&LV_GC_ROOT(_lv_drv_ll), sizeof(lv_fs_drv_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a drive is rady or not. If the `ready` function was not initialized `true` will be returned.
|
||||
* @param letter letter of the drive
|
||||
* @return true: drive is ready; false: drive is not ready
|
||||
*/
|
||||
bool lv_fs_is_ready(char letter)
|
||||
{
|
||||
lv_fs_drv_t * drv = lv_fs_get_drv(letter);
|
||||
|
||||
if(drv == NULL) return false; /*An unknown driver in not ready*/
|
||||
|
||||
if(drv->ready == NULL) return true; /*Assume the driver is always ready if no handler provided*/
|
||||
|
||||
return drv->ready();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a file
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
|
||||
* @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode)
|
||||
{
|
||||
file_p->drv = NULL;
|
||||
file_p->file_d = NULL;
|
||||
|
||||
if(path == NULL) return LV_FS_RES_INV_PARAM;
|
||||
|
||||
char letter = path[0];
|
||||
|
||||
file_p->drv = lv_fs_get_drv(letter);
|
||||
|
||||
if(file_p->drv == NULL) {
|
||||
file_p->file_d = NULL;
|
||||
return LV_FS_RES_NOT_EX;
|
||||
}
|
||||
|
||||
if(file_p->drv->ready != NULL) {
|
||||
if(file_p->drv->ready() == false) {
|
||||
file_p->drv = NULL;
|
||||
file_p->file_d = NULL;
|
||||
return LV_FS_RES_HW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
file_p->file_d = lv_mem_alloc(file_p->drv->file_size);
|
||||
lv_mem_assert(file_p->file_d);
|
||||
if(file_p->file_d == NULL) {
|
||||
file_p->drv = NULL;
|
||||
return LV_FS_RES_OUT_OF_MEM; /* Out of memory */
|
||||
}
|
||||
|
||||
if(file_p->drv->open == NULL) {
|
||||
return LV_FS_RES_NOT_IMP;
|
||||
}
|
||||
|
||||
const char * real_path = lv_fs_get_real_path(path);
|
||||
lv_fs_res_t res = file_p->drv->open(file_p->file_d, real_path, mode);
|
||||
|
||||
if(res != LV_FS_RES_OK) {
|
||||
lv_mem_free(file_p->file_d);
|
||||
file_p->file_d = NULL;
|
||||
file_p->drv = NULL;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close an already opened file
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_close(lv_fs_file_t * file_p)
|
||||
{
|
||||
if(file_p->drv == NULL) {
|
||||
return LV_FS_RES_INV_PARAM;
|
||||
}
|
||||
|
||||
if(file_p->drv->close == NULL) {
|
||||
return LV_FS_RES_NOT_IMP;
|
||||
}
|
||||
|
||||
lv_fs_res_t res = file_p->drv->close(file_p->file_d);
|
||||
|
||||
lv_mem_free(file_p->file_d); /*Clean up*/
|
||||
file_p->file_d = NULL;
|
||||
file_p->drv = NULL;
|
||||
file_p->file_d = NULL;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file
|
||||
* @param path path of the file to delete
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_remove(const char * path)
|
||||
{
|
||||
if(path == NULL) return LV_FS_RES_INV_PARAM;
|
||||
lv_fs_drv_t * drv = NULL;
|
||||
|
||||
char letter = path[0];
|
||||
|
||||
drv = lv_fs_get_drv(letter);
|
||||
if(drv == NULL) return LV_FS_RES_NOT_EX;
|
||||
if(drv->ready != NULL) {
|
||||
if(drv->ready() == false) return LV_FS_RES_HW_ERR;
|
||||
}
|
||||
|
||||
if(drv->remove == NULL) return LV_FS_RES_NOT_IMP;
|
||||
|
||||
const char * real_path = lv_fs_get_real_path(path);
|
||||
lv_fs_res_t res = drv->remove(real_path);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from a file
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @param buf pointer to a buffer where the read bytes are stored
|
||||
* @param btr Bytes To Read
|
||||
* @param br the number of real read bytes (Bytes Read). NULL if unused.
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_read(lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br)
|
||||
{
|
||||
if(br != NULL) *br = 0;
|
||||
if(file_p->drv == NULL) return LV_FS_RES_INV_PARAM;
|
||||
if(file_p->drv->read == NULL) return LV_FS_RES_NOT_IMP;
|
||||
|
||||
uint32_t br_tmp = 0;
|
||||
lv_fs_res_t res = file_p->drv->read(file_p->file_d, buf, btr, &br_tmp);
|
||||
if(br != NULL) *br = br_tmp;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write into a file
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @param buf pointer to a buffer with the bytes to write
|
||||
* @param btr Bytes To Write
|
||||
* @param br the number of real written bytes (Bytes Written). NULL if unused.
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_write(lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw)
|
||||
{
|
||||
if(bw != NULL) *bw = 0;
|
||||
|
||||
if(file_p->drv == NULL) {
|
||||
return LV_FS_RES_INV_PARAM;
|
||||
}
|
||||
|
||||
if(file_p->drv->write == NULL) {
|
||||
return LV_FS_RES_NOT_IMP;
|
||||
}
|
||||
|
||||
uint32_t bw_tmp = 0;
|
||||
lv_fs_res_t res = file_p->drv->write(file_p->file_d, buf, btw, &bw_tmp);
|
||||
if(bw != NULL) *bw = bw_tmp;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the position of the 'cursor' (read write pointer) in a file
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @param pos the new position expressed in bytes index (0: start of file)
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_seek(lv_fs_file_t * file_p, uint32_t pos)
|
||||
{
|
||||
if(file_p->drv == NULL) {
|
||||
return LV_FS_RES_INV_PARAM;
|
||||
}
|
||||
|
||||
if(file_p->drv->seek == NULL) {
|
||||
return LV_FS_RES_NOT_IMP;
|
||||
}
|
||||
|
||||
lv_fs_res_t res = file_p->drv->seek(file_p->file_d, pos);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the position of the read write pointer
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @param pos_p pointer to store the position of the read write pointer
|
||||
* @return LV_FS_RES_OK or any error from 'fs_res_t'
|
||||
*/
|
||||
lv_fs_res_t lv_fs_tell(lv_fs_file_t * file_p, uint32_t * pos)
|
||||
{
|
||||
if(file_p->drv == NULL) {
|
||||
pos = 0;
|
||||
return LV_FS_RES_INV_PARAM;
|
||||
}
|
||||
|
||||
if(file_p->drv->tell == NULL) {
|
||||
pos = 0;
|
||||
return LV_FS_RES_NOT_IMP;
|
||||
}
|
||||
|
||||
lv_fs_res_t res = file_p->drv->tell(file_p->file_d, pos);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate the file size to the current position of the read write pointer
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open )
|
||||
* @return LV_FS_RES_OK: no error, the file is read
|
||||
* any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_trunc(lv_fs_file_t * file_p)
|
||||
{
|
||||
if(file_p->drv == NULL) {
|
||||
return LV_FS_RES_INV_PARAM;
|
||||
}
|
||||
|
||||
if(file_p->drv->tell == NULL) {
|
||||
return LV_FS_RES_NOT_IMP;
|
||||
}
|
||||
|
||||
lv_fs_res_t res = file_p->drv->trunc(file_p->file_d);
|
||||
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* Give the size of a file bytes
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @param size pointer to a variable to store the size
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_size(lv_fs_file_t * file_p, uint32_t * size)
|
||||
{
|
||||
if(file_p->drv == NULL) {
|
||||
return LV_FS_RES_INV_PARAM;
|
||||
}
|
||||
|
||||
if(file_p->drv->size == NULL) return LV_FS_RES_NOT_IMP;
|
||||
|
||||
|
||||
if(size == NULL) return LV_FS_RES_INV_PARAM;
|
||||
|
||||
lv_fs_res_t res = file_p->drv->size(file_p->file_d, size);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename a file
|
||||
* @param oldname path to the file
|
||||
* @param newname path with the new name
|
||||
* @return LV_FS_RES_OK or any error from 'fs_res_t'
|
||||
*/
|
||||
lv_fs_res_t lv_fs_rename(const char * oldname, const char * newname)
|
||||
{
|
||||
if(!oldname || !newname) return LV_FS_RES_INV_PARAM;
|
||||
|
||||
char letter = oldname[0];
|
||||
|
||||
lv_fs_drv_t * drv = lv_fs_get_drv(letter);
|
||||
|
||||
if(!drv) {
|
||||
return LV_FS_RES_NOT_EX;
|
||||
}
|
||||
|
||||
if(drv->ready != NULL) {
|
||||
if(drv->ready() == false) {
|
||||
return LV_FS_RES_HW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
if(drv->rename == NULL) return LV_FS_RES_NOT_IMP;
|
||||
|
||||
const char * old_real = lv_fs_get_real_path(oldname);
|
||||
const char * new_real = lv_fs_get_real_path(newname);
|
||||
lv_fs_res_t res = drv->rename(old_real, new_real);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a 'fs_read_dir_t' variable for directory reading
|
||||
* @param rddir_p pointer to a 'fs_read_dir_t' variable
|
||||
* @param path path to a directory
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path)
|
||||
{
|
||||
if(path == NULL) return LV_FS_RES_INV_PARAM;
|
||||
|
||||
char letter = path[0];
|
||||
|
||||
rddir_p->drv = lv_fs_get_drv(letter);
|
||||
|
||||
if(rddir_p->drv == NULL) {
|
||||
rddir_p->dir_d = NULL;
|
||||
return LV_FS_RES_NOT_EX;
|
||||
}
|
||||
|
||||
rddir_p->dir_d = lv_mem_alloc(rddir_p->drv->rddir_size);
|
||||
lv_mem_assert(rddir_p->dir_d);
|
||||
if(rddir_p->dir_d == NULL) {
|
||||
rddir_p->dir_d = NULL;
|
||||
return LV_FS_RES_OUT_OF_MEM; /* Out of memory */
|
||||
}
|
||||
|
||||
if(rddir_p->drv->dir_open == NULL) {
|
||||
return LV_FS_RES_NOT_IMP;
|
||||
}
|
||||
|
||||
const char * real_path = lv_fs_get_real_path(path);
|
||||
lv_fs_res_t res = rddir_p->drv->dir_open(rddir_p->dir_d, real_path);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the next filename form a directory.
|
||||
* The name of the directories will begin with '/'
|
||||
* @param rddir_p pointer to an initialized 'fs_read_dir_t' variable
|
||||
* @param fn pointer to a buffer to store the filename
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_dir_read(lv_fs_dir_t * rddir_p, char * fn)
|
||||
{
|
||||
if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) {
|
||||
fn[0] = '\0';
|
||||
return LV_FS_RES_INV_PARAM;
|
||||
}
|
||||
|
||||
if(rddir_p->drv->dir_read == NULL) {
|
||||
return LV_FS_RES_NOT_IMP;
|
||||
}
|
||||
|
||||
lv_fs_res_t res = rddir_p->drv->dir_read(rddir_p->dir_d, fn);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the directory reading
|
||||
* @param rddir_p pointer to an initialized 'fs_read_dir_t' variable
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_dir_close(lv_fs_dir_t * rddir_p)
|
||||
{
|
||||
if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) {
|
||||
return LV_FS_RES_INV_PARAM;
|
||||
}
|
||||
|
||||
lv_fs_res_t res;
|
||||
|
||||
if(rddir_p->drv->dir_close == NULL) {
|
||||
res = LV_FS_RES_NOT_IMP;
|
||||
} else {
|
||||
res = rddir_p->drv->dir_close(rddir_p->dir_d);
|
||||
}
|
||||
|
||||
lv_mem_free(rddir_p->dir_d); /*Clean up*/
|
||||
rddir_p->dir_d = NULL;
|
||||
rddir_p->drv = NULL;
|
||||
rddir_p->dir_d = NULL;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the free and total size of a driver in kB
|
||||
* @param letter the driver letter
|
||||
* @param total_p pointer to store the total size [kB]
|
||||
* @param free_p pointer to store the free size [kB]
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_free_space(char letter, uint32_t * total_p, uint32_t * free_p)
|
||||
{
|
||||
lv_fs_drv_t * drv = lv_fs_get_drv(letter);
|
||||
|
||||
if(drv == NULL) {
|
||||
return LV_FS_RES_INV_PARAM;
|
||||
}
|
||||
|
||||
lv_fs_res_t res;
|
||||
|
||||
if(drv->free_space == NULL) {
|
||||
res = LV_FS_RES_NOT_IMP;
|
||||
} else {
|
||||
uint32_t total_tmp = 0;
|
||||
uint32_t free_tmp = 0;
|
||||
res = drv->free_space(&total_tmp, &free_tmp);
|
||||
|
||||
if(total_p != NULL) *total_p = total_tmp;
|
||||
if(free_p != NULL) *free_p = free_tmp;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new drive
|
||||
* @param drv_p pointer to an lv_fs_drv_t structure which is inited with the
|
||||
* corresponding function pointers. The data will be copied so the variable can be local.
|
||||
*/
|
||||
void lv_fs_add_drv(lv_fs_drv_t * drv_p)
|
||||
{
|
||||
/*Save the new driver*/
|
||||
lv_fs_drv_t * new_drv;
|
||||
new_drv = lv_ll_ins_head(&LV_GC_ROOT(_lv_drv_ll));
|
||||
lv_mem_assert(new_drv);
|
||||
if(new_drv == NULL) return;
|
||||
|
||||
memcpy(new_drv, drv_p, sizeof(lv_fs_drv_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill a buffer with the letters of existing drivers
|
||||
* @param buf buffer to store the letters ('\0' added after the last letter)
|
||||
* @return the buffer
|
||||
*/
|
||||
char * lv_fs_get_letters(char * buf)
|
||||
{
|
||||
lv_fs_drv_t * drv;
|
||||
uint8_t i = 0;
|
||||
|
||||
LV_LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) {
|
||||
buf[i] = drv->letter;
|
||||
i++;
|
||||
}
|
||||
|
||||
buf[i] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return with the extension of the filename
|
||||
* @param fn string with a filename
|
||||
* @return pointer to the beginning extension or empty string if no extension
|
||||
*/
|
||||
const char * lv_fs_get_ext(const char * fn)
|
||||
{
|
||||
uint16_t i;
|
||||
for(i = strlen(fn); i > 0; i --) {
|
||||
if(fn[i] == '.') {
|
||||
return &fn[i + 1];
|
||||
} else if(fn[i] == '/' || fn[i] == '\\') {
|
||||
return ""; /*No extension if a '\' or '/' found*/
|
||||
}
|
||||
}
|
||||
|
||||
return ""; /*Empty string if no '.' in the file name. */
|
||||
}
|
||||
|
||||
/**
|
||||
* Step up one level
|
||||
* @param path pointer to a file name
|
||||
* @return the truncated file name
|
||||
*/
|
||||
char * lv_fs_up(char * path)
|
||||
{
|
||||
uint16_t len = strlen(path);
|
||||
if(len == 0) return path;
|
||||
|
||||
len --; /*Go before the trailing '\0'*/
|
||||
|
||||
/*Ignore trailing '/' or '\'*/
|
||||
while(path[len] == '/' || path[len] == '\\') {
|
||||
path[len] = '\0';
|
||||
if(len > 0) len --;
|
||||
else return path;
|
||||
}
|
||||
|
||||
uint16_t i;
|
||||
for(i = len; i > 0; i --) {
|
||||
if(path[i] == '/' || path[i] == '\\') break;
|
||||
}
|
||||
|
||||
if(i > 0) path[i] = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last element of a path (e.g. U:/folder/file -> file)
|
||||
* @param path a character sting with the path to search in
|
||||
* @return pointer to the beginning of the last element in the path
|
||||
*/
|
||||
const char * lv_fs_get_last(const char * path)
|
||||
{
|
||||
uint16_t len = strlen(path);
|
||||
if(len == 0) return path;
|
||||
|
||||
len --; /*Go before the trailing '\0'*/
|
||||
|
||||
/*Ignore trailing '/' or '\'*/
|
||||
while(path[len] == '/' || path[len] == '\\') {
|
||||
if(len > 0) len --;
|
||||
else return path;
|
||||
}
|
||||
|
||||
uint16_t i;
|
||||
for(i = len; i > 0; i --) {
|
||||
if(path[i] == '/' || path[i] == '\\') break;
|
||||
}
|
||||
|
||||
/*No '/' or '\' in the path so return with path itself*/
|
||||
if(i == 0) return path;
|
||||
|
||||
return &path[i + 1];
|
||||
}
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Leave the driver letters and / or \ letters from beginning of the path
|
||||
* @param path path string (E.g. S:/folder/file.txt)
|
||||
* @return pointer to the beginning of the real path (E.g. folder/file.txt)
|
||||
*/
|
||||
static const char * lv_fs_get_real_path(const char * path)
|
||||
{
|
||||
/* Example path: "S:/folder/file.txt"
|
||||
* Leave the letter and the : / \ characters*/
|
||||
|
||||
path ++; /*Ignore the driver letter*/
|
||||
|
||||
while(*path != '\0') {
|
||||
if(*path == ':' || *path == '\\' || *path == '/') {
|
||||
path ++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give a pointer to a driver from its letter
|
||||
* @param letter the driver letter
|
||||
* @return pointer to a driver or NULL if not found
|
||||
*/
|
||||
static lv_fs_drv_t * lv_fs_get_drv(char letter)
|
||||
{
|
||||
lv_fs_drv_t * drv;
|
||||
|
||||
LV_LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) {
|
||||
if(drv->letter == letter) {
|
||||
return drv;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_FILESYSTEM*/
|
||||
277
src/lv_misc/lv_fs.h
Normal file
277
src/lv_misc/lv_fs.h
Normal file
@@ -0,0 +1,277 @@
|
||||
/**
|
||||
* @file lv_fs.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_FS_H
|
||||
#define LV_FS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if LV_USE_FILESYSTEM
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "lv_mem.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_FS_MAX_FN_LENGTH 64
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
enum
|
||||
{
|
||||
LV_FS_RES_OK = 0,
|
||||
LV_FS_RES_HW_ERR, /*Low level hardware error*/
|
||||
LV_FS_RES_FS_ERR, /*Error in the file system structure */
|
||||
LV_FS_RES_NOT_EX, /*Driver, file or directory is not exists*/
|
||||
LV_FS_RES_FULL, /*Disk full*/
|
||||
LV_FS_RES_LOCKED, /*The file is already opened*/
|
||||
LV_FS_RES_DENIED, /*Access denied. Check 'fs_open' modes and write protect*/
|
||||
LV_FS_RES_BUSY, /*The file system now can't handle it, try later*/
|
||||
LV_FS_RES_TOUT, /*Process time outed*/
|
||||
LV_FS_RES_NOT_IMP, /*Requested function is not implemented*/
|
||||
LV_FS_RES_OUT_OF_MEM, /*Not enough memory for an internal operation*/
|
||||
LV_FS_RES_INV_PARAM, /*Invalid parameter among arguments*/
|
||||
LV_FS_RES_UNKNOWN, /*Other unknown error*/
|
||||
};
|
||||
typedef uint8_t lv_fs_res_t;
|
||||
|
||||
struct __lv_fs_drv_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void * file_d;
|
||||
struct __lv_fs_drv_t* drv;
|
||||
} lv_fs_file_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void * dir_d;
|
||||
struct __lv_fs_drv_t * drv;
|
||||
} lv_fs_dir_t;
|
||||
|
||||
enum
|
||||
{
|
||||
LV_FS_MODE_WR = 0x01,
|
||||
LV_FS_MODE_RD = 0x02,
|
||||
};
|
||||
typedef uint8_t lv_fs_mode_t;
|
||||
|
||||
typedef struct __lv_fs_drv_t
|
||||
{
|
||||
char letter;
|
||||
uint16_t file_size;
|
||||
uint16_t rddir_size;
|
||||
bool (*ready) (void);
|
||||
|
||||
lv_fs_res_t (*open) (void * file_p, const char * path, lv_fs_mode_t mode);
|
||||
lv_fs_res_t (*close) (void * file_p);
|
||||
lv_fs_res_t (*remove) (const char * fn);
|
||||
lv_fs_res_t (*read) (void * file_p, void * buf, uint32_t btr, uint32_t * br);
|
||||
lv_fs_res_t (*write) (void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
|
||||
lv_fs_res_t (*seek) (void * file_p, uint32_t pos);
|
||||
lv_fs_res_t (*tell) (void * file_p, uint32_t * pos_p);
|
||||
lv_fs_res_t (*trunc) (void * file_p);
|
||||
lv_fs_res_t (*size) (void * file_p, uint32_t * size_p);
|
||||
lv_fs_res_t (*rename) (const char * oldname, const char * newname);
|
||||
lv_fs_res_t (*free_space) (uint32_t * total_p, uint32_t * free_p);
|
||||
|
||||
lv_fs_res_t (*dir_open) (void * rddir_p, const char * path);
|
||||
lv_fs_res_t (*dir_read) (void * rddir_p, char * fn);
|
||||
lv_fs_res_t (*dir_close) (void * rddir_p);
|
||||
} lv_fs_drv_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the File system interface
|
||||
*/
|
||||
void lv_fs_init(void);
|
||||
|
||||
/**
|
||||
* Add a new drive
|
||||
* @param drv_p pointer to an lv_fs_drv_t structure which is inited with the
|
||||
* corresponding function pointers. The data will be copied so the variable can be local.
|
||||
*/
|
||||
void lv_fs_add_drv(lv_fs_drv_t * drv_p);
|
||||
|
||||
/**
|
||||
* Test if a drive is rady or not. If the `ready` function was not initialized `true` will be returned.
|
||||
* @param letter letter of the drive
|
||||
* @return true: drive is ready; false: drive is not ready
|
||||
*/
|
||||
bool lv_fs_is_ready(char letter);
|
||||
|
||||
/**
|
||||
* Open a file
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
|
||||
* @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_open (lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode);
|
||||
|
||||
/**
|
||||
* Close an already opened file
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_close (lv_fs_file_t * file_p);
|
||||
|
||||
/**
|
||||
* Delete a file
|
||||
* @param path path of the file to delete
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_remove (const char * path);
|
||||
|
||||
/**
|
||||
* Read from a file
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @param buf pointer to a buffer where the read bytes are stored
|
||||
* @param btr Bytes To Read
|
||||
* @param br the number of real read bytes (Bytes Read). NULL if unused.
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_read (lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br);
|
||||
|
||||
/**
|
||||
* Write into a file
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @param buf pointer to a buffer with the bytes to write
|
||||
* @param btr Bytes To Write
|
||||
* @param br the number of real written bytes (Bytes Written). NULL if unused.
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_write (lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw);
|
||||
|
||||
/**
|
||||
* Set the position of the 'cursor' (read write pointer) in a file
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @param pos the new position expressed in bytes index (0: start of file)
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_seek (lv_fs_file_t * file_p, uint32_t pos);
|
||||
|
||||
/**
|
||||
* Give the position of the read write pointer
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @param pos_p pointer to store the position of the read write pointer
|
||||
* @return LV_FS_RES_OK or any error from 'fs_res_t'
|
||||
*/
|
||||
lv_fs_res_t lv_fs_tell (lv_fs_file_t * file_p, uint32_t * pos);
|
||||
|
||||
/**
|
||||
* Truncate the file size to the current position of the read write pointer
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open )
|
||||
* @return LV_FS_RES_OK: no error, the file is read
|
||||
* any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_trunc (lv_fs_file_t * file_p);
|
||||
|
||||
/**
|
||||
* Give the size of a file bytes
|
||||
* @param file_p pointer to a lv_fs_file_t variable
|
||||
* @param size pointer to a variable to store the size
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_size (lv_fs_file_t * file_p, uint32_t * size);
|
||||
|
||||
/**
|
||||
* Rename a file
|
||||
* @param oldname path to the file
|
||||
* @param newname path with the new name
|
||||
* @return LV_FS_RES_OK or any error from 'fs_res_t'
|
||||
*/
|
||||
lv_fs_res_t lv_fs_rename (const char * oldname, const char * newname);
|
||||
|
||||
/**
|
||||
* Initialize a 'fs_dir_t' variable for directory reading
|
||||
* @param rddir_p pointer to a 'fs_read_dir_t' variable
|
||||
* @param path path to a directory
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path);
|
||||
|
||||
/**
|
||||
* Read the next filename form a directory.
|
||||
* The name of the directories will begin with '/'
|
||||
* @param rddir_p pointer to an initialized 'fs_rdir_t' variable
|
||||
* @param fn pointer to a buffer to store the filename
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_dir_read (lv_fs_dir_t * rddir_p, char * fn);
|
||||
|
||||
/**
|
||||
* Close the directory reading
|
||||
* @param rddir_p pointer to an initialized 'fs_dir_t' variable
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_dir_close (lv_fs_dir_t * rddir_p);
|
||||
|
||||
/**
|
||||
* Get the free and total size of a driver in kB
|
||||
* @param letter the driver letter
|
||||
* @param total_p pointer to store the total size [kB]
|
||||
* @param free_p pointer to store the free size [kB]
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
lv_fs_res_t lv_fs_free_space (char letter, uint32_t * total_p, uint32_t * free_p);
|
||||
|
||||
/**
|
||||
* Fill a buffer with the letters of existing drivers
|
||||
* @param buf buffer to store the letters ('\0' added after the last letter)
|
||||
* @return the buffer
|
||||
*/
|
||||
char * lv_fs_get_letters(char * buf);
|
||||
|
||||
/**
|
||||
* Return with the extension of the filename
|
||||
* @param fn string with a filename
|
||||
* @return pointer to the beginning extension or empty string if no extension
|
||||
*/
|
||||
const char * lv_fs_get_ext(const char * fn);
|
||||
|
||||
/**
|
||||
* Step up one level
|
||||
* @param path pointer to a file name
|
||||
* @return the truncated file name
|
||||
*/
|
||||
char * lv_fs_up(char * path);
|
||||
|
||||
/**
|
||||
* Get the last element of a path (e.g. U:/folder/file -> file)
|
||||
* @param buf buffer to store the letters ('\0' added after the last letter)
|
||||
* @return pointer to the beginning of the last element in the path
|
||||
*/
|
||||
const char * lv_fs_get_last(const char * path);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_FILESYSTEM*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_FS_H*/
|
||||
40
src/lv_misc/lv_gc.c
Normal file
40
src/lv_misc/lv_gc.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @file lv_gc.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gc.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
#if (!defined(LV_ENABLE_GC)) || LV_ENABLE_GC == 0
|
||||
LV_ROOTS
|
||||
#endif /* LV_ENABLE_GC */
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
73
src/lv_misc/lv_gc.h
Normal file
73
src/lv_misc/lv_gc.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @file lv_gc.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GC_H
|
||||
#define LV_GC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "lv_mem.h"
|
||||
#include "lv_ll.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define LV_GC_ROOTS(prefix) \
|
||||
prefix lv_ll_t _lv_task_ll; /*Linked list to store the lv_tasks*/ \
|
||||
prefix lv_ll_t _lv_disp_ll; /*Linked list of screens*/ \
|
||||
prefix lv_ll_t _lv_indev_ll; /*Linked list of screens*/ \
|
||||
prefix lv_ll_t _lv_drv_ll;\
|
||||
prefix lv_ll_t _lv_file_ll;\
|
||||
prefix lv_ll_t _lv_anim_ll;\
|
||||
prefix lv_ll_t _lv_group_ll;\
|
||||
prefix void * _lv_task_act;\
|
||||
|
||||
|
||||
#define LV_NO_PREFIX
|
||||
#define LV_ROOTS LV_GC_ROOTS(LV_NO_PREFIX)
|
||||
|
||||
#if LV_ENABLE_GC == 1
|
||||
# if LV_MEM_CUSTOM != 1
|
||||
# error "GC requires CUSTOM_MEM"
|
||||
# endif /* LV_MEM_CUSTOM */
|
||||
#else /* LV_ENABLE_GC */
|
||||
# define LV_GC_ROOT(x) x
|
||||
LV_GC_ROOTS(extern)
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_GC_H*/
|
||||
391
src/lv_misc/lv_ll.c
Normal file
391
src/lv_misc/lv_ll.c
Normal file
@@ -0,0 +1,391 @@
|
||||
/**
|
||||
* @file lv_ll.c
|
||||
* Handle linked lists.
|
||||
* The nodes are dynamically allocated by the 'lv_mem' module,
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lv_ll.h"
|
||||
#include "lv_mem.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LL_NODE_META_SIZE (sizeof(lv_ll_node_t*) + sizeof(lv_ll_node_t*))
|
||||
#define LL_PREV_P_OFFSET(ll_p) (ll_p->n_size)
|
||||
#define LL_NEXT_P_OFFSET(ll_p) (ll_p->n_size + sizeof(lv_ll_node_t*))
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * prev);
|
||||
static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * next);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize linked list
|
||||
* @param ll_dsc pointer to ll_dsc variable
|
||||
* @param node_size the size of 1 node in bytes
|
||||
*/
|
||||
void lv_ll_init(lv_ll_t * ll_p, uint32_t node_size)
|
||||
{
|
||||
ll_p->head = NULL;
|
||||
ll_p->tail = NULL;
|
||||
#ifdef LV_MEM_ENV64
|
||||
/*Round the size up to 8*/
|
||||
if(node_size & 0x7) {
|
||||
node_size = node_size & (~0x7);
|
||||
node_size += 8;
|
||||
}
|
||||
#else
|
||||
/*Round the size up to 4*/
|
||||
if(node_size & 0x3) {
|
||||
node_size = node_size & (~0x3);
|
||||
node_size += 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
ll_p->n_size = node_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new head to a linked list
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the new head
|
||||
*/
|
||||
void * lv_ll_ins_head(lv_ll_t * ll_p)
|
||||
{
|
||||
lv_ll_node_t * n_new;
|
||||
|
||||
n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
|
||||
|
||||
if(n_new != NULL) {
|
||||
node_set_prev(ll_p, n_new, NULL); /*No prev. before the new head*/
|
||||
node_set_next(ll_p, n_new, ll_p->head); /*After new comes the old head*/
|
||||
|
||||
if(ll_p->head != NULL) { /*If there is old head then before it goes the new*/
|
||||
node_set_prev(ll_p, ll_p->head, n_new);
|
||||
}
|
||||
|
||||
ll_p->head = n_new; /*Set the new head in the dsc.*/
|
||||
if(ll_p->tail == NULL) {/*If there is no tail (1. node) set the tail too*/
|
||||
ll_p->tail = n_new;
|
||||
}
|
||||
}
|
||||
|
||||
return n_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new node in front of the n_act node
|
||||
* @param ll_p pointer to linked list
|
||||
* @param n_act pointer a node
|
||||
* @return pointer to the new head
|
||||
*/
|
||||
void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act)
|
||||
{
|
||||
lv_ll_node_t * n_new;
|
||||
lv_ll_node_t * n_prev;
|
||||
|
||||
if(NULL == ll_p || NULL == n_act) return NULL;
|
||||
|
||||
if(lv_ll_get_head(ll_p) == n_act) {
|
||||
n_new = lv_ll_ins_head(ll_p);
|
||||
if(n_new == NULL) return NULL;
|
||||
} else {
|
||||
n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
|
||||
if(n_new == NULL) return NULL;
|
||||
|
||||
n_prev = lv_ll_get_prev(ll_p, n_act);
|
||||
node_set_next(ll_p, n_prev, n_new);
|
||||
node_set_prev(ll_p, n_new, n_prev);
|
||||
node_set_prev(ll_p, n_act, n_new);
|
||||
node_set_next(ll_p, n_new, n_act);
|
||||
}
|
||||
|
||||
return n_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new tail to a linked list
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the new tail
|
||||
*/
|
||||
void * lv_ll_ins_tail(lv_ll_t * ll_p)
|
||||
{
|
||||
lv_ll_node_t * n_new;
|
||||
|
||||
n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
|
||||
if(n_new == NULL) return NULL;
|
||||
|
||||
if(n_new != NULL) {
|
||||
node_set_next(ll_p, n_new, NULL); /*No next after the new tail*/
|
||||
node_set_prev(ll_p, n_new, ll_p->tail); /*The prev. before new is tho old tail*/
|
||||
if(ll_p->tail != NULL) { /*If there is old tail then the new comes after it*/
|
||||
node_set_next(ll_p, ll_p->tail, n_new);
|
||||
}
|
||||
|
||||
ll_p->tail = n_new; /*Set the new tail in the dsc.*/
|
||||
if(ll_p->head == NULL) { /*If there is no head (1. node) set the head too*/
|
||||
ll_p->head = n_new;
|
||||
}
|
||||
}
|
||||
|
||||
return n_new;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the node 'node_p' from 'll_p' linked list.
|
||||
* It does not free the the memory of node.
|
||||
* @param ll_p pointer to the linked list of 'node_p'
|
||||
* @param node_p pointer to node in 'll_p' linked list
|
||||
*/
|
||||
void lv_ll_rem(lv_ll_t * ll_p, void * node_p)
|
||||
{
|
||||
if(lv_ll_get_head(ll_p) == node_p) {
|
||||
/*The new head will be the node after 'n_act'*/
|
||||
ll_p->head = lv_ll_get_next(ll_p, node_p);
|
||||
if(ll_p->head == NULL) {
|
||||
ll_p->tail = NULL;
|
||||
} else {
|
||||
node_set_prev(ll_p, ll_p->head, NULL);
|
||||
}
|
||||
} else if(lv_ll_get_tail(ll_p) == node_p) {
|
||||
/*The new tail will be the node before 'n_act'*/
|
||||
ll_p->tail = lv_ll_get_prev(ll_p, node_p);
|
||||
if(ll_p->tail == NULL) {
|
||||
ll_p->head = NULL;
|
||||
} else {
|
||||
node_set_next(ll_p, ll_p->tail, NULL);
|
||||
}
|
||||
} else {
|
||||
lv_ll_node_t * n_prev = lv_ll_get_prev(ll_p, node_p);
|
||||
lv_ll_node_t * n_next = lv_ll_get_next(ll_p, node_p);
|
||||
|
||||
node_set_next(ll_p, n_prev, n_next);
|
||||
node_set_prev(ll_p, n_next, n_prev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and free all elements from a linked list. The list remain valid but become empty.
|
||||
* @param ll_p pointer to linked list
|
||||
*/
|
||||
void lv_ll_clear(lv_ll_t * ll_p)
|
||||
{
|
||||
void * i;
|
||||
void * i_next;
|
||||
|
||||
i = lv_ll_get_head(ll_p);
|
||||
i_next = NULL;
|
||||
|
||||
while(i != NULL) {
|
||||
i_next = lv_ll_get_next(ll_p, i);
|
||||
|
||||
lv_ll_rem(ll_p, i);
|
||||
lv_mem_free(i);
|
||||
|
||||
i = i_next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a node to a new linked list
|
||||
* @param ll_ori_p pointer to the original (old) linked list
|
||||
* @param ll_new_p pointer to the new linked list
|
||||
* @param node pointer to a node
|
||||
*/
|
||||
void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node)
|
||||
{
|
||||
lv_ll_rem(ll_ori_p, node);
|
||||
|
||||
/*Set node as head*/
|
||||
node_set_prev(ll_new_p, node, NULL);
|
||||
node_set_next(ll_new_p, node, ll_new_p->head);
|
||||
|
||||
if(ll_new_p->head != NULL) { /*If there is old head then before it goes the new*/
|
||||
node_set_prev(ll_new_p, ll_new_p->head, node);
|
||||
}
|
||||
|
||||
ll_new_p->head = node; /*Set the new head in the dsc.*/
|
||||
if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/
|
||||
ll_new_p->tail = node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with head node of the linked list
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the head of 'll_p'
|
||||
*/
|
||||
void * lv_ll_get_head(const lv_ll_t * ll_p)
|
||||
{
|
||||
void * head = NULL;
|
||||
|
||||
if(ll_p != NULL) {
|
||||
head = ll_p->head;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with tail node of the linked list
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the head of 'll_p'
|
||||
*/
|
||||
void * lv_ll_get_tail(const lv_ll_t * ll_p)
|
||||
{
|
||||
void * tail = NULL;
|
||||
|
||||
if(ll_p != NULL) {
|
||||
tail = ll_p->tail;
|
||||
}
|
||||
|
||||
return tail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with the pointer of the next node after 'n_act'
|
||||
* @param ll_p pointer to linked list
|
||||
* @param n_act pointer a node
|
||||
* @return pointer to the next node
|
||||
*/
|
||||
void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act)
|
||||
{
|
||||
void * next = NULL;
|
||||
|
||||
if(ll_p != NULL) {
|
||||
const lv_ll_node_t * n_act_d = n_act;
|
||||
memcpy(&next, n_act_d + LL_NEXT_P_OFFSET(ll_p), sizeof(void *));
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with the pointer of the previous node after 'n_act'
|
||||
* @param ll_p pointer to linked list
|
||||
* @param n_act pointer a node
|
||||
* @return pointer to the previous node
|
||||
*/
|
||||
void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act)
|
||||
{
|
||||
void * prev = NULL;
|
||||
|
||||
if(ll_p != NULL) {
|
||||
const lv_ll_node_t * n_act_d = n_act;
|
||||
memcpy(&prev, n_act_d + LL_PREV_P_OFFSET(ll_p), sizeof(void *));
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
void lv_ll_swap(lv_ll_t * ll_p, void * n1_p, void * n2_p)
|
||||
{
|
||||
(void)(ll_p);
|
||||
(void)(n1_p);
|
||||
(void)(n2_p);
|
||||
/*TODO*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a nodw before an other node in the same linked list
|
||||
* @param ll_p pointer to a linked list
|
||||
* @param n_act pointer to node to move
|
||||
* @param n_after pointer to a node which should be after `n_act`
|
||||
*/
|
||||
void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after)
|
||||
{
|
||||
if(n_act == n_after) return; /*Can't move before itself*/
|
||||
|
||||
|
||||
void * n_before;
|
||||
if(n_after != NULL) n_before = lv_ll_get_prev(ll_p, n_after);
|
||||
else n_before = lv_ll_get_tail(ll_p); /*if `n_after` is NULL `n_act` should be the new tail*/
|
||||
|
||||
if(n_act == n_before) return; /*Already before `n_after`*/
|
||||
|
||||
/*It's much easier to remove from the list and add again*/
|
||||
lv_ll_rem(ll_p, n_act);
|
||||
|
||||
/*Add again by setting the prev. and next nodes*/
|
||||
node_set_next(ll_p, n_before, n_act);
|
||||
node_set_prev(ll_p, n_act, n_before);
|
||||
node_set_prev(ll_p, n_after, n_act);
|
||||
node_set_next(ll_p, n_act, n_after);
|
||||
|
||||
/*If `n_act` was moved before NULL then it become the new tail*/
|
||||
if(n_after == NULL) ll_p->tail = n_act;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a linked list is empty
|
||||
* @param ll_p pointer to a linked list
|
||||
* @return true: the linked list is empty; false: not empty
|
||||
*/
|
||||
bool lv_ll_is_empty(lv_ll_t * ll_p)
|
||||
{
|
||||
if(ll_p == NULL) return true;
|
||||
|
||||
if(ll_p->head == NULL && ll_p->tail == NULL) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set the 'pervious node pointer' of a node
|
||||
* @param ll_p pointer to linked list
|
||||
* @param act pointer to a node which prev. node pointer should be set
|
||||
* @param prev pointer to a node which should be the previous node before 'act'
|
||||
*/
|
||||
static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * prev)
|
||||
{
|
||||
if(act == NULL) return; /*Can't set the prev node of `NULL`*/
|
||||
|
||||
uint32_t node_p_size = sizeof(lv_ll_node_t *);
|
||||
if(prev) memcpy(act + LL_PREV_P_OFFSET(ll_p), &prev, node_p_size);
|
||||
else memset(act + LL_PREV_P_OFFSET(ll_p), 0, node_p_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the 'next node pointer' of a node
|
||||
* @param ll_p pointer to linked list
|
||||
* @param act pointer to a node which next node pointer should be set
|
||||
* @param next pointer to a node which should be the next node before 'act'
|
||||
*/
|
||||
static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * next)
|
||||
{
|
||||
if(act == NULL) return; /*Can't set the next node of `NULL`*/
|
||||
|
||||
uint32_t node_p_size = sizeof(lv_ll_node_t *);
|
||||
if(next) memcpy(act + LL_NEXT_P_OFFSET(ll_p), &next, node_p_size);
|
||||
else memset(act + LL_NEXT_P_OFFSET(ll_p), 0, node_p_size);
|
||||
}
|
||||
|
||||
152
src/lv_misc/lv_ll.h
Normal file
152
src/lv_misc/lv_ll.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* @file lv_ll.c
|
||||
* Handle linked lists. The nodes are dynamically allocated by the 'lv_mem' module.
|
||||
*/
|
||||
|
||||
#ifndef LV_LL_H
|
||||
#define LV_LL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_mem.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/*Dummy type to make handling easier*/
|
||||
typedef uint8_t lv_ll_node_t;
|
||||
|
||||
/*Description of a linked list*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t n_size;
|
||||
lv_ll_node_t* head;
|
||||
lv_ll_node_t* tail;
|
||||
} lv_ll_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize linked list
|
||||
* @param ll_dsc pointer to ll_dsc variable
|
||||
* @param node_size the size of 1 node in bytes
|
||||
*/
|
||||
void lv_ll_init(lv_ll_t * ll_p, uint32_t node_size);
|
||||
|
||||
/**
|
||||
* Add a new head to a linked list
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the new head
|
||||
*/
|
||||
void * lv_ll_ins_head(lv_ll_t * ll_p);
|
||||
|
||||
/**
|
||||
* Insert a new node in front of the n_act node
|
||||
* @param ll_p pointer to linked list
|
||||
* @param n_act pointer a node
|
||||
* @return pointer to the new head
|
||||
*/
|
||||
void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act);
|
||||
|
||||
/**
|
||||
* Add a new tail to a linked list
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the new tail
|
||||
*/
|
||||
void * lv_ll_ins_tail(lv_ll_t * ll_p);
|
||||
|
||||
/**
|
||||
* Remove the node 'node_p' from 'll_p' linked list.
|
||||
* It does not free the the memory of node.
|
||||
* @param ll_p pointer to the linked list of 'node_p'
|
||||
* @param node_p pointer to node in 'll_p' linked list
|
||||
*/
|
||||
void lv_ll_rem(lv_ll_t * ll_p, void * node_p);
|
||||
|
||||
/**
|
||||
* Remove and free all elements from a linked list. The list remain valid but become empty.
|
||||
* @param ll_p pointer to linked list
|
||||
*/
|
||||
void lv_ll_clear(lv_ll_t * ll_p);
|
||||
|
||||
/**
|
||||
* Move a node to a new linked list
|
||||
* @param ll_ori_p pointer to the original (old) linked list
|
||||
* @param ll_new_p pointer to the new linked list
|
||||
* @param node pointer to a node
|
||||
*/
|
||||
void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node);
|
||||
|
||||
/**
|
||||
* Return with head node of the linked list
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the head of 'll_p'
|
||||
*/
|
||||
void * lv_ll_get_head(const lv_ll_t * ll_p);
|
||||
|
||||
/**
|
||||
* Return with tail node of the linked list
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the head of 'll_p'
|
||||
*/
|
||||
void * lv_ll_get_tail(const lv_ll_t * ll_p);
|
||||
|
||||
/**
|
||||
* Return with the pointer of the next node after 'n_act'
|
||||
* @param ll_p pointer to linked list
|
||||
* @param n_act pointer a node
|
||||
* @return pointer to the next node
|
||||
*/
|
||||
void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act);
|
||||
|
||||
/**
|
||||
* Return with the pointer of the previous node after 'n_act'
|
||||
* @param ll_p pointer to linked list
|
||||
* @param n_act pointer a node
|
||||
* @return pointer to the previous node
|
||||
*/
|
||||
void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act);
|
||||
|
||||
/**
|
||||
* Move a nodw before an other node in the same linked list
|
||||
* @param ll_p pointer to a linked list
|
||||
* @param n_act pointer to node to move
|
||||
* @param n_after pointer to a node which should be after `n_act`
|
||||
*/
|
||||
void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after);
|
||||
|
||||
/**
|
||||
* Check if a linked list is empty
|
||||
* @param ll_p pointer to a linked list
|
||||
* @return true: the linked list is empty; false: not empty
|
||||
*/
|
||||
bool lv_ll_is_empty(lv_ll_t * ll_p);
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#define LV_LL_READ(list, i) for(i = lv_ll_get_head(&list); i != NULL; i = lv_ll_get_next(&list, i))
|
||||
|
||||
#define LV_LL_READ_BACK(list, i) for(i = lv_ll_get_tail(&list); i != NULL; i = lv_ll_get_prev(&list, i))
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
76
src/lv_misc/lv_log.c
Normal file
76
src/lv_misc/lv_log.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @file lv_log.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_log.h"
|
||||
#if LV_USE_LOG
|
||||
|
||||
#if LV_LOG_PRINTF
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static void (*print_cb)(lv_log_level_t, const char *, uint32_t, const char *);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Register custom print (or anything else) function to call when log is added
|
||||
* @param f a function pointer:
|
||||
* `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char * dsc)`
|
||||
*/
|
||||
void lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t, const char *))
|
||||
{
|
||||
print_cb = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a log
|
||||
* @param level the level of log. (From `lv_log_level_t` enum)
|
||||
* @param file name of the file when the log added
|
||||
* @param line line number in the source code where the log added
|
||||
* @param dsc description of the log
|
||||
*/
|
||||
void lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc)
|
||||
{
|
||||
if(level >= _LV_LOG_LEVEL_NUM) return; /*Invalid level*/
|
||||
|
||||
if(level >= LV_LOG_LEVEL) {
|
||||
|
||||
#if LV_LOG_PRINTF
|
||||
static const char * lvl_prefix[] = {"Trace", "Info", "Warn", "Error"};
|
||||
printf("%s: %s \t(%s #%d)\n", lvl_prefix[level], dsc, file, line);
|
||||
#else
|
||||
if(print_cb) print_cb(level, file, line, dsc);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_LOG*/
|
||||
86
src/lv_misc/lv_log.h
Normal file
86
src/lv_misc/lv_log.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @file lv_log.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_LOG_H
|
||||
#define LV_LOG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/*Possible log level. For compatibility declare it independently from `LV_USE_LOG`*/
|
||||
|
||||
#define LV_LOG_LEVEL_TRACE 0 /*A lot of logs to give detailed information*/
|
||||
#define LV_LOG_LEVEL_INFO 1 /*Log important events*/
|
||||
#define LV_LOG_LEVEL_WARN 2 /*Log if something unwanted happened but didn't caused problem*/
|
||||
#define LV_LOG_LEVEL_ERROR 3 /*Only critical issue, when the system may fail*/
|
||||
#define _LV_LOG_LEVEL_NUM 4
|
||||
|
||||
typedef int8_t lv_log_level_t;
|
||||
|
||||
#if LV_USE_LOG
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Register custom print (or anything else) function to call when log is added
|
||||
* @param f a function pointer:
|
||||
* `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char * dsc)`
|
||||
*/
|
||||
void lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t, const char *));
|
||||
|
||||
/**
|
||||
* Add a log
|
||||
* @param level the level of log. (From `lv_log_level_t` enum)
|
||||
* @param file name of the file when the log added
|
||||
* @param line line number in the source code where the log added
|
||||
* @param dsc description of the log
|
||||
*/
|
||||
void lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#define LV_LOG_TRACE(dsc) lv_log_add(LV_LOG_LEVEL_TRACE, __FILE__, __LINE__, dsc);
|
||||
#define LV_LOG_INFO(dsc) lv_log_add(LV_LOG_LEVEL_INFO, __FILE__, __LINE__, dsc);
|
||||
#define LV_LOG_WARN(dsc) lv_log_add(LV_LOG_LEVEL_WARN, __FILE__, __LINE__, dsc);
|
||||
#define LV_LOG_ERROR(dsc) lv_log_add(LV_LOG_LEVEL_ERROR, __FILE__, __LINE__, dsc);
|
||||
|
||||
#else /*LV_USE_LOG*/
|
||||
|
||||
/*Do nothing if `LV_USE_LOG 0`*/
|
||||
#define lv_log_add(level, file, line, dsc) {;}
|
||||
#define LV_LOG_TRACE(dsc) {;}
|
||||
#define LV_LOG_INFO(dsc) {;}
|
||||
#define LV_LOG_WARN(dsc) {;}
|
||||
#define LV_LOG_ERROR(dsc) {;}
|
||||
#endif /*LV_USE_LOG*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_LOG_H*/
|
||||
146
src/lv_misc/lv_math.c
Normal file
146
src/lv_misc/lv_math.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* @file lv_math.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_math.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static int16_t sin0_90_table[] = {
|
||||
0, 572, 1144, 1715, 2286, 2856, 3425, 3993, 4560, 5126,
|
||||
5690, 6252, 6813, 7371, 7927, 8481, 9032, 9580, 10126, 10668,
|
||||
11207, 11743, 12275, 12803, 13328, 13848, 14364, 14876, 15383, 15886,
|
||||
16383, 16876, 17364, 17846, 18323, 18794, 19260, 19720, 20173, 20621,
|
||||
21062, 21497, 21925, 22347, 22762, 23170, 23571, 23964, 24351, 24730,
|
||||
25101, 25465, 25821, 26169, 26509, 26841, 27165, 27481, 27788, 28087,
|
||||
28377, 28659, 28932, 29196, 29451, 29697, 29934, 30162, 30381, 30591,
|
||||
30791, 30982, 31163, 31335, 31498, 31650, 31794, 31927, 32051, 32165,
|
||||
32269, 32364, 32448, 32523, 32587, 32642, 32687, 32722, 32747, 32762,
|
||||
32767
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Convert a number to string
|
||||
* @param num a number
|
||||
* @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements)
|
||||
* @return same as `buf` (just for convenience)
|
||||
*/
|
||||
char * lv_math_num_to_str(int32_t num, char * buf)
|
||||
{
|
||||
if (num == 0) {
|
||||
buf[0] = '0';
|
||||
buf[1] = '\0';
|
||||
return buf;
|
||||
}
|
||||
int8_t digitCount = 0;
|
||||
int8_t i = 0;
|
||||
if (num < 0) {
|
||||
buf[digitCount++] = '-';
|
||||
num = abs(num);
|
||||
++i;
|
||||
}
|
||||
while (num) {
|
||||
char digit = num % 10;
|
||||
buf[digitCount++] = digit + 48;
|
||||
num /= 10;
|
||||
}
|
||||
buf[digitCount] = '\0';
|
||||
digitCount--;
|
||||
while (digitCount > i) {
|
||||
char temp = buf[i];
|
||||
buf[i] = buf[digitCount];
|
||||
buf[digitCount] = temp;
|
||||
digitCount--;
|
||||
i++;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with sinus of an angle
|
||||
* @param angle
|
||||
* @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767
|
||||
*/
|
||||
int16_t lv_trigo_sin(int16_t angle)
|
||||
{
|
||||
int16_t ret = 0;
|
||||
angle = angle % 360;
|
||||
|
||||
if(angle < 0) angle = 360 + angle;
|
||||
|
||||
if(angle < 90) {
|
||||
ret = sin0_90_table[angle];
|
||||
} else if(angle >= 90 && angle < 180) {
|
||||
angle = 180 - angle;
|
||||
ret = sin0_90_table[angle];
|
||||
} else if(angle >= 180 && angle < 270) {
|
||||
angle = angle - 180;
|
||||
ret = - sin0_90_table[angle];
|
||||
} else { /*angle >=270*/
|
||||
angle = 360 - angle;
|
||||
ret = - sin0_90_table[angle];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a value of a Cubic Bezier function.
|
||||
* @param t time in range of [0..LV_BEZIER_VAL_MAX]
|
||||
* @param u0 start values in range of [0..LV_BEZIER_VAL_MAX]
|
||||
* @param u1 control value 1 values in range of [0..LV_BEZIER_VAL_MAX]
|
||||
* @param u2 control value 2 in range of [0..LV_BEZIER_VAL_MAX]
|
||||
* @param u3 end values in range of [0..LV_BEZIER_VAL_MAX]
|
||||
* @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX]
|
||||
*/
|
||||
int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3)
|
||||
{
|
||||
uint32_t t_rem = 1024 - t;
|
||||
uint32_t t_rem2 = (t_rem * t_rem) >> 10;
|
||||
uint32_t t_rem3 = (t_rem2 * t_rem) >> 10;
|
||||
uint32_t t2 = (t * t) >> 10;
|
||||
uint32_t t3 = (t2 * t) >> 10;
|
||||
|
||||
|
||||
uint32_t v1 = ((uint32_t)t_rem3 * u0) >> 10;
|
||||
uint32_t v2 = ((uint32_t)3 * t_rem2 * t * u1) >> 20;
|
||||
uint32_t v3 = ((uint32_t)3 * t_rem * t2 * u2) >> 20;
|
||||
uint32_t v4 = ((uint32_t)t3 * u3) >> 10;
|
||||
|
||||
return v1 + v2 + v3 + v4;
|
||||
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
73
src/lv_misc/lv_math.h
Normal file
73
src/lv_misc/lv_math.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @file math_base.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_MATH_H
|
||||
#define LV_MATH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdint.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_MATH_MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define LV_MATH_MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define LV_MATH_ABS(x) ((x) > 0 ? (x) : (-(x)))
|
||||
|
||||
#define LV_TRIGO_SIN_MAX 32767
|
||||
#define LV_TRIGO_SHIFT 15 /* >> LV_TRIGO_SHIFT to normalize*/
|
||||
|
||||
#define LV_BEZIER_VAL_MAX 1024 /*Max time in Bezier functions (not [0..1] to use integers) */
|
||||
#define LV_BEZIER_VAL_SHIFT 10 /*log2(LV_BEZIER_VAL_MAX): used to normalize up scaled values*/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
/**
|
||||
* Convert a number to string
|
||||
* @param num a number
|
||||
* @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements)
|
||||
* @return same as `buf` (just for convenience)
|
||||
*/
|
||||
char * lv_math_num_to_str(int32_t num, char * buf);
|
||||
|
||||
/**
|
||||
* Return with sinus of an angle
|
||||
* @param angle
|
||||
* @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767
|
||||
*/
|
||||
int16_t lv_trigo_sin(int16_t angle);
|
||||
|
||||
/**
|
||||
* Calculate a value of a Cubic Bezier function.
|
||||
* @param t time in range of [0..LV_BEZIER_VAL_MAX]
|
||||
* @param u0 start values in range of [0..LV_BEZIER_VAL_MAX]
|
||||
* @param u1 control value 1 values in range of [0..LV_BEZIER_VAL_MAX]
|
||||
* @param u2 control value 2 in range of [0..LV_BEZIER_VAL_MAX]
|
||||
* @param u3 end values in range of [0..LV_BEZIER_VAL_MAX]
|
||||
* @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX]
|
||||
*/
|
||||
int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
464
src/lv_misc/lv_mem.c
Normal file
464
src/lv_misc/lv_mem.c
Normal file
@@ -0,0 +1,464 @@
|
||||
/**
|
||||
* @file lv_mem.c
|
||||
* General and portable implementation of malloc and free.
|
||||
* The dynamic memory monitoring is also supported.
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_mem.h"
|
||||
#include "lv_math.h"
|
||||
#include <string.h>
|
||||
|
||||
#if LV_MEM_CUSTOM != 0
|
||||
#include LV_MEM_CUSTOM_INCLUDE
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_MEM_ADD_JUNK 0 /*Add memory junk on alloc (0xaa) and free(0xbb) (just for testing purposes)*/
|
||||
|
||||
|
||||
#ifdef LV_MEM_ENV64
|
||||
# define MEM_UNIT uint64_t
|
||||
#else
|
||||
# define MEM_UNIT uint32_t
|
||||
#endif
|
||||
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
#if LV_ENABLE_GC == 0 /*gc custom allocations must not include header*/
|
||||
|
||||
/*The size of this union must be 4 bytes (uint32_t)*/
|
||||
typedef union {
|
||||
struct {
|
||||
MEM_UNIT used: 1; //1: if the entry is used
|
||||
MEM_UNIT d_size: 31; //Size off the data (1 means 4 bytes)
|
||||
} s;
|
||||
MEM_UNIT header; //The header (used + d_size)
|
||||
} lv_mem_header_t;
|
||||
|
||||
typedef struct {
|
||||
lv_mem_header_t header;
|
||||
uint8_t first_data; /*First data byte in the allocated data (Just for easily create a pointer)*/
|
||||
} lv_mem_ent_t;
|
||||
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e);
|
||||
static void * ent_alloc(lv_mem_ent_t * e, uint32_t size);
|
||||
static void ent_trunc(lv_mem_ent_t * e, uint32_t size);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
static uint8_t * work_mem;
|
||||
#endif
|
||||
|
||||
static uint32_t zero_mem; /*Give the address of this variable if 0 byte should be allocated*/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initiaiize the dyn_mem module (work memory and other variables)
|
||||
*/
|
||||
void lv_mem_init(void)
|
||||
{
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
|
||||
#if LV_MEM_ADR == 0
|
||||
/*Allocate a large array to store the dynamically allocated data*/
|
||||
static LV_MEM_ATTR MEM_UNIT work_mem_int[LV_MEM_SIZE / sizeof(MEM_UNIT)];
|
||||
work_mem = (uint8_t *) work_mem_int;
|
||||
#else
|
||||
work_mem = (uint8_t *) LV_MEM_ADR;
|
||||
#endif
|
||||
|
||||
lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem;
|
||||
full->header.s.used = 0;
|
||||
/*The total mem size id reduced by the first header and the close patterns */
|
||||
full->header.s.d_size = LV_MEM_SIZE - sizeof(lv_mem_header_t);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a memory dynamically
|
||||
* @param size size of the memory to allocate in bytes
|
||||
* @return pointer to the allocated memory
|
||||
*/
|
||||
void * lv_mem_alloc(uint32_t size)
|
||||
{
|
||||
if(size == 0) {
|
||||
return &zero_mem;
|
||||
}
|
||||
|
||||
#ifdef LV_MEM_ENV64
|
||||
/*Round the size up to 8*/
|
||||
if(size & 0x7) {
|
||||
size = size & (~0x7);
|
||||
size += 8;
|
||||
}
|
||||
#else
|
||||
/*Round the size up to 4*/
|
||||
if(size & 0x3) {
|
||||
size = size & (~0x3);
|
||||
size += 4;
|
||||
}
|
||||
#endif
|
||||
void * alloc = NULL;
|
||||
|
||||
#if LV_MEM_CUSTOM == 0 /*Use the allocation from dyn_mem*/
|
||||
lv_mem_ent_t * e = NULL;
|
||||
|
||||
//Search for a appropriate entry
|
||||
do {
|
||||
//Get the next entry
|
||||
e = ent_get_next(e);
|
||||
|
||||
/*If there is next entry then try to allocate there*/
|
||||
if(e != NULL) {
|
||||
alloc = ent_alloc(e, size);
|
||||
}
|
||||
//End if there is not next entry OR the alloc. is successful
|
||||
} while(e != NULL && alloc == NULL);
|
||||
|
||||
|
||||
#else /*Use custom, user defined malloc function*/
|
||||
#if LV_ENABLE_GC == 1 /*gc must not include header*/
|
||||
alloc = LV_MEM_CUSTOM_ALLOC(size);
|
||||
#else /* LV_ENABLE_GC */
|
||||
/*Allocate a header too to store the size*/
|
||||
alloc = LV_MEM_CUSTOM_ALLOC(size + sizeof(lv_mem_header_t));
|
||||
if(alloc != NULL) {
|
||||
((lv_mem_ent_t *) alloc)->header.s.d_size = size;
|
||||
((lv_mem_ent_t *) alloc)->header.s.used = 1;
|
||||
alloc = &((lv_mem_ent_t *) alloc)->first_data;
|
||||
}
|
||||
#endif /* LV_ENABLE_GC */
|
||||
#endif /* LV_MEM_CUSTOM */
|
||||
|
||||
#if LV_MEM_ADD_JUNK
|
||||
if(alloc != NULL) memset(alloc, 0xaa, size);
|
||||
#endif
|
||||
|
||||
if(alloc == NULL) LV_LOG_WARN("Couldn't allocate memory");
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free an allocated data
|
||||
* @param data pointer to an allocated memory
|
||||
*/
|
||||
void lv_mem_free(const void * data)
|
||||
{
|
||||
if(data == &zero_mem) return;
|
||||
if(data == NULL) return;
|
||||
|
||||
|
||||
#if LV_MEM_ADD_JUNK
|
||||
memset((void *)data, 0xbb, lv_mem_get_size(data));
|
||||
#endif
|
||||
|
||||
#if LV_ENABLE_GC==0
|
||||
/*e points to the header*/
|
||||
lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data - sizeof(lv_mem_header_t));
|
||||
e->header.s.used = 0;
|
||||
#endif
|
||||
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
#if LV_MEM_AUTO_DEFRAG
|
||||
/* Make a simple defrag.
|
||||
* Join the following free entries after this*/
|
||||
lv_mem_ent_t * e_next;
|
||||
e_next = ent_get_next(e);
|
||||
while(e_next != NULL) {
|
||||
if(e_next->header.s.used == 0) {
|
||||
e->header.s.d_size += e_next->header.s.d_size + sizeof(e->header);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
e_next = ent_get_next(e_next);
|
||||
}
|
||||
#endif
|
||||
#else /*Use custom, user defined free function*/
|
||||
#if LV_ENABLE_GC==0
|
||||
LV_MEM_CUSTOM_FREE(e);
|
||||
#else
|
||||
LV_MEM_CUSTOM_FREE((void*)data);
|
||||
#endif /*LV_ENABLE_GC*/
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Reallocate a memory with a new size. The old content will be kept.
|
||||
* @param data pointer to an allocated memory.
|
||||
* Its content will be copied to the new memory block and freed
|
||||
* @param new_size the desired new size in byte
|
||||
* @return pointer to the new memory
|
||||
*/
|
||||
|
||||
#if LV_ENABLE_GC==0
|
||||
|
||||
void * lv_mem_realloc(void * data_p, uint32_t new_size)
|
||||
{
|
||||
/*data_p could be previously freed pointer (in this case it is invalid)*/
|
||||
if(data_p != NULL) {
|
||||
lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data_p - sizeof(lv_mem_header_t));
|
||||
if(e->header.s.used == 0) {
|
||||
data_p = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t old_size = lv_mem_get_size(data_p);
|
||||
if(old_size == new_size) return data_p; /*Also avoid reallocating the same memory*/
|
||||
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
/* Only truncate the memory is possible
|
||||
* If the 'old_size' was extended by a header size in 'ent_trunc' it avoids reallocating this same memory */
|
||||
if(new_size < old_size) {
|
||||
lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data_p - sizeof(lv_mem_header_t));
|
||||
ent_trunc(e, new_size);
|
||||
return &e->first_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
void * new_p;
|
||||
new_p = lv_mem_alloc(new_size);
|
||||
|
||||
if(new_p != NULL && data_p != NULL) {
|
||||
/*Copy the old data to the new. Use the smaller size*/
|
||||
if(old_size != 0) {
|
||||
memcpy(new_p, data_p, LV_MATH_MIN(new_size, old_size));
|
||||
lv_mem_free(data_p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(new_p == NULL) LV_LOG_WARN("Couldn't allocate memory");
|
||||
|
||||
return new_p;
|
||||
}
|
||||
|
||||
#else /* LV_ENABLE_GC */
|
||||
|
||||
void * lv_mem_realloc(void * data_p, uint32_t new_size)
|
||||
{
|
||||
void * new_p = LV_MEM_CUSTOM_REALLOC(data_p, new_size);
|
||||
if(new_p == NULL) LV_LOG_WARN("Couldn't allocate memory");
|
||||
return new_p;
|
||||
}
|
||||
|
||||
#endif /* lv_enable_gc */
|
||||
|
||||
/**
|
||||
* Join the adjacent free memory blocks
|
||||
*/
|
||||
void lv_mem_defrag(void)
|
||||
{
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
lv_mem_ent_t * e_free;
|
||||
lv_mem_ent_t * e_next;
|
||||
e_free = ent_get_next(NULL);
|
||||
|
||||
while(1) {
|
||||
/*Search the next free entry*/
|
||||
while(e_free != NULL) {
|
||||
if(e_free->header.s.used != 0) {
|
||||
e_free = ent_get_next(e_free);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(e_free == NULL) return;
|
||||
|
||||
/*Joint the following free entries to the free*/
|
||||
e_next = ent_get_next(e_free);
|
||||
while(e_next != NULL) {
|
||||
if(e_next->header.s.used == 0) {
|
||||
e_free->header.s.d_size += e_next->header.s.d_size + sizeof(e_next->header);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
e_next = ent_get_next(e_next);
|
||||
}
|
||||
|
||||
if(e_next == NULL) return;
|
||||
|
||||
/*Continue from the lastly checked entry*/
|
||||
e_free = e_next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Give information about the work memory of dynamic allocation
|
||||
* @param mon_p pointer to a dm_mon_p variable,
|
||||
* the result of the analysis will be stored here
|
||||
*/
|
||||
void lv_mem_monitor(lv_mem_monitor_t * mon_p)
|
||||
{
|
||||
/*Init the data*/
|
||||
memset(mon_p, 0, sizeof(lv_mem_monitor_t));
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
lv_mem_ent_t * e;
|
||||
e = NULL;
|
||||
|
||||
e = ent_get_next(e);
|
||||
|
||||
while(e != NULL) {
|
||||
if(e->header.s.used == 0) {
|
||||
mon_p->free_cnt++;
|
||||
mon_p->free_size += e->header.s.d_size;
|
||||
if(e->header.s.d_size > mon_p->free_biggest_size) {
|
||||
mon_p->free_biggest_size = e->header.s.d_size;
|
||||
}
|
||||
} else {
|
||||
mon_p->used_cnt++;
|
||||
}
|
||||
|
||||
e = ent_get_next(e);
|
||||
}
|
||||
mon_p->total_size = LV_MEM_SIZE;
|
||||
mon_p->used_pct = 100 - (100U * mon_p->free_size) / mon_p->total_size;
|
||||
mon_p->frag_pct = (uint32_t)mon_p->free_biggest_size * 100U / mon_p->free_size;
|
||||
mon_p->frag_pct = 100 - mon_p->frag_pct;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the size of an allocated memory
|
||||
* @param data pointer to an allocated memory
|
||||
* @return the size of data memory in bytes
|
||||
*/
|
||||
|
||||
#if LV_ENABLE_GC==0
|
||||
|
||||
uint32_t lv_mem_get_size(const void * data)
|
||||
{
|
||||
if(data == NULL) return 0;
|
||||
if(data == &zero_mem) return 0;
|
||||
|
||||
lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data - sizeof(lv_mem_header_t));
|
||||
|
||||
return e->header.s.d_size;
|
||||
}
|
||||
|
||||
#else /* LV_ENABLE_GC */
|
||||
|
||||
uint32_t lv_mem_get_size(const void * data)
|
||||
{
|
||||
return LV_MEM_CUSTOM_GET_SIZE(data);
|
||||
}
|
||||
|
||||
#endif /*LV_ENABLE_GC*/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
/**
|
||||
* Give the next entry after 'act_e'
|
||||
* @param act_e pointer to an entry
|
||||
* @return pointer to an entry after 'act_e'
|
||||
*/
|
||||
static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e)
|
||||
{
|
||||
lv_mem_ent_t * next_e = NULL;
|
||||
|
||||
if(act_e == NULL) { /*NULL means: get the first entry*/
|
||||
next_e = (lv_mem_ent_t *) work_mem;
|
||||
} else { /*Get the next entry */
|
||||
uint8_t * data = &act_e->first_data;
|
||||
next_e = (lv_mem_ent_t *)&data[act_e->header.s.d_size];
|
||||
|
||||
if(&next_e->first_data >= &work_mem[LV_MEM_SIZE]) next_e = NULL;
|
||||
}
|
||||
|
||||
return next_e;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to do the real allocation with a given size
|
||||
* @param e try to allocate to this entry
|
||||
* @param size size of the new memory in bytes
|
||||
* @return pointer to the allocated memory or NULL if not enough memory in the entry
|
||||
*/
|
||||
static void * ent_alloc(lv_mem_ent_t * e, uint32_t size)
|
||||
{
|
||||
void * alloc = NULL;
|
||||
|
||||
/*If the memory is free and big enough then use it */
|
||||
if(e->header.s.used == 0 && e->header.s.d_size >= size) {
|
||||
/*Truncate the entry to the desired size */
|
||||
ent_trunc(e, size),
|
||||
|
||||
e->header.s.used = 1;
|
||||
|
||||
/*Save the allocated data*/
|
||||
alloc = &e->first_data;
|
||||
}
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate the data of entry to the given size
|
||||
* @param e Pointer to an entry
|
||||
* @param size new size in bytes
|
||||
*/
|
||||
static void ent_trunc(lv_mem_ent_t * e, uint32_t size)
|
||||
{
|
||||
#ifdef LV_MEM_ENV64
|
||||
/*Round the size up to 8*/
|
||||
if(size & 0x7) {
|
||||
size = size & (~0x7);
|
||||
size += 8;
|
||||
}
|
||||
#else
|
||||
/*Round the size up to 4*/
|
||||
if(size & 0x3) {
|
||||
size = size & (~0x3);
|
||||
size += 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*Don't let empty space only for a header without data*/
|
||||
if(e->header.s.d_size == size + sizeof(lv_mem_header_t)) {
|
||||
size = e->header.s.d_size;
|
||||
}
|
||||
|
||||
/* Create the new entry after the current if there is space for it */
|
||||
if(e->header.s.d_size != size) {
|
||||
uint8_t * e_data = &e->first_data;
|
||||
lv_mem_ent_t * after_new_e = (lv_mem_ent_t *)&e_data[size];
|
||||
after_new_e->header.s.used = 0;
|
||||
after_new_e->header.s.d_size = e->header.s.d_size - size - sizeof(lv_mem_header_t);
|
||||
}
|
||||
|
||||
/* Set the new size for the original entry */
|
||||
e->header.s.d_size = size;
|
||||
}
|
||||
|
||||
#endif
|
||||
127
src/lv_misc/lv_mem.h
Normal file
127
src/lv_misc/lv_mem.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @file lv_mem.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_MEM_H
|
||||
#define LV_MEM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "lv_log.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
// Check windows
|
||||
#ifdef __WIN64
|
||||
# define LV_MEM_ENV64
|
||||
#endif
|
||||
|
||||
// Check GCC
|
||||
#ifdef __GNUC__
|
||||
# if defined(__x86_64__) || defined(__ppc64__)
|
||||
# define LV_MEM_ENV64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t total_size;
|
||||
uint32_t free_cnt;
|
||||
uint32_t free_size;
|
||||
uint32_t free_biggest_size;
|
||||
uint32_t used_cnt;
|
||||
uint8_t used_pct;
|
||||
uint8_t frag_pct;
|
||||
} lv_mem_monitor_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
|
||||
/**
|
||||
* Initiaize the dyn_mem module (work memory and other variables)
|
||||
*/
|
||||
void lv_mem_init(void);
|
||||
|
||||
/**
|
||||
* Allocate a memory dynamically
|
||||
* @param size size of the memory to allocate in bytes
|
||||
* @return pointer to the allocated memory
|
||||
*/
|
||||
void * lv_mem_alloc(uint32_t size);
|
||||
|
||||
/**
|
||||
* Free an allocated data
|
||||
* @param data pointer to an allocated memory
|
||||
*/
|
||||
void lv_mem_free(const void * data);
|
||||
|
||||
/**
|
||||
* Reallocate a memory with a new size. The old content will be kept.
|
||||
* @param data pointer to an allocated memory.
|
||||
* Its content will be copied to the new memory block and freed
|
||||
* @param new_size the desired new size in byte
|
||||
* @return pointer to the new memory
|
||||
*/
|
||||
void * lv_mem_realloc(void * data_p, uint32_t new_size);
|
||||
|
||||
/**
|
||||
* Join the adjacent free memory blocks
|
||||
*/
|
||||
void lv_mem_defrag(void);
|
||||
|
||||
/**
|
||||
* Give information about the work memory of dynamic allocation
|
||||
* @param mon_p pointer to a dm_mon_p variable,
|
||||
* the result of the analysis will be stored here
|
||||
*/
|
||||
void lv_mem_monitor(lv_mem_monitor_t * mon_p);
|
||||
|
||||
/**
|
||||
* Give the size of an allocated memory
|
||||
* @param data pointer to an allocated memory
|
||||
* @return the size of data memory in bytes
|
||||
*/
|
||||
uint32_t lv_mem_get_size(const void * data);
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Halt on NULL pointer
|
||||
* p pointer to a memory
|
||||
*/
|
||||
#if LV_USE_LOG == 0
|
||||
# define lv_mem_assert(p) {if(p == NULL) while(1); }
|
||||
#else
|
||||
# define lv_mem_assert(p) {if(p == NULL) {LV_LOG_ERROR("Out of memory!"); while(1); }}
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_MEM_H*/
|
||||
|
||||
18
src/lv_misc/lv_misc.mk
Normal file
18
src/lv_misc/lv_misc.mk
Normal file
@@ -0,0 +1,18 @@
|
||||
CSRCS += lv_font.c
|
||||
CSRCS += lv_circ.c
|
||||
CSRCS += lv_area.c
|
||||
CSRCS += lv_task.c
|
||||
CSRCS += lv_fs.c
|
||||
CSRCS += lv_anim.c
|
||||
CSRCS += lv_mem.c
|
||||
CSRCS += lv_ll.c
|
||||
CSRCS += lv_color.c
|
||||
CSRCS += lv_txt.c
|
||||
CSRCS += lv_math.c
|
||||
CSRCS += lv_log.c
|
||||
CSRCS += lv_gc.c
|
||||
|
||||
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/src/lv_misc
|
||||
VPATH += :$(LVGL_DIR)/lvgl/src/lv_misc
|
||||
|
||||
CFLAGS += "-I$(LVGL_DIR)/lvgl/src/lv_misc"
|
||||
207
src/lv_misc/lv_symbol_def.h
Normal file
207
src/lv_misc/lv_symbol_def.h
Normal file
@@ -0,0 +1,207 @@
|
||||
#ifndef LV_SYMBOL_DEF_H
|
||||
#define LV_SYMBOL_DEF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* With no UTF-8 support (192- 255) (192..241 is used)
|
||||
*
|
||||
* With UTF-8 support (in Supplemental Private Use Area-A): 0xF800 .. 0xF831
|
||||
* - Basic symbols: 0xE000..0xE01F
|
||||
* - File symbols: 0xE020..0xE03F
|
||||
* - Feedback symbols: 0xE040..0xE05F
|
||||
* - Reserved: 0xE060..0xE07F
|
||||
*/
|
||||
|
||||
#if LV_TXT_UTF8 == 0
|
||||
#define LV_SYMBOL_GLYPH_FIRST 0xC0
|
||||
#define LV_SYMBOL_AUDIO _LV_SYMBOL_VALUE1(C0)
|
||||
#define LV_SYMBOL_VIDEO _LV_SYMBOL_VALUE1(C1)
|
||||
#define LV_SYMBOL_LIST _LV_SYMBOL_VALUE1(C2)
|
||||
#define LV_SYMBOL_OK _LV_SYMBOL_VALUE1(C3)
|
||||
#define LV_SYMBOL_CLOSE _LV_SYMBOL_VALUE1(C4)
|
||||
#define LV_SYMBOL_POWER _LV_SYMBOL_VALUE1(C5)
|
||||
#define LV_SYMBOL_SETTINGS _LV_SYMBOL_VALUE1(C6)
|
||||
#define LV_SYMBOL_TRASH _LV_SYMBOL_VALUE1(C7)
|
||||
#define LV_SYMBOL_HOME _LV_SYMBOL_VALUE1(C8)
|
||||
#define LV_SYMBOL_DOWNLOAD _LV_SYMBOL_VALUE1(C9)
|
||||
#define LV_SYMBOL_DRIVE _LV_SYMBOL_VALUE1(CA)
|
||||
#define LV_SYMBOL_REFRESH _LV_SYMBOL_VALUE1(CB)
|
||||
#define LV_SYMBOL_MUTE _LV_SYMBOL_VALUE1(CC)
|
||||
#define LV_SYMBOL_VOLUME_MID _LV_SYMBOL_VALUE1(CD)
|
||||
#define LV_SYMBOL_VOLUME_MAX _LV_SYMBOL_VALUE1(CE)
|
||||
#define LV_SYMBOL_IMAGE _LV_SYMBOL_VALUE1(CF)
|
||||
#define LV_SYMBOL_EDIT _LV_SYMBOL_VALUE1(D0)
|
||||
#define LV_SYMBOL_PREV _LV_SYMBOL_VALUE1(D1)
|
||||
#define LV_SYMBOL_PLAY _LV_SYMBOL_VALUE1(D2)
|
||||
#define LV_SYMBOL_PAUSE _LV_SYMBOL_VALUE1(D3)
|
||||
#define LV_SYMBOL_STOP _LV_SYMBOL_VALUE1(D4)
|
||||
#define LV_SYMBOL_NEXT _LV_SYMBOL_VALUE1(D5)
|
||||
#define LV_SYMBOL_EJECT _LV_SYMBOL_VALUE1(D6)
|
||||
#define LV_SYMBOL_LEFT _LV_SYMBOL_VALUE1(D7)
|
||||
#define LV_SYMBOL_RIGHT _LV_SYMBOL_VALUE1(D8)
|
||||
#define LV_SYMBOL_PLUS _LV_SYMBOL_VALUE1(D9)
|
||||
#define LV_SYMBOL_MINUS _LV_SYMBOL_VALUE1(DA)
|
||||
#define LV_SYMBOL_WARNING _LV_SYMBOL_VALUE1(DB)
|
||||
#define LV_SYMBOL_SHUFFLE _LV_SYMBOL_VALUE1(DC)
|
||||
#define LV_SYMBOL_UP _LV_SYMBOL_VALUE1(DD)
|
||||
#define LV_SYMBOL_DOWN _LV_SYMBOL_VALUE1(DE)
|
||||
#define LV_SYMBOL_LOOP _LV_SYMBOL_VALUE1(DF)
|
||||
#define LV_SYMBOL_DIRECTORY _LV_SYMBOL_VALUE1(E0)
|
||||
#define LV_SYMBOL_UPLOAD _LV_SYMBOL_VALUE1(E1)
|
||||
#define LV_SYMBOL_CALL _LV_SYMBOL_VALUE1(E2)
|
||||
#define LV_SYMBOL_CUT _LV_SYMBOL_VALUE1(E3)
|
||||
#define LV_SYMBOL_COPY _LV_SYMBOL_VALUE1(E4)
|
||||
#define LV_SYMBOL_SAVE _LV_SYMBOL_VALUE1(E5)
|
||||
#define LV_SYMBOL_CHARGE _LV_SYMBOL_VALUE1(E6)
|
||||
#define LV_SYMBOL_BELL _LV_SYMBOL_VALUE1(E7)
|
||||
#define LV_SYMBOL_KEYBOARD _LV_SYMBOL_VALUE1(E8)
|
||||
#define LV_SYMBOL_GPS _LV_SYMBOL_VALUE1(E9)
|
||||
#define LV_SYMBOL_FILE _LV_SYMBOL_VALUE1(EA)
|
||||
#define LV_SYMBOL_WIFI _LV_SYMBOL_VALUE1(EB)
|
||||
#define LV_SYMBOL_BATTERY_FULL _LV_SYMBOL_VALUE1(EC)
|
||||
#define LV_SYMBOL_BATTERY_3 _LV_SYMBOL_VALUE1(ED)
|
||||
#define LV_SYMBOL_BATTERY_2 _LV_SYMBOL_VALUE1(EE)
|
||||
#define LV_SYMBOL_BATTERY_1 _LV_SYMBOL_VALUE1(EF)
|
||||
#define LV_SYMBOL_BATTERY_EMPTY _LV_SYMBOL_VALUE1(F0)
|
||||
#define LV_SYMBOL_BLUETOOTH _LV_SYMBOL_VALUE1(F1)
|
||||
#define LV_SYMBOL_GLYPH_LAST 0xF1
|
||||
#define LV_SYMBOL_DUMMY _LV_SYMBOL_VALUE1(FF) /*Invalid symbol. If written before a string then `lv_img` will show it as a label*/
|
||||
|
||||
#else
|
||||
#define LV_SYMBOL_GLYPH_FIRST 0xF800
|
||||
#define LV_SYMBOL_AUDIO _LV_SYMBOL_VALUE3(EF,A0,80)
|
||||
#define LV_SYMBOL_VIDEO _LV_SYMBOL_VALUE3(EF,A0,81)
|
||||
#define LV_SYMBOL_LIST _LV_SYMBOL_VALUE3(EF,A0,82)
|
||||
#define LV_SYMBOL_OK _LV_SYMBOL_VALUE3(EF,A0,83)
|
||||
#define LV_SYMBOL_CLOSE _LV_SYMBOL_VALUE3(EF,A0,84)
|
||||
#define LV_SYMBOL_POWER _LV_SYMBOL_VALUE3(EF,A0,85)
|
||||
#define LV_SYMBOL_SETTINGS _LV_SYMBOL_VALUE3(EF,A0,86)
|
||||
#define LV_SYMBOL_TRASH _LV_SYMBOL_VALUE3(EF,A0,87)
|
||||
#define LV_SYMBOL_HOME _LV_SYMBOL_VALUE3(EF,A0,88)
|
||||
#define LV_SYMBOL_DOWNLOAD _LV_SYMBOL_VALUE3(EF,A0,89)
|
||||
#define LV_SYMBOL_DRIVE _LV_SYMBOL_VALUE3(EF,A0,8A)
|
||||
#define LV_SYMBOL_REFRESH _LV_SYMBOL_VALUE3(EF,A0,8B)
|
||||
#define LV_SYMBOL_MUTE _LV_SYMBOL_VALUE3(EF,A0,8C)
|
||||
#define LV_SYMBOL_VOLUME_MID _LV_SYMBOL_VALUE3(EF,A0,8D)
|
||||
#define LV_SYMBOL_VOLUME_MAX _LV_SYMBOL_VALUE3(EF,A0,8E)
|
||||
#define LV_SYMBOL_IMAGE _LV_SYMBOL_VALUE3(EF,A0,8F)
|
||||
#define LV_SYMBOL_EDIT _LV_SYMBOL_VALUE3(EF,A0,90)
|
||||
#define LV_SYMBOL_PREV _LV_SYMBOL_VALUE3(EF,A0,91)
|
||||
#define LV_SYMBOL_PLAY _LV_SYMBOL_VALUE3(EF,A0,92)
|
||||
#define LV_SYMBOL_PAUSE _LV_SYMBOL_VALUE3(EF,A0,93)
|
||||
#define LV_SYMBOL_STOP _LV_SYMBOL_VALUE3(EF,A0,94)
|
||||
#define LV_SYMBOL_NEXT _LV_SYMBOL_VALUE3(EF,A0,95)
|
||||
#define LV_SYMBOL_EJECT _LV_SYMBOL_VALUE3(EF,A0,96)
|
||||
#define LV_SYMBOL_LEFT _LV_SYMBOL_VALUE3(EF,A0,97)
|
||||
#define LV_SYMBOL_RIGHT _LV_SYMBOL_VALUE3(EF,A0,98)
|
||||
#define LV_SYMBOL_PLUS _LV_SYMBOL_VALUE3(EF,A0,99)
|
||||
#define LV_SYMBOL_MINUS _LV_SYMBOL_VALUE3(EF,A0,9A)
|
||||
#define LV_SYMBOL_WARNING _LV_SYMBOL_VALUE3(EF,A0,9B)
|
||||
#define LV_SYMBOL_SHUFFLE _LV_SYMBOL_VALUE3(EF,A0,9C)
|
||||
#define LV_SYMBOL_UP _LV_SYMBOL_VALUE3(EF,A0,9D)
|
||||
#define LV_SYMBOL_DOWN _LV_SYMBOL_VALUE3(EF,A0,9E)
|
||||
#define LV_SYMBOL_LOOP _LV_SYMBOL_VALUE3(EF,A0,9F)
|
||||
#define LV_SYMBOL_DIRECTORY _LV_SYMBOL_VALUE3(EF,A0,A0)
|
||||
#define LV_SYMBOL_UPLOAD _LV_SYMBOL_VALUE3(EF,A0,A1)
|
||||
#define LV_SYMBOL_CALL _LV_SYMBOL_VALUE3(EF,A0,A2)
|
||||
#define LV_SYMBOL_CUT _LV_SYMBOL_VALUE3(EF,A0,A3)
|
||||
#define LV_SYMBOL_COPY _LV_SYMBOL_VALUE3(EF,A0,A4)
|
||||
#define LV_SYMBOL_SAVE _LV_SYMBOL_VALUE3(EF,A0,A5)
|
||||
#define LV_SYMBOL_CHARGE _LV_SYMBOL_VALUE3(EF,A0,A6)
|
||||
#define LV_SYMBOL_BELL _LV_SYMBOL_VALUE3(EF,A0,A7)
|
||||
#define LV_SYMBOL_KEYBOARD _LV_SYMBOL_VALUE3(EF,A0,A8)
|
||||
#define LV_SYMBOL_GPS _LV_SYMBOL_VALUE3(EF,A0,A9)
|
||||
#define LV_SYMBOL_FILE _LV_SYMBOL_VALUE3(EF,A0,AA)
|
||||
#define LV_SYMBOL_WIFI _LV_SYMBOL_VALUE3(EF,A0,AB)
|
||||
#define LV_SYMBOL_BATTERY_FULL _LV_SYMBOL_VALUE3(EF,A0,AC)
|
||||
#define LV_SYMBOL_BATTERY_3 _LV_SYMBOL_VALUE3(EF,A0,AD)
|
||||
#define LV_SYMBOL_BATTERY_2 _LV_SYMBOL_VALUE3(EF,A0,AE)
|
||||
#define LV_SYMBOL_BATTERY_1 _LV_SYMBOL_VALUE3(EF,A0,AF)
|
||||
#define LV_SYMBOL_BATTERY_EMPTY _LV_SYMBOL_VALUE3(EF,A0,B0)
|
||||
#define LV_SYMBOL_BLUETOOTH _LV_SYMBOL_VALUE3(EF,A0,B1)
|
||||
#define LV_SYMBOL_GLYPH_LAST 0xF831
|
||||
#define LV_SYMBOL_DUMMY _LV_SYMBOL_VALUE3(EF,A3,BF) /*Invalid symbol at (U+F831). If written before a string then `lv_img` will show it as a label*/
|
||||
#endif
|
||||
|
||||
#define _LV_SYMBOL_VALUE1(x) (0x ## x)
|
||||
#define _LV_SYMBOL_VALUE3(x, y, z) (0x ## z ## y ## x)
|
||||
#define _LV_SYMBOL_NUMSTR(sym) LV_ ## sym ## _NUMSTR = sym
|
||||
|
||||
enum
|
||||
{
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_AUDIO),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_VIDEO),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_LIST),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_OK),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_CLOSE),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_POWER),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_SETTINGS),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_TRASH),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_HOME),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_DOWNLOAD),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_DRIVE),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_REFRESH),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_MUTE),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_VOLUME_MID),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_VOLUME_MAX),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_IMAGE),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_EDIT),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_PREV),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_PLAY),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_PAUSE),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_STOP),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_NEXT),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_EJECT),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_LEFT),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_RIGHT),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_PLUS),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_MINUS),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_WARNING),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_SHUFFLE),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_UP),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_DOWN),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_LOOP),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_DIRECTORY),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_UPLOAD),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_CALL),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_CUT),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_COPY),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_SAVE),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_CHARGE),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_BELL),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_KEYBOARD),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_GPS),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_FILE),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_WIFI),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_BATTERY_FULL),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_BATTERY_3),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_BATTERY_2),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_BATTERY_1),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_BATTERY_EMPTY),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_BLUETOOTH),
|
||||
_LV_SYMBOL_NUMSTR(LV_SYMBOL_DUMMY),
|
||||
};
|
||||
|
||||
#undef _LV_SYMBOL_VALUE1
|
||||
#undef _LV_SYMBOL_VALUE3
|
||||
|
||||
#define _LV_SYMBOL_STR_(x) #x
|
||||
#define _LV_SYMBOL_STR(x) _LV_SYMBOL_STR_(x)
|
||||
#define _LV_SYMBOL_CHAR(c) \x ## c
|
||||
#define _LV_SYMBOL_VALUE1(x) _LV_SYMBOL_STR(_LV_SYMBOL_CHAR(x))
|
||||
#define _LV_SYMBOL_VALUE3(x, y, z) _LV_SYMBOL_STR(_LV_SYMBOL_CHAR(x)_LV_SYMBOL_CHAR(y)_LV_SYMBOL_CHAR(z))
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*LV_LV_SYMBOL_DEF_H*/
|
||||
332
src/lv_misc/lv_task.c
Normal file
332
src/lv_misc/lv_task.c
Normal file
@@ -0,0 +1,332 @@
|
||||
/**
|
||||
* @file lv_task.c
|
||||
* An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically.
|
||||
* A priority (5 levels + disable) can be assigned to lv_tasks.
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stddef.h>
|
||||
#include "lv_task.h"
|
||||
#include "../lv_hal/lv_hal_tick.h"
|
||||
#include "lv_gc.h"
|
||||
|
||||
#if defined(LV_GC_INCLUDE)
|
||||
# include LV_GC_INCLUDE
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define IDLE_MEAS_PERIOD 500 /*[ms]*/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static bool lv_task_exec(lv_task_t * lv_task_p);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static bool lv_task_run = false;
|
||||
static uint8_t idle_last = 0;
|
||||
static bool task_deleted;
|
||||
static bool task_created;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Init the lv_task module
|
||||
*/
|
||||
void lv_task_init(void)
|
||||
{
|
||||
lv_ll_init(&LV_GC_ROOT(_lv_task_ll), sizeof(lv_task_t));
|
||||
|
||||
/*Initially enable the lv_task handling*/
|
||||
lv_task_enable(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call it periodically to handle lv_tasks.
|
||||
*/
|
||||
LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void)
|
||||
{
|
||||
LV_LOG_TRACE("lv_task_handler started");
|
||||
|
||||
/*Avoid concurrent running of the task handler*/
|
||||
static bool task_handler_mutex = false;
|
||||
if(task_handler_mutex) return;
|
||||
task_handler_mutex = true;
|
||||
|
||||
static uint32_t idle_period_start = 0;
|
||||
static uint32_t handler_start = 0;
|
||||
static uint32_t busy_time = 0;
|
||||
|
||||
if(lv_task_run == false) return;
|
||||
|
||||
handler_start = lv_tick_get();
|
||||
|
||||
/* Run all task from the highest to the lowest priority
|
||||
* If a lower priority task is executed check task again from the highest priority
|
||||
* but on the priority of executed tasks don't run tasks before the executed*/
|
||||
lv_task_t * task_interrupter = NULL;
|
||||
lv_task_t * next;
|
||||
bool end_flag;
|
||||
do {
|
||||
end_flag = true;
|
||||
task_deleted = false;
|
||||
task_created = false;
|
||||
LV_GC_ROOT(_lv_task_act) = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll));
|
||||
while(LV_GC_ROOT(_lv_task_act)) {
|
||||
/* The task might be deleted if it runs only once ('once = 1')
|
||||
* So get next element until the current is surely valid*/
|
||||
next = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), LV_GC_ROOT(_lv_task_act));
|
||||
|
||||
/*We reach priority of the turned off task. There is nothing more to do.*/
|
||||
if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_OFF) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*Here is the interrupter task. Don't execute it again.*/
|
||||
if(LV_GC_ROOT(_lv_task_act) == task_interrupter) {
|
||||
task_interrupter = NULL; /*From this point only task after the interrupter comes, so the interrupter is not interesting anymore*/
|
||||
LV_GC_ROOT(_lv_task_act) = next;
|
||||
continue; /*Load the next task*/
|
||||
}
|
||||
|
||||
/*Just try to run the tasks with highest priority.*/
|
||||
if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_HIGHEST) {
|
||||
lv_task_exec(LV_GC_ROOT(_lv_task_act));
|
||||
}
|
||||
/*Tasks with higher priority then the interrupted shall be run in every case*/
|
||||
else if(task_interrupter) {
|
||||
if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio > task_interrupter->prio) {
|
||||
if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) {
|
||||
task_interrupter = LV_GC_ROOT(_lv_task_act); /*Check all tasks again from the highest priority */
|
||||
end_flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* It is no interrupter task or we already reached it earlier.
|
||||
* Just run the remaining tasks*/
|
||||
else {
|
||||
if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) {
|
||||
task_interrupter = LV_GC_ROOT(_lv_task_act); /*Check all tasks again from the highest priority */
|
||||
end_flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(task_deleted) break; /*If a task was deleted then this or the next item might be corrupted*/
|
||||
if(task_created) break; /*If a task was deleted then this or the next item might be corrupted*/
|
||||
|
||||
LV_GC_ROOT(_lv_task_act) = next; /*Load the next task*/
|
||||
}
|
||||
} while(!end_flag);
|
||||
|
||||
busy_time += lv_tick_elaps(handler_start);
|
||||
uint32_t idle_period_time = lv_tick_elaps(idle_period_start);
|
||||
if(idle_period_time >= IDLE_MEAS_PERIOD) {
|
||||
|
||||
idle_last = (uint32_t)((uint32_t)busy_time * 100) / IDLE_MEAS_PERIOD; /*Calculate the busy percentage*/
|
||||
idle_last = idle_last > 100 ? 0 : 100 - idle_last; /*But we need idle time*/
|
||||
busy_time = 0;
|
||||
idle_period_start = lv_tick_get();
|
||||
|
||||
|
||||
}
|
||||
|
||||
task_handler_mutex = false; /*Release the mutex*/
|
||||
|
||||
LV_LOG_TRACE("lv_task_handler ready");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new lv_task
|
||||
* @param task a function which is the task itself
|
||||
* @param period call period in ms unit
|
||||
* @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped)
|
||||
* @param param free parameter
|
||||
* @return pointer to the new task
|
||||
*/
|
||||
lv_task_t * lv_task_create(void (*task)(void *), uint32_t period, lv_task_prio_t prio, void * param)
|
||||
{
|
||||
lv_task_t * new_lv_task = NULL;
|
||||
lv_task_t * tmp;
|
||||
|
||||
/*Create task lists in order of priority from high to low*/
|
||||
tmp = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll));
|
||||
if(NULL == tmp) { /*First task*/
|
||||
new_lv_task = lv_ll_ins_head(&LV_GC_ROOT(_lv_task_ll));
|
||||
lv_mem_assert(new_lv_task);
|
||||
if(new_lv_task == NULL) return NULL;
|
||||
} else {
|
||||
do {
|
||||
if(tmp->prio <= prio) {
|
||||
new_lv_task = lv_ll_ins_prev(&LV_GC_ROOT(_lv_task_ll), tmp);
|
||||
lv_mem_assert(new_lv_task);
|
||||
if(new_lv_task == NULL) return NULL;
|
||||
break;
|
||||
}
|
||||
tmp = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), tmp);
|
||||
} while(tmp != NULL);
|
||||
|
||||
if(tmp == NULL) { /*Only too high priority tasks were found*/
|
||||
new_lv_task = lv_ll_ins_tail(&LV_GC_ROOT(_lv_task_ll));
|
||||
lv_mem_assert(new_lv_task);
|
||||
if(new_lv_task == NULL) return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
new_lv_task->period = period;
|
||||
new_lv_task->task = task;
|
||||
new_lv_task->prio = prio;
|
||||
new_lv_task->param = param;
|
||||
new_lv_task->once = 0;
|
||||
new_lv_task->last_run = lv_tick_get();
|
||||
|
||||
task_created = true;
|
||||
|
||||
return new_lv_task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a lv_task
|
||||
* @param lv_task_p pointer to task created by lv_task_p
|
||||
*/
|
||||
void lv_task_del(lv_task_t * lv_task_p)
|
||||
{
|
||||
lv_ll_rem(&LV_GC_ROOT(_lv_task_ll), lv_task_p);
|
||||
|
||||
lv_mem_free(lv_task_p);
|
||||
|
||||
if(LV_GC_ROOT(_lv_task_act) == lv_task_p) task_deleted = true; /*The active task was deleted*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Set new priority for a lv_task
|
||||
* @param lv_task_p pointer to a lv_task
|
||||
* @param prio the new priority
|
||||
*/
|
||||
void lv_task_set_prio(lv_task_t * lv_task_p, lv_task_prio_t prio)
|
||||
{
|
||||
/*Find the tasks with new priority*/
|
||||
lv_task_t * i;
|
||||
LV_LL_READ(LV_GC_ROOT(_lv_task_ll), i) {
|
||||
if(i->prio <= prio) {
|
||||
if(i != lv_task_p) lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*There was no such a low priority so far then add the node to the tail*/
|
||||
if(i == NULL) {
|
||||
lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, NULL);
|
||||
}
|
||||
|
||||
|
||||
lv_task_p->prio = prio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set new period for a lv_task
|
||||
* @param lv_task_p pointer to a lv_task
|
||||
* @param period the new period
|
||||
*/
|
||||
void lv_task_set_period(lv_task_t * lv_task_p, uint32_t period)
|
||||
{
|
||||
lv_task_p->period = period;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a lv_task ready. It will not wait its period.
|
||||
* @param lv_task_p pointer to a lv_task.
|
||||
*/
|
||||
void lv_task_ready(lv_task_t * lv_task_p)
|
||||
{
|
||||
lv_task_p->last_run = lv_tick_get() - lv_task_p->period - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the lv_task after one call
|
||||
* @param lv_task_p pointer to a lv_task.
|
||||
*/
|
||||
void lv_task_once(lv_task_t * lv_task_p)
|
||||
{
|
||||
lv_task_p->once = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset a lv_task.
|
||||
* It will be called the previously set period milliseconds later.
|
||||
* @param lv_task_p pointer to a lv_task.
|
||||
*/
|
||||
void lv_task_reset(lv_task_t * lv_task_p)
|
||||
{
|
||||
lv_task_p->last_run = lv_tick_get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable the whole lv_task handling
|
||||
* @param en: true: lv_task handling is running, false: lv_task handling is suspended
|
||||
*/
|
||||
void lv_task_enable(bool en)
|
||||
{
|
||||
lv_task_run = en;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get idle percentage
|
||||
* @return the lv_task idle in percentage
|
||||
*/
|
||||
uint8_t lv_task_get_idle(void)
|
||||
{
|
||||
return idle_last;
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Execute task if its the priority is appropriate
|
||||
* @param lv_task_p pointer to lv_task
|
||||
* @return true: execute, false: not executed
|
||||
*/
|
||||
static bool lv_task_exec(lv_task_t * lv_task_p)
|
||||
{
|
||||
bool exec = false;
|
||||
|
||||
/*Execute if at least 'period' time elapsed*/
|
||||
uint32_t elp = lv_tick_elaps(lv_task_p->last_run);
|
||||
if(elp >= lv_task_p->period) {
|
||||
lv_task_p->last_run = lv_tick_get();
|
||||
task_deleted = false;
|
||||
task_created = false;
|
||||
lv_task_p->task(lv_task_p->param);
|
||||
|
||||
/*Delete if it was a one shot lv_task*/
|
||||
if(task_deleted == false) { /*The task might be deleted by itself as well*/
|
||||
if(lv_task_p->once != 0) {
|
||||
lv_task_del(lv_task_p);
|
||||
}
|
||||
}
|
||||
exec = true;
|
||||
}
|
||||
|
||||
return exec;
|
||||
}
|
||||
|
||||
149
src/lv_misc/lv_task.h
Normal file
149
src/lv_misc/lv_task.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @file lv_task.c
|
||||
* An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically.
|
||||
* A priority (5 levels + disable) can be assigned to lv_tasks.
|
||||
*/
|
||||
|
||||
#ifndef LV_TASK_H
|
||||
#define LV_TASK_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "lv_mem.h"
|
||||
#include "lv_ll.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#ifndef LV_ATTRIBUTE_TASK_HANDLER
|
||||
#define LV_ATTRIBUTE_TASK_HANDLER
|
||||
#endif
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
/**
|
||||
* Possible priorities for lv_tasks
|
||||
*/
|
||||
enum
|
||||
{
|
||||
LV_TASK_PRIO_OFF = 0,
|
||||
LV_TASK_PRIO_LOWEST,
|
||||
LV_TASK_PRIO_LOW,
|
||||
LV_TASK_PRIO_MID,
|
||||
LV_TASK_PRIO_HIGH,
|
||||
LV_TASK_PRIO_HIGHEST,
|
||||
LV_TASK_PRIO_NUM,
|
||||
};
|
||||
typedef uint8_t lv_task_prio_t;
|
||||
|
||||
/**
|
||||
* Descriptor of a lv_task
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t period;
|
||||
uint32_t last_run;
|
||||
void (*task) (void*);
|
||||
void * param;
|
||||
uint8_t prio:3;
|
||||
uint8_t once:1;
|
||||
} lv_task_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Init the lv_task module
|
||||
*/
|
||||
void lv_task_init(void);
|
||||
|
||||
/**
|
||||
* Call it periodically to handle lv_tasks.
|
||||
*/
|
||||
LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void);
|
||||
|
||||
/**
|
||||
* Create a new lv_task
|
||||
* @param task a function which is the task itself
|
||||
* @param period call period in ms unit
|
||||
* @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped)
|
||||
* @param param free parameter
|
||||
* @return pointer to the new task
|
||||
*/
|
||||
lv_task_t* lv_task_create(void (*task) (void *), uint32_t period, lv_task_prio_t prio, void * param);
|
||||
|
||||
/**
|
||||
* Delete a lv_task
|
||||
* @param lv_task_p pointer to task created by lv_task_p
|
||||
*/
|
||||
void lv_task_del(lv_task_t* lv_task_p);
|
||||
|
||||
/**
|
||||
* Set new priority for a lv_task
|
||||
* @param lv_task_p pointer to a lv_task
|
||||
* @param prio the new priority
|
||||
*/
|
||||
void lv_task_set_prio(lv_task_t* lv_task_p, lv_task_prio_t prio);
|
||||
|
||||
/**
|
||||
* Set new period for a lv_task
|
||||
* @param lv_task_p pointer to a lv_task
|
||||
* @param period the new period
|
||||
*/
|
||||
void lv_task_set_period(lv_task_t* lv_task_p, uint32_t period);
|
||||
|
||||
/**
|
||||
* Make a lv_task ready. It will not wait its period.
|
||||
* @param lv_task_p pointer to a lv_task.
|
||||
*/
|
||||
void lv_task_ready(lv_task_t* lv_task_p);
|
||||
|
||||
|
||||
/**
|
||||
* Delete the lv_task after one call
|
||||
* @param lv_task_p pointer to a lv_task.
|
||||
*/
|
||||
void lv_task_once(lv_task_t * lv_task_p);
|
||||
|
||||
/**
|
||||
* Reset a lv_task.
|
||||
* It will be called the previously set period milliseconds later.
|
||||
* @param lv_task_p pointer to a lv_task.
|
||||
*/
|
||||
void lv_task_reset(lv_task_t* lv_task_p);
|
||||
|
||||
/**
|
||||
* Enable or disable the whole lv_task handling
|
||||
* @param en: true: lv_task handling is running, false: lv_task handling is suspended
|
||||
*/
|
||||
void lv_task_enable(bool en);
|
||||
|
||||
/**
|
||||
* Get idle percentage
|
||||
* @return the lv_task idle in percentage
|
||||
*/
|
||||
uint8_t lv_task_get_idle(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
40
src/lv_misc/lv_templ.c
Normal file
40
src/lv_misc/lv_templ.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @file lv_templ.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/* This typedef exists purely to keep -Wpedantic happy when the file is empty. */
|
||||
/* It can be removed. */
|
||||
typedef int keep_pedantic_happy;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
38
src/lv_misc/lv_templ.h
Normal file
38
src/lv_misc/lv_templ.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file lv_templ.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_TEMPL_H
|
||||
#define LV_TEMPL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_TEMPL_H*/
|
||||
792
src/lv_misc/lv_txt.c
Normal file
792
src/lv_misc/lv_txt.c
Normal file
@@ -0,0 +1,792 @@
|
||||
/**
|
||||
* @file lv_text.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_txt.h"
|
||||
#include "lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define NO_BREAK_FOUND UINT32_MAX
|
||||
|
||||
#ifndef LV_TXT_LINE_BREAK_LONG_LEN
|
||||
#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */
|
||||
#endif
|
||||
|
||||
#ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN
|
||||
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */
|
||||
#endif
|
||||
|
||||
#ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN
|
||||
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static bool is_break_char(uint32_t letter);
|
||||
|
||||
#if LV_TXT_UTF8
|
||||
static uint8_t lv_txt_utf8_size(const char * str);
|
||||
static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni);
|
||||
static uint32_t lv_txt_utf8_conv_wc(uint32_t c);
|
||||
static uint32_t lv_txt_utf8_next(const char * txt, uint32_t * i);
|
||||
static uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i_start);
|
||||
static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id);
|
||||
static uint32_t lv_txt_utf8_get_char_id(const char * txt, uint32_t byte_id);
|
||||
static uint32_t lv_txt_utf8_get_length(const char * txt);
|
||||
#else
|
||||
static uint8_t lv_txt_ascii_size(const char * str);
|
||||
static uint32_t lv_txt_unicode_to_ascii(uint32_t letter_uni);
|
||||
static uint32_t lv_txt_ascii_conv_wc(uint32_t c);
|
||||
static uint32_t lv_txt_ascii_next(const char * txt, uint32_t * i);
|
||||
static uint32_t lv_txt_ascii_prev(const char * txt, uint32_t * i_start);
|
||||
static uint32_t lv_txt_ascii_get_byte_id(const char * txt, uint32_t utf8_id);
|
||||
static uint32_t lv_txt_ascii_get_char_id(const char * txt, uint32_t byte_id);
|
||||
static uint32_t lv_txt_ascii_get_length(const char * txt);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
#if LV_TXT_UTF8
|
||||
uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_utf8_size;
|
||||
uint32_t (*lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_utf8;
|
||||
uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_utf8_conv_wc;
|
||||
uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_utf8_next;
|
||||
uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_utf8_prev;
|
||||
uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_utf8_get_byte_id;
|
||||
uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) = lv_txt_utf8_get_char_id;
|
||||
uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_utf8_get_length;
|
||||
#else
|
||||
uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_ascii_size;
|
||||
uint32_t (*lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_ascii;
|
||||
uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_ascii_conv_wc;
|
||||
uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_ascii_next;
|
||||
uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_ascii_prev;
|
||||
uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_ascii_get_byte_id;
|
||||
uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) = lv_txt_ascii_get_char_id;
|
||||
uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_ascii_get_length;
|
||||
#endif
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Get size of a text
|
||||
* @param size_res pointer to a 'point_t' variable to store the result
|
||||
* @param text pointer to a text
|
||||
* @param font pinter to font of the text
|
||||
* @param letter_space letter space of the text
|
||||
* @param txt.line_space line space of the text
|
||||
* @param flags settings for the text from 'txt_flag_t' enum
|
||||
* @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks
|
||||
*/
|
||||
void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font,
|
||||
lv_coord_t letter_space, lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag)
|
||||
{
|
||||
size_res->x = 0;
|
||||
size_res->y = 0;
|
||||
|
||||
if(text == NULL) return;
|
||||
if(font == NULL) return;
|
||||
|
||||
if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX;
|
||||
|
||||
uint32_t line_start = 0;
|
||||
uint32_t new_line_start = 0;
|
||||
lv_coord_t act_line_length;
|
||||
uint8_t letter_height = lv_font_get_height(font);
|
||||
|
||||
/*Calc. the height and longest line*/
|
||||
while(text[line_start] != '\0') {
|
||||
new_line_start += lv_txt_get_next_line(&text[line_start], font, letter_space, max_width, flag);
|
||||
size_res->y += letter_height ;
|
||||
size_res->y += line_space;
|
||||
|
||||
/*Calculate the the longest line*/
|
||||
act_line_length = lv_txt_get_width(&text[line_start], new_line_start - line_start,
|
||||
font, letter_space, flag);
|
||||
|
||||
size_res->x = LV_MATH_MAX(act_line_length, size_res->x);
|
||||
line_start = new_line_start;
|
||||
}
|
||||
|
||||
/*Ma ke the text one line taller if the last character is '\n' or '\r'*/
|
||||
if((line_start != 0) && (text[line_start - 1] == '\n' || text[line_start - 1] == '\r')) {
|
||||
size_res->y += letter_height + line_space;
|
||||
}
|
||||
|
||||
/*Correction with the last line space or set the height manually if the text is empty*/
|
||||
if(size_res->y == 0) size_res->y = letter_height;
|
||||
else size_res->y -= line_space;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next line of text. Check line length and break chars too.
|
||||
* @param txt a '\0' terminated string
|
||||
* @param font pointer to a font
|
||||
* @param letter_space letter space
|
||||
* @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks
|
||||
* @param flags settings for the text from 'txt_flag_type' enum
|
||||
* @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different)
|
||||
*/
|
||||
uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font,
|
||||
lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag)
|
||||
{
|
||||
if(txt == NULL) return 0;
|
||||
if(font == NULL) return 0;
|
||||
|
||||
if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX;
|
||||
|
||||
uint32_t i = 0;
|
||||
lv_coord_t cur_w = 0;
|
||||
lv_coord_t w_at_last_break = 0;
|
||||
uint32_t n_char_since_last_break = 0; /* Used count word length of long words */
|
||||
uint32_t last_break = NO_BREAK_FOUND;
|
||||
lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT;
|
||||
uint32_t letter = 0;
|
||||
|
||||
while(txt[i] != '\0') {
|
||||
lv_coord_t letter_width;
|
||||
letter = lv_txt_encoded_next(txt, &i);
|
||||
|
||||
/*Handle the recolor command*/
|
||||
if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
|
||||
if(lv_txt_is_cmd(&cmd_state, letter) != false) {
|
||||
continue; /*Skip the letter is it is part of a command*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*Check for new line chars*/
|
||||
if(letter == '\n' || letter == '\r') {
|
||||
uint32_t i_tmp = i;
|
||||
uint32_t letter_next = lv_txt_encoded_next(txt, &i_tmp);
|
||||
if(letter == '\r' && letter_next == '\n') i = i_tmp;
|
||||
|
||||
return i; /*Return with the first letter of the next line*/
|
||||
|
||||
} else { /*Check the actual length*/
|
||||
n_char_since_last_break++;
|
||||
letter_width = lv_font_get_width(font, letter);
|
||||
cur_w += letter_width;
|
||||
|
||||
/* Get the length of the current work and determine best place
|
||||
* to break the line. */
|
||||
if(cur_w > max_width) {
|
||||
if( last_break != NO_BREAK_FOUND ) {
|
||||
/* Continue searching for next breakable character to see if the next word will fit */
|
||||
uint32_t n_char_fit = n_char_since_last_break - 1;
|
||||
if( n_char_since_last_break <= LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN ) {
|
||||
i = last_break;
|
||||
}
|
||||
else {
|
||||
uint32_t i_tmp = i;
|
||||
cur_w -= w_at_last_break + letter_space; /*ignore the first letter_space after the break char */
|
||||
bool other = true;
|
||||
while(txt[i_tmp] != '\0') {
|
||||
letter = lv_txt_encoded_next(txt, &i_tmp);
|
||||
|
||||
/*Handle the recolor command*/
|
||||
if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
|
||||
if(lv_txt_is_cmd(&cmd_state, letter) != false) {
|
||||
continue; /*Skip the letter is it is part of a command*/
|
||||
}
|
||||
}
|
||||
|
||||
/*Check for new line chars*/
|
||||
if(letter == '\n' || letter == '\r' || is_break_char(letter)) {
|
||||
if(n_char_since_last_break >= LV_TXT_LINE_BREAK_LONG_LEN) {
|
||||
/* Figure out the prettiest place to break */
|
||||
uint32_t char_remain;
|
||||
lv_txt_encoded_prev(txt, &i);
|
||||
for(char_remain=n_char_since_last_break - n_char_fit;
|
||||
char_remain < LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN;
|
||||
char_remain++) {
|
||||
lv_txt_encoded_prev(txt, &i);
|
||||
}
|
||||
}
|
||||
else{
|
||||
i = last_break;
|
||||
}
|
||||
other = false;
|
||||
break;
|
||||
}
|
||||
n_char_since_last_break++;
|
||||
lv_coord_t letter_width2 = lv_font_get_width(font, letter);
|
||||
cur_w += letter_width2;
|
||||
if(cur_w > max_width) {
|
||||
/* Current letter already exceeds, return previous */
|
||||
lv_txt_encoded_prev(txt, &i);
|
||||
other = false;
|
||||
break;
|
||||
}
|
||||
if(letter_width2 > 0){
|
||||
cur_w += letter_space;
|
||||
}
|
||||
}
|
||||
if( other ) {
|
||||
if(n_char_since_last_break >= LV_TXT_LINE_BREAK_LONG_LEN) {
|
||||
/* Figure out the prettiest place to break */
|
||||
uint32_t char_remain;
|
||||
lv_txt_encoded_prev(txt, &i);
|
||||
for(char_remain=n_char_since_last_break - n_char_fit;
|
||||
char_remain < LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN;
|
||||
char_remain++){
|
||||
lv_txt_encoded_prev(txt, &i);
|
||||
}
|
||||
}
|
||||
else{
|
||||
i = last_break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Now this character is out of the area so it will be first character of the next line*/
|
||||
/* But 'i' already points to the next character (because of lv_txt_utf8_next) step beck one*/
|
||||
lv_txt_encoded_prev(txt, &i);
|
||||
}
|
||||
|
||||
/* Do not let to return without doing nothing.
|
||||
* Find at least one character (Avoid infinite loop )*/
|
||||
if(i == 0) lv_txt_encoded_next(txt, &i);
|
||||
|
||||
return i;
|
||||
}
|
||||
/*If this char still can fit to this line then check if
|
||||
* txt can be broken here later */
|
||||
else if(is_break_char(letter)) {
|
||||
last_break = i; /*Save the first char index after break*/
|
||||
w_at_last_break = cur_w;
|
||||
if(letter_width > 0) {
|
||||
w_at_last_break += letter_space;
|
||||
}
|
||||
n_char_since_last_break = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(letter_width > 0) {
|
||||
cur_w += letter_space;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the length of a text with a given font
|
||||
* @param txt a '\0' terminate string
|
||||
* @param length length of 'txt' in byte count and not characters (Á is 1 character but 2 bytes in UTF-8)
|
||||
* @param font pointer to a font
|
||||
* @param letter_space letter space
|
||||
* @param flags settings for the text from 'txt_flag_t' enum
|
||||
* @return length of a char_num long text
|
||||
*/
|
||||
lv_coord_t lv_txt_get_width(const char * txt, uint16_t length,
|
||||
const lv_font_t * font, lv_coord_t letter_space, lv_txt_flag_t flag)
|
||||
{
|
||||
if(txt == NULL) return 0;
|
||||
if(font == NULL) return 0;
|
||||
|
||||
uint32_t i = 0;
|
||||
lv_coord_t width = 0;
|
||||
lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT;
|
||||
uint32_t letter;
|
||||
|
||||
if(length != 0) {
|
||||
while(i< length){
|
||||
letter = lv_txt_encoded_next(txt, &i);
|
||||
if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
|
||||
if(lv_txt_is_cmd(&cmd_state, letter) != false) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
lv_coord_t char_width = lv_font_get_width(font, letter);
|
||||
if(char_width > 0){
|
||||
width += lv_font_get_width(font, letter);
|
||||
width += letter_space;
|
||||
}
|
||||
}
|
||||
|
||||
if(width > 0) {
|
||||
width -= letter_space; /*Trim the last letter space. Important if the text is center aligned */
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check next character in a string and decide if the character is part of the command or not
|
||||
* @param state pointer to a txt_cmd_state_t variable which stores the current state of command processing
|
||||
* (Initied. to TXT_CMD_STATE_WAIT )
|
||||
* @param c the current character
|
||||
* @return true: the character is part of a command and should not be written,
|
||||
* false: the character should be written
|
||||
*/
|
||||
bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if(c == (uint32_t)LV_TXT_COLOR_CMD[0]) {
|
||||
if(*state == LV_TXT_CMD_STATE_WAIT) { /*Start char*/
|
||||
*state = LV_TXT_CMD_STATE_PAR;
|
||||
ret = true;
|
||||
} else if(*state == LV_TXT_CMD_STATE_PAR) { /*Other start char in parameter is escaped cmd. char */
|
||||
*state = LV_TXT_CMD_STATE_WAIT;
|
||||
} else if(*state == LV_TXT_CMD_STATE_IN) { /*Command end */
|
||||
*state = LV_TXT_CMD_STATE_WAIT;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*Skip the color parameter and wait the space after it*/
|
||||
if(*state == LV_TXT_CMD_STATE_PAR) {
|
||||
if(c == ' ') {
|
||||
*state = LV_TXT_CMD_STATE_IN; /*After the parameter the text is in the command*/
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a string into an other
|
||||
* @param txt_buf the original text (must be big enough for the result text)
|
||||
* @param pos position to insert. Expressed in character index and not byte index (Different in UTF-8)
|
||||
* 0: before the original text, 1: after the first char etc.
|
||||
* @param ins_txt text to insert
|
||||
*/
|
||||
void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt)
|
||||
{
|
||||
uint32_t old_len = strlen(txt_buf);
|
||||
uint32_t ins_len = strlen(ins_txt);
|
||||
uint32_t new_len = ins_len + old_len;
|
||||
#if LV_TXT_UTF8 != 0
|
||||
pos = lv_txt_encoded_get_byte_id(txt_buf, pos); /*Convert to byte index instead of letter index*/
|
||||
#endif
|
||||
/*Copy the second part into the end to make place to text to insert*/
|
||||
uint32_t i;
|
||||
for(i = new_len; i >= pos + ins_len; i--) {
|
||||
txt_buf[i] = txt_buf[i - ins_len];
|
||||
}
|
||||
|
||||
/* Copy the text into the new space*/
|
||||
memcpy(txt_buf + pos, ins_txt, ins_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a part of a string
|
||||
* @param txt string to modify
|
||||
* @param pos position where to start the deleting (0: before the first char, 1: after the first char etc.)
|
||||
* @param len number of characters to delete
|
||||
*/
|
||||
void lv_txt_cut(char * txt, uint32_t pos, uint32_t len)
|
||||
{
|
||||
|
||||
uint32_t old_len = strlen(txt);
|
||||
#if LV_TXT_UTF8 != 0
|
||||
pos = lv_txt_encoded_get_byte_id(txt, pos); /*Convert to byte index instead of letter index*/
|
||||
len = lv_txt_encoded_get_byte_id(&txt[pos], len);
|
||||
#endif
|
||||
|
||||
/*Copy the second part into the end to make place to text to insert*/
|
||||
uint32_t i;
|
||||
for(i = pos; i <= old_len - len; i++) {
|
||||
txt[i] = txt[i + len];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
* UTF-8 ENCODER/DECOER
|
||||
******************************/
|
||||
|
||||
#if LV_TXT_UTF8
|
||||
|
||||
/**
|
||||
* Give the size of an UTF-8 coded character
|
||||
* @param str pointer to a character in a string
|
||||
* @return length of the UTF-8 character (1,2,3 or 4). O on invalid code
|
||||
*/
|
||||
static uint8_t lv_txt_utf8_size(const char * str)
|
||||
{
|
||||
if((str[0] & 0x80) == 0) return 1;
|
||||
else if((str[0] & 0xE0) == 0xC0) return 2;
|
||||
else if((str[0] & 0xF0) == 0xE0) return 3;
|
||||
else if((str[0] & 0xF8) == 0xF0) return 4;
|
||||
return 1; /*If the char was invalid step tell it's 1 byte long*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert an Unicode letter to UTF-8.
|
||||
* @param letter_uni an Unicode letter
|
||||
* @return UTF-8 coded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ű')
|
||||
*/
|
||||
static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni)
|
||||
{
|
||||
if(letter_uni < 128) return letter_uni;
|
||||
uint8_t bytes[4];
|
||||
|
||||
if(letter_uni < 0x0800) {
|
||||
bytes[0] = ((letter_uni >> 6) & 0x1F) | 0xC0;
|
||||
bytes[1] = ((letter_uni >> 0) & 0x3F) | 0x80;
|
||||
bytes[2] = 0;
|
||||
bytes[3] = 0;
|
||||
} else if(letter_uni < 0x010000) {
|
||||
bytes[0] = ((letter_uni >> 12) & 0x0F) | 0xE0;
|
||||
bytes[1] = ((letter_uni >> 6) & 0x3F) | 0x80;
|
||||
bytes[2] = ((letter_uni >> 0) & 0x3F) | 0x80;
|
||||
bytes[3] = 0;
|
||||
} else if(letter_uni < 0x110000) {
|
||||
bytes[0] = ((letter_uni >> 18) & 0x07) | 0xF0;
|
||||
bytes[1] = ((letter_uni >> 12) & 0x3F) | 0x80;
|
||||
bytes[2] = ((letter_uni >> 6) & 0x3F) | 0x80;
|
||||
bytes[3] = ((letter_uni >> 0) & 0x3F) | 0x80;
|
||||
}
|
||||
|
||||
uint32_t * res_p = (uint32_t *)bytes;
|
||||
return *res_p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a wide character, e.g. 'Á' little endian to be UTF-8 compatible
|
||||
* @param c a wide character or a Little endian number
|
||||
* @return `c` in big endian
|
||||
*/
|
||||
static uint32_t lv_txt_utf8_conv_wc(uint32_t c)
|
||||
{
|
||||
/*Swap the bytes (UTF-8 is big endian, but the MCUs are little endian)*/
|
||||
if((c & 0x80) != 0) {
|
||||
uint32_t swapped;
|
||||
uint8_t c8[4];
|
||||
memcpy(c8, &c, 4);
|
||||
swapped = (c8[0] << 24) + (c8[1] << 16) + (c8[2] << 8) + (c8[3]);
|
||||
uint8_t i;
|
||||
for(i = 0; i < 4; i++) {
|
||||
if((swapped & 0xFF) == 0) swapped = (swapped >> 8); /*Ignore leading zeros (they were in the end originally)*/
|
||||
}
|
||||
c = swapped;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an UTF-8 character from a string.
|
||||
* @param txt pointer to '\0' terminated string
|
||||
* @param i start byte index in 'txt' where to start.
|
||||
* After call it will point to the next UTF-8 char in 'txt'.
|
||||
* NULL to use txt[0] as index
|
||||
* @return the decoded Unicode character or 0 on invalid UTF-8 code
|
||||
*/
|
||||
static uint32_t lv_txt_utf8_next(const char * txt, uint32_t * i)
|
||||
{
|
||||
/* Unicode to UTF-8
|
||||
* 00000000 00000000 00000000 0xxxxxxx -> 0xxxxxxx
|
||||
* 00000000 00000000 00000yyy yyxxxxxx -> 110yyyyy 10xxxxxx
|
||||
* 00000000 00000000 zzzzyyyy yyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx
|
||||
* 00000000 000wwwzz zzzzyyyy yyxxxxxx -> 11110www 10zzzzzz 10yyyyyy 10xxxxxx
|
||||
* */
|
||||
|
||||
uint32_t result = 0;
|
||||
|
||||
/*Dummy 'i' pointer is required*/
|
||||
uint32_t i_tmp = 0;
|
||||
if(i == NULL) i = &i_tmp;
|
||||
|
||||
/*Normal ASCII*/
|
||||
if((txt[*i] & 0x80) == 0) {
|
||||
result = txt[*i];
|
||||
(*i)++;
|
||||
}
|
||||
/*Real UTF-8 decode*/
|
||||
else {
|
||||
/*2 bytes UTF-8 code*/
|
||||
if((txt[*i] & 0xE0) == 0xC0) {
|
||||
result = (uint32_t)(txt[*i] & 0x1F) << 6;
|
||||
(*i)++;
|
||||
if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/
|
||||
result += (txt[*i] & 0x3F);
|
||||
(*i)++;
|
||||
}
|
||||
/*3 bytes UTF-8 code*/
|
||||
else if((txt[*i] & 0xF0) == 0xE0) {
|
||||
result = (uint32_t)(txt[*i] & 0x0F) << 12;
|
||||
(*i)++;
|
||||
|
||||
if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/
|
||||
result += (uint32_t)(txt[*i] & 0x3F) << 6;
|
||||
(*i)++;
|
||||
|
||||
if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/
|
||||
result += (txt[*i] & 0x3F);
|
||||
(*i)++;
|
||||
}
|
||||
/*4 bytes UTF-8 code*/
|
||||
else if((txt[*i] & 0xF8) == 0xF0) {
|
||||
result = (uint32_t)(txt[*i] & 0x07) << 18;
|
||||
(*i)++;
|
||||
|
||||
if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/
|
||||
result += (uint32_t)(txt[*i] & 0x3F) << 12;
|
||||
(*i)++;
|
||||
|
||||
if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/
|
||||
result += (uint32_t)(txt[*i] & 0x3F) << 6;
|
||||
(*i)++;
|
||||
|
||||
if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/
|
||||
result += txt[*i] & 0x3F;
|
||||
(*i)++;
|
||||
} else {
|
||||
(*i)++; /*Not UTF-8 char. Go the next.*/
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get previous UTF-8 character form a string.
|
||||
* @param txt pointer to '\0' terminated string
|
||||
* @param i start byte index in 'txt' where to start. After the call it will point to the previous UTF-8 char in 'txt'.
|
||||
* @return the decoded Unicode character or 0 on invalid UTF-8 code
|
||||
*/
|
||||
static uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i)
|
||||
{
|
||||
uint8_t c_size;
|
||||
uint8_t cnt = 0;
|
||||
|
||||
/*Try to find a !0 long UTF-8 char by stepping one character back*/
|
||||
(*i)--;
|
||||
do {
|
||||
if(cnt >= 4) return 0; /*No UTF-8 char found before the initial*/
|
||||
|
||||
c_size = lv_txt_encoded_size(&txt[*i]);
|
||||
if(c_size == 0) {
|
||||
if(*i != 0)(*i)--;
|
||||
else return 0;
|
||||
}
|
||||
cnt++;
|
||||
} while(c_size == 0);
|
||||
|
||||
uint32_t i_tmp = *i;
|
||||
uint32_t letter = lv_txt_encoded_next(txt, &i_tmp); /*Character found, get it*/
|
||||
|
||||
return letter;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a character index (in an UTF-8 text) to byte index.
|
||||
* E.g. in "AÁRT" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long
|
||||
* @param txt a '\0' terminated UTF-8 string
|
||||
* @param utf8_id character index
|
||||
* @return byte index of the 'utf8_id'th letter
|
||||
*/
|
||||
static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t byte_cnt = 0;
|
||||
for(i = 0; i < utf8_id; i++) {
|
||||
byte_cnt += lv_txt_encoded_size(&txt[byte_cnt]);
|
||||
}
|
||||
|
||||
return byte_cnt;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a byte index (in an UTF-8 text) to character index.
|
||||
* E.g. in "AÁRT" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long
|
||||
* @param txt a '\0' terminated UTF-8 string
|
||||
* @param byte_id byte index
|
||||
* @return character index of the letter at 'byte_id'th position
|
||||
*/
|
||||
static uint32_t lv_txt_utf8_get_char_id(const char * txt, uint32_t byte_id)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t char_cnt = 0;
|
||||
|
||||
while(i < byte_id) {
|
||||
lv_txt_encoded_next(txt, &i); /*'i' points to the next letter so use the prev. value*/
|
||||
char_cnt++;
|
||||
}
|
||||
|
||||
return char_cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of characters (and NOT bytes) in a string. Decode it with UTF-8 if enabled.
|
||||
* E.g.: "ÁBC" is 3 characters (but 4 bytes)
|
||||
* @param txt a '\0' terminated char string
|
||||
* @return number of characters
|
||||
*/
|
||||
static uint32_t lv_txt_utf8_get_length(const char * txt)
|
||||
{
|
||||
#if LV_TXT_UTF8 == 0
|
||||
return strlen(txt);
|
||||
#else
|
||||
uint32_t len = 0;
|
||||
uint32_t i = 0;
|
||||
|
||||
while(txt[i] != '\0') {
|
||||
lv_txt_encoded_next(txt, &i);
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
/**
|
||||
* Give the size of an UTF-8 coded character
|
||||
* @param str pointer to a character in a string
|
||||
* @return length of the UTF-8 character (1,2,3 or 4). O on invalid code
|
||||
*/
|
||||
static uint8_t lv_txt_ascii_size(const char * str)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert an Unicode letter to UTF-8.
|
||||
* @param letter_uni an Unicode letter
|
||||
* @return UTF-8 coded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ű')
|
||||
*/
|
||||
static uint32_t lv_txt_unicode_to_ascii(uint32_t letter_uni)
|
||||
{
|
||||
if(letter_uni < 128) return letter_uni;
|
||||
else return ' ';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert wide characters to ASCII, however wide characters in ASCII range (e.g. 'A') are ASCII compatible by default.
|
||||
* So this function does nothing just returns with `c`.
|
||||
* @param c a character, e.g. 'A'
|
||||
* @return same as `c`
|
||||
*/
|
||||
static uint32_t lv_txt_ascii_conv_wc(uint32_t c)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an UTF-8 character from a string.
|
||||
* @param txt pointer to '\0' terminated string
|
||||
* @param i start byte index in 'txt' where to start.
|
||||
* After call it will point to the next UTF-8 char in 'txt'.
|
||||
* NULL to use txt[0] as index
|
||||
* @return the decoded Unicode character or 0 on invalid UTF-8 code
|
||||
*/
|
||||
static uint32_t lv_txt_ascii_next(const char * txt, uint32_t * i)
|
||||
{
|
||||
if(i == NULL) return txt[1]; /*Get the next char */
|
||||
|
||||
uint8_t letter = txt[*i] ;
|
||||
(*i)++;
|
||||
return letter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get previous UTF-8 character form a string.
|
||||
* @param txt pointer to '\0' terminated string
|
||||
* @param i start byte index in 'txt' where to start. After the call it will point to the previous UTF-8 char in 'txt'.
|
||||
* @return the decoded Unicode character or 0 on invalid UTF-8 code
|
||||
*/
|
||||
static uint32_t lv_txt_ascii_prev(const char * txt, uint32_t * i)
|
||||
{
|
||||
if(i == NULL) return *(txt - 1); /*Get the prev. char */
|
||||
|
||||
(*i)--;
|
||||
uint8_t letter = txt[*i] ;
|
||||
|
||||
return letter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a character index (in an UTF-8 text) to byte index.
|
||||
* E.g. in "AÁRT" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long
|
||||
* @param txt a '\0' terminated UTF-8 string
|
||||
* @param utf8_id character index
|
||||
* @return byte index of the 'utf8_id'th letter
|
||||
*/
|
||||
static uint32_t lv_txt_ascii_get_byte_id(const char * txt, uint32_t utf8_id)
|
||||
{
|
||||
return utf8_id; /*In Non encoded no difference*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a byte index (in an UTF-8 text) to character index.
|
||||
* E.g. in "AÁRT" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long
|
||||
* @param txt a '\0' terminated UTF-8 string
|
||||
* @param byte_id byte index
|
||||
* @return character index of the letter at 'byte_id'th position
|
||||
*/
|
||||
static uint32_t lv_txt_ascii_get_char_id(const char * txt, uint32_t byte_id)
|
||||
{
|
||||
return byte_id; /*In Non encoded no difference*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of characters (and NOT bytes) in a string. Decode it with UTF-8 if enabled.
|
||||
* E.g.: "ÁBC" is 3 characters (but 4 bytes)
|
||||
* @param txt a '\0' terminated char string
|
||||
* @return number of characters
|
||||
*/
|
||||
static uint32_t lv_txt_ascii_get_length(const char * txt)
|
||||
{
|
||||
return strlen(txt);
|
||||
}
|
||||
#endif
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Test if char is break char or not (a text can broken here or not)
|
||||
* @param letter a letter
|
||||
* @return false: 'letter' is not break char
|
||||
*/
|
||||
static bool is_break_char(uint32_t letter)
|
||||
{
|
||||
uint8_t i;
|
||||
bool ret = false;
|
||||
|
||||
/*Compare the letter to TXT_BREAK_CHARS*/
|
||||
for(i = 0; LV_TXT_BREAK_CHARS[i] != '\0'; i++) {
|
||||
if(letter == (uint32_t)LV_TXT_BREAK_CHARS[i]) {
|
||||
ret = true; /*If match then it is break char*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
198
src/lv_misc/lv_txt.h
Normal file
198
src/lv_misc/lv_txt.h
Normal file
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* @file lv_text.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_TXT_H
|
||||
#define LV_TXT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "lv_area.h"
|
||||
#include "lv_font.h"
|
||||
#include "lv_area.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_TXT_COLOR_CMD "#"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
enum
|
||||
{
|
||||
LV_TXT_FLAG_NONE = 0x00,
|
||||
LV_TXT_FLAG_RECOLOR = 0x01, /*Enable parsing of recolor command*/
|
||||
LV_TXT_FLAG_EXPAND = 0x02, /*Ignore width to avoid automatic word wrapping*/
|
||||
LV_TXT_FLAG_CENTER = 0x04, /*Align the text to the middle*/
|
||||
LV_TXT_FLAG_RIGHT = 0x08, /*Align the text to the right*/
|
||||
};
|
||||
typedef uint8_t lv_txt_flag_t;
|
||||
|
||||
enum
|
||||
{
|
||||
LV_TXT_CMD_STATE_WAIT, /*Waiting for command*/
|
||||
LV_TXT_CMD_STATE_PAR, /*Processing the parameter*/
|
||||
LV_TXT_CMD_STATE_IN, /*Processing the command*/
|
||||
};
|
||||
typedef uint8_t lv_txt_cmd_state_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Get size of a text
|
||||
* @param size_res pointer to a 'point_t' variable to store the result
|
||||
* @param text pointer to a text
|
||||
* @param font pinter to font of the text
|
||||
* @param letter_space letter space of the text
|
||||
* @param line_space line space of the text
|
||||
* @param flags settings for the text from 'txt_flag_t' enum
|
||||
* @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks
|
||||
*/
|
||||
void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font,
|
||||
lv_coord_t letter_space, lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag);
|
||||
|
||||
/**
|
||||
* Get the next line of text. Check line length and break chars too.
|
||||
* @param txt a '\0' terminated string
|
||||
* @param font pointer to a font
|
||||
* @param letter_space letter space
|
||||
* @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks
|
||||
* @param flags settings for the text from 'txt_flag_type' enum
|
||||
* @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different)
|
||||
*/
|
||||
uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font,
|
||||
lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag);
|
||||
|
||||
/**
|
||||
* Give the length of a text with a given font
|
||||
* @param txt a '\0' terminate string
|
||||
* @param length length of 'txt' in byte count and not characters (Á is 1 character but 2 bytes in UTF-8)
|
||||
* @param font pointer to a font
|
||||
* @param letter_space letter space
|
||||
* @param flags settings for the text from 'txt_flag_t' enum
|
||||
* @return length of a char_num long text
|
||||
*/
|
||||
lv_coord_t lv_txt_get_width(const char * txt, uint16_t length,
|
||||
const lv_font_t * font, lv_coord_t letter_space, lv_txt_flag_t flag);
|
||||
|
||||
|
||||
/**
|
||||
* Check next character in a string and decide if te character is part of the command or not
|
||||
* @param state pointer to a txt_cmd_state_t variable which stores the current state of command processing
|
||||
* @param c the current character
|
||||
* @return true: the character is part of a command and should not be written,
|
||||
* false: the character should be written
|
||||
*/
|
||||
bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c);
|
||||
|
||||
/**
|
||||
* Insert a string into an other
|
||||
* @param txt_buf the original text (must be big enough for the result text)
|
||||
* @param pos position to insert (0: before the original text, 1: after the first char etc.)
|
||||
* @param ins_txt text to insert
|
||||
*/
|
||||
void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt);
|
||||
|
||||
/**
|
||||
* Delete a part of a string
|
||||
* @param txt string to modify
|
||||
* @param pos position where to start the deleting (0: before the first char, 1: after the first char etc.)
|
||||
* @param len number of characters to delete
|
||||
*/
|
||||
void lv_txt_cut(char * txt, uint32_t pos, uint32_t len);
|
||||
|
||||
/***************************************************************
|
||||
* GLOBAL FUNCTION POINTERS FOR CAHRACTER ENCODING INTERFACE
|
||||
***************************************************************/
|
||||
|
||||
/**
|
||||
* Give the size of an encoded character
|
||||
* @param str pointer to a character in a string
|
||||
* @return length of the encoded character (1,2,3 ...). O in invalid
|
||||
*/
|
||||
extern uint8_t (*lv_txt_encoded_size)(const char *);
|
||||
|
||||
|
||||
/**
|
||||
* Convert an Unicode letter to encoded
|
||||
* @param letter_uni an Unicode letter
|
||||
* @return Encoded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ü')
|
||||
*/
|
||||
extern uint32_t (*lv_txt_unicode_to_encoded)(uint32_t );
|
||||
|
||||
/**
|
||||
* Convert a wide character, e.g. 'Á' little endian to be compatible with the encoded format.
|
||||
* @param c a wide character
|
||||
* @return `c` in the encoded format
|
||||
*/
|
||||
extern uint32_t (*lv_txt_encoded_conv_wc) (uint32_t c);
|
||||
|
||||
/**
|
||||
* Decode the next encoded character from a string.
|
||||
* @param txt pointer to '\0' terminated string
|
||||
* @param i start index in 'txt' where to start.
|
||||
* After the call it will point to the next encoded char in 'txt'.
|
||||
* NULL to use txt[0] as index
|
||||
* @return the decoded Unicode character or 0 on invalid data code
|
||||
*/
|
||||
extern uint32_t (*lv_txt_encoded_next)(const char *, uint32_t * );
|
||||
|
||||
/**
|
||||
* Get the previous encoded character form a string.
|
||||
* @param txt pointer to '\0' terminated string
|
||||
* @param i_start index in 'txt' where to start. After the call it will point to the previous encoded char in 'txt'.
|
||||
* @return the decoded Unicode character or 0 on invalid data
|
||||
*/
|
||||
extern uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *);
|
||||
|
||||
/**
|
||||
* Convert a letter index (in an the encoded text) to byte index.
|
||||
* E.g. in UTF-8 "AÁRT" index of 'R' is 2 but start at byte 3 because 'Á' is 2 bytes long
|
||||
* @param txt a '\0' terminated UTF-8 string
|
||||
* @param enc_id letter index
|
||||
* @return byte index of the 'enc_id'th letter
|
||||
*/
|
||||
extern uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t);
|
||||
|
||||
/**
|
||||
* Convert a byte index (in an encoded text) to character index.
|
||||
* E.g. in UTF-8 "AÁRT" index of 'R' is 2 but start at byte 3 because 'Á' is 2 bytes long
|
||||
* @param txt a '\0' terminated UTF-8 string
|
||||
* @param byte_id byte index
|
||||
* @return character index of the letter at 'byte_id'th position
|
||||
*/
|
||||
extern uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t);
|
||||
|
||||
/**
|
||||
* Get the number of characters (and NOT bytes) in a string.
|
||||
* E.g. in UTF-8 "ÁBC" is 3 characters (but 4 bytes)
|
||||
* @param txt a '\0' terminated char string
|
||||
* @return number of characters
|
||||
*/
|
||||
extern uint32_t (*lv_txt_get_encoded_length)(const char *);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*USE_TXT*/
|
||||
310
src/lv_objx/lv_arc.c
Normal file
310
src/lv_objx/lv_arc.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* @file lv_arc.c
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_arc.h"
|
||||
#if LV_USE_ARC != 0
|
||||
|
||||
#include "../lv_misc/lv_math.h"
|
||||
#include "../lv_draw/lv_draw_arc.h"
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static bool lv_arc_design(lv_obj_t * arc, const lv_area_t * mask, lv_design_mode_t mode);
|
||||
static lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_signal_cb_t ancestor_signal;
|
||||
static lv_design_cb_t ancestor_design;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a arc object
|
||||
* @param par pointer to an object, it will be the parent of the new arc
|
||||
* @param copy pointer to a arc object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created arc
|
||||
*/
|
||||
lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
{
|
||||
|
||||
LV_LOG_TRACE("arc create started");
|
||||
|
||||
/*Create the ancestor of arc*/
|
||||
lv_obj_t * new_arc = lv_obj_create(par, copy);
|
||||
lv_mem_assert(new_arc);
|
||||
if(new_arc == NULL) return NULL;
|
||||
|
||||
/*Allocate the arc type specific extended data*/
|
||||
lv_arc_ext_t * ext = lv_obj_allocate_ext_attr(new_arc, sizeof(lv_arc_ext_t));
|
||||
lv_mem_assert(ext);
|
||||
if(ext == NULL) return NULL;
|
||||
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_arc);
|
||||
if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_arc);
|
||||
|
||||
/*Initialize the allocated 'ext' */
|
||||
ext->angle_start = 45;
|
||||
ext->angle_end = 315;
|
||||
|
||||
/*The signal and design functions are not copied so set them here*/
|
||||
lv_obj_set_signal_cb(new_arc, lv_arc_signal);
|
||||
lv_obj_set_design_cb(new_arc, lv_arc_design);
|
||||
|
||||
/*Init the new arc arc*/
|
||||
if(copy == NULL) {
|
||||
/*Set the default styles*/
|
||||
lv_theme_t * th = lv_theme_get_current();
|
||||
if(th) {
|
||||
lv_arc_set_style(new_arc, LV_ARC_STYLE_MAIN, th->style.arc);
|
||||
} else {
|
||||
lv_arc_set_style(new_arc, LV_ARC_STYLE_MAIN, &lv_style_plain_color);
|
||||
}
|
||||
|
||||
}
|
||||
/*Copy an existing arc*/
|
||||
else {
|
||||
lv_arc_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
|
||||
ext->angle_start = copy_ext->angle_start;
|
||||
ext->angle_end = copy_ext->angle_end;
|
||||
|
||||
/*Refresh the style with new signal function*/
|
||||
lv_obj_refresh_style(new_arc);
|
||||
}
|
||||
|
||||
LV_LOG_INFO("arc created");
|
||||
|
||||
return new_arc;
|
||||
}
|
||||
|
||||
/*======================
|
||||
* Add/remove functions
|
||||
*=====================*/
|
||||
|
||||
/*
|
||||
* New object specific "add" or "remove" functions come here
|
||||
*/
|
||||
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set the start and end angles of an arc. 0 deg: bottom, 90 deg: right etc.
|
||||
* @param arc pointer to an arc object
|
||||
* @param start the start angle [0..360]
|
||||
* @param end the end angle [0..360]
|
||||
*/
|
||||
void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end)
|
||||
{
|
||||
lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
|
||||
|
||||
if(start > 360) start = 360;
|
||||
if(end > 360) end = 360;
|
||||
|
||||
ext->angle_start = start;
|
||||
ext->angle_end = end;
|
||||
|
||||
lv_obj_invalidate(arc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a style of a arc.
|
||||
* @param arc pointer to arc object
|
||||
* @param type which style should be set
|
||||
* @param style pointer to a style
|
||||
* */
|
||||
void lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, lv_style_t * style)
|
||||
{
|
||||
switch(type) {
|
||||
case LV_ARC_STYLE_MAIN:
|
||||
lv_obj_set_style(arc, style);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Get the start angle of an arc.
|
||||
* @param arc pointer to an arc object
|
||||
* @return the start angle [0..360]
|
||||
*/
|
||||
uint16_t lv_arc_get_angle_start(lv_obj_t * arc)
|
||||
{
|
||||
lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
|
||||
|
||||
return ext->angle_start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the end angle of an arc.
|
||||
* @param arc pointer to an arc object
|
||||
* @return the end angle [0..360]
|
||||
*/
|
||||
uint16_t lv_arc_get_angle_end(lv_obj_t * arc)
|
||||
{
|
||||
lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
|
||||
|
||||
return ext->angle_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get style of a arc.
|
||||
* @param arc pointer to arc object
|
||||
* @param type which style should be get
|
||||
* @return style pointer to the style
|
||||
* */
|
||||
lv_style_t * lv_arc_get_style(const lv_obj_t * arc, lv_arc_style_t type)
|
||||
{
|
||||
lv_style_t * style = NULL;
|
||||
|
||||
switch(type) {
|
||||
case LV_ARC_STYLE_MAIN:
|
||||
style = lv_obj_get_style(arc);
|
||||
break;
|
||||
default:
|
||||
style = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
|
||||
/*
|
||||
* New object specific "other" functions come here
|
||||
*/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Handle the drawing related tasks of the arcs
|
||||
* @param arc pointer to an object
|
||||
* @param mask the object will be drawn only in this area
|
||||
* @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
|
||||
* (return 'true' if yes)
|
||||
* LV_DESIGN_DRAW: draw the object (always return 'true')
|
||||
* LV_DESIGN_DRAW_POST: drawing after every children are drawn
|
||||
* @param return true/false, depends on 'mode'
|
||||
*/
|
||||
static bool lv_arc_design(lv_obj_t * arc, const lv_area_t * mask, lv_design_mode_t mode)
|
||||
{
|
||||
/*Return false if the object is not covers the mask_p area*/
|
||||
if(mode == LV_DESIGN_COVER_CHK) {
|
||||
return false;
|
||||
}
|
||||
/*Draw the object*/
|
||||
else if(mode == LV_DESIGN_DRAW_MAIN) {
|
||||
lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
|
||||
lv_style_t * style = lv_arc_get_style(arc, LV_ARC_STYLE_MAIN);
|
||||
|
||||
lv_coord_t r = (LV_MATH_MIN(lv_obj_get_width(arc), lv_obj_get_height(arc))) / 2;
|
||||
lv_coord_t x = arc->coords.x1 + lv_obj_get_width(arc) / 2;
|
||||
lv_coord_t y = arc->coords.y1 + lv_obj_get_height(arc) / 2;
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(arc);
|
||||
lv_draw_arc(x, y, r, mask, ext->angle_start, ext->angle_end, style, opa_scale);
|
||||
|
||||
|
||||
/*Draw circle on the ends if enabled */
|
||||
if(style->line.rounded) {
|
||||
lv_coord_t thick_half = style->line.width / 2;
|
||||
lv_coord_t cir_x = ((r - thick_half) * lv_trigo_sin(ext->angle_start) >> LV_TRIGO_SHIFT);
|
||||
lv_coord_t cir_y = ((r - thick_half) * lv_trigo_sin(ext->angle_start + 90) >> LV_TRIGO_SHIFT);
|
||||
|
||||
lv_style_t cir_style;
|
||||
lv_style_copy(&cir_style, &lv_style_plain);
|
||||
cir_style.body.grad_color = style->line.color;
|
||||
cir_style.body.main_color = cir_style.body.grad_color;
|
||||
cir_style.body.radius = LV_RADIUS_CIRCLE;
|
||||
lv_area_t cir_area;
|
||||
cir_area.x1 = cir_x + x - thick_half;
|
||||
cir_area.y1 = cir_y + y - thick_half;
|
||||
cir_area.x2 = cir_x + x + thick_half;
|
||||
cir_area.y2 = cir_y + y + thick_half;
|
||||
|
||||
lv_draw_rect(&cir_area, mask, &cir_style, opa_scale);
|
||||
|
||||
cir_x = ((r - thick_half) * lv_trigo_sin(ext->angle_end) >> LV_TRIGO_SHIFT);
|
||||
cir_y = ((r - thick_half) * lv_trigo_sin(ext->angle_end + 90) >> LV_TRIGO_SHIFT);
|
||||
|
||||
cir_area.x1 = cir_x + x - thick_half;
|
||||
cir_area.y1 = cir_y + y - thick_half;
|
||||
cir_area.x2 = cir_x + x + thick_half;
|
||||
cir_area.y2 = cir_y + y + thick_half;
|
||||
|
||||
lv_draw_rect(&cir_area, mask, &cir_style, opa_scale);
|
||||
}
|
||||
|
||||
}
|
||||
/*Post draw when the children are drawn*/
|
||||
else if(mode == LV_DESIGN_DRAW_POST) {
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal function of the arc
|
||||
* @param arc pointer to a arc object
|
||||
* @param sign a signal type from lv_signal_t enum
|
||||
* @param param pointer to a signal specific variable
|
||||
* @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
|
||||
*/
|
||||
static lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param)
|
||||
{
|
||||
lv_res_t res;
|
||||
|
||||
/* Include the ancient signal function */
|
||||
res = ancestor_signal(arc, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
|
||||
|
||||
if(sign == LV_SIGNAL_CLEANUP) {
|
||||
/*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_arc";
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
127
src/lv_objx/lv_arc.h
Normal file
127
src/lv_objx/lv_arc.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @file lv_arc.h
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LV_ARC_H
|
||||
#define LV_ARC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if LV_USE_ARC != 0
|
||||
|
||||
#include "../lv_core/lv_obj.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
/*Data of arc*/
|
||||
typedef struct {
|
||||
/*New data for this type */
|
||||
lv_coord_t angle_start;
|
||||
lv_coord_t angle_end;
|
||||
} lv_arc_ext_t;
|
||||
|
||||
|
||||
/*Styles*/
|
||||
enum {
|
||||
LV_ARC_STYLE_MAIN,
|
||||
};
|
||||
typedef uint8_t lv_arc_style_t;
|
||||
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a arc objects
|
||||
* @param par pointer to an object, it will be the parent of the new arc
|
||||
* @param copy pointer to a arc object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created arc
|
||||
*/
|
||||
lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy);
|
||||
|
||||
/*======================
|
||||
* Add/remove functions
|
||||
*=====================*/
|
||||
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set the start and end angles of an arc. 0 deg: bottom, 90 deg: right etc.
|
||||
* @param arc pointer to an arc object
|
||||
* @param start the start angle [0..360]
|
||||
* @param end the end angle [0..360]
|
||||
*/
|
||||
void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end);
|
||||
|
||||
/**
|
||||
* Set a style of a arc.
|
||||
* @param arc pointer to arc object
|
||||
* @param type which style should be set
|
||||
* @param style pointer to a style
|
||||
* */
|
||||
void lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, lv_style_t *style);
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Get the start angle of an arc.
|
||||
* @param arc pointer to an arc object
|
||||
* @return the start angle [0..360]
|
||||
*/
|
||||
uint16_t lv_arc_get_angle_start(lv_obj_t * arc);
|
||||
|
||||
/**
|
||||
* Get the end angle of an arc.
|
||||
* @param arc pointer to an arc object
|
||||
* @return the end angle [0..360]
|
||||
*/
|
||||
uint16_t lv_arc_get_angle_end(lv_obj_t * arc);
|
||||
|
||||
/**
|
||||
* Get style of a arc.
|
||||
* @param arc pointer to arc object
|
||||
* @param type which style should be get
|
||||
* @return style pointer to the style
|
||||
* */
|
||||
lv_style_t * lv_arc_get_style(const lv_obj_t * arc, lv_arc_style_t type);
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_ARC*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_ARC_H*/
|
||||
479
src/lv_objx/lv_bar.c
Normal file
479
src/lv_objx/lv_bar.c
Normal file
@@ -0,0 +1,479 @@
|
||||
|
||||
|
||||
/**
|
||||
* @file lv_bar.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_bar.h"
|
||||
#if LV_USE_BAR != 0
|
||||
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
#include "../lv_misc/lv_anim.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode_t mode);
|
||||
static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param);
|
||||
|
||||
static void lv_bar_animate(void * bar, int32_t value);
|
||||
static void lv_bar_anim_ready(void * bar);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_design_cb_t ancestor_design_f;
|
||||
static lv_signal_cb_t ancestor_signal;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a bar objects
|
||||
* @param par pointer to an object, it will be the parent of the new bar
|
||||
* @param copy pointer to a bar object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created bar
|
||||
*/
|
||||
lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
{
|
||||
LV_LOG_TRACE("lv_bar create started");
|
||||
|
||||
/*Create the ancestor basic object*/
|
||||
lv_obj_t * new_bar = lv_obj_create(par, copy);
|
||||
lv_mem_assert(new_bar);
|
||||
if(new_bar == NULL) return NULL;
|
||||
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_bar);
|
||||
if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_bar);
|
||||
|
||||
/*Allocate the object type specific extended data*/
|
||||
lv_bar_ext_t * ext = lv_obj_allocate_ext_attr(new_bar, sizeof(lv_bar_ext_t));
|
||||
lv_mem_assert(ext);
|
||||
if(ext == NULL) return NULL;
|
||||
|
||||
ext->min_value = 0;
|
||||
ext->max_value = 100;
|
||||
ext->cur_value = 0;
|
||||
ext->anim_time = 200;
|
||||
ext->anim_start = 0;
|
||||
ext->anim_end = 0;
|
||||
ext->anim_state = LV_BAR_ANIM_STATE_INV;
|
||||
ext->sym = 0;
|
||||
ext->style_indic = &lv_style_pretty_color;
|
||||
|
||||
lv_obj_set_signal_cb(new_bar, lv_bar_signal);
|
||||
lv_obj_set_design_cb(new_bar, lv_bar_design);
|
||||
|
||||
/*Init the new bar object*/
|
||||
if(copy == NULL) {
|
||||
lv_obj_set_click(new_bar, false);
|
||||
lv_obj_set_size(new_bar, LV_DPI * 2, LV_DPI / 3);
|
||||
lv_bar_set_value(new_bar, ext->cur_value, false);
|
||||
|
||||
lv_theme_t * th = lv_theme_get_current();
|
||||
if(th) {
|
||||
lv_bar_set_style(new_bar, LV_BAR_STYLE_BG, th->style.bar.bg);
|
||||
lv_bar_set_style(new_bar, LV_BAR_STYLE_INDIC, th->style.bar.indic);
|
||||
} else {
|
||||
lv_obj_set_style(new_bar, &lv_style_pretty);
|
||||
}
|
||||
} else {
|
||||
lv_bar_ext_t * ext_copy = lv_obj_get_ext_attr(copy);
|
||||
ext->min_value = ext_copy->min_value;
|
||||
ext->max_value = ext_copy->max_value;
|
||||
ext->cur_value = ext_copy->cur_value;
|
||||
ext->style_indic = ext_copy->style_indic;
|
||||
ext->sym = ext_copy->sym;
|
||||
/*Refresh the style with new signal function*/
|
||||
lv_obj_refresh_style(new_bar);
|
||||
|
||||
lv_bar_set_value(new_bar, ext->cur_value, false);
|
||||
}
|
||||
|
||||
LV_LOG_INFO("bar created");
|
||||
|
||||
return new_bar;
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set a new value on the bar
|
||||
* @param bar pointer to a bar object
|
||||
* @param value new value
|
||||
* @param anim true: set the value with an animation; false: change the value immediatelly
|
||||
*/
|
||||
void lv_bar_set_value(lv_obj_t * bar, int16_t value, bool anim)
|
||||
{
|
||||
#if LV_USE_ANIMATION == 0
|
||||
anim = false;
|
||||
#endif
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
if(ext->cur_value == value) return;
|
||||
|
||||
int16_t new_value;
|
||||
new_value = value > ext->max_value ? ext->max_value : value;
|
||||
new_value = new_value < ext->min_value ? ext->min_value : new_value;
|
||||
|
||||
if(ext->cur_value == new_value) return;
|
||||
|
||||
if(anim == false) {
|
||||
ext->cur_value = new_value;
|
||||
lv_obj_invalidate(bar);
|
||||
} else {
|
||||
#if LV_USE_ANIMATION
|
||||
/*No animation in progress -> simply set the values*/
|
||||
if(ext->anim_state == LV_BAR_ANIM_STATE_INV) {
|
||||
ext->anim_start = ext->cur_value;
|
||||
ext->anim_end = new_value;
|
||||
}
|
||||
/*Animation in progress. Start from the animation end value*/
|
||||
else {
|
||||
ext->anim_start = ext->anim_end;
|
||||
ext->anim_end = new_value;
|
||||
}
|
||||
|
||||
lv_anim_t a;
|
||||
a.var = bar;
|
||||
a.start = LV_BAR_ANIM_STATE_START;
|
||||
a.end = LV_BAR_ANIM_STATE_END;
|
||||
a.fp = (lv_anim_fp_t)lv_bar_animate;
|
||||
a.path = lv_anim_path_linear;
|
||||
a.end_cb = lv_bar_anim_ready;
|
||||
a.act_time = 0;
|
||||
a.time = ext->anim_time;
|
||||
a.playback = 0;
|
||||
a.playback_pause = 0;
|
||||
a.repeat = 0;
|
||||
a.repeat_pause = 0;
|
||||
|
||||
lv_anim_create(&a);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set minimum and the maximum values of a bar
|
||||
* @param bar pointer to the bar object
|
||||
* @param min minimum value
|
||||
* @param max maximum value
|
||||
*/
|
||||
void lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max)
|
||||
{
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
if(ext->min_value == min && ext->max_value == max) return;
|
||||
|
||||
ext->max_value = max;
|
||||
ext->min_value = min;
|
||||
if(ext->cur_value > max) {
|
||||
ext->cur_value = max;
|
||||
lv_bar_set_value(bar, ext->cur_value, false);
|
||||
}
|
||||
if(ext->cur_value < min) {
|
||||
ext->cur_value = min;
|
||||
lv_bar_set_value(bar, ext->cur_value, false);
|
||||
}
|
||||
lv_obj_invalidate(bar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the bar symmetric to zero. The indicator will grow from zero instead of the minimum position.
|
||||
* @param bar pointer to a bar object
|
||||
* @param en true: enable disable symmetric behavior; false: disable
|
||||
*/
|
||||
void lv_bar_set_sym(lv_obj_t * bar, bool en)
|
||||
{
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
ext->sym = en ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a style of a bar
|
||||
* @param bar pointer to a bar object
|
||||
* @param type which style should be set
|
||||
* @param style pointer to a style
|
||||
*/
|
||||
void lv_bar_set_style(lv_obj_t * bar, lv_bar_style_t type, lv_style_t * style)
|
||||
{
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
|
||||
switch(type) {
|
||||
case LV_BAR_STYLE_BG:
|
||||
lv_obj_set_style(bar, style);
|
||||
break;
|
||||
case LV_BAR_STYLE_INDIC:
|
||||
ext->style_indic = style;
|
||||
lv_obj_refresh_ext_size(bar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Get the value of a bar
|
||||
* @param bar pointer to a bar object
|
||||
* @return the value of the bar
|
||||
*/
|
||||
int16_t lv_bar_get_value(const lv_obj_t * bar)
|
||||
{
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
/*If animated tell that it's already at the end value*/
|
||||
if(ext->anim_state != LV_BAR_ANIM_STATE_INV) return ext->anim_end;
|
||||
/*No animation, simple return the current value*/
|
||||
else return ext->cur_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum value of a bar
|
||||
* @param bar pointer to a bar object
|
||||
* @return the minimum value of the bar
|
||||
*/
|
||||
int16_t lv_bar_get_min_value(const lv_obj_t * bar)
|
||||
{
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
return ext->min_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum value of a bar
|
||||
* @param bar pointer to a bar object
|
||||
* @return the maximum value of the bar
|
||||
*/
|
||||
int16_t lv_bar_get_max_value(const lv_obj_t * bar)
|
||||
{
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
return ext->max_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the bar is symmetric or not.
|
||||
* @param bar pointer to a bar object
|
||||
* @return true: symmetric is enabled; false: disable
|
||||
*/
|
||||
bool lv_bar_get_sym(lv_obj_t * bar)
|
||||
{
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
return ext->sym ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a style of a bar
|
||||
* @param bar pointer to a bar object
|
||||
* @param type which style should be get
|
||||
* @return style pointer to a style
|
||||
*/
|
||||
lv_style_t * lv_bar_get_style(const lv_obj_t * bar, lv_bar_style_t type)
|
||||
{
|
||||
lv_style_t * style = NULL;
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
|
||||
switch(type) {
|
||||
case LV_BAR_STYLE_BG:
|
||||
style = lv_obj_get_style(bar);
|
||||
break;
|
||||
case LV_BAR_STYLE_INDIC:
|
||||
style = ext->style_indic;
|
||||
break;
|
||||
default:
|
||||
style = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Handle the drawing related tasks of the bars
|
||||
* @param bar pointer to an object
|
||||
* @param mask the object will be drawn only in this area
|
||||
* @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
|
||||
* (return 'true' if yes)
|
||||
* LV_DESIGN_DRAW: draw the object (always return 'true')
|
||||
* LV_DESIGN_DRAW_POST: drawing after every children are drawn
|
||||
* @param return true/false, depends on 'mode'
|
||||
*/
|
||||
static bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode_t mode)
|
||||
{
|
||||
if(mode == LV_DESIGN_COVER_CHK) {
|
||||
/*Return false if the object is not covers the mask area*/
|
||||
return ancestor_design_f(bar, mask, mode);
|
||||
} else if(mode == LV_DESIGN_DRAW_MAIN) {
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(bar);
|
||||
|
||||
#if LV_USE_GROUP == 0
|
||||
ancestor_design_f(bar, mask, mode);
|
||||
#else
|
||||
/* Draw the borders later if the bar is focused.
|
||||
* At value = 100% the indicator can cover to whole background and the focused style won't be visible*/
|
||||
if(lv_obj_is_focused(bar)) {
|
||||
lv_style_t * style_bg = lv_bar_get_style(bar, LV_BAR_STYLE_BG);
|
||||
lv_style_t style_tmp;
|
||||
lv_style_copy(&style_tmp, style_bg);
|
||||
style_tmp.body.border.width = 0;
|
||||
lv_draw_rect(&bar->coords, mask, &style_tmp, opa_scale);
|
||||
} else {
|
||||
ancestor_design_f(bar, mask, mode);
|
||||
}
|
||||
#endif
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
|
||||
if(ext->cur_value != ext->min_value || ext->sym || ext->anim_start != LV_BAR_ANIM_STATE_INV) {
|
||||
lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC);
|
||||
lv_area_t indic_area;
|
||||
lv_area_copy(&indic_area, &bar->coords);
|
||||
indic_area.x1 += style_indic->body.padding.left;
|
||||
indic_area.x2 -= style_indic->body.padding.right;
|
||||
indic_area.y1 += style_indic->body.padding.top;
|
||||
indic_area.y2 -= style_indic->body.padding.bottom;
|
||||
|
||||
lv_coord_t w = lv_area_get_width(&indic_area);
|
||||
lv_coord_t h = lv_area_get_height(&indic_area);
|
||||
|
||||
if(w >= h) {
|
||||
/*Horizontal*/
|
||||
if(ext->anim_state != LV_BAR_ANIM_STATE_INV) {
|
||||
/*Calculate the coordinates of anim. start and end*/
|
||||
lv_coord_t anim_start_x = (int32_t)((int32_t)w * (ext->anim_start - ext->min_value)) / (ext->max_value - ext->min_value);
|
||||
lv_coord_t anim_end_x = (int32_t)((int32_t)w * (ext->anim_end - ext->min_value)) / (ext->max_value - ext->min_value);
|
||||
|
||||
/*Calculate the real position based on `anim_state` (between `anim_start` and `anim_end`)*/
|
||||
indic_area.x2 = anim_start_x + (((anim_end_x - anim_start_x) * ext->anim_state) >> LV_BAR_ANIM_STATE_NORM);
|
||||
} else {
|
||||
indic_area.x2 = (int32_t)((int32_t)w * (ext->cur_value - ext->min_value)) / (ext->max_value - ext->min_value);
|
||||
}
|
||||
|
||||
indic_area.x2 = indic_area.x1 + indic_area.x2 - 1;
|
||||
if(ext->sym && ext->min_value < 0 && ext->max_value > 0) {
|
||||
/*Calculate the coordinate of the zero point*/
|
||||
lv_coord_t zero;
|
||||
zero = indic_area.x1 + (-ext->min_value * w) / (ext->max_value - ext->min_value);
|
||||
if(indic_area.x2 > zero) indic_area.x1 = zero;
|
||||
else {
|
||||
indic_area.x1 = indic_area.x2;
|
||||
indic_area.x2 = zero;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(ext->anim_state != LV_BAR_ANIM_STATE_INV) {
|
||||
/*Calculate the coordinates of anim. start and end*/
|
||||
lv_coord_t anim_start_y = (int32_t)((int32_t)h * (ext->anim_start - ext->min_value)) / (ext->max_value - ext->min_value);
|
||||
lv_coord_t anim_end_y = (int32_t)((int32_t)h * (ext->anim_end - ext->min_value)) / (ext->max_value - ext->min_value);
|
||||
|
||||
/*Calculate the real position based on `anim_state` (between `anim_start` and `anim_end`)*/
|
||||
indic_area.y1 = anim_start_y + (((anim_end_y - anim_start_y) * ext->anim_state) >> LV_BAR_ANIM_STATE_NORM);
|
||||
} else {
|
||||
indic_area.y1 = (int32_t)((int32_t)h * (ext->cur_value - ext->min_value)) / (ext->max_value - ext->min_value);
|
||||
}
|
||||
|
||||
indic_area.y1 = indic_area.y2 - indic_area.y1 + 1;
|
||||
|
||||
if(ext->sym && ext->min_value < 0 && ext->max_value > 0) {
|
||||
/*Calculate the coordinate of the zero point*/
|
||||
lv_coord_t zero;
|
||||
zero = indic_area.y2 - (-ext->min_value * h) / (ext->max_value - ext->min_value);
|
||||
if(indic_area.y1 < zero) indic_area.y2 = zero;
|
||||
else {
|
||||
indic_area.y2 = indic_area.y1;
|
||||
indic_area.y1 = zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*Draw the indicator*/
|
||||
lv_draw_rect(&indic_area, mask, style_indic, opa_scale);
|
||||
}
|
||||
} else if(mode == LV_DESIGN_DRAW_POST) {
|
||||
#if LV_USE_GROUP
|
||||
/*Draw the border*/
|
||||
if(lv_obj_is_focused(bar)) {
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(bar);
|
||||
lv_style_t * style_bg = lv_bar_get_style(bar, LV_BAR_STYLE_BG);
|
||||
lv_style_t style_tmp;
|
||||
lv_style_copy(&style_tmp, style_bg);
|
||||
style_tmp.body.opa = LV_OPA_TRANSP;
|
||||
style_tmp.body.shadow.width = 0;
|
||||
lv_draw_rect(&bar->coords, mask, &style_tmp, opa_scale);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal function of the bar
|
||||
* @param bar pointer to a bar object
|
||||
* @param sign a signal type from lv_signal_t enum
|
||||
* @param param pointer to a signal specific variable
|
||||
* @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
|
||||
*/
|
||||
static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param)
|
||||
{
|
||||
lv_res_t res;
|
||||
|
||||
/* Include the ancient signal function */
|
||||
res = ancestor_signal(bar, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
|
||||
if(sign == LV_SIGNAL_REFR_EXT_SIZE) {
|
||||
lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC);
|
||||
if(style_indic->body.shadow.width > bar->ext_size) bar->ext_size = style_indic->body.shadow.width;
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_bar";
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void lv_bar_animate(void * bar, int32_t value)
|
||||
{
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
ext->anim_state = value;
|
||||
lv_obj_invalidate(bar);
|
||||
}
|
||||
|
||||
static void lv_bar_anim_ready(void * bar)
|
||||
{
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
ext->anim_state = LV_BAR_ANIM_STATE_INV;
|
||||
lv_bar_set_value(bar, ext->anim_end, false);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
160
src/lv_objx/lv_bar.h
Normal file
160
src/lv_objx/lv_bar.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* @file lv_bar.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_BAR_H
|
||||
#define LV_BAR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if LV_USE_BAR != 0
|
||||
|
||||
#include "../lv_core/lv_obj.h"
|
||||
#include "lv_cont.h"
|
||||
#include "lv_btn.h"
|
||||
#include "lv_label.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_BAR_ANIM_STATE_START 0
|
||||
#define LV_BAR_ANIM_STATE_END 256
|
||||
#define LV_BAR_ANIM_STATE_INV -1
|
||||
#define LV_BAR_ANIM_STATE_NORM 8 /*log2(LV_BAR_ANIM_STATE_END) used to normalize data*/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/*Data of bar*/
|
||||
typedef struct
|
||||
{
|
||||
/*No inherited ext*/ /*Ext. of ancestor*/
|
||||
/*New data for this type */
|
||||
int16_t cur_value; /*Current value of the bar*/
|
||||
int16_t min_value; /*Minimum value of the bar*/
|
||||
int16_t max_value; /*Maximum value of the bar*/
|
||||
int16_t anim_start;
|
||||
int16_t anim_end;
|
||||
int16_t anim_state;
|
||||
uint16_t anim_time;
|
||||
uint8_t sym :1; /*Symmetric: means the center is around zero value*/
|
||||
lv_style_t *style_indic; /*Style of the indicator*/
|
||||
} lv_bar_ext_t;
|
||||
|
||||
enum {
|
||||
LV_BAR_STYLE_BG,
|
||||
LV_BAR_STYLE_INDIC,
|
||||
};
|
||||
typedef uint8_t lv_bar_style_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a bar objects
|
||||
* @param par pointer to an object, it will be the parent of the new bar
|
||||
* @param copy pointer to a bar object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created bar
|
||||
*/
|
||||
lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy);
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set a new value on the bar
|
||||
* @param bar pointer to a bar object
|
||||
* @param value new value
|
||||
* @param anim true: set the value with an animation; false: change the value immediatelly
|
||||
*/
|
||||
void lv_bar_set_value(lv_obj_t * bar, int16_t value, bool anim);
|
||||
|
||||
/**
|
||||
* Set minimum and the maximum values of a bar
|
||||
* @param bar pointer to the bar object
|
||||
* @param min minimum value
|
||||
* @param max maximum value
|
||||
*/
|
||||
void lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max);
|
||||
|
||||
/**
|
||||
* Make the bar symmetric to zero. The indicator will grow from zero instead of the minimum position.
|
||||
* @param bar pointer to a bar object
|
||||
* @param en true: enable disable symmetric behavior; false: disable
|
||||
*/
|
||||
void lv_bar_set_sym(lv_obj_t * bar, bool en);
|
||||
|
||||
/**
|
||||
* Set a style of a bar
|
||||
* @param bar pointer to a bar object
|
||||
* @param type which style should be set
|
||||
* @param style pointer to a style
|
||||
*/
|
||||
void lv_bar_set_style(lv_obj_t *bar, lv_bar_style_t type, lv_style_t *style);
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Get the value of a bar
|
||||
* @param bar pointer to a bar object
|
||||
* @return the value of the bar
|
||||
*/
|
||||
int16_t lv_bar_get_value(const lv_obj_t * bar);
|
||||
|
||||
/**
|
||||
* Get the minimum value of a bar
|
||||
* @param bar pointer to a bar object
|
||||
* @return the minimum value of the bar
|
||||
*/
|
||||
int16_t lv_bar_get_min_value(const lv_obj_t * bar);
|
||||
|
||||
/**
|
||||
* Get the maximum value of a bar
|
||||
* @param bar pointer to a bar object
|
||||
* @return the maximum value of the bar
|
||||
*/
|
||||
int16_t lv_bar_get_max_value(const lv_obj_t * bar);
|
||||
|
||||
/**
|
||||
* Get whether the bar is symmetric or not.
|
||||
* @param bar pointer to a bar object
|
||||
* @return true: symmetric is enabled; false: disable
|
||||
*/
|
||||
bool lv_bar_get_sym(lv_obj_t * bar);
|
||||
|
||||
/**
|
||||
* Get a style of a bar
|
||||
* @param bar pointer to a bar object
|
||||
* @param type which style should be get
|
||||
* @return style pointer to a style
|
||||
*/
|
||||
lv_style_t * lv_bar_get_style(const lv_obj_t *bar, lv_bar_style_t type);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_BAR*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_BAR_H*/
|
||||
705
src/lv_objx/lv_btn.c
Normal file
705
src/lv_objx/lv_btn.c
Normal file
@@ -0,0 +1,705 @@
|
||||
/**
|
||||
* @file lv_btn.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_btn.h"
|
||||
#if LV_USE_BTN != 0
|
||||
|
||||
#include <string.h>
|
||||
#include "../lv_core/lv_group.h"
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
#include "../lv_misc/lv_area.h"
|
||||
#include "../lv_misc/lv_color.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_BTN_INK_VALUE_MAX 256
|
||||
#define LV_BTN_INK_VALUE_MAX_SHIFT 8
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static bool lv_btn_design(lv_obj_t * btn, const lv_area_t * mask, lv_design_mode_t mode);
|
||||
static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param);
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
static void lv_btn_ink_effect_anim(lv_obj_t * btn, int32_t val);
|
||||
static void lv_btn_ink_effect_anim_ready(void * p);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_signal_cb_t ancestor_signal;
|
||||
static lv_design_cb_t ancestor_design;
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
static lv_coord_t ink_act_value;
|
||||
static lv_obj_t * ink_obj;
|
||||
static lv_btn_state_t ink_bg_state;
|
||||
static lv_btn_state_t ink_top_state;
|
||||
static bool ink_ready;
|
||||
static bool ink_playback;
|
||||
static lv_point_t ink_point;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a button objects
|
||||
* @param par pointer to an object, it will be the parent of the new button
|
||||
* @param copy pointer to a button object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created button
|
||||
*/
|
||||
lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
{
|
||||
LV_LOG_TRACE("button create started");
|
||||
|
||||
lv_obj_t * new_btn;
|
||||
|
||||
new_btn = lv_cont_create(par, copy);
|
||||
lv_mem_assert(new_btn);
|
||||
if(new_btn == NULL) return NULL;
|
||||
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_btn);
|
||||
if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_btn);
|
||||
|
||||
/*Allocate the extended data*/
|
||||
lv_btn_ext_t * ext = lv_obj_allocate_ext_attr(new_btn, sizeof(lv_btn_ext_t));
|
||||
lv_mem_assert(ext);
|
||||
if(ext == NULL) return NULL;
|
||||
|
||||
ext->state = LV_BTN_STATE_REL;
|
||||
|
||||
ext->styles[LV_BTN_STATE_REL] = &lv_style_btn_rel;
|
||||
ext->styles[LV_BTN_STATE_PR] = &lv_style_btn_pr;
|
||||
ext->styles[LV_BTN_STATE_TGL_REL] = &lv_style_btn_tgl_rel;
|
||||
ext->styles[LV_BTN_STATE_TGL_PR] = &lv_style_btn_tgl_pr;
|
||||
ext->styles[LV_BTN_STATE_INA] = &lv_style_btn_ina;
|
||||
|
||||
ext->toggle = 0;
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
ext->ink_in_time = 0;
|
||||
ext->ink_wait_time = 0;
|
||||
ext->ink_out_time = 0;
|
||||
#endif
|
||||
|
||||
lv_obj_set_signal_cb(new_btn, lv_btn_signal);
|
||||
lv_obj_set_design_cb(new_btn, lv_btn_design);
|
||||
|
||||
/*If no copy do the basic initialization*/
|
||||
if(copy == NULL) {
|
||||
/*Set layout if the button is not a screen*/
|
||||
if(par != NULL) {
|
||||
lv_btn_set_layout(new_btn, LV_LAYOUT_CENTER);
|
||||
}
|
||||
|
||||
lv_obj_set_click(new_btn, true); /*Be sure the button is clickable*/
|
||||
|
||||
/*Set the default styles*/
|
||||
lv_theme_t * th = lv_theme_get_current();
|
||||
if(th) {
|
||||
lv_btn_set_style(new_btn, LV_BTN_STYLE_REL, th->style.btn.rel);
|
||||
lv_btn_set_style(new_btn, LV_BTN_STYLE_PR, th->style.btn.pr);
|
||||
lv_btn_set_style(new_btn, LV_BTN_STYLE_TGL_REL, th->style.btn.tgl_rel);
|
||||
lv_btn_set_style(new_btn, LV_BTN_STYLE_TGL_PR, th->style.btn.tgl_pr);
|
||||
lv_btn_set_style(new_btn, LV_BTN_STYLE_INA, th->style.btn.ina);
|
||||
} else {
|
||||
lv_obj_set_style(new_btn, ext->styles[LV_BTN_STATE_REL]);
|
||||
}
|
||||
}
|
||||
/*Copy 'copy'*/
|
||||
else {
|
||||
lv_btn_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
|
||||
ext->state = copy_ext->state;
|
||||
ext->toggle = copy_ext->toggle;
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
ext->ink_in_time = copy_ext->ink_in_time;
|
||||
ext->ink_wait_time = copy_ext->ink_wait_time;
|
||||
ext->ink_out_time = copy_ext->ink_out_time;
|
||||
#endif
|
||||
memcpy(ext->styles, copy_ext->styles, sizeof(ext->styles));
|
||||
|
||||
/*Refresh the style with new signal function*/
|
||||
lv_obj_refresh_style(new_btn);
|
||||
}
|
||||
|
||||
LV_LOG_INFO("button created");
|
||||
|
||||
return new_btn;
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Enable the toggled states
|
||||
* @param btn pointer to a button object
|
||||
* @param tgl true: enable toggled states, false: disable
|
||||
*/
|
||||
void lv_btn_set_toggle(lv_obj_t * btn, bool tgl)
|
||||
{
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
|
||||
ext->toggle = tgl != false ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state of the button
|
||||
* @param btn pointer to a button object
|
||||
* @param state the new state of the button (from lv_btn_state_t enum)
|
||||
*/
|
||||
void lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state)
|
||||
{
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
if(ext->state != state) {
|
||||
ext->state = state;
|
||||
lv_obj_set_style(btn, ext->styles[state]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the state of the button (ON->OFF, OFF->ON)
|
||||
* @param btn pointer to a button object
|
||||
*/
|
||||
void lv_btn_toggle(lv_obj_t * btn)
|
||||
{
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
switch(ext->state) {
|
||||
case LV_BTN_STATE_REL:
|
||||
lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);
|
||||
break;
|
||||
case LV_BTN_STATE_PR:
|
||||
lv_btn_set_state(btn, LV_BTN_STATE_TGL_PR);
|
||||
break;
|
||||
case LV_BTN_STATE_TGL_REL:
|
||||
lv_btn_set_state(btn, LV_BTN_STATE_REL);
|
||||
break;
|
||||
case LV_BTN_STATE_TGL_PR:
|
||||
lv_btn_set_state(btn, LV_BTN_STATE_PR);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time of the ink effect (draw a circle on click to animate in the new state)
|
||||
* @param btn pointer to a button object
|
||||
* @param time the time of the ink animation
|
||||
*/
|
||||
void lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time)
|
||||
{
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
ext->ink_in_time = time;
|
||||
#else
|
||||
(void)btn; /*Unused*/
|
||||
(void)time; /*Unused*/
|
||||
LV_LOG_WARN("`lv_btn_set_ink_ink_time` has no effect if LV_BTN_INK_EFEFCT or LV_USE_ANIMATION is disabled")
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the wait time before the ink disappears
|
||||
* @param btn pointer to a button object
|
||||
* @param time the time of the ink animation
|
||||
*/
|
||||
void lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time)
|
||||
{
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
ext->ink_wait_time = time;
|
||||
#else
|
||||
(void)btn; /*Unused*/
|
||||
(void)time; /*Unused*/
|
||||
LV_LOG_WARN("`lv_btn_set_ink_wait_time` has no effect if LV_BTN_INK_EFEFCT or LV_USE_ANIMATION is disabled")
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time of the ink out effect (animate to the released state)
|
||||
* @param btn pointer to a button object
|
||||
* @param time the time of the ink animation
|
||||
*/
|
||||
void lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time)
|
||||
{
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
ext->ink_out_time = time;
|
||||
#else
|
||||
(void)btn; /*Unused*/
|
||||
(void)time; /*Unused*/
|
||||
LV_LOG_WARN("`lv_btn_set_ink_out_time` has no effect if LV_BTN_INK_EFEFCT or LV_USE_ANIMATION is disabled")
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a style of a button
|
||||
* @param btn pointer to a button object
|
||||
* @param type which style should be set
|
||||
* @param style pointer to a style
|
||||
*/
|
||||
void lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, lv_style_t * style)
|
||||
{
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
|
||||
switch(type) {
|
||||
case LV_BTN_STYLE_REL:
|
||||
ext->styles[LV_BTN_STATE_REL] = style;
|
||||
break;
|
||||
case LV_BTN_STYLE_PR:
|
||||
ext->styles[LV_BTN_STATE_PR] = style;
|
||||
break;
|
||||
case LV_BTN_STYLE_TGL_REL:
|
||||
ext->styles[LV_BTN_STATE_TGL_REL] = style;
|
||||
break;
|
||||
case LV_BTN_STYLE_TGL_PR:
|
||||
ext->styles[LV_BTN_STATE_TGL_PR] = style;
|
||||
break;
|
||||
case LV_BTN_STYLE_INA:
|
||||
ext->styles[LV_BTN_STATE_INA] = style;
|
||||
break;
|
||||
}
|
||||
|
||||
/*Refresh the object with the new style*/
|
||||
lv_obj_set_style(btn, ext->styles[ext->state]);
|
||||
}
|
||||
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Get the current state of the button
|
||||
* @param btn pointer to a button object
|
||||
* @return the state of the button (from lv_btn_state_t enum)
|
||||
*/
|
||||
lv_btn_state_t lv_btn_get_state(const lv_obj_t * btn)
|
||||
{
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
return ext->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the toggle enable attribute of the button
|
||||
* @param btn pointer to a button object
|
||||
* @return ture: toggle enabled, false: disabled
|
||||
*/
|
||||
bool lv_btn_get_toggle(const lv_obj_t * btn)
|
||||
{
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
|
||||
return ext->toggle != 0 ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get time of the ink in effect (draw a circle on click to animate in the new state)
|
||||
* @param btn pointer to a button object
|
||||
* @return the time of the ink animation
|
||||
*/
|
||||
uint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn)
|
||||
{
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
return ext->ink_in_time;
|
||||
#else
|
||||
(void)btn; /*Unused*/
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the wait time before the ink disappears
|
||||
* @param btn pointer to a button object
|
||||
* @return the time of the ink animation
|
||||
*/
|
||||
uint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn)
|
||||
{
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
return ext->ink_wait_time;
|
||||
#else
|
||||
(void)btn; /*Unused*/
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* Get time of the ink out effect (animate to the releases state)
|
||||
* @param btn pointer to a button object
|
||||
* @return the time of the ink animation
|
||||
*/
|
||||
uint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn)
|
||||
{
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
return ext->ink_in_time;
|
||||
#else
|
||||
(void)btn; /*Unused*/
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a style of a button
|
||||
* @param btn pointer to a button object
|
||||
* @param type which style should be get
|
||||
* @return style pointer to a style
|
||||
*/
|
||||
lv_style_t * lv_btn_get_style(const lv_obj_t * btn, lv_btn_style_t type)
|
||||
{
|
||||
lv_style_t * style = NULL;
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
|
||||
switch(type) {
|
||||
case LV_BTN_STYLE_REL:
|
||||
style = ext->styles[LV_BTN_STATE_REL];
|
||||
break;
|
||||
case LV_BTN_STYLE_PR:
|
||||
style = ext->styles[LV_BTN_STATE_PR];
|
||||
break;
|
||||
case LV_BTN_STYLE_TGL_REL:
|
||||
style = ext->styles[LV_BTN_STATE_TGL_REL];
|
||||
break;
|
||||
case LV_BTN_STYLE_TGL_PR:
|
||||
style = ext->styles[LV_BTN_STATE_TGL_PR];
|
||||
break;
|
||||
case LV_BTN_STYLE_INA:
|
||||
style = ext->styles[LV_BTN_STATE_INA];
|
||||
break;
|
||||
default:
|
||||
style = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
/**
|
||||
* Handle the drawing related tasks of the drop down lists
|
||||
* @param btn pointer to an object
|
||||
* @param mask the object will be drawn only in this area
|
||||
* @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
|
||||
* (return 'true' if yes)
|
||||
* LV_DESIGN_DRAW: draw the object (always return 'true')
|
||||
* LV_DESIGN_DRAW_POST: drawing after every children are drawn
|
||||
* @param return true/false, depends on 'mode'
|
||||
*/
|
||||
static bool lv_btn_design(lv_obj_t * btn, const lv_area_t * mask, lv_design_mode_t mode)
|
||||
{
|
||||
if(mode == LV_DESIGN_COVER_CHK) {
|
||||
return false;
|
||||
} else if(mode == LV_DESIGN_DRAW_MAIN) {
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
if(btn != ink_obj) {
|
||||
ancestor_design(btn, mask, mode);
|
||||
} else {
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(btn);
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
|
||||
/*Draw the normal button*/
|
||||
if(ink_playback == false) {
|
||||
lv_style_t style_tmp;
|
||||
lv_style_copy(&style_tmp, ext->styles[ink_bg_state]);
|
||||
style_tmp.body.shadow.width = ext->styles[ink_top_state]->body.shadow.width;
|
||||
lv_draw_rect(&btn->coords, mask, &style_tmp, opa_scale);
|
||||
|
||||
lv_coord_t w = lv_obj_get_width(btn);
|
||||
lv_coord_t h = lv_obj_get_height(btn);
|
||||
lv_coord_t r_max = LV_MATH_MIN(w, h) / 2;
|
||||
|
||||
/*In the first part of the animation increase the size of the circle (ink effect) */
|
||||
lv_area_t cir_area;
|
||||
|
||||
lv_coord_t coord_state = ink_act_value < LV_BTN_INK_VALUE_MAX / 2 ? ink_act_value : LV_BTN_INK_VALUE_MAX / 2;
|
||||
lv_point_t p_act;
|
||||
p_act.x = ink_point.x;
|
||||
p_act.y = ink_point.y;
|
||||
lv_coord_t x_err = (btn->coords.x1 + w / 2) - p_act.x;
|
||||
lv_coord_t y_err = (btn->coords.y1 + h / 2) - p_act.y;
|
||||
|
||||
p_act.x += (x_err * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1);
|
||||
p_act.y += (y_err * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1);
|
||||
|
||||
lv_coord_t half_side = LV_MATH_MAX(w, h) / 2;
|
||||
cir_area.x1 = p_act.x - ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1));
|
||||
cir_area.y1 = p_act.y - ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1));
|
||||
cir_area.x2 = p_act.x + ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1));
|
||||
cir_area.y2 = p_act.y + ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1));
|
||||
|
||||
lv_area_intersect(&cir_area, &btn->coords, &cir_area); /*Limit the area. (It might be too big on the smaller side)*/
|
||||
|
||||
/*In the second part animate the radius. Circle -> body.radius*/
|
||||
lv_coord_t r_state = ink_act_value > LV_BTN_INK_VALUE_MAX / 2 ? ink_act_value - LV_BTN_INK_VALUE_MAX / 2 : 0;
|
||||
|
||||
lv_style_copy(&style_tmp, ext->styles[ink_top_state]);
|
||||
style_tmp.body.radius = r_max + (((ext->styles[ink_bg_state]->body.radius - r_max) * r_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1));
|
||||
style_tmp.body.border.width = 0;
|
||||
|
||||
/*Draw the circle*/
|
||||
lv_draw_rect(&cir_area, mask, &style_tmp, opa_scale);
|
||||
} else {
|
||||
lv_style_t res;
|
||||
lv_style_copy(&res, ext->styles[ink_bg_state]);
|
||||
lv_style_mix(ext->styles[ink_bg_state], ext->styles[ink_top_state], &res, ink_act_value);
|
||||
lv_draw_rect(&btn->coords, mask, &res, opa_scale);
|
||||
|
||||
}
|
||||
}
|
||||
#else
|
||||
ancestor_design(btn, mask, mode);
|
||||
#endif
|
||||
} else if(mode == LV_DESIGN_DRAW_POST) {
|
||||
ancestor_design(btn, mask, mode);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal function of the button
|
||||
* @param btn pointer to a button object
|
||||
* @param sign a signal type from lv_signal_t enum
|
||||
* @param param pointer to a signal specific variable
|
||||
* @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
|
||||
*/
|
||||
static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param)
|
||||
{
|
||||
lv_res_t res;
|
||||
|
||||
/* Include the ancient signal function */
|
||||
res = ancestor_signal(btn, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
bool tgl = lv_btn_get_toggle(btn);
|
||||
|
||||
if(sign == LV_SIGNAL_PRESSED) {
|
||||
/*Refresh the state*/
|
||||
if(ext->state == LV_BTN_STATE_REL) {
|
||||
lv_btn_set_state(btn, LV_BTN_STATE_PR);
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
ink_bg_state = LV_BTN_STATE_REL;
|
||||
ink_top_state = LV_BTN_STATE_PR;
|
||||
#endif
|
||||
} else if(ext->state == LV_BTN_STATE_TGL_REL) {
|
||||
lv_btn_set_state(btn, LV_BTN_STATE_TGL_PR);
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
ink_bg_state = LV_BTN_STATE_TGL_REL;
|
||||
ink_top_state = LV_BTN_STATE_TGL_PR;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
/*Forget the old inked button*/
|
||||
if(ink_obj != NULL && ink_obj != btn) {
|
||||
lv_anim_del(ink_obj, (lv_anim_fp_t)lv_btn_ink_effect_anim);
|
||||
lv_obj_invalidate(ink_obj);
|
||||
ink_obj = NULL;
|
||||
}
|
||||
/*Save the new data for inking and start it's animation if enabled*/
|
||||
if(ext->ink_in_time > 0) {
|
||||
ink_obj = btn;
|
||||
ink_playback = false;
|
||||
ink_ready = false;
|
||||
lv_indev_get_point(lv_indev_get_act(), &ink_point);
|
||||
|
||||
lv_anim_t a;
|
||||
a.var = btn;
|
||||
a.start = 0;
|
||||
a.end = LV_BTN_INK_VALUE_MAX;
|
||||
a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim;
|
||||
a.path = lv_anim_path_linear;
|
||||
a.end_cb = lv_btn_ink_effect_anim_ready;
|
||||
a.act_time = 0;
|
||||
a.time = ext->ink_in_time;
|
||||
a.playback = 0;
|
||||
a.playback_pause = 0;
|
||||
a.repeat = 0;
|
||||
a.repeat_pause = 0;
|
||||
lv_anim_create(&a);
|
||||
}
|
||||
#endif
|
||||
} else if(sign == LV_SIGNAL_PRESS_LOST) {
|
||||
/*Refresh the state*/
|
||||
if(ext->state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL);
|
||||
else if(ext->state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);
|
||||
} else if(sign == LV_SIGNAL_PRESSING) {
|
||||
/*When the button begins to drag revert pressed states to released*/
|
||||
if(lv_indev_is_dragging(param) != false) {
|
||||
if(ext->state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL);
|
||||
else if(ext->state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);
|
||||
}
|
||||
} else if(sign == LV_SIGNAL_RELEASED) {
|
||||
/*If not dragged and it was not long press action then
|
||||
*change state and run the action*/
|
||||
if(lv_indev_is_dragging(param) == false) {
|
||||
if(ext->state == LV_BTN_STATE_PR && tgl == false) {
|
||||
lv_btn_set_state(btn, LV_BTN_STATE_REL);
|
||||
} else if(ext->state == LV_BTN_STATE_TGL_PR && tgl == false) {
|
||||
lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);
|
||||
} else if(ext->state == LV_BTN_STATE_PR && tgl == true) {
|
||||
lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);
|
||||
} else if(ext->state == LV_BTN_STATE_TGL_PR && tgl == true) {
|
||||
lv_btn_set_state(btn, LV_BTN_STATE_REL);
|
||||
}
|
||||
|
||||
if(tgl) {
|
||||
res = lv_obj_send_event(btn, LV_EVENT_VALUE_CHANGED);
|
||||
if(res != LV_RES_OK) return res;
|
||||
}
|
||||
|
||||
} else { /*If dragged change back the state*/
|
||||
if(ext->state == LV_BTN_STATE_PR) {
|
||||
lv_btn_set_state(btn, LV_BTN_STATE_REL);
|
||||
} else if(ext->state == LV_BTN_STATE_TGL_PR) {
|
||||
lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
/*Draw the toggled state in the inking instead*/
|
||||
if(ext->toggle) {
|
||||
ink_top_state = ext->state;
|
||||
}
|
||||
/*If not a toggle button and the "IN" inking is ready then start an "OUT" inking*/
|
||||
else if(ink_ready && ext->ink_out_time > 0) {
|
||||
ink_obj = btn;
|
||||
ink_playback = true; /*It is the playback. If not set `lv_btn_ink_effect_anim_ready` will start its own playback*/
|
||||
lv_indev_get_point(lv_indev_get_act(), &ink_point);
|
||||
|
||||
lv_anim_t a;
|
||||
a.var = ink_obj;
|
||||
a.start = LV_BTN_INK_VALUE_MAX;
|
||||
a.end = 0;
|
||||
a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim;
|
||||
a.path = lv_anim_path_linear;
|
||||
a.end_cb = lv_btn_ink_effect_anim_ready;
|
||||
a.act_time = 0;
|
||||
a.time = ext->ink_out_time;
|
||||
a.playback = 0;
|
||||
a.playback_pause = 0;
|
||||
a.repeat = 0;
|
||||
a.repeat_pause = 0;
|
||||
lv_anim_create(&a);
|
||||
}
|
||||
#endif
|
||||
} else if(sign == LV_SIGNAL_CONTROLL) {
|
||||
char c = *((char *)param);
|
||||
if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_UP) {
|
||||
if(lv_btn_get_toggle(btn)) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);
|
||||
|
||||
} else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_DOWN) {
|
||||
if(lv_btn_get_toggle(btn)) lv_btn_set_state(btn, LV_BTN_STATE_REL);
|
||||
}
|
||||
// else if(c == LV_GROUP_KEY_ENTER) {
|
||||
// if(lv_btn_get_toggle(btn)) {
|
||||
// if(state == LV_BTN_STATE_REL || state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);
|
||||
// else if(state == LV_BTN_STATE_TGL_REL || state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL);
|
||||
// } else {
|
||||
// if(state == LV_BTN_STATE_REL || state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL);
|
||||
// else if(state == LV_BTN_STATE_TGL_REL || state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);
|
||||
// }
|
||||
// res = lv_obj_send_event(btn, LV_EVENT_VALUE_CHANGED);
|
||||
// if(res != LV_RES_OK) return res;
|
||||
// }
|
||||
} else if(sign == LV_SIGNAL_CLEANUP) {
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
if(btn == ink_obj) {
|
||||
lv_anim_del(ink_obj, (lv_anim_fp_t)lv_btn_ink_effect_anim);
|
||||
ink_obj = NULL;
|
||||
}
|
||||
#endif
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_btn";
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
|
||||
/**
|
||||
* The animator function of inking. CAlled to increase the radius of ink
|
||||
* @param btn pointer to the animated button
|
||||
* @param val the new radius
|
||||
*/
|
||||
static void lv_btn_ink_effect_anim(lv_obj_t * btn, int32_t val)
|
||||
{
|
||||
if(btn) {
|
||||
ink_act_value = val;
|
||||
lv_obj_invalidate(btn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to clean up when the ink animation is ready
|
||||
* @param p unused
|
||||
*/
|
||||
static void lv_btn_ink_effect_anim_ready(void * p)
|
||||
{
|
||||
(void) p; /*Unused*/
|
||||
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(ink_obj);
|
||||
lv_btn_state_t state = lv_btn_get_state(ink_obj);
|
||||
|
||||
lv_obj_invalidate(ink_obj);
|
||||
ink_ready = true;
|
||||
|
||||
if((state == LV_BTN_STATE_REL || state == LV_BTN_STATE_TGL_REL) && ext->toggle == 0 && ink_playback == false) {
|
||||
lv_anim_t a;
|
||||
a.var = ink_obj;
|
||||
a.start = LV_BTN_INK_VALUE_MAX;
|
||||
a.end = 0;
|
||||
a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim;
|
||||
a.path = lv_anim_path_linear;
|
||||
a.end_cb = lv_btn_ink_effect_anim_ready;
|
||||
a.act_time = -ext->ink_wait_time;
|
||||
a.time = ext->ink_out_time;
|
||||
a.playback = 0;
|
||||
a.playback_pause = 0;
|
||||
a.repeat = 0;
|
||||
a.repeat_pause = 0;
|
||||
lv_anim_create(&a);
|
||||
|
||||
ink_playback = true;
|
||||
} else {
|
||||
ink_obj = NULL;
|
||||
}
|
||||
}
|
||||
#endif /*LV_USE_ANIMATION*/
|
||||
|
||||
#endif
|
||||
298
src/lv_objx/lv_btn.h
Normal file
298
src/lv_objx/lv_btn.h
Normal file
@@ -0,0 +1,298 @@
|
||||
/**
|
||||
* @file lv_btn.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_BTN_H
|
||||
#define LV_BTN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if LV_USE_BTN != 0
|
||||
|
||||
/*Testing of dependencies*/
|
||||
#if LV_USE_CONT == 0
|
||||
#error "lv_btn: lv_cont is required. Enable it in lv_conf.h (LV_USE_CONT 1) "
|
||||
#endif
|
||||
|
||||
#include "lv_cont.h"
|
||||
#include "../lv_core/lv_indev.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/* Button states
|
||||
* It can be used not only by buttons but other button-like objects too*/
|
||||
enum
|
||||
{
|
||||
LV_BTN_STATE_REL,
|
||||
LV_BTN_STATE_PR,
|
||||
LV_BTN_STATE_TGL_REL,
|
||||
LV_BTN_STATE_TGL_PR,
|
||||
LV_BTN_STATE_INA,
|
||||
LV_BTN_STATE_NUM,
|
||||
};
|
||||
typedef uint8_t lv_btn_state_t;
|
||||
|
||||
/*Data of button*/
|
||||
typedef struct
|
||||
{
|
||||
lv_cont_ext_t cont; /*Ext. of ancestor*/
|
||||
/*New data for this type */
|
||||
lv_style_t * styles[LV_BTN_STATE_NUM]; /*Styles in each state*/
|
||||
lv_btn_state_t state; /*Current state of the button from 'lv_btn_state_t' enum*/
|
||||
#if LV_BTN_INK_EFFECT
|
||||
uint16_t ink_in_time; /*[ms] Time of ink fill effect (0: disable ink effect)*/
|
||||
uint16_t ink_wait_time; /*[ms] Wait before the ink disappears */
|
||||
uint16_t ink_out_time; /*[ms] Time of ink disappearing*/
|
||||
#endif
|
||||
uint8_t toggle :1; /*1: Toggle enabled*/
|
||||
} lv_btn_ext_t;
|
||||
|
||||
/*Styles*/
|
||||
enum {
|
||||
LV_BTN_STYLE_REL,
|
||||
LV_BTN_STYLE_PR,
|
||||
LV_BTN_STYLE_TGL_REL,
|
||||
LV_BTN_STYLE_TGL_PR,
|
||||
LV_BTN_STYLE_INA,
|
||||
};
|
||||
typedef uint8_t lv_btn_style_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a button objects
|
||||
* @param par pointer to an object, it will be the parent of the new button
|
||||
* @param copy pointer to a button object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created button
|
||||
*/
|
||||
lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy);
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Enable the toggled states. On release the button will change from/to toggled state.
|
||||
* @param btn pointer to a button object
|
||||
* @param tgl true: enable toggled states, false: disable
|
||||
*/
|
||||
void lv_btn_set_toggle(lv_obj_t * btn, bool tgl);
|
||||
|
||||
/**
|
||||
* Set the state of the button
|
||||
* @param btn pointer to a button object
|
||||
* @param state the new state of the button (from lv_btn_state_t enum)
|
||||
*/
|
||||
void lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state);
|
||||
|
||||
/**
|
||||
* Toggle the state of the button (ON->OFF, OFF->ON)
|
||||
* @param btn pointer to a button object
|
||||
*/
|
||||
void lv_btn_toggle(lv_obj_t * btn);
|
||||
|
||||
/**
|
||||
* Set the layout on a button
|
||||
* @param btn pointer to a button object
|
||||
* @param layout a layout from 'lv_cont_layout_t'
|
||||
*/
|
||||
static inline void lv_btn_set_layout(lv_obj_t * btn, lv_layout_t layout)
|
||||
{
|
||||
lv_cont_set_layout(btn, layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the fit policy in all 4 directions separately.
|
||||
* It tell how to change the button size automatically.
|
||||
* @param btn pointer to a button object
|
||||
* @param left left fit policy from `lv_fit_t`
|
||||
* @param right right fit policy from `lv_fit_t`
|
||||
* @param top bottom fit policy from `lv_fit_t`
|
||||
* @param bottom bottom fit policy from `lv_fit_t`
|
||||
*/
|
||||
static inline void lv_btn_set_fit4(lv_obj_t * btn, lv_fit_t left, lv_fit_t right, lv_fit_t top, lv_fit_t bottom)
|
||||
{
|
||||
lv_cont_set_fit4(btn, left, right, top, bottom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the fit policy horizontally and vertically separately.
|
||||
* It tell how to change the button size automatically.
|
||||
* @param btn pointer to a button object
|
||||
* @param hot horizontal fit policy from `lv_fit_t`
|
||||
* @param ver vertical fit policy from `lv_fit_t`
|
||||
*/
|
||||
static inline void lv_btn_set_fit2(lv_obj_t * btn, lv_fit_t hor, lv_fit_t ver)
|
||||
{
|
||||
lv_cont_set_fit2(btn, hor, ver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the fit policy in all 4 direction at once.
|
||||
* It tell how to change the button size automatically.
|
||||
* @param btn pointer to a button object
|
||||
* @param fit fit policy from `lv_fit_t`
|
||||
*/
|
||||
static inline void lv_btn_set_fit(lv_obj_t * cont, lv_fit_t fit)
|
||||
{
|
||||
lv_cont_set_fit(cont, fit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time of the ink effect (draw a circle on click to animate in the new state)
|
||||
* @param btn pointer to a button object
|
||||
* @param time the time of the ink animation
|
||||
*/
|
||||
void lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time);
|
||||
|
||||
/**
|
||||
* Set the wait time before the ink disappears
|
||||
* @param btn pointer to a button object
|
||||
* @param time the time of the ink animation
|
||||
*/
|
||||
void lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time);
|
||||
|
||||
/**
|
||||
* Set time of the ink out effect (animate to the released state)
|
||||
* @param btn pointer to a button object
|
||||
* @param time the time of the ink animation
|
||||
*/
|
||||
void lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time);
|
||||
|
||||
/**
|
||||
* Set a style of a button.
|
||||
* @param btn pointer to button object
|
||||
* @param type which style should be set
|
||||
* @param style pointer to a style
|
||||
* */
|
||||
void lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, lv_style_t *style);
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Get the current state of the button
|
||||
* @param btn pointer to a button object
|
||||
* @return the state of the button (from lv_btn_state_t enum)
|
||||
*/
|
||||
lv_btn_state_t lv_btn_get_state(const lv_obj_t * btn);
|
||||
|
||||
/**
|
||||
* Get the toggle enable attribute of the button
|
||||
* @param btn pointer to a button object
|
||||
* @return ture: toggle enabled, false: disabled
|
||||
*/
|
||||
bool lv_btn_get_toggle(const lv_obj_t * btn);
|
||||
|
||||
/**
|
||||
* Get the layout of a button
|
||||
* @param btn pointer to button object
|
||||
* @return the layout from 'lv_cont_layout_t'
|
||||
*/
|
||||
static inline lv_layout_t lv_btn_get_layout(const lv_obj_t * btn)
|
||||
{
|
||||
return lv_cont_get_layout(btn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the left fit mode
|
||||
* @param btn pointer to a button object
|
||||
* @return an element of `lv_fit_t`
|
||||
*/
|
||||
static inline lv_fit_t lv_btn_get_fit_left(const lv_obj_t * btn)
|
||||
{
|
||||
return lv_cont_get_fit_left(btn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the right fit mode
|
||||
* @param btn pointer to a button object
|
||||
* @return an element of `lv_fit_t`
|
||||
*/
|
||||
static inline lv_fit_t lv_btn_get_fit_right(const lv_obj_t * btn)
|
||||
{
|
||||
return lv_cont_get_fit_right(btn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the top fit mode
|
||||
* @param btn pointer to a button object
|
||||
* @return an element of `lv_fit_t`
|
||||
*/
|
||||
static inline lv_fit_t lv_btn_get_fit_top(const lv_obj_t * btn)
|
||||
{
|
||||
return lv_cont_get_fit_top(btn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bottom fit mode
|
||||
* @param btn pointer to a button object
|
||||
* @return an element of `lv_fit_t`
|
||||
*/
|
||||
static inline lv_fit_t lv_btn_get_fit_bottom(const lv_obj_t * btn)
|
||||
{
|
||||
return lv_cont_get_fit_bottom(btn);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get time of the ink in effect (draw a circle on click to animate in the new state)
|
||||
* @param btn pointer to a button object
|
||||
* @return the time of the ink animation
|
||||
*/
|
||||
uint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn);
|
||||
|
||||
/**
|
||||
* Get the wait time before the ink disappears
|
||||
* @param btn pointer to a button object
|
||||
* @return the time of the ink animation
|
||||
*/
|
||||
uint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn);
|
||||
|
||||
/**
|
||||
* Get time of the ink out effect (animate to the releases state)
|
||||
* @param btn pointer to a button object
|
||||
* @return the time of the ink animation
|
||||
*/
|
||||
uint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn);
|
||||
|
||||
/**
|
||||
* Get style of a button.
|
||||
* @param btn pointer to button object
|
||||
* @param type which style should be get
|
||||
* @return style pointer to the style
|
||||
* */
|
||||
lv_style_t * lv_btn_get_style(const lv_obj_t * btn, lv_btn_style_t type);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_BUTTON*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_BTN_H*/
|
||||
1135
src/lv_objx/lv_btnm.c
Normal file
1135
src/lv_objx/lv_btnm.c
Normal file
File diff suppressed because it is too large
Load Diff
318
src/lv_objx/lv_btnm.h
Normal file
318
src/lv_objx/lv_btnm.h
Normal file
@@ -0,0 +1,318 @@
|
||||
/**
|
||||
* @file lv_btnm.h
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LV_BTNM_H
|
||||
#define LV_BTNM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if LV_USE_BTNM != 0
|
||||
|
||||
#include "../lv_core/lv_obj.h"
|
||||
#include "lv_label.h"
|
||||
#include "lv_btn.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/*Control byte*/
|
||||
#define LV_BTNM_WIDTH_MASK 0x07
|
||||
#define LV_BTNM_BTN_HIDDEN 0x08
|
||||
#define LV_BTNM_BTN_NO_REPEAT 0x10
|
||||
#define LV_BTNM_BTN_INACTIVE 0x20
|
||||
#define LV_BTNM_BTN_TOGGLE 0x40
|
||||
#define LV_BTNM_BTN_TOGGLE_STATE 0x80
|
||||
|
||||
#define LV_BTNM_BTN_NONE 0xFFFF
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/* Type to store button control bits (disabled, hidden etc.) */
|
||||
typedef uint8_t lv_btnm_ctrl_t;
|
||||
|
||||
/*Data of button matrix*/
|
||||
typedef struct
|
||||
{
|
||||
/*No inherited ext.*/ /*Ext. of ancestor*/
|
||||
/*New data for this type */
|
||||
const char ** map_p; /*Pointer to the current map*/
|
||||
lv_area_t *button_areas; /*Array of areas of buttons*/
|
||||
lv_btnm_ctrl_t *ctrl_bits; /*Array of control bytes*/
|
||||
lv_style_t *styles_btn[LV_BTN_STATE_NUM]; /*Styles of buttons in each state*/
|
||||
uint16_t btn_cnt; /*Number of button in 'map_p'(Handled by the library)*/
|
||||
uint16_t btn_id_pr; /*Index of the currently pressed button or LV_BTNM_BTN_NONE*/
|
||||
uint16_t btn_id_act; /*Index of the active button (being pressed/released etc) or LV_BTNM_BTN_NONE */
|
||||
uint8_t recolor :1; /*Enable button recoloring*/
|
||||
} lv_btnm_ext_t;
|
||||
|
||||
enum {
|
||||
LV_BTNM_STYLE_BG,
|
||||
LV_BTNM_STYLE_BTN_REL,
|
||||
LV_BTNM_STYLE_BTN_PR,
|
||||
LV_BTNM_STYLE_BTN_TGL_REL,
|
||||
LV_BTNM_STYLE_BTN_TGL_PR,
|
||||
LV_BTNM_STYLE_BTN_INA,
|
||||
};
|
||||
typedef uint8_t lv_btnm_style_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a button matrix objects
|
||||
* @param par pointer to an object, it will be the parent of the new button matrix
|
||||
* @param copy pointer to a button matrix object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created button matrix
|
||||
*/
|
||||
lv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy);
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set a new map. Buttons will be created/deleted according to the map. The
|
||||
* button matrix keeps a reference to the map and so the string array must not
|
||||
* be deallocated during the life of the matrix.
|
||||
* @param btnm pointer to a button matrix object
|
||||
* @param map pointer a string array. The last string has to be: "". Use "\n" to make a line break.
|
||||
*/
|
||||
void lv_btnm_set_map(const lv_obj_t * btnm, const char ** map);
|
||||
|
||||
/**
|
||||
* Set the button control map (hidden, disabled etc.) for a button matrix. The
|
||||
* control map array will be copied and so may be deallocated after this
|
||||
* function returns.
|
||||
* @param btnm pointer to a button matrix object
|
||||
* @param ctrl_map pointer to an array of `lv_btn_ctrl_t` control bytes. The
|
||||
* length of the array and position of the elements must match
|
||||
* the number and order of the individual buttons (i.e. excludes
|
||||
* newline entries).
|
||||
* The control bits are:
|
||||
* - bit 5 : 1 = inactive (disabled)
|
||||
* - bit 4 : 1 = no repeat (on long press)
|
||||
* - bit 3 : 1 = hidden
|
||||
* - bit 2..0: Relative width compared to the buttons in the
|
||||
* same row. [1..7]
|
||||
*/
|
||||
void lv_btnm_set_ctrl_map(const lv_obj_t * btnm, const lv_btnm_ctrl_t * ctrl_map);
|
||||
|
||||
/**
|
||||
* Set the pressed button i.e. visually highlight it.
|
||||
* Mainly used a when the btnm is in a group to show the selected button
|
||||
* @param btnm pointer to button matrix object
|
||||
* @param id index of the currently pressed button (`LV_BTNM_BTN_NONE` to unpress)
|
||||
*/
|
||||
void lv_btnm_set_pressed(const lv_obj_t * btnm, uint16_t id);
|
||||
|
||||
/**
|
||||
* Set a style of a button matrix
|
||||
* @param btnm pointer to a button matrix object
|
||||
* @param type which style should be set
|
||||
* @param style pointer to a style
|
||||
*/
|
||||
void lv_btnm_set_style(lv_obj_t * btnm, lv_btnm_style_t type, lv_style_t * style);
|
||||
|
||||
/**
|
||||
* Enable recoloring of button's texts
|
||||
* @param btnm pointer to button matrix object
|
||||
* @param en true: enable recoloring; false: disable
|
||||
*/
|
||||
void lv_btnm_set_recolor(const lv_obj_t * btnm, bool en);
|
||||
|
||||
/**
|
||||
* Show/hide a single button in the matrix
|
||||
* @param btnm pointer to button matrix object
|
||||
* @param btn_idx 0 based index of the button to modify.
|
||||
* @param hidden true: hide the button
|
||||
*/
|
||||
void lv_btnm_set_btn_hidden(const lv_obj_t * btnm, uint16_t btn_idx, bool hidden);
|
||||
|
||||
/**
|
||||
* Enable/disable a single button in the matrix
|
||||
* @param btnm pointer to button matrix object
|
||||
* @param btn_id 0 based index of the button to modify.
|
||||
* @param ina true: make the button inactive
|
||||
*/
|
||||
void lv_btnm_set_btn_inactive(const lv_obj_t * btnm, uint16_t btn_id, bool ina);
|
||||
|
||||
/**
|
||||
* Enable/disable long press for a single button in the matrix
|
||||
* @param btnm pointer to button matrix object
|
||||
* @param btn_id 0 based index of the button to modify.
|
||||
* @param no_rep true: disable repeat
|
||||
*/
|
||||
void lv_btnm_set_btn_no_repeat(const lv_obj_t * btnm, uint16_t btn_id, bool no_rep);
|
||||
|
||||
/**
|
||||
* Enable/disable toggling a single button in the matrix
|
||||
* @param btnm pointer to button matrix object
|
||||
* @param btn_id 0 based index of the button to modify.
|
||||
* @param tgl true: toggle enable
|
||||
*/
|
||||
void lv_btnm_set_btn_toggle(const lv_obj_t * btnm, uint16_t btn_id, bool tgl);
|
||||
|
||||
/**
|
||||
* Make the a single button button toggled or not toggled.
|
||||
* @param btnm pointer to button matrix object
|
||||
* @param btn_id index of button (not counting "\n")
|
||||
* @param state true: toggled; false: not toggled
|
||||
*/
|
||||
void lv_btnm_set_btn_toggle_state(lv_obj_t * btnm, uint16_t btn_id, bool toggle);
|
||||
|
||||
/**
|
||||
* Set hidden/disabled/repeat flags for a single button.
|
||||
* @param btnm pointer to button matrix object
|
||||
* @param btn_id 0 based index of the button to modify.
|
||||
* @param hidden true: hide the button
|
||||
* @param inactive true: disable the button
|
||||
* @param no_repeat true: disable repeat
|
||||
* @param toggle true: enable toggling
|
||||
* @param toggled_state true: set toggled state
|
||||
*/
|
||||
void lv_btnm_set_btn_flags(const lv_obj_t * btnm, uint16_t btn_id, bool hidden, bool inactive, bool no_repeat, bool toggle, bool toggle_state);
|
||||
|
||||
/**
|
||||
* Set a single buttons relative width.
|
||||
* This method will cause the matrix be regenerated and is a relatively
|
||||
* expensive operation. It is recommended that initial width be specified using
|
||||
* `lv_btnm_set_ctrl_map` and this method only be used for dynamic changes.
|
||||
* @param btnm pointer to button matrix object
|
||||
* @param btn_id 0 based index of the button to modify.
|
||||
* @param width Relative width compared to the buttons in the same row. [1..7]
|
||||
*/
|
||||
void lv_btnm_set_btn_width(const lv_obj_t * btnm, uint16_t btn_id, uint8_t width);
|
||||
|
||||
/**
|
||||
* Set the toggle state of all buttons
|
||||
* @param btnm pointer to a button matrix object
|
||||
* @param state true: toggled; false: not toggled
|
||||
*/
|
||||
void lv_btnm_set_btn_toggle_state_all(lv_obj_t * btnm, bool state);
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Get the current map of a button matrix
|
||||
* @param btnm pointer to a button matrix object
|
||||
* @return the current map
|
||||
*/
|
||||
const char ** lv_btnm_get_map(const lv_obj_t * btnm);
|
||||
|
||||
/**
|
||||
* Check whether the button's text can use recolor or not
|
||||
* @param btnm pointer to button matrix object
|
||||
* @return true: text recolor enable; false: disabled
|
||||
*/
|
||||
bool lv_btnm_get_recolor(const lv_obj_t * btnm);
|
||||
|
||||
/**
|
||||
* Get the index of the lastly "activated" button by the user (pressed, released etc)
|
||||
* Useful in the the `event_cb` to get the text of the button, check if hidden etc.
|
||||
* @param btnm pointer to button matrix object
|
||||
* @return index of the last released button (LV_BTNM_BTN_NONE: if unset)
|
||||
*/
|
||||
uint16_t lv_btnm_get_active_btn(const lv_obj_t * btnm);
|
||||
|
||||
/**
|
||||
* Get the text of the lastly "activated" button by the user (pressed, released etc)
|
||||
* Useful in the the `event_cb`
|
||||
* @param btnm pointer to button matrix object
|
||||
* @return text of the last released button (NULL: if unset)
|
||||
*/
|
||||
const char * lv_btnm_get_active_btn_text(const lv_obj_t * btnm);
|
||||
|
||||
/**
|
||||
* Get the pressed button's index.
|
||||
* The button be really pressed by the user or manually set to pressed with `lv_btnm_set_pressed`
|
||||
* @param btnm pointer to button matrix object
|
||||
* @return index of the pressed button (LV_BTNM_BTN_NONE: if unset)
|
||||
*/
|
||||
uint16_t lv_btnm_get_pressed_btn(const lv_obj_t * btnm);
|
||||
|
||||
/**
|
||||
* Get the button's text
|
||||
* @param btnm pointer to button matrix object
|
||||
* @param btn_index the index a button not counting new line characters. (The return value of lv_btnm_get_pressed/released)
|
||||
* @return text of btn_index` button
|
||||
*/
|
||||
const char * lv_btnm_get_btn_text(const lv_obj_t * btnm, uint16_t btn_id);
|
||||
|
||||
/**
|
||||
* Check whether "no repeat" for a button is set or not.
|
||||
* The `LV_EVENT_LONG_PRESS_REPEAT` will be sent anyway but it can be ignored by the user if this function returns `true`
|
||||
* @param btnm pointer to a button matrix object
|
||||
* @param btn_index the index a button not counting new line characters. (The return value of lv_btnm_get_pressed/released)
|
||||
* @return true: long press repeat is disabled; false: long press repeat enabled
|
||||
*/
|
||||
bool lv_btnm_get_btn_no_repeate(lv_obj_t * btnm, uint16_t btn_id);
|
||||
|
||||
/**
|
||||
* Check whether a button for a button is hidden or not.
|
||||
* Events will be sent anyway but they can be ignored by the user if this function returns `true`
|
||||
* @param btnm pointer to a button matrix object
|
||||
* @param btn_id the index a button not counting new line characters. (The return value of lv_btnm_get_pressed/released)
|
||||
* @return true: hidden; false: not hidden
|
||||
*/
|
||||
bool lv_btnm_get_btn_hidden(lv_obj_t * btnm, uint16_t btn_id);
|
||||
|
||||
/**
|
||||
* Check whether a button for a button is inactive or not.
|
||||
* Events will be sent anyway but they can be ignored by the user if this function returns `true`
|
||||
* @param btnm pointer to a button matrix object
|
||||
* @param btn_id the index a button not counting new line characters. (The return value of lv_btnm_get_pressed/released)
|
||||
* @return true: inactive; false: not inactive
|
||||
*/
|
||||
bool lv_btnm_get_btn_inactive(lv_obj_t * btnm, uint16_t btn_id);
|
||||
|
||||
/**
|
||||
* Check if the button can be toggled or not
|
||||
* @param btnm pointer to button matrix object
|
||||
* @return btn_id index a of a button not counting "\n". (The return value of lv_btnm_get_pressed/released)
|
||||
*/
|
||||
bool lv_btnm_get_btn_toggle(const lv_obj_t * btnm, int16_t btn_id);
|
||||
|
||||
/**
|
||||
* Check if the button is toggled or not
|
||||
* @param btnm pointer to button matrix object
|
||||
* @return btn_id index a of a button not counting "\n". (The return value of lv_btnm_get_pressed/released)
|
||||
*/
|
||||
bool lv_btnm_get_btn_toggle_state(const lv_obj_t * btnm, int16_t btn_id);
|
||||
|
||||
/**
|
||||
* Get a style of a button matrix
|
||||
* @param btnm pointer to a button matrix object
|
||||
* @param type which style should be get
|
||||
* @return style pointer to a style
|
||||
*/
|
||||
lv_style_t * lv_btnm_get_style(const lv_obj_t * btnm, lv_btnm_style_t type);
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_BTNM*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_BTNM_H*/
|
||||
976
src/lv_objx/lv_calendar.c
Normal file
976
src/lv_objx/lv_calendar.c
Normal file
@@ -0,0 +1,976 @@
|
||||
/**
|
||||
* @file lv_calendar.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_calendar.h"
|
||||
#if LV_USE_CALENDAR != 0
|
||||
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_hal/lv_hal_indev.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
#include "../lv_core/lv_indev.h"
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
#include <string.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
enum {
|
||||
DAY_DRAW_PREV_MONTH,
|
||||
DAY_DRAW_ACT_MONTH,
|
||||
DAY_DRAW_NEXT_MONTH,
|
||||
};
|
||||
typedef uint8_t day_draw_state_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static bool lv_calendar_design(lv_obj_t * calendar, const lv_area_t * mask, lv_design_mode_t mode);
|
||||
static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void * param);
|
||||
static bool calculate_touched_day(lv_obj_t * calendar, const lv_point_t * touched_point);
|
||||
static lv_coord_t get_header_height(lv_obj_t * calendar);
|
||||
static lv_coord_t get_day_names_height(lv_obj_t * calendar);
|
||||
static void draw_header(lv_obj_t * calendar, const lv_area_t * mask);
|
||||
static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask);
|
||||
static void draw_days(lv_obj_t * calendar, const lv_area_t * mask);
|
||||
static uint8_t get_day_of_week(uint32_t year, uint32_t month, uint32_t day);
|
||||
static bool is_highlighted(lv_obj_t * calendar, int32_t year, int32_t month, int32_t day);
|
||||
static const char * get_day_name(lv_obj_t * calendar, uint8_t day);
|
||||
static const char * get_month_name(lv_obj_t * calendar, int32_t month);
|
||||
static uint8_t get_month_length(int32_t year, int32_t month);
|
||||
static uint8_t is_leap_year(uint32_t year);
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_signal_cb_t ancestor_signal;
|
||||
static lv_design_cb_t ancestor_design;
|
||||
static const char * day_name[7] = {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"};
|
||||
static const char * month_name[12] = {"January", "February", "March", "April",
|
||||
"May", "June", "July", "August",
|
||||
"September", "October", "November", "December"
|
||||
};
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a calendar object
|
||||
* @param par pointer to an object, it will be the parent of the new calendar
|
||||
* @param copy pointer to a calendar object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created calendar
|
||||
*/
|
||||
lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
{
|
||||
LV_LOG_TRACE("calendar create started");
|
||||
|
||||
/*Create the ancestor of calendar*/
|
||||
lv_obj_t * new_calendar = lv_obj_create(par, copy);
|
||||
lv_mem_assert(new_calendar);
|
||||
if(new_calendar == NULL) return NULL;
|
||||
|
||||
/*Allocate the calendar type specific extended data*/
|
||||
lv_calendar_ext_t * ext = lv_obj_allocate_ext_attr(new_calendar, sizeof(lv_calendar_ext_t));
|
||||
lv_mem_assert(ext);
|
||||
if(ext == NULL) return NULL;
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_calendar);
|
||||
if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_calendar);
|
||||
|
||||
/*Initialize the allocated 'ext' */
|
||||
ext->today.year = 2018;
|
||||
ext->today.month = 1;
|
||||
ext->today.day = 1;
|
||||
|
||||
ext->showed_date.year = 2018;
|
||||
ext->showed_date.month = 1;
|
||||
ext->showed_date.day = 1;
|
||||
|
||||
ext->pressed_date.year = 0;
|
||||
ext->pressed_date.month = 0;
|
||||
ext->pressed_date.day = 0;
|
||||
|
||||
ext->highlighted_dates = NULL;
|
||||
ext->highlighted_dates_num = 0;
|
||||
ext->day_names = NULL;
|
||||
ext->month_names = NULL;
|
||||
ext->style_header = &lv_style_plain_color;
|
||||
ext->style_header_pr = &lv_style_pretty_color;
|
||||
ext->style_highlighted_days = &lv_style_plain_color;
|
||||
ext->style_inactive_days = &lv_style_btn_ina;
|
||||
ext->style_week_box = &lv_style_plain_color;
|
||||
ext->style_today_box = &lv_style_pretty_color;
|
||||
ext->style_day_names = &lv_style_pretty;
|
||||
|
||||
/*The signal and design functions are not copied so set them here*/
|
||||
lv_obj_set_signal_cb(new_calendar, lv_calendar_signal);
|
||||
lv_obj_set_design_cb(new_calendar, lv_calendar_design);
|
||||
|
||||
/*Init the new calendar calendar*/
|
||||
if(copy == NULL) {
|
||||
lv_obj_set_size(new_calendar, LV_DPI * 2, LV_DPI * 2);
|
||||
lv_obj_set_style(new_calendar, &lv_style_pretty);
|
||||
|
||||
lv_theme_t * th = lv_theme_get_current();
|
||||
if(th) {
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_BG, th->style.calendar.bg);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER, th->style.calendar.header);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER_PR, th->style.calendar.header_pr);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_DAY_NAMES, th->style.calendar.day_names);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_WEEK_BOX, th->style.calendar.week_box);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_TODAY_BOX, th->style.calendar.today_box);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, th->style.calendar.highlighted_days);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_INACTIVE_DAYS, th->style.calendar.inactive_days);
|
||||
} else {
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_BG, &lv_style_pretty);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER, ext->style_header);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER_PR, ext->style_header_pr);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_DAY_NAMES, ext->style_day_names);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_WEEK_BOX, ext->style_week_box);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_TODAY_BOX, ext->style_today_box);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, ext->style_highlighted_days);
|
||||
lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_INACTIVE_DAYS, ext->style_inactive_days);
|
||||
}
|
||||
}
|
||||
/*Copy an existing calendar*/
|
||||
else {
|
||||
lv_calendar_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
|
||||
ext->today.year = copy_ext->today.year;
|
||||
ext->today.month = copy_ext->today.month;
|
||||
ext->today.day = copy_ext->today.day;
|
||||
|
||||
ext->showed_date.year = copy_ext->showed_date.year;
|
||||
ext->showed_date.month = copy_ext->showed_date.month;
|
||||
ext->showed_date.day = copy_ext->showed_date.day;
|
||||
|
||||
ext->highlighted_dates = copy_ext->highlighted_dates;
|
||||
ext->highlighted_dates_num = copy_ext->highlighted_dates_num;
|
||||
ext->day_names = copy_ext->day_names;
|
||||
|
||||
ext->month_names = copy_ext->month_names;
|
||||
ext->style_header = copy_ext->style_header;
|
||||
ext->style_header_pr = copy_ext->style_header_pr;
|
||||
ext->style_highlighted_days = copy_ext->style_highlighted_days;
|
||||
ext->style_inactive_days = copy_ext->style_inactive_days;
|
||||
ext->style_week_box = copy_ext->style_week_box;
|
||||
ext->style_today_box = copy_ext->style_today_box;
|
||||
ext->style_day_names = copy_ext->style_day_names;
|
||||
/*Refresh the style with new signal function*/
|
||||
lv_obj_refresh_style(new_calendar);
|
||||
}
|
||||
|
||||
LV_LOG_INFO("calendar created");
|
||||
|
||||
return new_calendar;
|
||||
}
|
||||
|
||||
/*======================
|
||||
* Add/remove functions
|
||||
*=====================*/
|
||||
|
||||
/*
|
||||
* New object specific "add" or "remove" functions come here
|
||||
*/
|
||||
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set the today's date
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value will be saved it can be local variable too.
|
||||
*/
|
||||
void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
ext->today.year = today->year;
|
||||
ext->today.month = today->month;
|
||||
ext->today.day = today->day;
|
||||
|
||||
lv_obj_invalidate(calendar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the currently showed
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value will be saved it can be local variable too.
|
||||
*/
|
||||
void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
ext->showed_date.year = showed->year;
|
||||
ext->showed_date.month = showed->month;
|
||||
ext->showed_date.day = showed->day;
|
||||
|
||||
lv_obj_invalidate(calendar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the the highlighted dates
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER WILL BE SAVED! CAN'T BE LOCAL ARRAY.
|
||||
* @param date_num number of dates in the array
|
||||
*/
|
||||
void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
ext->highlighted_dates = highlighted;
|
||||
ext->highlighted_dates_num = date_num;
|
||||
|
||||
lv_obj_invalidate(calendar);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the days
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param day_names pointer to an array with the names. E.g. `const char * days[7] = {"Sun", "Mon", ...}`
|
||||
* Only the pointer will be saved so this variable can't be local which will be destroyed later.
|
||||
*/
|
||||
void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
ext->day_names = day_names;
|
||||
lv_obj_invalidate(calendar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the month
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param day_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb", ...}`
|
||||
* Only the pointer will be saved so this variable can't be local which will be destroyed later.
|
||||
*/
|
||||
void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
ext->month_names = day_names;
|
||||
lv_obj_invalidate(calendar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a style of a calendar.
|
||||
* @param calendar pointer to calendar object
|
||||
* @param type which style should be set
|
||||
* @param style pointer to a style
|
||||
* */
|
||||
void lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, lv_style_t * style)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
|
||||
switch(type) {
|
||||
case LV_CALENDAR_STYLE_BG:
|
||||
lv_obj_set_style(calendar, style);
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_DAY_NAMES:
|
||||
ext->style_day_names = style;
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_HEADER:
|
||||
ext->style_header = style;
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_HEADER_PR:
|
||||
ext->style_header_pr = style;
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS:
|
||||
ext->style_highlighted_days = style;
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_INACTIVE_DAYS:
|
||||
ext->style_inactive_days = style;
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_TODAY_BOX:
|
||||
ext->style_today_box = style;
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_WEEK_BOX:
|
||||
ext->style_week_box = style;
|
||||
break;
|
||||
}
|
||||
|
||||
lv_obj_invalidate(calendar);
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Get the today's date
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return return pointer to an `lv_calendar_date_t` variable containing the date of today.
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return &ext->today;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently showed
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return pointer to an `lv_calendar_date_t` variable containing the date is being shown.
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return &ext->showed_date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the the pressed date.
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return pointer to an `lv_calendar_date_t` variable containing the pressed date.
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return &ext->pressed_date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the the highlighted dates
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return pointer to an `lv_calendar_date_t` array containing the dates.
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return ext->highlighted_dates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of the highlighted dates
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return number of highlighted days
|
||||
*/
|
||||
uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return ext->highlighted_dates_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the days
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return pointer to the array of day names
|
||||
*/
|
||||
const char ** lv_calendar_get_day_names(const lv_obj_t * calendar)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return ext->day_names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the month
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return pointer to the array of month names
|
||||
*/
|
||||
const char ** lv_calendar_get_month_names(const lv_obj_t * calendar)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return ext->month_names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get style of a calendar.
|
||||
* @param calendar pointer to calendar object
|
||||
* @param type which style should be get
|
||||
* @return style pointer to the style
|
||||
* */
|
||||
lv_style_t * lv_calendar_get_style(const lv_obj_t * calendar, lv_calendar_style_t type)
|
||||
{
|
||||
lv_style_t * style = NULL;
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
|
||||
switch(type) {
|
||||
case LV_CALENDAR_STYLE_BG:
|
||||
style = lv_obj_get_style(calendar);
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_HEADER:
|
||||
style = ext->style_header;
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_HEADER_PR:
|
||||
style = ext->style_header_pr;
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_DAY_NAMES:
|
||||
style = ext->style_day_names;
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS:
|
||||
style = ext->style_highlighted_days;
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_INACTIVE_DAYS:
|
||||
style = ext->style_inactive_days;
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_WEEK_BOX:
|
||||
style = ext->style_week_box;
|
||||
break;
|
||||
case LV_CALENDAR_STYLE_TODAY_BOX:
|
||||
style = ext->style_today_box;
|
||||
break;
|
||||
default:
|
||||
style = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
|
||||
/*
|
||||
* New object specific "other" functions come here
|
||||
*/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Handle the drawing related tasks of the calendars
|
||||
* @param calendar pointer to an object
|
||||
* @param mask the object will be drawn only in this area
|
||||
* @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
|
||||
* (return 'true' if yes)
|
||||
* LV_DESIGN_DRAW: draw the object (always return 'true')
|
||||
* LV_DESIGN_DRAW_POST: drawing after every children are drawn
|
||||
* @param return true/false, depends on 'mode'
|
||||
*/
|
||||
static bool lv_calendar_design(lv_obj_t * calendar, const lv_area_t * mask, lv_design_mode_t mode)
|
||||
{
|
||||
/*Return false if the object is not covers the mask_p area*/
|
||||
if(mode == LV_DESIGN_COVER_CHK) {
|
||||
return false;
|
||||
}
|
||||
/*Draw the object*/
|
||||
else if(mode == LV_DESIGN_DRAW_MAIN) {
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar);
|
||||
lv_draw_rect(&calendar->coords, mask, lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG), opa_scale);
|
||||
|
||||
draw_header(calendar, mask);
|
||||
draw_day_names(calendar, mask);
|
||||
draw_days(calendar, mask);
|
||||
|
||||
}
|
||||
/*Post draw when the children are drawn*/
|
||||
else if(mode == LV_DESIGN_DRAW_POST) {
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal function of the calendar
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param sign a signal type from lv_signal_t enum
|
||||
* @param param pointer to a signal specific variable
|
||||
* @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
|
||||
*/
|
||||
static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void * param)
|
||||
{
|
||||
lv_res_t res;
|
||||
|
||||
/* Include the ancient signal function */
|
||||
res = ancestor_signal(calendar, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
|
||||
|
||||
if(sign == LV_SIGNAL_CLEANUP) {
|
||||
/*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/
|
||||
} else if(sign == LV_SIGNAL_PRESSING) {
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
lv_area_t header_area;
|
||||
lv_area_copy(&header_area, &calendar->coords);
|
||||
header_area.y2 = header_area.y1 + get_header_height(calendar);
|
||||
|
||||
lv_indev_t * indev = lv_indev_get_act();
|
||||
lv_point_t p;
|
||||
lv_indev_get_point(indev, &p);
|
||||
|
||||
if(lv_area_is_point_on(&header_area, &p)) {
|
||||
if(p.x < header_area.x1 + lv_area_get_width(&header_area) / 2) {
|
||||
if(ext->btn_pressing != -1) lv_obj_invalidate(calendar);
|
||||
ext->btn_pressing = -1;
|
||||
} else {
|
||||
if(ext->btn_pressing != 1) lv_obj_invalidate(calendar);
|
||||
ext->btn_pressing = 1;
|
||||
}
|
||||
|
||||
ext->pressed_date.year = 0;
|
||||
} else if(calculate_touched_day(calendar, &p)) {
|
||||
if(ext->btn_pressing != 0) lv_obj_invalidate(calendar);
|
||||
ext->btn_pressing = 0;
|
||||
} else {
|
||||
if(ext->btn_pressing != 0) lv_obj_invalidate(calendar);
|
||||
ext->btn_pressing = 0;
|
||||
ext->pressed_date.year = 0;
|
||||
}
|
||||
} else if(sign == LV_SIGNAL_PRESS_LOST) {
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
ext->pressed_date.year = 0;
|
||||
ext->btn_pressing = 0;
|
||||
lv_obj_invalidate(calendar);
|
||||
|
||||
} else if(sign == LV_SIGNAL_RELEASED) {
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
if(ext->btn_pressing < 0) {
|
||||
if(ext->showed_date.month <= 1) {
|
||||
ext->showed_date.month = 12;
|
||||
ext->showed_date.year --;
|
||||
} else {
|
||||
ext->showed_date.month --;
|
||||
}
|
||||
} else if(ext->btn_pressing > 0) {
|
||||
if(ext->showed_date.month >= 12) {
|
||||
ext->showed_date.month = 1;
|
||||
ext->showed_date.year ++;
|
||||
} else {
|
||||
ext->showed_date.month ++;
|
||||
}
|
||||
}
|
||||
else if(ext->pressed_date.year != 0)
|
||||
{
|
||||
res = lv_obj_send_event(calendar, LV_EVENT_VALUE_CHANGED);
|
||||
if(res != LV_RES_OK) return res;
|
||||
}
|
||||
|
||||
ext->pressed_date.year = 0;
|
||||
ext->btn_pressing = 0;
|
||||
lv_obj_invalidate(calendar);
|
||||
} else if(sign == LV_SIGNAL_CONTROLL) {
|
||||
uint8_t c = *((uint8_t *) param);
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_UP) {
|
||||
if(ext->showed_date.month >= 12) {
|
||||
ext->showed_date.month = 1;
|
||||
ext->showed_date.year ++;
|
||||
} else {
|
||||
ext->showed_date.month ++;
|
||||
}
|
||||
lv_obj_invalidate(calendar);
|
||||
} else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_DOWN) {
|
||||
if(ext->showed_date.month <= 1) {
|
||||
ext->showed_date.month = 12;
|
||||
ext->showed_date.year --;
|
||||
} else {
|
||||
ext->showed_date.month --;
|
||||
}
|
||||
lv_obj_invalidate(calendar);
|
||||
}
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set date*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_calendar";
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* It will check if the days part of calendar is touched
|
||||
* and if it is, it will calculate the day and put it in pressed_date of calendar object.
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param pointer to a point
|
||||
* @return true: days part of calendar is touched and its related date is put in pressed date
|
||||
* false: the point is out of days part area.
|
||||
*/
|
||||
static bool calculate_touched_day(lv_obj_t * calendar, const lv_point_t * touched_point)
|
||||
{
|
||||
lv_area_t days_area;
|
||||
lv_area_copy(&days_area, &calendar->coords);
|
||||
lv_style_t * style_bg = lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG);
|
||||
days_area.x1 += style_bg->body.padding.left;
|
||||
days_area.x2 -= style_bg->body.padding.right;
|
||||
days_area.y1 = calendar->coords.y1 + get_header_height(calendar) + get_day_names_height(calendar) - style_bg->body.padding.top;
|
||||
|
||||
if(lv_area_is_point_on(&days_area, touched_point)) {
|
||||
lv_coord_t w = (days_area.x2 - days_area.x1 + 1) / 7;
|
||||
lv_coord_t h = (days_area.y2 - days_area.y1 + 1) / 6;
|
||||
uint8_t x_pos = 0;
|
||||
x_pos = (touched_point->x - days_area.x1) / w;
|
||||
if(x_pos > 6) x_pos = 6;
|
||||
uint8_t y_pos = 0;
|
||||
y_pos = (touched_point->y - days_area.y1) / h;
|
||||
if(y_pos > 5) y_pos = 5;
|
||||
|
||||
uint8_t i_pos = 0;
|
||||
i_pos = (y_pos * 7) + x_pos;
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
if(i_pos < get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) ) {
|
||||
ext->pressed_date.year = ext->showed_date.year - (ext->showed_date.month == 1 ? 1 : 0);
|
||||
ext->pressed_date.month = ext->showed_date.month == 1 ? 12 : (ext->showed_date.month - 1);
|
||||
ext->pressed_date.day = get_month_length(ext->pressed_date.year, ext->pressed_date.month) -
|
||||
get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) + 1 + i_pos;
|
||||
}
|
||||
else if(i_pos < (get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) +
|
||||
get_month_length(ext->showed_date.year, ext->showed_date.month))) {
|
||||
ext->pressed_date.year = ext->showed_date.year;
|
||||
ext->pressed_date.month = ext->showed_date.month;
|
||||
ext->pressed_date.day = i_pos + 1 - get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1);
|
||||
}
|
||||
else if(i_pos < 42) {
|
||||
ext->pressed_date.year = ext->showed_date.year + (ext->showed_date.month == 12 ? 1 : 0);
|
||||
ext->pressed_date.month = ext->showed_date.month == 12 ? 1 : (ext->showed_date.month + 1);
|
||||
ext->pressed_date.day = i_pos + 1 - get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1)
|
||||
- get_month_length(ext->showed_date.year, ext->showed_date.month);
|
||||
}
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of a calendar's header based on it's style
|
||||
* @param calendar point to a calendar
|
||||
* @return the header's height
|
||||
*/
|
||||
static lv_coord_t get_header_height(lv_obj_t * calendar)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
|
||||
return lv_font_get_height(ext->style_header->text.font) + ext->style_header->body.padding.top + ext->style_header->body.padding.bottom ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of a calendar's day_names based on it's style
|
||||
* @param calendar point to a calendar
|
||||
* @return the day_names's height
|
||||
*/
|
||||
static lv_coord_t get_day_names_height(lv_obj_t * calendar)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
|
||||
return lv_font_get_height(ext->style_day_names->text.font) + ext->style_day_names->body.padding.top + ext->style_day_names->body.padding.bottom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the calendar header with month name and arrows
|
||||
* @param calendar point to a calendar
|
||||
* @param mask a mask for drawing
|
||||
*/
|
||||
static void draw_header(lv_obj_t * calendar, const lv_area_t * mask)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar);
|
||||
|
||||
lv_area_t header_area;
|
||||
header_area.x1 = calendar->coords.x1;
|
||||
header_area.x2 = calendar->coords.x2;
|
||||
header_area.y1 = calendar->coords.y1;
|
||||
header_area.y2 = calendar->coords.y1 + get_header_height(calendar);
|
||||
|
||||
lv_draw_rect(&header_area, mask, ext->style_header, opa_scale);
|
||||
|
||||
/*Add the year + month name*/
|
||||
char txt_buf[64];
|
||||
lv_math_num_to_str(ext->showed_date.year, txt_buf);
|
||||
txt_buf[4] = ' ';
|
||||
txt_buf[5] = '\0';
|
||||
strcpy(&txt_buf[5], get_month_name(calendar, ext->showed_date.month));
|
||||
header_area.y1 += ext->style_header->body.padding.top;
|
||||
lv_draw_label(&header_area, mask, ext->style_header, opa_scale, txt_buf, LV_TXT_FLAG_CENTER, NULL);
|
||||
|
||||
/*Add the left arrow*/
|
||||
lv_style_t * arrow_style = ext->btn_pressing < 0 ? ext->style_header_pr : ext->style_header;
|
||||
header_area.x1 += ext->style_header->body.padding.left;
|
||||
lv_draw_label(&header_area, mask, arrow_style, opa_scale, LV_SYMBOL_LEFT, LV_TXT_FLAG_NONE, NULL);
|
||||
|
||||
/*Add the right arrow*/
|
||||
arrow_style = ext->btn_pressing > 0 ? ext->style_header_pr : ext->style_header;
|
||||
header_area.x1 = header_area.x2 - ext->style_header->body.padding.right -
|
||||
lv_txt_get_width(LV_SYMBOL_RIGHT, strlen(LV_SYMBOL_RIGHT), arrow_style->text.font,
|
||||
arrow_style->text.line_space, LV_TXT_FLAG_NONE);
|
||||
lv_draw_label(&header_area, mask, arrow_style, opa_scale, LV_SYMBOL_RIGHT, LV_TXT_FLAG_NONE, NULL);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the day's name below the header
|
||||
* @param calendar point to a calendar
|
||||
* @param mask a mask for drawing
|
||||
*/
|
||||
static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar);
|
||||
|
||||
lv_coord_t l_pad = ext->style_day_names->body.padding.left;
|
||||
lv_coord_t w = lv_obj_get_width(calendar) - ext->style_day_names->body.padding.left - ext->style_day_names->body.padding.right;
|
||||
lv_coord_t box_w = w / 7;
|
||||
lv_area_t label_area;
|
||||
label_area.y1 = calendar->coords.y1 + get_header_height(calendar) + ext->style_day_names->body.padding.top;
|
||||
label_area.y2 = label_area.y1 + lv_font_get_height(ext->style_day_names->text.font);
|
||||
uint32_t i;
|
||||
for(i = 0; i < 7; i++) {
|
||||
label_area.x1 = calendar->coords.x1 + (w * i) / 7 + l_pad;
|
||||
label_area.x2 = label_area.x1 + box_w;
|
||||
lv_draw_label(&label_area, mask, ext->style_day_names, opa_scale, get_day_name(calendar, i), LV_TXT_FLAG_CENTER, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the date numbers in a matrix
|
||||
* @param calendar point to a calendar
|
||||
* @param mask a mask for drawing
|
||||
*/
|
||||
static void draw_days(lv_obj_t * calendar, const lv_area_t * mask)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
lv_style_t * style_bg = lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG);
|
||||
lv_area_t label_area;
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar);
|
||||
label_area.y1 = calendar->coords.y1 + get_header_height(calendar) +
|
||||
ext->style_day_names->body.padding.top + lv_font_get_height(ext->style_day_names->text.font) +
|
||||
ext->style_day_names->body.padding.bottom;
|
||||
label_area.y2 = label_area.y1 + lv_font_get_height(style_bg->text.font);
|
||||
|
||||
lv_coord_t w = lv_obj_get_width(calendar) - style_bg->body.padding.left - style_bg->body.padding.right;
|
||||
lv_coord_t h = calendar->coords.y2 - label_area.y1 - style_bg->body.padding.bottom;
|
||||
lv_coord_t box_w = w / 7;
|
||||
lv_coord_t vert_space = (h - (6 * lv_font_get_height(style_bg->text.font))) / 5;
|
||||
|
||||
uint32_t week;
|
||||
uint8_t day_cnt;
|
||||
uint8_t month_start_day = get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1);
|
||||
day_draw_state_t draw_state; /*true: Not the prev. or next month is drawn*/
|
||||
lv_style_t * act_style;
|
||||
|
||||
/*If starting with the first day of the week then the previous month is not visible*/
|
||||
if(month_start_day == 0) {
|
||||
day_cnt = 1;
|
||||
draw_state = DAY_DRAW_ACT_MONTH;
|
||||
act_style = style_bg;
|
||||
} else {
|
||||
draw_state = DAY_DRAW_PREV_MONTH;
|
||||
day_cnt = get_month_length(ext->showed_date.year, ext->showed_date.month - 1); /*Length of the previous month*/
|
||||
day_cnt -= month_start_day - 1; /*First visible number of the previous month*/
|
||||
act_style = ext->style_inactive_days;
|
||||
}
|
||||
|
||||
|
||||
bool month_of_today_shown = false;
|
||||
if(ext->showed_date.year == ext->today.year &&
|
||||
ext->showed_date.month == ext->today.month) {
|
||||
month_of_today_shown = true;
|
||||
}
|
||||
|
||||
char buf[3];
|
||||
bool in_week_box = false;
|
||||
|
||||
/*Draw 6 weeks*/
|
||||
for(week = 0; week < 6; week++) {
|
||||
|
||||
/*Draw the "week box"*/
|
||||
if(month_of_today_shown &&
|
||||
((draw_state == DAY_DRAW_ACT_MONTH && ext->today.day >= day_cnt && ext->today.day < day_cnt + 7) ||
|
||||
(draw_state == DAY_DRAW_PREV_MONTH && ext->today.day <= 7 - month_start_day && week == 0))) {
|
||||
lv_area_t week_box_area;
|
||||
lv_area_copy(&week_box_area, &label_area); /*'label_area' is already set for this row*/
|
||||
week_box_area.x1 = calendar->coords.x1 + style_bg->body.padding.left - ext->style_week_box->body.padding.left;
|
||||
week_box_area.x2 = calendar->coords.x2 - style_bg->body.padding.right + ext->style_week_box->body.padding.right;
|
||||
|
||||
week_box_area.y1 -= ext->style_week_box->body.padding.top;
|
||||
week_box_area.y2 += ext->style_week_box->body.padding.bottom;
|
||||
lv_draw_rect(&week_box_area, mask, ext->style_week_box, opa_scale);
|
||||
|
||||
in_week_box = true;
|
||||
} else {
|
||||
in_week_box = false;
|
||||
}
|
||||
|
||||
/*Draw the 7 days of a week*/
|
||||
uint32_t day;
|
||||
for(day = 0; day < 7; day++) {
|
||||
/*The previous month is over*/
|
||||
if(draw_state == DAY_DRAW_PREV_MONTH && day == month_start_day) {
|
||||
draw_state = DAY_DRAW_ACT_MONTH;
|
||||
day_cnt = 1;
|
||||
act_style = style_bg;
|
||||
}
|
||||
/*The current month is over*/
|
||||
if(draw_state == DAY_DRAW_ACT_MONTH &&
|
||||
day_cnt > get_month_length(ext->showed_date.year, ext->showed_date.month)) {
|
||||
draw_state = DAY_DRAW_NEXT_MONTH;
|
||||
day_cnt = 1;
|
||||
act_style = ext->style_inactive_days;
|
||||
}
|
||||
|
||||
label_area.x1 = calendar->coords.x1 + (w * day) / 7 + style_bg->body.padding.left + style_bg->body.padding.right;
|
||||
label_area.x2 = label_area.x1 + box_w;
|
||||
|
||||
/*Draw the "today box"*/
|
||||
if(draw_state == DAY_DRAW_ACT_MONTH && month_of_today_shown && ext->today.day == day_cnt) {
|
||||
lv_area_t today_box_area;
|
||||
lv_area_copy(&today_box_area, &label_area);
|
||||
today_box_area.x1 = label_area.x1;
|
||||
today_box_area.x2 = label_area.x2;
|
||||
|
||||
today_box_area.y1 = label_area.y1 - ext->style_today_box->body.padding.top;
|
||||
today_box_area.y2 = label_area.y2 + ext->style_today_box->body.padding.bottom;
|
||||
lv_draw_rect(&today_box_area, mask, ext->style_today_box, opa_scale);
|
||||
}
|
||||
|
||||
/*Get the final style : highlighted/week box/today box/normal*/
|
||||
lv_style_t * final_style;
|
||||
if(draw_state == DAY_DRAW_PREV_MONTH &&
|
||||
is_highlighted(calendar, ext->showed_date.year - (ext->showed_date.month == 1 ? 1 : 0),
|
||||
ext->showed_date.month == 1 ? 12 : ext->showed_date.month - 1,
|
||||
day_cnt)) {
|
||||
final_style = ext->style_highlighted_days;
|
||||
} else if(draw_state == DAY_DRAW_ACT_MONTH &&
|
||||
is_highlighted(calendar, ext->showed_date.year,
|
||||
ext->showed_date.month,
|
||||
day_cnt)) {
|
||||
final_style = ext->style_highlighted_days;
|
||||
} else if(draw_state == DAY_DRAW_NEXT_MONTH &&
|
||||
is_highlighted(calendar, ext->showed_date.year + (ext->showed_date.month == 12 ? 1 : 0),
|
||||
ext->showed_date.month == 12 ? 1 : ext->showed_date.month + 1,
|
||||
day_cnt)) {
|
||||
final_style = ext->style_highlighted_days;
|
||||
} else if(month_of_today_shown && day_cnt == ext->today.day && draw_state == DAY_DRAW_ACT_MONTH) final_style = ext->style_today_box;
|
||||
else if(in_week_box && draw_state == DAY_DRAW_ACT_MONTH) final_style = ext->style_week_box;
|
||||
else final_style = act_style;
|
||||
|
||||
/*Write the day's number*/
|
||||
lv_math_num_to_str(day_cnt, buf);
|
||||
lv_draw_label(&label_area, mask, final_style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL);
|
||||
|
||||
/*Go to the next day*/
|
||||
day_cnt ++;
|
||||
|
||||
}
|
||||
|
||||
/*Got to the next weeks row*/
|
||||
label_area.y1 += vert_space + lv_font_get_height(style_bg->text.font);
|
||||
label_area.y2 += vert_space + lv_font_get_height(style_bg->text.font);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check weather a date is highlighted or not
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param year a year
|
||||
* @param month a month [1..12]
|
||||
* @param day a day [1..31]
|
||||
* @return true: highlighted
|
||||
*/
|
||||
static bool is_highlighted(lv_obj_t * calendar, int32_t year, int32_t month, int32_t day)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
|
||||
if(ext->highlighted_dates == NULL || ext->highlighted_dates_num == 0) return false;
|
||||
|
||||
uint32_t i;
|
||||
for(i = 0; i < ext->highlighted_dates_num; i++) {
|
||||
if(ext->highlighted_dates[i].year == year &&
|
||||
ext->highlighted_dates[i].month == month &&
|
||||
ext->highlighted_dates[i].day == day) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the day name
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param day a day in [0..6]
|
||||
* @return
|
||||
*/
|
||||
static const char * get_day_name(lv_obj_t * calendar, uint8_t day)
|
||||
{
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
if(ext->day_names) return ext->day_names[day];
|
||||
else return day_name[day];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the month name
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param month a month. The range is basically [1..12] but [-11..1] is also supported to handle previous year
|
||||
* @return
|
||||
*/
|
||||
static const char * get_month_name(lv_obj_t * calendar, int32_t month)
|
||||
{
|
||||
month --; /*Range of months id [1..12] but range of indexes is [0..11]*/
|
||||
if(month < 0) month = 12 + month;
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
if(ext->month_names) return ext->month_names[month];
|
||||
else return month_name[month];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of days in a month
|
||||
* @param year a year
|
||||
* @param month a month. The range is basically [1..12] but [-11..1] is also supported to handle previous year
|
||||
* @return [28..31]
|
||||
*/
|
||||
static uint8_t get_month_length(int32_t year, int32_t month)
|
||||
{
|
||||
month --; /*Range of months id [1..12] but range of indexes is [0..11]*/
|
||||
if(month < 0) {
|
||||
year--; /*Already in the previous year (won't be less then -12 to skip a whole year)*/
|
||||
month = 12 + month; /*`month` is negative, the result will be < 12*/
|
||||
}
|
||||
if(month >= 12) {
|
||||
year ++;
|
||||
month -= 12;
|
||||
}
|
||||
|
||||
/*month == 1 is february*/
|
||||
return (month == 1) ? (28 + is_leap_year(year)) : 31 - month % 7 % 2;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether a year is leap year or not
|
||||
* @param year a year
|
||||
* @return 0: not leap year; 1: leap year
|
||||
*/
|
||||
static uint8_t is_leap_year(uint32_t year)
|
||||
{
|
||||
return (year % 4) || ((year % 100 == 0) && (year % 400)) ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the day of the week
|
||||
* @param year a year
|
||||
* @param month a month
|
||||
* @param day a day
|
||||
* @return [0..6] which means [Sun..Sat]
|
||||
*/
|
||||
static uint8_t get_day_of_week(uint32_t year, uint32_t month, uint32_t day)
|
||||
{
|
||||
uint32_t a = month < 3 ? 1 : 0;
|
||||
uint32_t b = year - a;
|
||||
|
||||
uint32_t day_of_week = (day + (31 * (month - 2 + 12 * a) / 12) +
|
||||
b + (b / 4) - (b / 100) + (b / 400)) % 7;
|
||||
|
||||
return day_of_week;
|
||||
}
|
||||
|
||||
#endif
|
||||
223
src/lv_objx/lv_calendar.h
Normal file
223
src/lv_objx/lv_calendar.h
Normal file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* @file lv_calendar.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_CALENDAR_H
|
||||
#define LV_CALENDAR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if LV_USE_CALENDAR != 0
|
||||
|
||||
#include "../lv_core/lv_obj.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
uint16_t year;
|
||||
int8_t month;
|
||||
int8_t day;
|
||||
} lv_calendar_date_t;
|
||||
|
||||
/*Data of calendar*/
|
||||
typedef struct {
|
||||
/*None*/ /*Ext. of ancestor*/
|
||||
/*New data for this type */
|
||||
lv_calendar_date_t today; /*Date of today*/
|
||||
lv_calendar_date_t showed_date; /*Currently visible month (day is ignored)*/
|
||||
lv_calendar_date_t * highlighted_dates; /*Apply different style on these days (pointer to an array defined by the user)*/
|
||||
uint8_t highlighted_dates_num; /*Number of elements in `highlighted_days`*/
|
||||
int8_t btn_pressing; /*-1: prev month pressing, +1 next month pressing on the header*/
|
||||
lv_calendar_date_t pressed_date;
|
||||
const char ** day_names; /*Pointer to an array with the name of the days (NULL: use default names)*/
|
||||
const char ** month_names; /*Pointer to an array with the name of the month (NULL. use default names)*/
|
||||
|
||||
/*Styles*/
|
||||
lv_style_t * style_header;
|
||||
lv_style_t * style_header_pr;
|
||||
lv_style_t * style_day_names;
|
||||
lv_style_t * style_highlighted_days;
|
||||
lv_style_t * style_inactive_days;
|
||||
lv_style_t * style_week_box;
|
||||
lv_style_t * style_today_box;
|
||||
} lv_calendar_ext_t;
|
||||
|
||||
/*Styles*/
|
||||
enum {
|
||||
LV_CALENDAR_STYLE_BG, /*Also the style of the "normal" date numbers*/
|
||||
LV_CALENDAR_STYLE_HEADER,
|
||||
LV_CALENDAR_STYLE_HEADER_PR,
|
||||
LV_CALENDAR_STYLE_DAY_NAMES,
|
||||
LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS,
|
||||
LV_CALENDAR_STYLE_INACTIVE_DAYS,
|
||||
LV_CALENDAR_STYLE_WEEK_BOX,
|
||||
LV_CALENDAR_STYLE_TODAY_BOX,
|
||||
};
|
||||
typedef uint8_t lv_calendar_style_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a calendar objects
|
||||
* @param par pointer to an object, it will be the parent of the new calendar
|
||||
* @param copy pointer to a calendar object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created calendar
|
||||
*/
|
||||
lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy);
|
||||
|
||||
/*======================
|
||||
* Add/remove functions
|
||||
*=====================*/
|
||||
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set the today's date
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value will be saved it can be local variable too.
|
||||
*/
|
||||
void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today);
|
||||
|
||||
/**
|
||||
* Set the currently showed
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value will be saved it can be local variable too.
|
||||
*/
|
||||
void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed);
|
||||
|
||||
/**
|
||||
* Set the the highlighted dates
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER WILL BE SAVED! CAN'T BE LOCAL ARRAY.
|
||||
* @param date_num number of dates in the array
|
||||
*/
|
||||
void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num);
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the days
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param day_names pointer to an array with the names. E.g. `const char * days[7] = {"Sun", "Mon", ...}`
|
||||
* Only the pointer will be saved so this variable can't be local which will be destroyed later.
|
||||
*/
|
||||
void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names);
|
||||
|
||||
/**
|
||||
* Set the name of the month
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param day_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb", ...}`
|
||||
* Only the pointer will be saved so this variable can't be local which will be destroyed later.
|
||||
*/
|
||||
void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names);
|
||||
|
||||
/**
|
||||
* Set a style of a calendar.
|
||||
* @param calendar pointer to calendar object
|
||||
* @param type which style should be set
|
||||
* @param style pointer to a style
|
||||
* */
|
||||
void lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, lv_style_t *style);
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Get the today's date
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return return pointer to an `lv_calendar_date_t` variable containing the date of today.
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar);
|
||||
|
||||
/**
|
||||
* Get the currently showed
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return pointer to an `lv_calendar_date_t` variable containing the date is being shown.
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar);
|
||||
|
||||
/**
|
||||
* Get the the pressed date.
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return pointer to an `lv_calendar_date_t` variable containing the pressed date.
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar);
|
||||
|
||||
/**
|
||||
* Get the the highlighted dates
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return pointer to an `lv_calendar_date_t` array containing the dates.
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar);
|
||||
|
||||
/**
|
||||
* Get the number of the highlighted dates
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return number of highlighted days
|
||||
*/
|
||||
uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar);
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of the days
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return pointer to the array of day names
|
||||
*/
|
||||
const char ** lv_calendar_get_day_names(const lv_obj_t * calendar);
|
||||
|
||||
/**
|
||||
* Get the name of the month
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return pointer to the array of month names
|
||||
*/
|
||||
const char ** lv_calendar_get_month_names(const lv_obj_t * calendar);
|
||||
|
||||
/**
|
||||
* Get style of a calendar.
|
||||
* @param calendar pointer to calendar object
|
||||
* @param type which style should be get
|
||||
* @return style pointer to the style
|
||||
* */
|
||||
lv_style_t * lv_calendar_get_style(const lv_obj_t * calendar, lv_calendar_style_t type);
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_CALENDAR*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_CALENDAR_H*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user