mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-14 06:42:58 +08:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
039deed864
@ -22,7 +22,7 @@ https://littlevgl.com
|
||||
|
||||
## Porting
|
||||
In the simplest case you need 5 things:
|
||||
1. Call `lv_tick_inc(x)` every `x` millisecods in a Timer or Task (`x` should be between 1 and 10)
|
||||
1. Call `lv_tick_inc(x)` every `x` milliseconds in a Timer or Task (`x` should be between 1 and 10)
|
||||
2. Register a function which can **copy a pixel array** to an area of the screen.
|
||||
3. Register a function which can **read an input device**. (E.g. touch pad)
|
||||
4. Copy `lv_conf_templ.h` as `lv_conf.h` and set at least `LV_HOR_RES`, `LV_VER_RES` and `LV_COLOR_DEPTH`.
|
||||
@ -32,7 +32,7 @@ Or check the [Porting tutorial](https://github.com/littlevgl/lv_examples/blob/ma
|
||||
|
||||
## Project set-up
|
||||
1. **Clone** or [Download](https://littlevgl.com/download) the lvgl repository: `git clone https://github.com/littlevgl/lvgl.git`
|
||||
2. **Create project** with your prefered IDE and add the *lvgl* folder
|
||||
2. **Create project** with your preferred IDE and add the *lvgl* folder
|
||||
3. Copy **lvgl/lv_conf_templ.h** as **lv_conf.h** next to the *lvgl* folder
|
||||
4. In the lv_conf.h delete the first `#if 0` and its `#endif`. Leave the default configuration for the first try.
|
||||
5. In your *main.c*: #include "lvgl/lvgl.h"
|
||||
@ -44,12 +44,12 @@ Or check the [Porting tutorial](https://github.com/littlevgl/lv_examples/blob/ma
|
||||
9. Compile the code and load it to your embedded hardware
|
||||
|
||||
## PC Simulator
|
||||
If you don't have an embedded hardware you can test the graphics library in a PC simulator. The simulator uses [SDL2](https://www.libsdl.org/) library to emulate a display on your monitor and a touch pad with your mouse.
|
||||
You can test the graphics library in a PC simulator, if you don't have an embedded hardware. The simulator uses [SDL2](https://www.libsdl.org/) library to emulate a display on your monitor and a touch pad with your mouse.
|
||||
|
||||
There is a pre-configured PC project for **Eclipse CDT** in this repository: https://github.com/littlevgl/pc_simulator
|
||||
|
||||
## Related repositories
|
||||
* PC simualtor: https://github.com/littlevgl/pc_simulator
|
||||
* PC simulator: https://github.com/littlevgl/pc_simulator
|
||||
* Projects: https://github.com/littlevgl/lv_projects
|
||||
* Examples: https://github.com/littlevgl/lv_examples
|
||||
* Drivers: https://github.com/littlevgl/lv_drivers
|
||||
|
@ -22,13 +22,13 @@ Please, take a look at [CODE_OF_CONDUCT](https://github.com/littlevgl/lvgl/blob/
|
||||
|
||||
There are few **general rules**
|
||||
* We use [GitHub's issue tracker](https://github.com/littlevgl/lvgl/issues)
|
||||
* Be kind and respectful. Strating with "Hi" is always a good idea :)
|
||||
* If somebedy helped you give a feedback.
|
||||
* Be kind and respectful. Starting with "Hi" is always a good idea :)
|
||||
* If somebody helped you give a feedback.
|
||||
* One issue should be about one topic. If you have other questions please open a new issue.
|
||||
* Always create an issue before creating a [Pull request](https://help.github.com/articles/about-pull-requests/) to discuss the idea first
|
||||
* Create small, "digestable" Pull requests.
|
||||
* Create small, "digestible" Pull requests.
|
||||
* Tell your remarks in a structured way. Use paragraphs and the [Markdown](https://guides.github.com/features/mastering-markdown/) support of GitHub.
|
||||
* Be sure you are using the lates version (from `master` branch)
|
||||
* Be sure you are using the latest version (from `master` branch)
|
||||
* Keep in mind LittlevGL should be and should remain:
|
||||
- usable on small MCUs as well (think about memory footprint)
|
||||
- compilable with "non-standard" tools like Arduino (no gcc specific options)
|
||||
@ -43,12 +43,12 @@ If you found a **simple and straightforward bug** like:
|
||||
* anything else which can be fixed locally with a few lines of code
|
||||
* or defective documentation
|
||||
|
||||
then tell
|
||||
then tell:
|
||||
* where you found the bug (which file/function/variable)
|
||||
* how can it cause problem
|
||||
* what is your suggeseted solution if you have
|
||||
* what is your suggested solution if you have
|
||||
|
||||
If you faced with **something more clomplex** like:
|
||||
If you faced with **something more complex** like:
|
||||
* might be simple but you don't know its origin
|
||||
* affects a whole file, module or even the architecture
|
||||
* needs deeper discussion
|
||||
@ -57,7 +57,7 @@ then please
|
||||
* tell what do you experience
|
||||
* tell what do you expect to happen
|
||||
* tell how to reproduce the issue
|
||||
* provide a simlified code example (better if can be tested with copy-paste)
|
||||
* provide a simplified code example (better if can be tested with copy-paste)
|
||||
* attache your lv_conf.h (if you feel it's important)
|
||||
* logs and long codes should be attached in a file (instead of copying into a comment)
|
||||
|
||||
@ -69,16 +69,16 @@ If you have a good and useful idea open issue to tell it! Please note the follow
|
||||
* Can you help in implementing it?
|
||||
|
||||
Your suggestion can have 4 possible outcomes:
|
||||
1. This feature is already exists. In this case you will learn how to achive your goal.
|
||||
1. This feature is already exists. In this case you will learn how to achieve your goal.
|
||||
2. You can simply realize it with the current functionality.
|
||||
3. Although it's a new feature but it would break LittlevGL's platform independent and/or resource minimalist nature.
|
||||
4. It's really a new feature which would be good to be in LittlevGL. Hurray! In a discussion we figure out the technical details and implementation options. With the knowledge of how to do it somebody can implement the new feature.
|
||||
|
||||
Keep in mind if you wouldn't like to do the implementation there is no guarantee that it will be ready in the near future.
|
||||
However if you would like to force it, take a look at this page: [Feature request service](http://www.gl.littlev.hu/services#feature)
|
||||
However, if you would like to force it, take a look at this page: [Feature request service](http://www.gl.littlev.hu/services#feature)
|
||||
|
||||
## How to implement a feature?
|
||||
In [docs/TODO_MINOR.md](https://github.com/littlevgl/lvgl/blob/master/docs/TODO_MINOR.md) and [docs/TODO_PATCH.md](https://github.com/littlevgl/lvgl/blob/master/docs/TODO_PATCH.md) you can see some ideas which are waiting for somebody to realize them! If want to deal with a feature from this files, please start an issue and discusse the details.
|
||||
In [docs/TODO_MINOR.md](https://github.com/littlevgl/lvgl/blob/master/docs/TODO_MINOR.md) and [docs/TODO_PATCH.md](https://github.com/littlevgl/lvgl/blob/master/docs/TODO_PATCH.md) you can see some ideas which are waiting for somebody to realize them! If want to deal with a feature from these files, please start an issue and discuss the details.
|
||||
|
||||
The new feature should be in a new branch.
|
||||
|
||||
@ -88,7 +88,7 @@ The new feature should be in a new branch.
|
||||
Use [lv_misc/lv_templ.c](https://github.com/littlevgl/lvgl/blob/master/lv_misc/lv_templ.c) and [lv_misc/lv_templ.h](https://github.com/littlevgl/lvgl/blob/master/lv_misc/lv_templ.h)
|
||||
|
||||
### Naming conventions
|
||||
* Words are sparated by '_'
|
||||
* Words are separated by '_'
|
||||
* In variable and function names use only lower case letters (e.g. *height_tmp*)
|
||||
* In enums and defines use only upper case letters (e.g. *e.g. MAX_LINE_NUM*)
|
||||
* Global names (API):
|
||||
@ -100,13 +100,13 @@ Use [lv_misc/lv_templ.c](https://github.com/littlevgl/lvgl/blob/master/lv_misc/l
|
||||
* prefer `typedef struct` and `typedef enum` instead of `struct name` and `enum name`
|
||||
* always add a closing *..._t*
|
||||
* Abbreviations:
|
||||
* Use abbreviations on public names only if they become longer then 32 characters
|
||||
* Use only very straightforward (e.g. pos: position) or well established (e.g. pr: press) abbreviatons
|
||||
* Use abbreviations on public names only if they become longer than 32 characters
|
||||
* Use only very straightforward (e.g. pos: position) or well-established (e.g. pr: press) abbreviations
|
||||
|
||||
### Coding guide
|
||||
* Functions:
|
||||
* Try to write function shorter then is 50 lines
|
||||
* Always shorter then 100 lines (except very straightforwards)
|
||||
* Try to write function shorter than is 50 lines
|
||||
* Always shorter than 100 lines (except very straightforwards)
|
||||
* Variables:
|
||||
* One line, one declaration (BAD: char x, y;)
|
||||
* Use `<stdint.h>` (*uint8_t*, *int32_t* etc)
|
||||
@ -138,7 +138,7 @@ You should write **why** have you done this:
|
||||
|
||||
Short "code summaries" of a few lines are accepted. E.g. `/*Calculate the new coordinates*/`
|
||||
|
||||
In comments use \` \` when refering to a variable. E.g. ``/*Update the value of `x_act`*/``
|
||||
In comments use \` \` when referring to a variable. E.g. ``/*Update the value of `x_act`*/``
|
||||
|
||||
### Formatting
|
||||
Here is example to show bracket placing and using of white spaces:
|
||||
@ -149,7 +149,7 @@ Here is example to show bracket placing and using of white spaces:
|
||||
* @param text '\0' terminated character string. NULL to refresh with the current text.
|
||||
*/
|
||||
void lv_label_set_text(lv_obj_t * label, const char * text)
|
||||
{ /* Main bracket of functions in new line*/
|
||||
{ /* Main brackets of functions in new line*/
|
||||
|
||||
if(label == NULL) return; /*No bracket only if the command is inline with the if statement*/
|
||||
|
||||
@ -168,3 +168,14 @@ void lv_label_set_text(lv_obj_t * label, const char * text)
|
||||
```
|
||||
|
||||
Use 4 spaces indentation instead of tab.
|
||||
|
||||
You can use **astyle** to format the code. The required config flies are: `docs/astyle_c` and `docs/astyle_h`.
|
||||
To format the source files:
|
||||
`$ find . -type f -name "*.c" | xargs astyle --options=docs/astyle_c`
|
||||
|
||||
To format the header files:
|
||||
`$ find . -type f -name "*.h" | xargs astyle --options=docs/astyle_h`
|
||||
|
||||
Append `-n` to the end to skip creation of backup file OR use `$ find . -type f -name "*.bak" -delete` (for source file's backups) and `find . -type f -name "*.orig" -delete` (for header file's backups)
|
||||
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
# TODOs for major versions
|
||||
Major versions released typically when API changes are required
|
||||
|
||||
## Contributing
|
||||
Please create an issue to suggest a new feature instead of adding pull request to this file.
|
||||
|
||||
## v6 (released on: in progrss)
|
||||
- [ ] lv_img_upscale removal (generate image with with opacity instead)
|
||||
- [ ] disp_map and disp_fill removal
|
||||
- [ ] disp_flush, mem_blend, mem_fill rework: usea lv_area_t as parameter an GPU support 2D area
|
||||
- [ ] disp_flush: not const color map
|
||||
- [ ] ext size removal, enable drawing on full parent.
|
||||
- [ ] multiple display support
|
||||
- [ ] lv_ufs removal (was required only in the the old image system)
|
||||
|
||||
## v5 (released on: 20.12.2017)
|
||||
**Architectural changes**
|
||||
- [x] Rename repository from *proj_pc* to *pc_simulator*
|
||||
- [x] Integrate *hal* in LittlevGL as a normal folder
|
||||
- [x] Create a new repository for examples
|
||||
- [x] Convert Applications into simple examples
|
||||
- [x] Add tests for all object types
|
||||
|
||||
**API changes**
|
||||
- [x] Rework lv_style_t structure
|
||||
- [x] Remove LV_DOWNSCALE (LV_ANTIALIAS will be used instead)
|
||||
- [x] Rename (and slightly rework) some function, defines and enums to be more descriptive
|
||||
- [x] lv_btnm: rework width control. Now a control byte is used for *width*, *hide* and *no long press* settings.
|
||||
- [x] LV_LABEL_LONG_DOTS removed, use LV_LABEL_LONG_ROLL instead
|
||||
- [x] *lv_list_set_element_text_roll()* removed.
|
||||
- [x] *lv_ddlist_set_fix_height()* instead of *auto_size*
|
||||
- [x] *lv_list_set_sb_out()* removed because now the scrollbar style can position the scrollbar
|
||||
- [x] *lv_gauge* rework to make it more like line meter (remove background but add scale lines)
|
||||
- [x] rename *lv_dispi_...* to *lv_indev_...*
|
||||
- [x] *lv_dispi_t* removed from *lv_action_type_t*. Use lv_indev_act() instead
|
||||
- [x] make styles to global variable to ensure less typing
|
||||
- [x] make fonts to global variables to ensure less typing and easy user-font adding
|
||||
- [x] join symbol fonts into normal built-in fonts
|
||||
- [x] add inline functions to avoide direct use of anchestor functions (e.g. for buttons: lv_cont_set_fit -> lv_btn_set_fit)
|
@ -1,84 +0,0 @@
|
||||
# TODOs for minor versions
|
||||
Minor versions (x.1.0, x.2.0 ...) released when one or more new feature is addded without changing the API. New features can be added with major versions (1.0.0, 2.0.0 ...) too.
|
||||
|
||||
## Contributing
|
||||
Please create an issue to suggest a new feature instead of adding pull request to this file.
|
||||
|
||||
## Ideas
|
||||
Here are ideas which are not assigned to a minor version yet:
|
||||
- label: add a horzintal line (e.g. underline or line through).
|
||||
- lv_split: new object type, a hor. or ver. line for decoration purpose
|
||||
- lv_valset: new object type, a label with "+" and "-" buttons
|
||||
- lv_listctrl: new object type, a list various controls on th right (sw, cb erc.)
|
||||
- lv_inlist: new object type, inline drop down list (a button wich opens a list in place)
|
||||
- lv_char: new_object type: characteristic set (like chart with draggable points)
|
||||
- lv_vol: new_object type: volume meter (like a bar with segments)
|
||||
- Anim. paths: monentum (tnh(x)), curve (exp), shake
|
||||
- Hover, hover_lost signals
|
||||
- Detached area (for video rendering where LittlevGL don't put pixels)
|
||||
- lv_ta: add placeholder text
|
||||
- image rotate
|
||||
|
||||
## v5.3 (planned)
|
||||
Mainly graphical/drawing improvments and Lua support
|
||||
- [ ] API extension: turn the relevant "lv_obj" functions to the specific type (lv_btn_set_size)
|
||||
- [ ] Lua interface to create GUI with script
|
||||
- [ ] Arabic glyph convert (based on letter position)
|
||||
- [ ] Arc rawing
|
||||
- [ ] Right-to-left write support
|
||||
- [ ] Bit based VDB: 1, 2 or 4 bit
|
||||
- [ ] Ttriangle drawing
|
||||
|
||||
## v5.2 (in progress)
|
||||
Mainly new object and new feauters:
|
||||
- [ ] New object type: Listview (table) #137
|
||||
- [ ] New object type: Calendar
|
||||
- [ ] New object type: Icon (button like image) #182
|
||||
- [ ] New object type: QR code #199
|
||||
- [ ] lv_page: scroll on LV_GROUP_KEY_UP/DOWN/LEFT/RIGHT
|
||||
- [ ] lv_obj_align: option in lv_conf.h sav the last alignment's coordinate ad aply it on lv_obj_realign
|
||||
- [ ] lv_line: perpndicular line ending
|
||||
- [ ] lv_gauge: option to put lables outside of the scale
|
||||
- [ ] lv_img: png support #254
|
||||
- [ ] lv_tabview: add option to put the tab button to the bottom
|
||||
- [ ] Error callback: add an option to register a callback called on error
|
||||
- [ ] Support more character coding (e.g. UTF8, UTF16 etc)
|
||||
|
||||
## v5.1 (released on: 09.03.2018)
|
||||
- [x] lv_refr_set_roundig_callback: set a function to modify the invalidated area for special display controllers
|
||||
- [x] lv_group_set_focus_callback: set function to call when a new object is focused #94
|
||||
- [x] lv_obj_get_type() return string, e.g. "lv_slider", "lv_btn" etc #91
|
||||
- [x] Font handling extension for effective Chiese font handling (cutsom read functions)
|
||||
- [x] Remove LV_FONT_ANTIALIAS and add fonts with BPP (bit-per-pixel): 1, 2, 4 and 8
|
||||
- [x] lv_img: add pixel level opacity option (ARGB8888 or ARGB8565) (make image upscale pointless)
|
||||
- [x] LV_ANTIALIAS rework: meaning anti-alias lines and curves
|
||||
- [x] Merge symbol fonts (basic, file and feedback) into one font
|
||||
- [x] lv_group: different default style_mod function with LV_COLOR_DEPTH 1
|
||||
- [x] lv_img_set_src() to handle file path, symbols and const variables with one function
|
||||
- [x] LV_PROTECT_PRESS_LOST: prevent the input devices to NOT find new object when the object's pressing is lost
|
||||
- [x] lv_label: draw style.body.padding.hor/ver greater body if body_draw is enabled
|
||||
- [x] LV_LAYOUT_PRETTY: in one row align obeóject vertically to middle
|
||||
- [x] Add user data option to lv_indev_drv_t and pass it with lv_indev_data_t to the read function. #115
|
||||
- [x] LV_GROUP_KEY_ENTER_LONG: sent by the library on long press of LV_GROUP_KEY_ENTER to trigger long press of the object #113
|
||||
- [x] LV_INDEV_TYPE_BUTTON: for a hatdware buttons which press a point on a screen
|
||||
|
||||
## v5.0 (released on: 20.12.2017)
|
||||
- [x] UTF-8 support
|
||||
- [x] lv_tabview: new object type to organise content with tabs
|
||||
- [x] lv_sw: new object type, switch, turn on/off by tap (a little slider)
|
||||
- [x] lv_roller: new object type, a roller to select a value (like on smartphones)
|
||||
- [x] lv_kb: new object type, Keyboard
|
||||
- [x] lv_btnm: lv_btnm_set_tgl() to toggle last button
|
||||
- [x] lv_ta: cursor types
|
||||
- [x] add themes with predefined styles
|
||||
- [x] partial border draw in styles
|
||||
|
||||
## v4.2 (released on: 17.08.2017)
|
||||
- [x] Double VDB support: one for rendering, another to transfer former rendered image to frame buffer in the background (e.g. with DMA) [#15](https://github.com/littlevgl/lvgl/issues/15)
|
||||
- [x] lv_group: to control without touch pad. Issue [#14](https://github.com/littlevgl/lvgl/issues/14)
|
||||
- [x] lv_page: scrl def fit modification: hor:false, ver:true, and always set width to parent width
|
||||
- [x] lv_btn: add lv_btn_get_..._action
|
||||
- [x] lv_list: add lv_list_get_element_label/img
|
||||
- [x] lv_ta: lv_ta_set_one_line to configure the Text area to one lined input field
|
||||
- [x] style animations add
|
||||
- [x] lv_btnm: besides 0. byte (width dsc) 1. byte: hidden (\177, 0x7F, delete)
|
@ -1,62 +0,0 @@
|
||||
# TODOs for patch versions
|
||||
Patch versions (x.y.1, x.y.2) contain bugfixes without changing the API but they can apppear in minor (x.1.0, x.2.0) or major (1.0.0, 2.0.0) versions too.
|
||||
|
||||
The bugfixes of the still not released version are in `beta` branche.
|
||||
|
||||
## Contributing
|
||||
Please create an issue to introduce a bug instead of adding pull request to this file.
|
||||
|
||||
## v5.1.1 (released on: 20.05.2018)
|
||||
- [x] lv_line: set line.width ext. size to not trim parts on x = 0, y = 0 coordinates
|
||||
- [x] lv_conf.h: add LV_COMPILER_VLA_SUPPORTED
|
||||
- [x] lv_group_create: init focus_cb
|
||||
- [x] fix of 16 bit image drawing with alpha bytes
|
||||
- [x] fix text opacity
|
||||
- [x] lv_mbox: enable navigation with LV_GROUP_KEY_DOWN/UP too
|
||||
- [x] lv_conf.h: add LV_COMPILER_VLA_SUPPORTED
|
||||
- [x] lv_slider: inicator draw bugfix
|
||||
- [x] lv_slider: draw greater background on negative padding if knob_in == 1
|
||||
- [x] mono theme: fix typo
|
||||
- [x] style animations: add opacity handling to image, text and line
|
||||
- [x] lv_kb: before ok/close action don't deassign the lv_ta if there is user defined action
|
||||
- [x] in lv_objx_set_... functions apply the new value only if it's different from the current
|
||||
- [x] don't invalide hidden objects
|
||||
- [x] lv_group_del: remove the objects from the groups too
|
||||
|
||||
## v5.0.3 (released on: 09.03.2018)
|
||||
- [x] lv_chart: Fix the use of point_num more then 256 (Thanks to upbeat27)
|
||||
- [x] lv_label: fix 'offset' with LV_ANTIALIAS (LV_LABEL_LONG_ROLL was effected)
|
||||
- [x] lv_label: anim. time wasn't allyed for LV_LABEL_LONG_ROLL
|
||||
- [x] lv_txt_ut8_size fiy for 4 byte characters
|
||||
- [x] lv_slider: fix knob_in with not zero min value
|
||||
- [x] lv_area_is_on: handled some cases wrong
|
||||
- [x] lv_indev: buffered indevs (return *true* in indev_read) was handled as non-buffered
|
||||
- [x] drag: don't invalidate if the object wasn't moved
|
||||
|
||||
## v5.0.2 (released on: 19.01.2018)
|
||||
- [x] Fix dependencied (Thanks to Zaltora)
|
||||
- [x] lv_group: fix memory leak (Thanks to BenQoo)
|
||||
- [x] LV_INDEV_READ_PERIOD 0 build bugfix
|
||||
- [x] lv_roller: lv_roller_get_selected_str: bugfix (was recursive call)
|
||||
- [x] lv_obj_get_style: with NULL style check if the parent is focused and use the focused style
|
||||
- [x] lv_roller: add missing action handling
|
||||
- [x] Set 24 bit colors upper byte (alpha) to 0xFF
|
||||
|
||||
## v5.0.1 (released on: 02.01.2018)
|
||||
- [x] lv_list: fixed when mouse and keyboard used together
|
||||
- [x] lv_btnm: fix bottom border visibility
|
||||
- [x] theme updates
|
||||
- [x] line width fix width anti-aliasing
|
||||
- [x] lv_conf_templ.h add more info
|
||||
|
||||
## v5.0 (released on: 21.12.2017)
|
||||
- [x] lv_btnm: check hide code (\177) at 0. byte position too (if width is not specified)
|
||||
- [x] lv_img: define *lv_img_raw_header* in *lv_draw.h* because now lv_img can't be disabled
|
||||
- [x] lv_list: ignore image related things when *lv_img* is not enebled
|
||||
- [x] lv_ta: fix hegiht if *one_line* and *FONT_ANTIALIAS*
|
||||
- [x] lv_obj_set_style: fix to update self style too (not only children)
|
||||
|
||||
## v4.2 (released on: 17.08.2017)
|
||||
- [x] lv_slider: don't let indicator or bar to disappear because of hpad/vpad
|
||||
- [x] lv_ta: memory leak if deleted in password mode
|
||||
- [x] lv_list: work without *lv_img* by ignore the image file name parameter of *lv_list_add()*
|
1
docs/astyle_c
Normal file
1
docs/astyle_c
Normal file
@ -0,0 +1 @@
|
||||
--style=kr --convert-tabs --indent=spaces=4 --indent-switches --pad-oper --unpad-paren --align-pointer=middle --suffix=.bak --lineend=linux --min-conditional-indent=
|
1
docs/astyle_h
Normal file
1
docs/astyle_h
Normal file
@ -0,0 +1 @@
|
||||
--convert-tabs --indent=spaces=4
|
103
lv_conf_templ.h
103
lv_conf_templ.h
@ -1,16 +1,20 @@
|
||||
/**
|
||||
* @file lv_conf.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#if 0 /*Remove this to enable the content (Delete the last #endif too!)*/
|
||||
/*
|
||||
* COPY THIS FILE AS lv_conf.h
|
||||
*/
|
||||
|
||||
#if 0 /*Set it to "1" to enable content*/
|
||||
|
||||
#ifndef LV_CONF_H
|
||||
#define LV_CONF_H
|
||||
|
||||
/*----------------
|
||||
* Dynamic memory
|
||||
*----------------*/
|
||||
/*===================
|
||||
Dynamic memory
|
||||
*===================*/
|
||||
|
||||
/* Memory size which will be used by the library
|
||||
* to store the graphical objects and other data */
|
||||
@ -38,19 +42,20 @@
|
||||
* Required for buffered drawing, opacity and anti-aliasing
|
||||
* VDB makes the double buffering, you don't need to deal with it!
|
||||
* Typical size: ~1/10 screen */
|
||||
#define LV_VDB_SIZE (20 * LV_HOR_RES) /*Size of VDB in pixel count (1/10 screen size is good for first)*/
|
||||
#define LV_VDB_ADR 0 /*Place VDB to a specific address (e.g. in external RAM) (0: allocate automatically into RAM)*/
|
||||
#define LV_VDB_SIZE (30 * LV_HOR_RES) /*Size of VDB in pixel count (1/10 screen size is good for first)*/
|
||||
#define LV_VDB_PX_BPP LV_COLOR_SIZE /*Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays. (Set `disp_drv->vdb_wr` and `disp_drv->vdb_rd` too)*/
|
||||
#define LV_VDB_ADR 0 /*Place VDB to a specific address (e.g. in external RAM) (0: allocate automatically into RAM; LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`)*/
|
||||
|
||||
/* Use two Virtual Display buffers (VDB) parallelize rendering and flushing (optional)
|
||||
* The flushing should use DMA to write the frame buffer in the background*/
|
||||
#define LV_VDB_DOUBLE 0 /*1: Enable the use of 2 VDBs*/
|
||||
#define LV_VDB2_ADR 0 /*Place VDB2 to a specific address (e.g. in external RAM) (0: allocate automatically into RAM)*/
|
||||
#define LV_VDB2_ADR 0 /*Place VDB2 to a specific address (e.g. in external RAM) (0: allocate automatically into RAM; LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`)*/
|
||||
|
||||
/* Enable anti-aliasing (lines, and radiuses will be smoothed) */
|
||||
#define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/
|
||||
|
||||
/*Screen refresh settings*/
|
||||
#define LV_REFR_PERIOD 50 /*Screen refresh period in milliseconds*/
|
||||
#define LV_REFR_PERIOD 30 /*Screen refresh period in milliseconds*/
|
||||
#define LV_INV_FIFO_SIZE 32 /*The average count of objects on a screen */
|
||||
|
||||
/*=================
|
||||
@ -66,7 +71,9 @@
|
||||
#define LV_INDEV_LONG_PRESS_REP_TIME 100 /*Repeated trigger period in long press [ms] */
|
||||
|
||||
/*Color settings*/
|
||||
#define LV_COLOR_DEPTH 16 /*Color depth: 1/8/16/24*/
|
||||
#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)*/
|
||||
|
||||
/*Text settings*/
|
||||
@ -82,13 +89,39 @@
|
||||
#define USE_LV_FILESYSTEM 1 /*1: Enable file system (required by images*/
|
||||
|
||||
/*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_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 "Arduino.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*/
|
||||
|
||||
|
||||
/*Log settings*/
|
||||
#define USE_LV_LOG 1 /*Enable/disable the log module*/
|
||||
#if USE_LV_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 caused problem
|
||||
* LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
|
||||
*/
|
||||
#define LV_LOG_LEVEL LV_LOG_LEVEL_INFO
|
||||
/* 1: Print the log with 'printf'; 0: user need to register a callback*/
|
||||
|
||||
#define LV_LOG_PRINTF 0
|
||||
#endif /*USE_LV_LOG*/
|
||||
|
||||
/*================
|
||||
* THEME USAGE
|
||||
*================*/
|
||||
#define LV_THEME_LIVE_UPDATE 0 /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/
|
||||
|
||||
#define USE_LV_THEME_TEMPL 0 /*Just for test*/
|
||||
#define USE_LV_THEME_DEFAULT 0 /*Built mainly from the built-in styles. Consumes very few RAM*/
|
||||
#define USE_LV_THEME_ALIEN 0 /*Dark futuristic theme*/
|
||||
@ -96,6 +129,7 @@
|
||||
#define USE_LV_THEME_MONO 0 /*Mono color theme for monochrome displays*/
|
||||
#define USE_LV_THEME_MATERIAL 0 /*Flat theme with bold colors and light shadows*/
|
||||
#define USE_LV_THEME_ZEN 0 /*Peaceful, mainly light theme */
|
||||
#define USE_LV_THEME_NEMO 0 /*Water-like theme based on the movie "Finding Nemo"*/
|
||||
|
||||
/*==================
|
||||
* FONT USAGE
|
||||
@ -104,8 +138,6 @@
|
||||
/* More info about fonts: https://littlevgl.com/basics#fonts
|
||||
* To enable a built-in font use 1,2,4 or 8 values
|
||||
* which will determine the bit-per-pixel */
|
||||
#define LV_FONT_DEFAULT &lv_font_dejavu_20 /*Always set a default font from the built-in fonts*/
|
||||
|
||||
#define USE_LV_FONT_DEJAVU_10 0
|
||||
#define USE_LV_FONT_DEJAVU_10_LATIN_SUP 0
|
||||
#define USE_LV_FONT_DEJAVU_10_CYRILLIC 0
|
||||
@ -126,6 +158,18 @@
|
||||
#define USE_LV_FONT_DEJAVU_40_CYRILLIC 0
|
||||
#define USE_LV_FONT_SYMBOL_40 0
|
||||
|
||||
#define USE_LV_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
|
||||
*==================*/
|
||||
@ -133,7 +177,7 @@
|
||||
#define LV_OBJ_FREE_PTR 1 /*Enable the free pointer attribute*/
|
||||
|
||||
/*==================
|
||||
* LV OBJ X USAGE
|
||||
* LV OBJ X USAGE
|
||||
*================*/
|
||||
/*
|
||||
* Documentation of the object types: https://littlevgl.com/object-types
|
||||
@ -151,10 +195,17 @@
|
||||
|
||||
/*Image (dependencies: lv_label*/
|
||||
#define USE_LV_IMG 1
|
||||
#if USE_LV_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 USE_LV_LINE 1
|
||||
|
||||
/*Arc (dependencies: -)*/
|
||||
#define USE_LV_ARC 1
|
||||
|
||||
/*******************
|
||||
* Container objects
|
||||
*******************/
|
||||
@ -203,12 +254,28 @@
|
||||
#define LV_TA_PWD_SHOW_TIME 1500 /*ms*/
|
||||
#endif
|
||||
|
||||
/*Calendar (dependencies: -)*/
|
||||
#define USE_LV_CALENDAR 1
|
||||
|
||||
/*Preload (dependencies: arc)*/
|
||||
#define USE_LV_PRELOAD 1
|
||||
#if USE_LV_PRELOAD != 0
|
||||
#define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/
|
||||
#define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/
|
||||
#endif
|
||||
|
||||
/*************************
|
||||
* User input objects
|
||||
*************************/
|
||||
|
||||
/*Button (dependencies: lv_cont*/
|
||||
#define USE_LV_BTN 1
|
||||
#if USE_LV_BTN != 0
|
||||
#define LV_BTN_INK_EFFECT 1 /*Enable button-state animations - draw a circle on click (dependencies: USE_LV_ANIMATION)*/
|
||||
#endif
|
||||
|
||||
/*Image Button (dependencies: lv_btn*/
|
||||
#define USE_LV_IMGBTN 1
|
||||
|
||||
/*Button matrix (dependencies: -)*/
|
||||
#define USE_LV_BTNM 1
|
||||
@ -252,6 +319,4 @@
|
||||
|
||||
#endif /*LV_CONF_H*/
|
||||
|
||||
|
||||
#endif /*Remove this to enable the content*/
|
||||
|
||||
#endif /*End of "Content enable"*/
|
||||
|
@ -22,6 +22,7 @@
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void style_mod_def(lv_style_t * style);
|
||||
static void style_mod_edit_def(lv_style_t * style);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@ -42,12 +43,17 @@ static void style_mod_def(lv_style_t * style);
|
||||
lv_group_t * lv_group_create(void)
|
||||
{
|
||||
lv_group_t * group = lv_mem_alloc(sizeof(lv_group_t));
|
||||
lv_mem_assert(group);
|
||||
if(group == NULL) return NULL;
|
||||
lv_ll_init(&group->obj_ll, sizeof(lv_obj_t *));
|
||||
|
||||
group->style_mod = style_mod_def;
|
||||
group->style_mod_edit = style_mod_edit_def;
|
||||
group->obj_focus = NULL;
|
||||
group->frozen = 0;
|
||||
group->focus_cb = NULL;
|
||||
group->click_focus = 1;
|
||||
group->editing = 0;
|
||||
|
||||
return group;
|
||||
}
|
||||
@ -58,17 +64,17 @@ lv_group_t * lv_group_create(void)
|
||||
*/
|
||||
void lv_group_del(lv_group_t * group)
|
||||
{
|
||||
/*Defocus the the currently focussed object*/
|
||||
/*Defocus the the currently focused object*/
|
||||
if(group->obj_focus != NULL) {
|
||||
(*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
|
||||
lv_obj_invalidate(*group->obj_focus);
|
||||
}
|
||||
|
||||
/*Remove the objects from the group*/
|
||||
lv_obj_t ** obj;
|
||||
LL_READ(group->obj_ll, obj) {
|
||||
(*obj)->group_p = NULL;
|
||||
}
|
||||
/*Remove the objects from the group*/
|
||||
lv_obj_t ** obj;
|
||||
LL_READ(group->obj_ll, obj) {
|
||||
(*obj)->group_p = NULL;
|
||||
}
|
||||
|
||||
lv_ll_clear(&(group->obj_ll));
|
||||
lv_mem_free(group);
|
||||
@ -81,8 +87,21 @@ void lv_group_del(lv_group_t * group)
|
||||
*/
|
||||
void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj)
|
||||
{
|
||||
if(group == NULL) return;
|
||||
|
||||
/*If the object is already in a group and focused then defocuse it*/
|
||||
if(obj->group_p) {
|
||||
if(lv_obj_is_focused(obj)) {
|
||||
lv_group_focus_next(obj->group_p);
|
||||
|
||||
LV_LOG_INFO("group: 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.
|
||||
@ -100,10 +119,17 @@ 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)*/
|
||||
|
||||
if(*g->obj_focus == obj) {
|
||||
lv_group_focus_next(g);
|
||||
}
|
||||
lv_group_focus_next(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;
|
||||
@ -130,6 +156,7 @@ void lv_group_focus_obj(lv_obj_t * obj)
|
||||
lv_obj_t ** i;
|
||||
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_func(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
|
||||
lv_obj_invalidate(*g->obj_focus);
|
||||
@ -137,8 +164,9 @@ void lv_group_focus_obj(lv_obj_t * obj)
|
||||
|
||||
g->obj_focus = i;
|
||||
|
||||
if(g->obj_focus != NULL){
|
||||
if(g->obj_focus != NULL) {
|
||||
(*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_FOCUS, NULL);
|
||||
if(g->focus_cb) g->focus_cb(g);
|
||||
lv_obj_invalidate(*g->obj_focus);
|
||||
}
|
||||
break;
|
||||
@ -166,7 +194,7 @@ void lv_group_focus_next(lv_group_t * group)
|
||||
if(obj_next == NULL) obj_next = lv_ll_get_head(&group->obj_ll);
|
||||
group->obj_focus = obj_next;
|
||||
|
||||
if(group->obj_focus){
|
||||
if(group->obj_focus) {
|
||||
(*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_FOCUS, NULL);
|
||||
lv_obj_invalidate(*group->obj_focus);
|
||||
|
||||
@ -194,7 +222,7 @@ void lv_group_focus_prev(lv_group_t * group)
|
||||
if(obj_next == NULL) obj_next = lv_ll_get_tail(&group->obj_ll);
|
||||
group->obj_focus = obj_next;
|
||||
|
||||
if(group->obj_focus != NULL){
|
||||
if(group->obj_focus != NULL) {
|
||||
(*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_FOCUS, NULL);
|
||||
lv_obj_invalidate(*group->obj_focus);
|
||||
|
||||
@ -232,12 +260,22 @@ void lv_group_send_data(lv_group_t * group, uint32_t c)
|
||||
* @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)
|
||||
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
|
||||
@ -249,6 +287,28 @@ 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)
|
||||
{
|
||||
group->editing = edit ? 1 : 0;
|
||||
lv_obj_t * focused = lv_group_get_focused(group);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify a style with the set 'style_mod' function. The input style remains unchanged.
|
||||
* @param group pointer to group
|
||||
@ -259,9 +319,13 @@ lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style)
|
||||
{
|
||||
lv_style_copy(&group->style_tmp, style);
|
||||
|
||||
if(group->style_mod != NULL) group->style_mod(&group->style_tmp);
|
||||
else style_mod_def(&group->style_tmp);
|
||||
|
||||
if(group->editing) {
|
||||
if(group->style_mod_edit != NULL) group->style_mod_edit(&group->style_tmp);
|
||||
else style_mod_edit_def(&group->style_tmp);
|
||||
} else {
|
||||
if(group->style_mod != NULL) group->style_mod(&group->style_tmp);
|
||||
else style_mod_def(&group->style_tmp);
|
||||
}
|
||||
return &group->style_tmp;
|
||||
}
|
||||
|
||||
@ -270,9 +334,9 @@ lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style)
|
||||
* @param group pointer to a group
|
||||
* @return pointer to the focused object
|
||||
*/
|
||||
lv_obj_t * lv_group_get_focused(lv_group_t * group)
|
||||
lv_obj_t * lv_group_get_focused(const lv_group_t * group)
|
||||
{
|
||||
if(group == NULL) return NULL;
|
||||
if(!group) return NULL;
|
||||
if(group->obj_focus == NULL) return NULL;
|
||||
|
||||
return *group->obj_focus;
|
||||
@ -283,21 +347,56 @@ lv_obj_t * lv_group_get_focused(lv_group_t * 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(lv_group_t * group)
|
||||
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(lv_group_t * group)
|
||||
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;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@ -309,6 +408,7 @@ lv_group_focus_cb_t lv_group_get_focus_cb(lv_group_t * group)
|
||||
static void style_mod_def(lv_style_t * style)
|
||||
{
|
||||
#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;
|
||||
@ -321,6 +421,35 @@ static void style_mod_def(lv_style_t * style)
|
||||
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 style pointer to a style to modify. (Typically group.style_tmp) It will be OVERWRITTEN.
|
||||
*/
|
||||
static void style_mod_edit_def(lv_style_t * style)
|
||||
{
|
||||
#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.empty == 0 || 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;
|
||||
|
@ -13,7 +13,12 @@ extern "C" {
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include "lv_obj.h"
|
||||
|
||||
/*********************
|
||||
@ -26,12 +31,11 @@ extern "C" {
|
||||
#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 28 /*0x1C*/
|
||||
#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_ENTER_LONG 14 /*0x0E, Sent by the library if ENTER is long pressed*/
|
||||
|
||||
#if USE_LV_GROUP != 0
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@ -45,11 +49,14 @@ 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; /*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 */
|
||||
uint8_t frozen:1; /*1: can't focus to new object*/
|
||||
}lv_group_t;
|
||||
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 */
|
||||
} lv_group_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
@ -117,7 +124,14 @@ void lv_group_send_data(lv_group_t * group, uint32_t c);
|
||||
* @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);
|
||||
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
|
||||
@ -126,6 +140,20 @@ void lv_group_set_style_mod_cb(lv_group_t * group,lv_group_style_mod_func_t styl
|
||||
*/
|
||||
void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Modify a style with the set 'style_mod' function. The input style remains unchanged.
|
||||
* @param group pointer to group
|
||||
@ -139,21 +167,43 @@ lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style);
|
||||
* @param group pointer to a group
|
||||
* @return pointer to the focused object
|
||||
*/
|
||||
lv_obj_t * lv_group_get_focused(lv_group_t * group);
|
||||
lv_obj_t * lv_group_get_focused(const lv_group_t * group);
|
||||
|
||||
/**
|
||||
* 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(lv_group_t * group);
|
||||
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(lv_group_t * group);
|
||||
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);
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
|
@ -1,13 +1,12 @@
|
||||
/**
|
||||
* @file lv_indev_proc.c
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
********************/
|
||||
#include "lv_indev.h"
|
||||
#include "../../lv_conf.h"
|
||||
|
||||
#include "../lv_hal/lv_hal_tick.h"
|
||||
#include "../lv_core/lv_group.h"
|
||||
@ -33,11 +32,12 @@
|
||||
static void indev_proc_task(void * param);
|
||||
static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data);
|
||||
static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data);
|
||||
static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data);
|
||||
static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data);
|
||||
static void indev_proc_press(lv_indev_proc_t * proc);
|
||||
static void indev_proc_release(lv_indev_proc_t * proc);
|
||||
static void indev_proc_reset_query_handler(lv_indev_t * indev);
|
||||
static lv_obj_t * indev_search_obj(const lv_indev_proc_t * indev, lv_obj_t * obj);
|
||||
static lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj);
|
||||
static void indev_drag(lv_indev_proc_t * state);
|
||||
static void indev_drag_throw(lv_indev_proc_t * state);
|
||||
#endif
|
||||
@ -45,7 +45,7 @@ static void indev_drag_throw(lv_indev_proc_t * state);
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_indev_t *indev_act;
|
||||
static lv_indev_t * indev_act;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
@ -76,6 +76,17 @@ lv_indev_t * lv_indev_get_act(void)
|
||||
return indev_act;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if(indev == NULL) return LV_INDEV_TYPE_NONE;
|
||||
|
||||
return indev->driver.type;
|
||||
}
|
||||
/**
|
||||
* Reset one or all input devices
|
||||
* @param indev pointer to an input device to reset or NULL to reset all of them
|
||||
@ -110,10 +121,10 @@ void lv_indev_reset_lpr(lv_indev_t * indev)
|
||||
*/
|
||||
void lv_indev_enable(lv_hal_indev_type_t type, bool enable)
|
||||
{
|
||||
lv_indev_t *i = lv_indev_next(NULL);
|
||||
lv_indev_t * i = lv_indev_next(NULL);
|
||||
|
||||
while (i) {
|
||||
if (i->driver.type == type) i->proc.disabled = enable == false ? 1 : 0;
|
||||
while(i) {
|
||||
if(i->driver.type == type) i->proc.disabled = enable == false ? 1 : 0;
|
||||
i = lv_indev_next(i);
|
||||
}
|
||||
}
|
||||
@ -123,7 +134,7 @@ void lv_indev_enable(lv_hal_indev_type_t type, bool enable)
|
||||
* @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)
|
||||
void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj)
|
||||
{
|
||||
if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) return;
|
||||
|
||||
@ -138,9 +149,9 @@ void lv_indev_set_cursor(lv_indev_t *indev, lv_obj_t *cur_obj)
|
||||
* @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)
|
||||
void lv_indev_set_group(lv_indev_t * indev, lv_group_t * group)
|
||||
{
|
||||
if(indev->driver.type == LV_INDEV_TYPE_KEYPAD) indev->group = group;
|
||||
if(indev->driver.type == LV_INDEV_TYPE_KEYPAD || indev->driver.type == LV_INDEV_TYPE_ENCODER) indev->group = group;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -150,7 +161,7 @@ void lv_indev_set_group(lv_indev_t *indev, lv_group_t *group)
|
||||
* @param indev pointer to an input device
|
||||
* @param group point to a group
|
||||
*/
|
||||
void lv_indev_set_button_points(lv_indev_t *indev, lv_point_t *points)
|
||||
void lv_indev_set_button_points(lv_indev_t * indev, lv_point_t * points)
|
||||
{
|
||||
if(indev->driver.type == LV_INDEV_TYPE_BUTTON) indev->btn_points = points;
|
||||
}
|
||||
@ -160,23 +171,34 @@ void lv_indev_set_button_points(lv_indev_t *indev, lv_point_t *points)
|
||||
* @param indev pointer to an input device
|
||||
* @param point pointer to a point to store the result
|
||||
*/
|
||||
void lv_indev_get_point(lv_indev_t * indev, lv_point_t * point)
|
||||
void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point)
|
||||
{
|
||||
if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) {
|
||||
point->x = 0;
|
||||
point->y = 0;
|
||||
point->x = -1;
|
||||
point->y = -1;
|
||||
} else {
|
||||
point->x = indev->proc.act_point.x;
|
||||
point->y = indev->proc.act_point.y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last 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)
|
||||
{
|
||||
if(indev->driver.type != LV_INDEV_TYPE_KEYPAD) return 0;
|
||||
else return indev->proc.last_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(lv_indev_t * indev)
|
||||
bool lv_indev_is_dragging(const lv_indev_t * indev)
|
||||
{
|
||||
if(indev == NULL) return false;
|
||||
if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) return false;
|
||||
@ -188,7 +210,7 @@ bool lv_indev_is_dragging(lv_indev_t * indev)
|
||||
* @param indev pointer to an input device
|
||||
* @param point pointer to a point to store the vector
|
||||
*/
|
||||
void lv_indev_get_vect(lv_indev_t * indev, lv_point_t * point)
|
||||
void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point)
|
||||
{
|
||||
if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) {
|
||||
point->x = 0;
|
||||
@ -204,13 +226,13 @@ void lv_indev_get_vect(lv_indev_t * indev, lv_point_t * point)
|
||||
* @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(lv_indev_t * indev)
|
||||
uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev)
|
||||
{
|
||||
uint32_t t;
|
||||
|
||||
if(indev) return t = lv_tick_elaps(indev->last_activity_time);
|
||||
|
||||
lv_indev_t *i;
|
||||
lv_indev_t * i;
|
||||
t = UINT16_MAX;
|
||||
i = lv_indev_next(NULL);
|
||||
while(i) {
|
||||
@ -243,6 +265,9 @@ static void indev_proc_task(void * param)
|
||||
{
|
||||
(void)param;
|
||||
|
||||
|
||||
LV_LOG_TRACE("indev task started");
|
||||
|
||||
lv_indev_data_t data;
|
||||
lv_indev_t * i;
|
||||
i = lv_indev_next(NULL);
|
||||
@ -259,6 +284,7 @@ static void indev_proc_task(void * param)
|
||||
do {
|
||||
/*Read the data*/
|
||||
more_to_read = lv_indev_read(i, &data);
|
||||
indev_proc_reset_query_handler(i); /*The active object might deleted even in the read function*/
|
||||
i->proc.state = data.state;
|
||||
|
||||
if(i->proc.state == LV_INDEV_STATE_PR) {
|
||||
@ -266,12 +292,12 @@ static void indev_proc_task(void * param)
|
||||
}
|
||||
|
||||
if(i->driver.type == LV_INDEV_TYPE_POINTER) {
|
||||
indev_pointer_proc(i,&data);
|
||||
}
|
||||
else if(i->driver.type == LV_INDEV_TYPE_KEYPAD) {
|
||||
indev_pointer_proc(i, &data);
|
||||
} else if(i->driver.type == LV_INDEV_TYPE_KEYPAD) {
|
||||
indev_keypad_proc(i, &data);
|
||||
}
|
||||
else if(i->driver.type == LV_INDEV_TYPE_BUTTON) {
|
||||
} else if(i->driver.type == LV_INDEV_TYPE_ENCODER) {
|
||||
indev_encoder_proc(i, &data);
|
||||
} else if(i->driver.type == LV_INDEV_TYPE_BUTTON) {
|
||||
indev_button_proc(i, &data);
|
||||
}
|
||||
/*Handle reset query if it happened in during processing*/
|
||||
@ -282,6 +308,8 @@ static void indev_proc_task(void * param)
|
||||
}
|
||||
|
||||
indev_act = NULL; /*End of indev processing, so no act indev*/
|
||||
|
||||
LV_LOG_TRACE("indev task finished");
|
||||
}
|
||||
|
||||
|
||||
@ -294,24 +322,23 @@ static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data)
|
||||
{
|
||||
/*Move the cursor if set and moved*/
|
||||
if(i->cursor != NULL &&
|
||||
(i->proc.last_point.x != data->point.x ||
|
||||
i->proc.last_point.y != data->point.y))
|
||||
{
|
||||
(i->proc.last_point.x != data->point.x ||
|
||||
i->proc.last_point.y != data->point.y)) {
|
||||
lv_obj_set_pos(i->cursor, data->point.x, data->point.y);
|
||||
}
|
||||
|
||||
i->proc.act_point.x = data->point.x;
|
||||
i->proc.act_point.y = data->point.y;
|
||||
|
||||
if(i->proc.state == LV_INDEV_STATE_PR){
|
||||
#if LV_INDEV_POINT_MARKER != 0
|
||||
if(i->proc.state == LV_INDEV_STATE_PR) {
|
||||
#if LV_INDEV_POINT_MARKER != 0
|
||||
lv_area_t area;
|
||||
area.x1 = i->proc.act_point.x - (LV_INDEV_POINT_MARKER >> 1);
|
||||
area.y1 = i->proc.act_point.y - (LV_INDEV_POINT_MARKER >> 1);
|
||||
area.x2 = i->proc.act_point.x + ((LV_INDEV_POINT_MARKER >> 1) | 0x1);
|
||||
area.y2 = i->proc.act_point.y + ((LV_INDEV_POINT_MARKER >> 1) | 0x1);
|
||||
lv_rfill(&area, NULL, LV_COLOR_MAKE(0xFF, 0, 0), LV_OPA_COVER);
|
||||
#endif
|
||||
#endif
|
||||
indev_proc_press(&i->proc);
|
||||
} else {
|
||||
indev_proc_release(&i->proc);
|
||||
@ -333,38 +360,51 @@ static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)
|
||||
|
||||
/*Key press happened*/
|
||||
if(data->state == LV_INDEV_STATE_PR &&
|
||||
i->proc.last_state == LV_INDEV_STATE_REL)
|
||||
{
|
||||
i->proc.last_state == LV_INDEV_STATE_REL) {
|
||||
i->proc.pr_timestamp = lv_tick_get();
|
||||
}
|
||||
/*Pressing*/
|
||||
else if(data->state == LV_INDEV_STATE_PR && i->proc.last_state == LV_INDEV_STATE_PR) {
|
||||
if(data->key == LV_GROUP_KEY_ENTER &&
|
||||
i->proc.long_pr_sent == 0 &&
|
||||
lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME)
|
||||
{
|
||||
|
||||
lv_group_send_data(i->group, LV_GROUP_KEY_ENTER_LONG);
|
||||
i->proc.long_pr_sent = 1;
|
||||
|
||||
i->proc.long_pr_sent == 0 &&
|
||||
lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) {
|
||||
/*On enter long press leave edit mode.*/
|
||||
lv_obj_t * focused = lv_group_get_focused(i->group);
|
||||
if(focused) {
|
||||
focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act);
|
||||
i->proc.long_pr_sent = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Release happened*/
|
||||
else if(data->state == LV_INDEV_STATE_REL && i->proc.last_state == LV_INDEV_STATE_PR)
|
||||
{
|
||||
/*The user might clear the key it was released. Always release the pressed key*/
|
||||
else if(data->state == LV_INDEV_STATE_REL && i->proc.last_state == LV_INDEV_STATE_PR) {
|
||||
/*The user might clear the key when it was released. Always release the pressed key*/
|
||||
data->key = i->proc.last_key;
|
||||
|
||||
/* Edit mode is not used by KEYPAD devices.
|
||||
* So leave edit mode if we are in it before focusing on the next/prev object*/
|
||||
if(data->key == LV_GROUP_KEY_NEXT || data->key == LV_GROUP_KEY_PREV) {
|
||||
if(lv_group_get_editing(i->group)) {
|
||||
lv_group_set_editing(i->group, false);
|
||||
lv_obj_t * focused = lv_group_get_focused(i->group);
|
||||
if(focused) focused->signal_func(focused, LV_SIGNAL_FOCUS, NULL); /*Focus again to properly leave edit mode*/
|
||||
}
|
||||
}
|
||||
|
||||
if(data->key == LV_GROUP_KEY_NEXT) {
|
||||
lv_group_focus_next(i->group);
|
||||
}
|
||||
else if(data->key == LV_GROUP_KEY_PREV) {
|
||||
lv_group_focus_next(i->group);
|
||||
} else if(data->key == LV_GROUP_KEY_PREV) {
|
||||
lv_group_focus_prev(i->group);
|
||||
}
|
||||
else {
|
||||
} else if(data->key == LV_GROUP_KEY_ENTER) {
|
||||
if(!i->proc.long_pr_sent) {
|
||||
lv_group_send_data(i->group, data->key);
|
||||
}
|
||||
} else {
|
||||
lv_group_send_data(i->group, data->key);
|
||||
}
|
||||
|
||||
if(i->proc.reset_query) return; /*The object might be deleted in `focus_cb` or due to any other user event*/
|
||||
|
||||
i->proc.pr_timestamp = 0;
|
||||
i->proc.long_pr_sent = 0;
|
||||
}
|
||||
@ -374,6 +414,98 @@ static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a new point from LV_INDEV_TYPE_ENCODER input device
|
||||
* @param i pointer to an input device
|
||||
* @param data pointer to the data read from the input device
|
||||
*/
|
||||
static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
|
||||
{
|
||||
#if USE_LV_GROUP
|
||||
if(i->group == NULL) return;
|
||||
|
||||
/*Process the steps first. They are valid only with released button*/
|
||||
if(data->state == LV_INDEV_STATE_REL) {
|
||||
/*In edit mode send LEFT/RIGHT keys*/
|
||||
if(lv_group_get_editing(i->group)) {
|
||||
int32_t s;
|
||||
if(data->enc_diff < 0) {
|
||||
for(s = 0; s < -data->enc_diff; s++) lv_group_send_data(i->group, LV_GROUP_KEY_LEFT);
|
||||
} else if(data->enc_diff > 0) {
|
||||
for(s = 0; s < data->enc_diff; s++) lv_group_send_data(i->group, LV_GROUP_KEY_RIGHT);
|
||||
}
|
||||
}
|
||||
/*In navigate mode focus on the next/prev objects*/
|
||||
else {
|
||||
int32_t s;
|
||||
if(data->enc_diff < 0) {
|
||||
for(s = 0; s < -data->enc_diff; s++) lv_group_focus_prev(i->group);
|
||||
} else if(data->enc_diff > 0) {
|
||||
for(s = 0; s < data->enc_diff; s++) lv_group_focus_next(i->group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Key press happened*/
|
||||
if(data->state == LV_INDEV_STATE_PR &&
|
||||
i->proc.last_state == LV_INDEV_STATE_REL) {
|
||||
i->proc.pr_timestamp = lv_tick_get();
|
||||
}
|
||||
/*Pressing*/
|
||||
else if(data->state == LV_INDEV_STATE_PR && i->proc.last_state == LV_INDEV_STATE_PR) {
|
||||
if(i->proc.long_pr_sent == 0 &&
|
||||
lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) {
|
||||
/*On enter long press leave edit mode.*/
|
||||
lv_obj_t * focused = lv_group_get_focused(i->group);
|
||||
|
||||
bool editable = false;
|
||||
if(focused) focused->signal_func(focused, LV_SIGNAL_GET_EDITABLE, &editable);
|
||||
|
||||
if(editable) {
|
||||
i->group->editing = i->group->editing ? 0 : 1;
|
||||
if(focused) focused->signal_func(focused, LV_SIGNAL_FOCUS, NULL); /*Focus again. Some object do something on navigate->edit change*/
|
||||
LV_LOG_INFO("Edit mode changed");
|
||||
if(focused) lv_obj_invalidate(focused);
|
||||
}
|
||||
/*If not editable then just send a long press signal*/
|
||||
else {
|
||||
if(focused) focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act);
|
||||
}
|
||||
i->proc.long_pr_sent = 1;
|
||||
}
|
||||
}
|
||||
/*Release happened*/
|
||||
else if(data->state == LV_INDEV_STATE_REL && i->proc.last_state == LV_INDEV_STATE_PR) {
|
||||
lv_obj_t * focused = lv_group_get_focused(i->group);
|
||||
bool editable = false;
|
||||
if(focused) focused->signal_func(focused, LV_SIGNAL_GET_EDITABLE, &editable);
|
||||
|
||||
/*The button was released on a non-editable object. Just send enter*/
|
||||
if(!editable) {
|
||||
lv_group_send_data(i->group, LV_GROUP_KEY_ENTER);
|
||||
}
|
||||
/*An object is being edited and the button is releases. Just send enter */
|
||||
else if(i->group->editing) {
|
||||
if(!i->proc.long_pr_sent) lv_group_send_data(i->group, LV_GROUP_KEY_ENTER); /*Ignore long pressed enter release because it comes from mode switch*/
|
||||
}
|
||||
/*If the focused object is editable and now in navigate mode then enter edit mode*/
|
||||
else if(editable && !i->group->editing && !i->proc.long_pr_sent) {
|
||||
i->group->editing = i->group->editing ? 0 : 1;
|
||||
if(focused) focused->signal_func(focused, LV_SIGNAL_FOCUS, NULL); /*Focus again. Some object do something on navigate->edit change*/
|
||||
LV_LOG_INFO("Edit mode changed (edit)");
|
||||
if(focused) lv_obj_invalidate(focused);
|
||||
}
|
||||
|
||||
if(i->proc.reset_query) return; /*The object might be deleted in `focus_cb` or due to any other user event*/
|
||||
|
||||
i->proc.pr_timestamp = 0;
|
||||
i->proc.long_pr_sent = 0;
|
||||
}
|
||||
|
||||
i->proc.last_state = data->state;
|
||||
i->proc.last_key = data->key;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Process new points from a input device. indev->state.pressed has to be set
|
||||
@ -388,8 +520,8 @@ static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data)
|
||||
|
||||
/*Still the same point is pressed*/
|
||||
if(i->proc.last_point.x == i->proc.act_point.x &&
|
||||
i->proc.last_point.y == i->proc.act_point.y &&
|
||||
data->state == LV_INDEV_STATE_PR) {
|
||||
i->proc.last_point.y == i->proc.act_point.y &&
|
||||
data->state == LV_INDEV_STATE_PR) {
|
||||
#if LV_INDEV_POINT_MARKER != 0
|
||||
lv_area_t area;
|
||||
area.x1 = i->proc.act_point.x - (LV_INDEV_POINT_MARKER >> 1);
|
||||
@ -415,7 +547,7 @@ static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data)
|
||||
static void indev_proc_press(lv_indev_proc_t * proc)
|
||||
{
|
||||
lv_obj_t * pr_obj = proc->act_obj;
|
||||
|
||||
|
||||
if(proc->wait_unil_release != 0) return;
|
||||
|
||||
/*If there is no last object then search*/
|
||||
@ -431,23 +563,23 @@ static void indev_proc_press(lv_indev_proc_t * proc)
|
||||
}
|
||||
/*If a dragable or a protected object was the last then keep it*/
|
||||
else {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*If a new object was found reset some variables and send a pressed signal*/
|
||||
if(pr_obj != proc->act_obj) {
|
||||
|
||||
proc->last_point.x = proc->act_point.x;
|
||||
proc->last_point.y = proc->act_point.y;
|
||||
|
||||
|
||||
/*If a new object found the previous was lost, so send a signal*/
|
||||
if(proc->act_obj != NULL) {
|
||||
proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESS_LOST, indev_act);
|
||||
if(proc->reset_query != 0) return;
|
||||
}
|
||||
|
||||
|
||||
if(pr_obj != NULL) {
|
||||
/* Save the time when the obj pressed.
|
||||
/* Save the time when the obj pressed.
|
||||
* It is necessary to count the long press time.*/
|
||||
proc->pr_timestamp = lv_tick_get();
|
||||
proc->long_pr_sent = 0;
|
||||
@ -459,15 +591,15 @@ static void indev_proc_press(lv_indev_proc_t * proc)
|
||||
/*Search for 'top' attribute*/
|
||||
lv_obj_t * i = pr_obj;
|
||||
lv_obj_t * last_top = NULL;
|
||||
while(i != NULL){
|
||||
if(i->top != 0) last_top = i;
|
||||
i = lv_obj_get_parent(i);
|
||||
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*/
|
||||
/*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);
|
||||
}
|
||||
@ -477,7 +609,7 @@ static void indev_proc_press(lv_indev_proc_t * proc)
|
||||
if(proc->reset_query != 0) return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
proc->act_obj = pr_obj; /*Save the pressed object*/
|
||||
proc->last_obj = proc->act_obj; /*Refresh the last_obj*/
|
||||
|
||||
@ -536,14 +668,60 @@ static void indev_proc_release(lv_indev_proc_t * proc)
|
||||
|
||||
/*Forgot the act obj and send a released signal */
|
||||
if(proc->act_obj != NULL) {
|
||||
proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_RELEASED, indev_act);
|
||||
/* If the object was protected against press lost then it possible that
|
||||
* the object is already not pressed but still it is the `act_obj`.
|
||||
* In this case send the `LV_SIGNAL_RELEASED` if the indev is ON the `act_obj` */
|
||||
if(lv_obj_is_protected(proc->act_obj, LV_PROTECT_PRESS_LOST)) {
|
||||
/* Search the object on the current current coordinates.
|
||||
* The start object is the object itself. If not ON it the the result will be NULL*/
|
||||
lv_obj_t * obj_on = indev_search_obj(proc, proc->act_obj);
|
||||
if(obj_on == proc->act_obj) proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_RELEASED, indev_act);
|
||||
else proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESS_LOST, indev_act);
|
||||
|
||||
}
|
||||
/* The simple case: `act_obj` was not protected against press lost.
|
||||
* If it is already not pressed then was handled in `indev_proc_press`*/
|
||||
else {
|
||||
proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_RELEASED, indev_act);
|
||||
}
|
||||
/*Handle click focus*/
|
||||
#if USE_LV_GROUP
|
||||
/*Edit mode is not used by POINTER devices. So leave edit mode if we are in it*/
|
||||
lv_group_t * act_g = lv_obj_get_group(proc->act_obj);
|
||||
if(lv_group_get_editing(act_g)) {
|
||||
lv_group_set_editing(act_g, false);
|
||||
proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_FOCUS, NULL); /*Focus again to properly leave edit mode*/
|
||||
}
|
||||
|
||||
/*Check, if the parent is in a group focus on it.*/
|
||||
if(lv_obj_is_protected(proc->act_obj, LV_PROTECT_CLICK_FOCUS) == false) { /*Respect the click protection*/
|
||||
lv_group_t * g = lv_obj_get_group(proc->act_obj);
|
||||
lv_obj_t * parent = proc->act_obj;
|
||||
|
||||
while(g == NULL) {
|
||||
parent = lv_obj_get_parent(parent);
|
||||
if(parent == NULL) break;
|
||||
if(lv_obj_is_protected(parent, LV_PROTECT_CLICK_FOCUS)) { /*Ignore is the protected against click focus*/
|
||||
parent = NULL;
|
||||
break;
|
||||
}
|
||||
g = lv_obj_get_group(parent);
|
||||
}
|
||||
|
||||
if(g != NULL && parent != NULL)
|
||||
if(lv_group_get_click_focus(g)) {
|
||||
lv_group_focus_obj(parent);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(proc->reset_query != 0) return;
|
||||
proc->act_obj = NULL;
|
||||
proc->pr_timestamp = 0;
|
||||
proc->longpr_rep_timestamp = 0;
|
||||
}
|
||||
|
||||
/*The reset can be set in the signal function.
|
||||
|
||||
/*The reset can be set in the signal function.
|
||||
* In case of reset query ignore the remaining parts.*/
|
||||
if(proc->last_obj != NULL && proc->reset_query == 0) {
|
||||
indev_drag_throw(proc);
|
||||
@ -575,43 +753,43 @@ static void indev_proc_reset_query_handler(lv_indev_t * indev)
|
||||
}
|
||||
/**
|
||||
* Search the most top, clickable object on the last point of an input device
|
||||
* @param indev pointer to an input device
|
||||
* @param proc pointer to the `lv_indev_proc_t` part of the input device
|
||||
* @param obj pointer to a start object, typically the screen
|
||||
* @return pointer to the found object or NULL if there was no suitable object
|
||||
* @return pointer to the found object or NULL if there was no suitable object
|
||||
*/
|
||||
static lv_obj_t * indev_search_obj(const lv_indev_proc_t * indev, lv_obj_t * obj)
|
||||
static lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj)
|
||||
{
|
||||
lv_obj_t * found_p = NULL;
|
||||
|
||||
|
||||
/*If the point is on this object*/
|
||||
/*Check its children too*/
|
||||
if(lv_area_is_point_on(&obj->coords, &indev->act_point)) {
|
||||
if(lv_area_is_point_on(&obj->coords, &proc->act_point)) {
|
||||
lv_obj_t * i;
|
||||
|
||||
|
||||
LL_READ(obj->child_ll, i) {
|
||||
found_p = indev_search_obj(indev, i);
|
||||
|
||||
found_p = indev_search_obj(proc, i);
|
||||
|
||||
/*If a child was found then break*/
|
||||
if(found_p != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*If then the children was not ok, and this obj is clickable
|
||||
* and it or its parent is not hidden then save this object*/
|
||||
if(found_p == NULL && lv_obj_get_click(obj) != false) {
|
||||
lv_obj_t * hidden_i = obj;
|
||||
while(hidden_i != NULL) {
|
||||
if(lv_obj_get_hidden(hidden_i) == true) break;
|
||||
hidden_i = lv_obj_get_parent(hidden_i);
|
||||
}
|
||||
/*No parent found with hidden == true*/
|
||||
if(hidden_i == NULL) found_p = obj;
|
||||
lv_obj_t * hidden_i = obj;
|
||||
while(hidden_i != NULL) {
|
||||
if(lv_obj_get_hidden(hidden_i) == true) break;
|
||||
hidden_i = lv_obj_get_parent(hidden_i);
|
||||
}
|
||||
/*No parent found with hidden == true*/
|
||||
if(hidden_i == NULL) found_p = obj;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return found_p;
|
||||
|
||||
return found_p;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -621,35 +799,34 @@ static lv_obj_t * indev_search_obj(const lv_indev_proc_t * indev, lv_obj_t * obj
|
||||
static void indev_drag(lv_indev_proc_t * state)
|
||||
{
|
||||
lv_obj_t * drag_obj = state->act_obj;
|
||||
|
||||
/*If drag parent is active check recursively the drag_parent attribute*/
|
||||
while(lv_obj_get_drag_parent(drag_obj) != false &&
|
||||
drag_obj != NULL) {
|
||||
drag_obj = lv_obj_get_parent(drag_obj);
|
||||
}
|
||||
|
||||
if(drag_obj == NULL) return;
|
||||
|
||||
/*If drag parent is active check recursively the drag_parent attribute*/
|
||||
while(lv_obj_get_drag_parent(drag_obj) != false &&
|
||||
drag_obj != NULL) {
|
||||
drag_obj = lv_obj_get_parent(drag_obj);
|
||||
}
|
||||
|
||||
if(drag_obj == NULL) return;
|
||||
|
||||
if(lv_obj_get_drag(drag_obj) == false) return;
|
||||
|
||||
/*If still there is no drag then count the movement*/
|
||||
if(state->drag_range_out == 0) {
|
||||
state->drag_sum.x += state->vect.x;
|
||||
state->drag_sum.y += state->vect.y;
|
||||
|
||||
|
||||
/*If a move is greater then LV_DRAG_LIMIT then begin the drag*/
|
||||
if(LV_MATH_ABS(state->drag_sum.x) >= LV_INDEV_DRAG_LIMIT ||
|
||||
LV_MATH_ABS(state->drag_sum.y) >= LV_INDEV_DRAG_LIMIT)
|
||||
{
|
||||
state->drag_range_out = 1;
|
||||
}
|
||||
LV_MATH_ABS(state->drag_sum.y) >= LV_INDEV_DRAG_LIMIT) {
|
||||
state->drag_range_out = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*If the drag limit is stepped over then handle the dragging*/
|
||||
if(state->drag_range_out != 0) {
|
||||
/*Set new position if the vector is not zero*/
|
||||
if(state->vect.x != 0 ||
|
||||
state->vect.y != 0) {
|
||||
state->vect.y != 0) {
|
||||
/*Get the coordinates of the object and modify them*/
|
||||
lv_coord_t act_x = lv_obj_get_x(drag_obj);
|
||||
lv_coord_t act_y = lv_obj_get_y(drag_obj);
|
||||
@ -684,33 +861,32 @@ static void indev_drag(lv_indev_proc_t * state)
|
||||
*/
|
||||
static void indev_drag_throw(lv_indev_proc_t * state)
|
||||
{
|
||||
if(state->drag_in_prog == 0) return;
|
||||
if(state->drag_in_prog == 0) return;
|
||||
|
||||
/*Set new position if the vector is not zero*/
|
||||
lv_obj_t * drag_obj = state->last_obj;
|
||||
|
||||
/*If drag parent is active check recursively the drag_parent attribute*/
|
||||
while(lv_obj_get_drag_parent(drag_obj) != false &&
|
||||
drag_obj != NULL) {
|
||||
drag_obj = lv_obj_get_parent(drag_obj);
|
||||
}
|
||||
|
||||
if(drag_obj == NULL) return;
|
||||
|
||||
/*If drag parent is active check recursively the drag_parent attribute*/
|
||||
while(lv_obj_get_drag_parent(drag_obj) != false &&
|
||||
drag_obj != NULL) {
|
||||
drag_obj = lv_obj_get_parent(drag_obj);
|
||||
}
|
||||
|
||||
if(drag_obj == NULL) return;
|
||||
|
||||
/*Return if the drag throw is not enabled*/
|
||||
if(lv_obj_get_drag_throw(drag_obj) == false ){
|
||||
state->drag_in_prog = 0;
|
||||
if(lv_obj_get_drag_throw(drag_obj) == false) {
|
||||
state->drag_in_prog = 0;
|
||||
drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*Reduce the vectors*/
|
||||
state->vect.x = state->vect.x * (100 -LV_INDEV_DRAG_THROW) / 100;
|
||||
state->vect.y = state->vect.y * (100 -LV_INDEV_DRAG_THROW) / 100;
|
||||
|
||||
state->vect.x = state->vect.x * (100 - LV_INDEV_DRAG_THROW) / 100;
|
||||
state->vect.y = state->vect.y * (100 - LV_INDEV_DRAG_THROW) / 100;
|
||||
|
||||
if(state->vect.x != 0 ||
|
||||
state->vect.y != 0)
|
||||
{
|
||||
state->vect.y != 0) {
|
||||
/*Get the coordinates and modify them*/
|
||||
lv_coord_t act_x = lv_obj_get_x(drag_obj) + state->vect.x;
|
||||
lv_coord_t act_y = lv_obj_get_y(drag_obj) + state->vect.y;
|
||||
@ -718,7 +894,7 @@ static void indev_drag_throw(lv_indev_proc_t * state)
|
||||
|
||||
/*If non of the coordinates are changed then do not continue throwing*/
|
||||
if((lv_obj_get_x(drag_obj) != act_x || state->vect.x == 0) &&
|
||||
(lv_obj_get_y(drag_obj) != act_y || state->vect.y == 0)) {
|
||||
(lv_obj_get_y(drag_obj) != act_y || state->vect.y == 0)) {
|
||||
state->drag_in_prog = 0;
|
||||
state->vect.x = 0;
|
||||
state->vect.y = 0;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_indev_proc.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_INDEV_H
|
||||
@ -40,6 +40,14 @@ void lv_indev_init(void);
|
||||
*/
|
||||
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
|
||||
@ -88,27 +96,34 @@ void lv_indev_set_button_points(lv_indev_t *indev, lv_point_t *points);
|
||||
* @param indev pointer to an input device
|
||||
* @param point pointer to a point to store the result
|
||||
*/
|
||||
void lv_indev_get_point(lv_indev_t * indev, lv_point_t * point);
|
||||
void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point);
|
||||
|
||||
/**
|
||||
* Get the last 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(lv_indev_t * indev);
|
||||
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(lv_indev_t * indev, lv_point_t * point);
|
||||
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(lv_indev_t * indev);
|
||||
uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev);
|
||||
|
||||
/**
|
||||
* Do nothing until the next release
|
||||
|
685
lv_core/lv_obj.c
685
lv_core/lv_obj.c
File diff suppressed because it is too large
Load Diff
213
lv_core/lv_obj.h
213
lv_core/lv_obj.h
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_obj.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_H
|
||||
@ -13,7 +13,12 @@ extern "C" {
|
||||
/*********************
|
||||
* 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"
|
||||
@ -21,6 +26,7 @@ extern "C" {
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
#include "../lv_misc/lv_ll.h"
|
||||
#include "../lv_misc/lv_color.h"
|
||||
#include "../lv_misc/lv_log.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -48,9 +54,9 @@ extern "C" {
|
||||
#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_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
|
||||
/**********************
|
||||
@ -59,32 +65,34 @@ extern "C" {
|
||||
|
||||
struct _lv_obj_t;
|
||||
|
||||
typedef enum
|
||||
enum
|
||||
{
|
||||
LV_DESIGN_DRAW_MAIN,
|
||||
LV_DESIGN_DRAW_POST,
|
||||
LV_DESIGN_COVER_CHK,
|
||||
}lv_design_mode_t;
|
||||
};
|
||||
typedef uint8_t lv_design_mode_t;
|
||||
|
||||
typedef bool (* lv_design_func_t) (struct _lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode);
|
||||
|
||||
typedef enum
|
||||
enum
|
||||
{
|
||||
LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action function*/
|
||||
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*/
|
||||
}lv_res_t;
|
||||
};
|
||||
typedef uint8_t lv_res_t;
|
||||
|
||||
typedef enum
|
||||
enum
|
||||
{
|
||||
/*General signals*/
|
||||
LV_SIGNAL_CLEANUP,
|
||||
LV_SIGNAL_CLEANUP,
|
||||
LV_SIGNAL_CHILD_CHG,
|
||||
LV_SIGNAL_CORD_CHG,
|
||||
LV_SIGNAL_STYLE_CHG,
|
||||
LV_SIGNAL_REFR_EXT_SIZE,
|
||||
LV_SIGNAL_GET_TYPE,
|
||||
LV_SIGNAL_REFR_EXT_SIZE,
|
||||
LV_SIGNAL_GET_TYPE,
|
||||
|
||||
/*Input device related*/
|
||||
/*Input device related*/
|
||||
LV_SIGNAL_PRESSED,
|
||||
LV_SIGNAL_PRESSING,
|
||||
LV_SIGNAL_PRESS_LOST,
|
||||
@ -94,11 +102,13 @@ typedef enum
|
||||
LV_SIGNAL_DRAG_BEGIN,
|
||||
LV_SIGNAL_DRAG_END,
|
||||
|
||||
/*Group related*/
|
||||
/*Group related*/
|
||||
LV_SIGNAL_FOCUS,
|
||||
LV_SIGNAL_DEFOCUS,
|
||||
LV_SIGNAL_CONTROLL,
|
||||
}lv_signal_t;
|
||||
LV_SIGNAL_GET_EDITABLE,
|
||||
};
|
||||
typedef uint8_t lv_signal_t;
|
||||
|
||||
typedef lv_res_t (* lv_signal_func_t) (struct _lv_obj_t * obj, lv_signal_t sign, void * param);
|
||||
|
||||
@ -106,12 +116,12 @@ 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_signal_func_t signal_func; /*Object type specific signal function*/
|
||||
lv_design_func_t design_func; /*Object type specific design function*/
|
||||
|
||||
|
||||
void * ext_attr; /*Object type specific extended data*/
|
||||
lv_style_t * style_p; /*Pointer to the object's style*/
|
||||
|
||||
@ -123,43 +133,45 @@ typedef struct _lv_obj_t
|
||||
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 reserved :1;
|
||||
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 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*/
|
||||
|
||||
uint8_t protect; /*Automatically happening actions can be prevented. 'OR'ed values from lv_obj_prot_t*/
|
||||
|
||||
lv_coord_t ext_size; /*EXTtend the size of the object in every direction. E.g. for shadow drawing*/
|
||||
lv_coord_t ext_size; /*EXTtend the size of the object in every direction. E.g. for shadow drawing*/
|
||||
|
||||
#ifdef LV_OBJ_FREE_NUM_TYPE
|
||||
LV_OBJ_FREE_NUM_TYPE free_num; /*Application specific identifier (set it freely)*/
|
||||
LV_OBJ_FREE_NUM_TYPE free_num; /*Application specific identifier (set it freely)*/
|
||||
#endif
|
||||
}lv_obj_t;
|
||||
} lv_obj_t;
|
||||
|
||||
typedef lv_res_t (*lv_action_t) (struct _lv_obj_t * obj);
|
||||
|
||||
/*Protect some attributes (max. 8 bit)*/
|
||||
typedef enum
|
||||
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, /*TODO */
|
||||
}lv_protect_t;
|
||||
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;
|
||||
} lv_obj_type_t;
|
||||
|
||||
typedef enum
|
||||
enum
|
||||
{
|
||||
LV_ALIGN_CENTER = 0,
|
||||
LV_ALIGN_IN_TOP_LEFT,
|
||||
@ -182,18 +194,20 @@ typedef enum
|
||||
LV_ALIGN_OUT_RIGHT_TOP,
|
||||
LV_ALIGN_OUT_RIGHT_MID,
|
||||
LV_ALIGN_OUT_RIGHT_BOTTOM,
|
||||
}lv_align_t;
|
||||
};
|
||||
typedef uint8_t lv_align_t;
|
||||
|
||||
typedef enum
|
||||
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*/
|
||||
}lv_anim_builtin_t;
|
||||
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
|
||||
@ -215,7 +229,7 @@ void lv_init(void);
|
||||
* @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, lv_obj_t * copy);
|
||||
lv_obj_t * lv_obj_create(lv_obj_t * parent,const lv_obj_t * copy);
|
||||
|
||||
/**
|
||||
* Delete 'obj' and all of its children
|
||||
@ -234,7 +248,7 @@ 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(lv_obj_t * obj);
|
||||
void lv_obj_invalidate(const lv_obj_t * obj);
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
@ -256,8 +270,8 @@ void lv_scr_load(lv_obj_t * scr);
|
||||
|
||||
/**
|
||||
* Set a new parent for an object. Its relative position will be the same.
|
||||
* @param obj pointer to an object
|
||||
* @param parent pointer to the new parent object
|
||||
* @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);
|
||||
|
||||
@ -317,7 +331,7 @@ void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h);
|
||||
* @param x_mod x coordinate shift after alignment
|
||||
* @param y_mod y coordinate shift after alignment
|
||||
*/
|
||||
void lv_obj_align(lv_obj_t * obj,lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod);
|
||||
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);
|
||||
|
||||
|
||||
/*---------------------
|
||||
@ -392,17 +406,39 @@ void lv_obj_set_drag_throw(lv_obj_t * obj, bool en);
|
||||
*/
|
||||
void lv_obj_set_drag_parent(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Set editable parameter Used by groups and keyboard/encoder control.
|
||||
* Editable object has something inside to choose (the elements of a list)
|
||||
* @param obj pointer to an object
|
||||
* @param en true: enable editing
|
||||
*/
|
||||
void lv_obj_set_editable(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_obj_prot_t
|
||||
* @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_obj_prot_t
|
||||
* @param prot 'OR'-ed values from `lv_protect_t`
|
||||
*/
|
||||
void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot);
|
||||
|
||||
@ -503,7 +539,7 @@ lv_obj_t * lv_layer_sys(void);
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to a screen
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_screen(lv_obj_t * obj);
|
||||
lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj);
|
||||
|
||||
/*---------------------
|
||||
* Parent/children get
|
||||
@ -514,7 +550,7 @@ lv_obj_t * lv_obj_get_screen(lv_obj_t * obj);
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to the parent of 'obj'
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_parent(lv_obj_t * 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")
|
||||
@ -523,7 +559,7 @@ lv_obj_t * lv_obj_get_parent(lv_obj_t * obj);
|
||||
* 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(lv_obj_t * obj, lv_obj_t * 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)
|
||||
@ -532,14 +568,14 @@ lv_obj_t * lv_obj_get_child(lv_obj_t * obj, lv_obj_t * child);
|
||||
* 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(lv_obj_t * obj, lv_obj_t * 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(lv_obj_t * obj);
|
||||
uint16_t lv_obj_count_children(const lv_obj_t * obj);
|
||||
|
||||
/*---------------------
|
||||
* Coordinate get
|
||||
@ -550,42 +586,42 @@ uint16_t lv_obj_count_children(lv_obj_t * obj);
|
||||
* @param obj pointer to an object
|
||||
* @param cords_p pointer to an area to store the coordinates
|
||||
*/
|
||||
void lv_obj_get_coords(lv_obj_t * obj, lv_area_t * cords_p);
|
||||
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(lv_obj_t * obj);
|
||||
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(lv_obj_t * obj);
|
||||
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(lv_obj_t * obj);
|
||||
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(lv_obj_t * obj);
|
||||
lv_coord_t lv_obj_get_height(const 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(lv_obj_t * obj);
|
||||
lv_coord_t lv_obj_get_ext_size(const lv_obj_t * obj);
|
||||
|
||||
/*-----------------
|
||||
* Appearance get
|
||||
@ -596,7 +632,7 @@ lv_coord_t lv_obj_get_ext_size(lv_obj_t * obj);
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to a style
|
||||
*/
|
||||
lv_style_t * lv_obj_get_style(lv_obj_t * obj);
|
||||
lv_style_t * lv_obj_get_style(const lv_obj_t * obj);
|
||||
|
||||
/*-----------------
|
||||
* Attribute get
|
||||
@ -607,71 +643,78 @@ lv_style_t * lv_obj_get_style(lv_obj_t * obj);
|
||||
* @param obj pointer to an object
|
||||
* @return true: the object is hidden
|
||||
*/
|
||||
bool lv_obj_get_hidden(lv_obj_t * obj);
|
||||
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(lv_obj_t * obj);
|
||||
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 feture is enabled
|
||||
*/
|
||||
bool lv_obj_get_top(lv_obj_t * obj);
|
||||
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(lv_obj_t * obj);
|
||||
bool lv_obj_get_drag(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the drag thow enable attribute of an object
|
||||
* @param obj pointer to an object
|
||||
* @return true: drag throw is enabled
|
||||
*/
|
||||
bool lv_obj_get_drag_throw(lv_obj_t * obj);
|
||||
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(lv_obj_t * obj);
|
||||
bool lv_obj_get_drag_parent(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_obj_prot_t)
|
||||
* @return protect field ('OR'ed values of `lv_protect_t`)
|
||||
*/
|
||||
uint8_t lv_obj_get_protect(lv_obj_t * obj);
|
||||
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_obj_prot_t)
|
||||
* @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(lv_obj_t * obj, uint8_t prot);
|
||||
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_func_t lv_obj_get_signal_func(lv_obj_t * obj);
|
||||
lv_signal_func_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_func_t lv_obj_get_design_func(lv_obj_t * obj);
|
||||
lv_design_func_t lv_obj_get_design_func(const lv_obj_t * obj);
|
||||
|
||||
/*------------------
|
||||
* Other get
|
||||
@ -683,7 +726,7 @@ lv_design_func_t lv_obj_get_design_func(lv_obj_t * obj);
|
||||
* @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(lv_obj_t * obj);
|
||||
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.
|
||||
@ -699,7 +742,7 @@ void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf);
|
||||
* @param obj pointer to an object
|
||||
* @return the free number
|
||||
*/
|
||||
LV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(lv_obj_t * obj);
|
||||
LV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(const lv_obj_t * obj);
|
||||
#endif
|
||||
|
||||
#if LV_OBJ_FREE_PTR != 0
|
||||
@ -708,7 +751,7 @@ LV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(lv_obj_t * obj);
|
||||
* @param obj pointer to an object
|
||||
* @return the free pointer
|
||||
*/
|
||||
void * lv_obj_get_free_ptr(lv_obj_t * obj);
|
||||
void * lv_obj_get_free_ptr(const lv_obj_t * obj);
|
||||
#endif
|
||||
|
||||
#if USE_LV_GROUP
|
||||
@ -717,14 +760,22 @@ void * lv_obj_get_free_ptr(lv_obj_t * obj);
|
||||
* @param obj pointer to an object
|
||||
* @return the pointer to group of the object
|
||||
*/
|
||||
void * lv_obj_get_group(lv_obj_t * obj);
|
||||
void * lv_obj_get_group(const lv_obj_t * obj);
|
||||
|
||||
|
||||
/**
|
||||
* Tell whether the ohe 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
|
||||
**********************/
|
||||
#define LV_SCALE(x) (x << LV_ANTIALIAS)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -1,12 +1,11 @@
|
||||
/**
|
||||
* @file lv_refr.c
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../lv_conf.h"
|
||||
#include <stddef.h>
|
||||
#include "lv_refr.h"
|
||||
#include "lv_vdb.h"
|
||||
@ -21,11 +20,10 @@
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
lv_area_t area;
|
||||
uint8_t joined;
|
||||
}lv_join_t;
|
||||
} lv_join_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
@ -49,7 +47,7 @@ static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p);
|
||||
static lv_join_t inv_buf[LV_INV_FIFO_SIZE];
|
||||
static uint16_t inv_buf_p;
|
||||
static void (*monitor_cb)(uint32_t, uint32_t); /*Monitor the rendering time*/
|
||||
static void (*round_cb)(lv_area_t*); /*If set then called to modify invalidated areas for special display controllers*/
|
||||
static void (*round_cb)(lv_area_t *); /*If set then called to modify invalidated areas for special display controllers*/
|
||||
static uint32_t px_num;
|
||||
|
||||
/**********************
|
||||
@ -64,15 +62,27 @@ static uint32_t px_num;
|
||||
* Initialize the screen refresh subsystem
|
||||
*/
|
||||
void lv_refr_init(void)
|
||||
{
|
||||
{
|
||||
inv_buf_p = 0;
|
||||
memset(inv_buf, 0, sizeof(inv_buf));
|
||||
|
||||
lv_task_t* task;
|
||||
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 redarwing is peridocally 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 shoud be updated.
|
||||
*/
|
||||
void lv_refr_now(void)
|
||||
{
|
||||
lv_refr_task(NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invalidate an area
|
||||
* @param area_p pointer to area which should be invalidated
|
||||
@ -84,36 +94,36 @@ void lv_inv_area(const lv_area_t * area_p)
|
||||
inv_buf_p = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
lv_area_t scr_area;
|
||||
scr_area.x1 = 0;
|
||||
scr_area.y1 = 0;
|
||||
scr_area.x2 = LV_HOR_RES - 1;
|
||||
scr_area.y2 = LV_VER_RES - 1;
|
||||
|
||||
lv_area_t com_area;
|
||||
|
||||
lv_area_t com_area;
|
||||
bool suc;
|
||||
|
||||
suc = lv_area_union(&com_area, area_p, &scr_area);
|
||||
suc = lv_area_intersect(&com_area, area_p, &scr_area);
|
||||
|
||||
/*The area is truncated to the screen*/
|
||||
if(suc != false) {
|
||||
if(round_cb) round_cb(&com_area);
|
||||
|
||||
/*Save only if this area is not in one of the saved areas*/
|
||||
uint16_t i;
|
||||
for(i = 0; i < inv_buf_p; i++) {
|
||||
if(lv_area_is_in(&com_area, &inv_buf[i].area) != false) return;
|
||||
}
|
||||
/*Save only if this area is not in one of the saved areas*/
|
||||
uint16_t i;
|
||||
for(i = 0; i < inv_buf_p; i++) {
|
||||
if(lv_area_is_in(&com_area, &inv_buf[i].area) != false) return;
|
||||
}
|
||||
|
||||
/*Save the area*/
|
||||
if(inv_buf_p < LV_INV_FIFO_SIZE) {
|
||||
lv_area_copy(&inv_buf[inv_buf_p].area,&com_area);
|
||||
} else {/*If no place for the area add the screen*/
|
||||
inv_buf_p = 0;
|
||||
lv_area_copy(&inv_buf[inv_buf_p].area,&scr_area);
|
||||
if(inv_buf_p < LV_INV_FIFO_SIZE) {
|
||||
lv_area_copy(&inv_buf[inv_buf_p].area, &com_area);
|
||||
} else {/*If no place for the area add the screen*/
|
||||
inv_buf_p = 0;
|
||||
lv_area_copy(&inv_buf[inv_buf_p].area, &scr_area);
|
||||
}
|
||||
inv_buf_p ++;
|
||||
inv_buf_p ++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,7 +144,7 @@ void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t))
|
||||
* Special display controllers may require special coordinate rounding
|
||||
* @param cb pointer to the a function which will modify the area
|
||||
*/
|
||||
void lv_refr_set_round_cb(void(*cb)(lv_area_t*))
|
||||
void lv_refr_set_round_cb(void(*cb)(lv_area_t *))
|
||||
{
|
||||
round_cb = cb;
|
||||
}
|
||||
@ -170,10 +180,12 @@ static void lv_refr_task(void * param)
|
||||
{
|
||||
(void)param;
|
||||
|
||||
LV_LOG_TRACE("display refresh task started");
|
||||
|
||||
uint32_t start = lv_tick_get();
|
||||
|
||||
lv_refr_join_area();
|
||||
|
||||
|
||||
lv_refr_areas();
|
||||
|
||||
bool refr_done = false;
|
||||
@ -188,6 +200,8 @@ static void lv_refr_task(void * param)
|
||||
monitor_cb(lv_tick_elaps(start), px_num);
|
||||
}
|
||||
}
|
||||
|
||||
LV_LOG_TRACE("display refresh task finished");
|
||||
}
|
||||
|
||||
|
||||
@ -201,7 +215,7 @@ static void lv_refr_join_area(void)
|
||||
lv_area_t joined_area;
|
||||
for(join_in = 0; join_in < inv_buf_p; join_in++) {
|
||||
if(inv_buf[join_in].joined != 0) continue;
|
||||
|
||||
|
||||
/*Check all areas to join them in 'join_in'*/
|
||||
for(join_from = 0; join_from < inv_buf_p; join_from++) {
|
||||
/*Handle only unjoined areas and ignore itself*/
|
||||
@ -211,23 +225,22 @@ static void lv_refr_join_area(void)
|
||||
|
||||
/*Check if the areas are on each other*/
|
||||
if(lv_area_is_on(&inv_buf[join_in].area,
|
||||
&inv_buf[join_from].area) == false)
|
||||
{
|
||||
&inv_buf[join_from].area) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
lv_area_join(&joined_area, &inv_buf[join_in].area,
|
||||
&inv_buf[join_from].area);
|
||||
&inv_buf[join_from].area);
|
||||
|
||||
/*Join two area only if the joined area size is smaller*/
|
||||
if(lv_area_get_size(&joined_area) <
|
||||
(lv_area_get_size(&inv_buf[join_in].area) + lv_area_get_size(&inv_buf[join_from].area))) {
|
||||
if(lv_area_get_size(&joined_area) <
|
||||
(lv_area_get_size(&inv_buf[join_in].area) + lv_area_get_size(&inv_buf[join_from].area))) {
|
||||
lv_area_copy(&inv_buf[join_in].area, &joined_area);
|
||||
|
||||
/*Mark 'join_form' is joined into 'join_in'*/
|
||||
inv_buf[join_from].joined = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,12 +276,16 @@ static void lv_refr_areas(void)
|
||||
static void lv_refr_area_no_vdb(const lv_area_t * area_p)
|
||||
{
|
||||
lv_obj_t * top_p;
|
||||
|
||||
/*Get top object which is not covered by others*/
|
||||
|
||||
/*Get top object which is not covered by others*/
|
||||
top_p = lv_refr_get_top_obj(area_p, lv_scr_act());
|
||||
|
||||
|
||||
/*Do the refreshing*/
|
||||
lv_refr_obj_and_children(top_p, area_p);
|
||||
|
||||
/*Also refresh top and sys layer unconditionally*/
|
||||
lv_refr_obj_and_children(lv_layer_top(), area_p);
|
||||
lv_refr_obj_and_children(lv_layer_sys(), area_p);
|
||||
}
|
||||
|
||||
#else
|
||||
@ -284,14 +301,43 @@ static void lv_refr_area_with_vdb(const lv_area_t * area_p)
|
||||
lv_coord_t h = lv_area_get_height(area_p);
|
||||
lv_coord_t y2 = area_p->y2 >= LV_VER_RES ? y2 = LV_VER_RES - 1 : area_p->y2;
|
||||
|
||||
uint32_t max_row = (uint32_t) LV_VDB_SIZE / w;
|
||||
int32_t max_row = (uint32_t) LV_VDB_SIZE / w;
|
||||
|
||||
if(max_row > h) max_row = h;
|
||||
|
||||
|
||||
/*Round down the lines of VDB if rounding is added*/
|
||||
if(round_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;
|
||||
round_cb(&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*/
|
||||
uint32_t row;
|
||||
lv_coord_t row;
|
||||
lv_coord_t row_last = 0;
|
||||
for(row = area_p->y1; row + max_row - 1 <= y2; row += max_row) {
|
||||
lv_vdb_t * vdb_p = lv_vdb_get();
|
||||
if(!vdb_p) {
|
||||
LV_LOG_WARN("Invalid VDB pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
/*Calc. the next y coordinates of VDB*/
|
||||
vdb_p->area.x1 = area_p->x1;
|
||||
@ -302,10 +348,14 @@ static void lv_refr_area_with_vdb(const lv_area_t * area_p)
|
||||
row_last = vdb_p->area.y2;
|
||||
lv_refr_area_part_vdb(area_p);
|
||||
}
|
||||
|
||||
|
||||
/*If the last y coordinates are not handled yet ...*/
|
||||
if(y2 != row_last) {
|
||||
lv_vdb_t * vdb_p = lv_vdb_get();
|
||||
if(!vdb_p) {
|
||||
LV_LOG_WARN("Invalid VDB pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
/*Calc. the next y coordinates of VDB*/
|
||||
vdb_p->area.x1 = area_p->x1;
|
||||
@ -325,12 +375,16 @@ static void lv_refr_area_with_vdb(const lv_area_t * area_p)
|
||||
static void lv_refr_area_part_vdb(const lv_area_t * area_p)
|
||||
{
|
||||
lv_vdb_t * vdb_p = lv_vdb_get();
|
||||
if(!vdb_p) {
|
||||
LV_LOG_WARN("Invalid VDB pointer");
|
||||
return;
|
||||
}
|
||||
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_union(&start_mask, area_p, &vdb_p->area);
|
||||
lv_area_intersect(&start_mask, area_p, &vdb_p->area);
|
||||
|
||||
/*Get the most top object which is not covered by others*/
|
||||
top_p = lv_refr_get_top_obj(&start_mask, lv_scr_act());
|
||||
@ -342,7 +396,7 @@ static void lv_refr_area_part_vdb(const lv_area_t * area_p)
|
||||
lv_refr_obj_and_children(lv_layer_top(), &start_mask);
|
||||
lv_refr_obj_and_children(lv_layer_sys(), &start_mask);
|
||||
|
||||
/*Flush the content of the VDB*/
|
||||
/*Flush the content of the VDB*/
|
||||
lv_vdb_flush();
|
||||
}
|
||||
|
||||
@ -352,35 +406,35 @@ static void lv_refr_area_part_vdb(const lv_area_t * area_p)
|
||||
* 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
|
||||
* @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)
|
||||
{
|
||||
if(lv_area_is_in(area_p, &obj->coords) && obj->hidden == 0) {
|
||||
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_func(obj, area_p, LV_DESIGN_COVER_CHK) != false) {
|
||||
obj->design_func(obj, area_p, LV_DESIGN_COVER_CHK) != false &&
|
||||
lv_obj_get_opa_scale(obj) == LV_OPA_COVER) {
|
||||
found_p = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return found_p;
|
||||
}
|
||||
|
||||
@ -395,10 +449,10 @@ static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p)
|
||||
* 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_scr_act();
|
||||
|
||||
|
||||
/*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;
|
||||
@ -411,12 +465,12 @@ static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p)
|
||||
/*object before border_p has to be redrawn*/
|
||||
i = lv_ll_get_prev(&(par->child_ll), border_p);
|
||||
|
||||
while(i != NULL) {
|
||||
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;
|
||||
@ -441,7 +495,7 @@ 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 */
|
||||
@ -454,8 +508,8 @@ static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p)
|
||||
obj_area.y1 -= ext_size;
|
||||
obj_area.x2 += ext_size;
|
||||
obj_area.y2 += ext_size;
|
||||
union_ok = lv_area_union(&obj_ext_mask, mask_ori_p, &obj_area);
|
||||
|
||||
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) {
|
||||
|
||||
@ -468,34 +522,33 @@ static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p)
|
||||
|
||||
/*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_union(&obj_mask, mask_ori_p, &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;
|
||||
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_union(&mask_child, &obj_mask, &child_area);
|
||||
lv_area_t mask_child; /*Mask from obj and its child*/
|
||||
lv_obj_t * child_p;
|
||||
lv_area_t child_area;
|
||||
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 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 */
|
||||
if(style->body.opa != LV_OPA_TRANSP) {
|
||||
obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_POST);
|
||||
}
|
||||
obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_POST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_refr.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_REFR_H
|
||||
@ -16,7 +16,6 @@ extern "C" {
|
||||
#include "lv_obj.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
@ -46,6 +45,14 @@ extern "C" {
|
||||
*/
|
||||
void lv_refr_init(void);
|
||||
|
||||
/**
|
||||
* Redraw the invalidated areas now.
|
||||
* Normally the redarwing is peridocally 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 shoud be updated.
|
||||
*/
|
||||
void lv_refr_now(void);
|
||||
|
||||
/**
|
||||
* Invalidate an area
|
||||
* @param area_p pointer to area which should be invalidated
|
||||
|
@ -6,21 +6,18 @@
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../lv_conf.h"
|
||||
#include "lv_style.h"
|
||||
#include "lv_obj.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#if USE_LV_ANIMATION
|
||||
#define LV_STYLE_ANIM_RES 256
|
||||
#define LV_STYLE_ANIM_SHIFT 8 /*log2(LV_STYLE_ANIM_RES)*/
|
||||
#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;}
|
||||
|
||||
#define VAL_PROP(v1, v2, r) v1 + (((v2-v1) * r) >> LV_STYLE_ANIM_SHIFT)
|
||||
#define STYLE_ATTR_ANIM(attr, r) if(start->attr != end->attr) act->attr = VAL_PROP(start->attr, end->attr, r)
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@ -29,9 +26,9 @@
|
||||
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;
|
||||
lv_style_t * style_anim;
|
||||
void (*end_cb)(void *);
|
||||
}lv_style_anim_dsc_t;
|
||||
} lv_style_anim_dsc_t;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
@ -39,7 +36,7 @@ typedef struct {
|
||||
**********************/
|
||||
#if USE_LV_ANIMATION
|
||||
static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val);
|
||||
static void style_animation_common_end_cb(void *ptr);
|
||||
static void style_animation_common_end_cb(void * ptr);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
@ -70,7 +67,7 @@ lv_style_t lv_style_btn_ina;
|
||||
/**
|
||||
* Init the basic styles
|
||||
*/
|
||||
void lv_style_init (void)
|
||||
void lv_style_init(void)
|
||||
{
|
||||
/* Not White/Black/Gray colors are created by HSV model with
|
||||
* HUE = 210*/
|
||||
@ -106,7 +103,8 @@ void lv_style_init (void)
|
||||
|
||||
lv_style_scr.line.opa = LV_OPA_COVER;
|
||||
lv_style_scr.line.color = LV_COLOR_MAKE(0x20, 0x20, 0x20);
|
||||
lv_style_scr.line.width = 1;
|
||||
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));
|
||||
@ -146,12 +144,12 @@ void lv_style_init (void)
|
||||
lv_style_transp.glass = 1;
|
||||
lv_style_transp.body.border.width = 0;
|
||||
|
||||
/*Transparent tight style*/
|
||||
/*Transparent fitting size*/
|
||||
memcpy(&lv_style_transp_fit, &lv_style_transp, sizeof(lv_style_t));
|
||||
lv_style_transp_fit.body.padding.hor = 0;
|
||||
lv_style_transp_fit.body.padding.ver = 0;
|
||||
|
||||
/*Transparent fitting size*/
|
||||
/*Transparent tight style*/
|
||||
memcpy(&lv_style_transp_tight, &lv_style_transp_fit, sizeof(lv_style_t));
|
||||
lv_style_transp_tight.body.padding.inner = 0;
|
||||
|
||||
@ -216,25 +214,84 @@ 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.hor, ratio);
|
||||
STYLE_ATTR_MIX(body.padding.ver, 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.empty = start->body.empty;
|
||||
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.empty = end->body.empty;
|
||||
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 USE_LV_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)
|
||||
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.var = (void *)dsc;
|
||||
a.start = 0;
|
||||
a.end = LV_STYLE_ANIM_RES;
|
||||
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;
|
||||
@ -246,7 +303,10 @@ void lv_style_anim_create(lv_style_anim_t * anim)
|
||||
a.repeat_pause = anim->repeat_pause;
|
||||
|
||||
lv_anim_create(&a);
|
||||
|
||||
return dsc;
|
||||
}
|
||||
|
||||
#endif
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
@ -263,44 +323,7 @@ static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val)
|
||||
const lv_style_t * end = &dsc->style_end;
|
||||
lv_style_t * act = dsc->style_anim;
|
||||
|
||||
STYLE_ATTR_ANIM(body.opa, val);
|
||||
STYLE_ATTR_ANIM(body.radius, val);
|
||||
STYLE_ATTR_ANIM(body.border.width, val);
|
||||
STYLE_ATTR_ANIM(body.shadow.width, val);
|
||||
STYLE_ATTR_ANIM(body.padding.hor, val);
|
||||
STYLE_ATTR_ANIM(body.padding.ver, val);
|
||||
STYLE_ATTR_ANIM(body.padding.inner, val);
|
||||
STYLE_ATTR_ANIM(text.line_space, val);
|
||||
STYLE_ATTR_ANIM(text.letter_space, val);
|
||||
STYLE_ATTR_ANIM(text.opa, val);
|
||||
STYLE_ATTR_ANIM(line.width, val);
|
||||
STYLE_ATTR_ANIM(line.opa, val);
|
||||
STYLE_ATTR_ANIM(image.intense, val);
|
||||
STYLE_ATTR_ANIM(image.opa, val);
|
||||
|
||||
lv_opa_t opa = val == LV_STYLE_ANIM_RES ? LV_OPA_COVER : val;
|
||||
|
||||
act->body.main_color = lv_color_mix(end->body.main_color, start->body.main_color, opa);
|
||||
act->body.grad_color = lv_color_mix(end->body.grad_color, start->body.grad_color, opa);
|
||||
act->body.border.color = lv_color_mix(end->body.border.color, start->body.border.color, opa);
|
||||
act->body.shadow.color = lv_color_mix(end->body.shadow.color, start->body.shadow.color, opa);
|
||||
act->text.color = lv_color_mix(end->text.color, start->text.color, opa);
|
||||
act->image.color = lv_color_mix(end->image.color, start->image.color, opa);
|
||||
act->line.color = lv_color_mix(end->line.color, start->line.color, opa);
|
||||
|
||||
if(val == 0) {
|
||||
act->body.empty = start->body.empty;
|
||||
act->glass = start->glass;
|
||||
act->text.font = start->text.font;
|
||||
act->body.shadow.type = start->body.shadow.type;
|
||||
}
|
||||
|
||||
if(val == LV_STYLE_ANIM_RES) {
|
||||
act->body.empty = end->body.empty;
|
||||
act->glass = end->glass;
|
||||
act->text.font = end->text.font;
|
||||
act->body.shadow.type = end->body.shadow.type;
|
||||
}
|
||||
lv_style_mix(start, end, act, val);
|
||||
|
||||
lv_obj_report_style_mod(dsc->style_anim);
|
||||
}
|
||||
@ -310,9 +333,9 @@ static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val)
|
||||
* 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)
|
||||
static void style_animation_common_end_cb(void * ptr)
|
||||
{
|
||||
lv_style_anim_dsc_t *dsc = ptr; /*To avoid casting*/
|
||||
lv_style_anim_dsc_t * dsc = ptr; /*To avoid casting*/
|
||||
|
||||
if(dsc->end_cb) dsc->end_cb(dsc);
|
||||
|
||||
|
@ -29,7 +29,7 @@ extern "C" {
|
||||
**********************/
|
||||
|
||||
/*Border types (Use 'OR'ed values)*/
|
||||
typedef enum
|
||||
enum
|
||||
{
|
||||
LV_BORDER_NONE = 0x00,
|
||||
LV_BORDER_BOTTOM = 0x01,
|
||||
@ -37,22 +37,24 @@ typedef enum
|
||||
LV_BORDER_LEFT = 0x04,
|
||||
LV_BORDER_RIGHT = 0x08,
|
||||
LV_BORDER_FULL = 0x0F,
|
||||
}lv_border_part_t;
|
||||
};
|
||||
typedef uint8_t lv_border_part_t;
|
||||
|
||||
/*Shadow types*/
|
||||
typedef enum
|
||||
enum
|
||||
{
|
||||
LV_SHADOW_BOTTOM = 0,
|
||||
LV_SHADOW_FULL,
|
||||
}lv_shadow_type_t;
|
||||
};
|
||||
typedef uint8_t lv_shadow_type_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t glass :1; /*1: Do not inherit this style*/
|
||||
uint8_t glass :1; /*1: Do not inherit this style*/
|
||||
|
||||
struct {
|
||||
lv_color_t main_color;
|
||||
lv_color_t grad_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;
|
||||
|
||||
@ -61,22 +63,22 @@ typedef struct
|
||||
lv_coord_t width;
|
||||
lv_border_part_t part;
|
||||
lv_opa_t opa;
|
||||
}border;
|
||||
} border;
|
||||
|
||||
struct {
|
||||
lv_color_t color;
|
||||
lv_coord_t width;
|
||||
uint8_t type;
|
||||
}shadow;
|
||||
lv_shadow_type_t type;
|
||||
} shadow;
|
||||
|
||||
struct {
|
||||
lv_coord_t ver;
|
||||
lv_coord_t hor;
|
||||
lv_coord_t inner;
|
||||
}padding;
|
||||
} padding;
|
||||
|
||||
uint8_t empty :1; /*Transparent background (border still drawn)*/
|
||||
}body;
|
||||
} body;
|
||||
|
||||
|
||||
struct {
|
||||
@ -85,20 +87,21 @@ typedef struct
|
||||
lv_coord_t letter_space;
|
||||
lv_coord_t line_space;
|
||||
lv_opa_t opa;
|
||||
}text;
|
||||
} text;
|
||||
|
||||
struct {
|
||||
lv_color_t color;
|
||||
lv_opa_t intense;
|
||||
lv_opa_t opa;
|
||||
}image;
|
||||
} image;
|
||||
|
||||
struct {
|
||||
lv_color_t color;
|
||||
lv_coord_t width;
|
||||
lv_opa_t opa;
|
||||
}line;
|
||||
}lv_style_t;
|
||||
uint8_t rounded :1; /*1: rounded line endings*/
|
||||
} line;
|
||||
} lv_style_t;
|
||||
|
||||
#if USE_LV_ANIMATION
|
||||
typedef struct {
|
||||
@ -112,7 +115,7 @@ typedef struct {
|
||||
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;
|
||||
} lv_style_anim_t;
|
||||
|
||||
/* Example initialization
|
||||
lv_style_anim_t a;
|
||||
@ -146,12 +149,24 @@ void lv_style_init (void);
|
||||
*/
|
||||
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 USE_LV_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);
|
||||
void * lv_style_anim_create(lv_style_anim_t * anim);
|
||||
#endif
|
||||
|
||||
/*************************
|
||||
|
112
lv_core/lv_vdb.c
112
lv_core/lv_vdb.c
@ -1,17 +1,17 @@
|
||||
/**
|
||||
* @file lv_vdb.c
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include "../../lv_conf.h"
|
||||
#if LV_VDB_SIZE != 0
|
||||
|
||||
#include "../lv_hal/lv_hal_disp.h"
|
||||
#include <stddef.h>
|
||||
#include "lv_vdb.h"
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_vdb.h"
|
||||
#if LV_VDB_SIZE != 0
|
||||
|
||||
#include "../lv_hal/lv_hal_disp.h"
|
||||
#include "../lv_misc/lv_log.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -20,11 +20,12 @@
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef enum {
|
||||
LV_VDB_STATE_FREE = 0,
|
||||
LV_VDB_STATE_ACTIVE,
|
||||
LV_VDB_STATE_FLUSH,
|
||||
} lv_vdb_state_t;
|
||||
enum {
|
||||
LV_VDB_STATE_FREE = 0, /*Not used*/
|
||||
LV_VDB_STATE_ACTIVE, /*Being used to render*/
|
||||
LV_VDB_STATE_FLUSH, /*Flushing pixels from it*/
|
||||
};
|
||||
typedef uint8_t lv_vdb_state_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
@ -34,29 +35,28 @@ typedef enum {
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
|
||||
#if LV_VDB_DOUBLE == 0
|
||||
/*Simple VDB*/
|
||||
static volatile lv_vdb_state_t vdb_state = LV_VDB_STATE_ACTIVE;
|
||||
/*Simple VDB*/
|
||||
static volatile lv_vdb_state_t vdb_state = LV_VDB_STATE_ACTIVE;
|
||||
# if LV_VDB_ADR == 0
|
||||
/*If the buffer address is not specified simply allocate it*/
|
||||
static lv_color_t vdb_buf[LV_VDB_SIZE];
|
||||
static lv_vdb_t vdb = {.buf = vdb_buf};
|
||||
# else
|
||||
/*If the buffer address is specified use that address*/
|
||||
static lv_vdb_t vdb = {.buf = (lv_color_t *)LV_VDB_ADR};
|
||||
/*If the buffer address is not specified simply allocate it*/
|
||||
static uint8_t vdb_buf[LV_VDB_SIZE_IN_BYTES];
|
||||
static lv_vdb_t vdb = {.buf = (lv_color_t *)vdb_buf};
|
||||
# else /*LV_VDB_ADR != 0*/
|
||||
/*If the buffer address is specified use that address*/
|
||||
static lv_vdb_t vdb = {.buf = (lv_color_t *)LV_VDB_ADR};
|
||||
# endif
|
||||
#else
|
||||
/*Double VDB*/
|
||||
static volatile lv_vdb_state_t vdb_state[2] = {LV_VDB_STATE_FREE, LV_VDB_STATE_FREE};
|
||||
#else /*LV_VDB_DOUBLE != 0*/
|
||||
/*Double VDB*/
|
||||
static volatile lv_vdb_state_t vdb_state[2] = {LV_VDB_STATE_FREE, LV_VDB_STATE_FREE};
|
||||
# if LV_VDB_ADR == 0
|
||||
/*If the buffer address is not specified simply allocate it*/
|
||||
static lv_color_t vdb_buf1[LV_VDB_SIZE];
|
||||
static lv_color_t vdb_buf2[LV_VDB_SIZE];
|
||||
static lv_vdb_t vdb[2] = {{.buf = vdb_buf1}, {.buf = vdb_buf2}};
|
||||
# else
|
||||
/*If the buffer address is specified use that address*/
|
||||
static lv_vdb_t vdb[2] = {{.buf = (lv_color_t *)LV_VDB_ADR}, {.buf = (lv_color_t *)LV_VDB2_ADR}};
|
||||
/*If the buffer address is not specified simply allocate it*/
|
||||
static uint8_t vdb_buf1[LV_VDB_SIZE_IN_BYTES];
|
||||
static uint8_t vdb_buf2[LV_VDB_SIZE_IN_BYTES];
|
||||
static lv_vdb_t vdb[2] = {{.buf = (lv_color_t *) vdb_buf1}, {.buf = (lv_color_t *) vdb_buf2}};
|
||||
# else /*LV_VDB_ADR != 0*/
|
||||
/*If the buffer address is specified use that address*/
|
||||
static lv_vdb_t vdb[2] = {{.buf = (lv_color_t *)LV_VDB_ADR}, {.buf = (lv_color_t *)LV_VDB2_ADR}};
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@ -78,6 +78,11 @@ lv_vdb_t * lv_vdb_get(void)
|
||||
/* Wait until VDB become ACTIVE from FLUSH by the
|
||||
* user call of 'lv_flush_ready()' in display drivers's flush function*/
|
||||
while(vdb_state != LV_VDB_STATE_ACTIVE);
|
||||
|
||||
if(vdb.buf == (void *)LV_VDB_ADR_INV) {
|
||||
LV_LOG_ERROR("VDB address is invalid. Use `lv_vdb_set_adr` to set a valid address or use LV_VDB_ADR = 0 in lv_conf.h");
|
||||
return NULL;
|
||||
}
|
||||
return &vdb;
|
||||
#else
|
||||
/*If already there is an active do nothing*/
|
||||
@ -105,8 +110,10 @@ lv_vdb_t * lv_vdb_get(void)
|
||||
void lv_vdb_flush(void)
|
||||
{
|
||||
lv_vdb_t * vdb_act = lv_vdb_get();
|
||||
if(vdb_act == NULL) return;
|
||||
|
||||
if(!vdb_act) {
|
||||
LV_LOG_WARN("Invalid VDB pointer");
|
||||
return;
|
||||
}
|
||||
#if LV_VDB_DOUBLE == 0
|
||||
vdb_state = LV_VDB_STATE_FLUSH; /*User call to 'lv_flush_ready()' will set to ACTIVE 'disp_flush'*/
|
||||
#else
|
||||
@ -120,10 +127,28 @@ void lv_vdb_flush(void)
|
||||
#endif
|
||||
|
||||
/*Flush the rendered content to the display*/
|
||||
lv_disp_flush(vdb_act->area.x1, vdb_act->area.y1, vdb_act->area.x2, vdb_act->area.y2, vdb_act->buf);
|
||||
lv_disp_flush(vdb_act->area.x1, vdb_act->area.y1, vdb_act->area.x2, vdb_act->area.y2, vdb_act->buf);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`.
|
||||
* It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES`
|
||||
* @param buf1 address of the VDB.
|
||||
* @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0`
|
||||
*/
|
||||
void lv_vdb_set_adr(void * buf1, void * buf2)
|
||||
{
|
||||
#if LV_VDB_DOUBLE == 0
|
||||
(void) buf2; /*unused*/
|
||||
vdb.buf = buf1;
|
||||
#else
|
||||
vdb[0].buf = buf1;
|
||||
vdb[1].buf = buf2;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Call in the display driver's 'disp_flush' function when the flushing is finished
|
||||
*/
|
||||
@ -131,9 +156,24 @@ void lv_flush_ready(void)
|
||||
{
|
||||
#if LV_VDB_DOUBLE == 0
|
||||
vdb_state = LV_VDB_STATE_ACTIVE;
|
||||
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
memset(vdb_buf, 0x00, LV_VDB_SIZE_IN_BYTES);
|
||||
#endif
|
||||
|
||||
#else
|
||||
if(vdb_state[0] == LV_VDB_STATE_FLUSH) vdb_state[0] = LV_VDB_STATE_FREE;
|
||||
if(vdb_state[1] == LV_VDB_STATE_FLUSH) vdb_state[1] = LV_VDB_STATE_FREE;
|
||||
if(vdb_state[0] == LV_VDB_STATE_FLUSH) {
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
memset(vdb_buf[0], 0x00, LV_VDB_SIZE_IN_BYTES);
|
||||
#endif
|
||||
vdb_state[0] = LV_VDB_STATE_FREE;
|
||||
}
|
||||
if(vdb_state[1] == LV_VDB_STATE_FLUSH) {
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
memset(vdb_buf[1], 0x00, LV_VDB_SIZE_IN_BYTES);
|
||||
#endif
|
||||
vdb_state[1] = LV_VDB_STATE_FREE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_vdb.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_VDB_H
|
||||
@ -13,7 +13,11 @@ extern "C" {
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if LV_VDB_SIZE != 0
|
||||
|
||||
@ -23,6 +27,19 @@ extern "C" {
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
/*Can be used in `lv_conf.h` the set an invalid address for the VDB. It should be replaced later by a valid address using `lv_vdb_set_adr()`*/
|
||||
#define LV_VDB_ADR_INV 8 /*8 is still too small to be valid but it's aligned on 64 bit machines as well*/
|
||||
|
||||
#ifndef LV_VDB_PX_BPP
|
||||
#warning "LV_VDB_PX_BPP is not specified in lv_conf.h. Use the default value (LV_COLOR_SIZE)"
|
||||
#define LV_VDB_PX_BPP LV_COLOR_SIZE
|
||||
#endif
|
||||
|
||||
/* The size of VDB in bytes.
|
||||
* (LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3): just divide by 8 to convert bits to bytes
|
||||
* (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0): add an extra byte to round up.
|
||||
* E.g. if LV_VDB_SIZE = 10 and LV_VDB_PX_BPP = 1 -> 10 bits -> 2 bytes*/
|
||||
#define LV_VDB_SIZE_IN_BYTES ((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@ -32,7 +49,7 @@ typedef struct
|
||||
{
|
||||
lv_area_t area;
|
||||
lv_color_t *buf;
|
||||
}lv_vdb_t;
|
||||
} lv_vdb_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
@ -49,10 +66,16 @@ lv_vdb_t * lv_vdb_get(void);
|
||||
*/
|
||||
void lv_vdb_flush(void);
|
||||
|
||||
/**
|
||||
* Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`.
|
||||
* It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES`
|
||||
* @param buf1 address of the VDB.
|
||||
* @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0`
|
||||
*/
|
||||
void lv_vdb_set_adr(void * buf1, void * buf2);
|
||||
|
||||
/**
|
||||
* In 'LV_VDB_DOUBLE' mode has to be called when 'disp_map()'
|
||||
* is ready with copying the map to a frame buffer.
|
||||
* Call in the display driver's 'disp_flush' function when the flushing is finished
|
||||
*/
|
||||
void lv_flush_ready(void);
|
||||
|
||||
|
2131
lv_draw/lv_draw.c
2131
lv_draw/lv_draw.c
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_draw.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_H
|
||||
@ -13,6 +13,12 @@ extern "C" {
|
||||
/*********************
|
||||
* 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"
|
||||
|
||||
@ -24,114 +30,83 @@ extern "C" {
|
||||
# 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 == 24
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
# define LV_IMG_PX_SIZE_ALPHA_BYTE 4
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
**********************/
|
||||
|
||||
/* Image header it is compatible with
|
||||
* the result image converter utility*/
|
||||
typedef struct
|
||||
{
|
||||
union{
|
||||
struct {
|
||||
uint32_t chroma_keyed:1; /*1: The image contains transparent pixels with LV_COLOR_TRANSP color*/
|
||||
uint32_t alpha_byte :1; /*Every pixel is extended with a 8 bit alpha channel*/
|
||||
uint32_t format :6; /*See: lv_img_px_format*/
|
||||
uint32_t w:12; /*Width of the image map*/
|
||||
uint32_t h:12; /*Height of the image map*/
|
||||
}header;
|
||||
uint8_t src_type;
|
||||
};
|
||||
|
||||
union {
|
||||
const uint8_t * pixel_map; /*For internal images (c arrays) pointer to the pixels array*/
|
||||
uint8_t first_pixel; /*For external images (binary) the first byte of the pixels (just for convenient)*/
|
||||
};
|
||||
}lv_img_t;
|
||||
|
||||
typedef enum {
|
||||
LV_IMG_FORMAT_UNKOWN = 0,
|
||||
LV_IMG_FORMAT_INTERNAL_RAW, /*'lv_img_t' variable compiled with the code*/
|
||||
LV_IMG_FORMAT_FILE_RAW_RGB332, /*8 bit*/
|
||||
LV_IMG_FORMAT_FILE_RAW_RGB565, /*16 bit*/
|
||||
LV_IMG_FORMAT_FILE_RAW_RGB888, /*24 bit (stored on 32 bit)*/
|
||||
}lv_img_format_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
LV_IMG_SRC_VARIABLE,
|
||||
LV_IMG_SRC_FILE,
|
||||
LV_IMG_SRC_SYMBOL,
|
||||
LV_IMG_SRC_UNKNOWN,
|
||||
}lv_img_src_t;
|
||||
};
|
||||
typedef uint8_t lv_img_src_t;
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw a rectangle
|
||||
* @param cords_p the coordinates of the rectangle
|
||||
* @param mask_p the rectangle will be drawn only in this mask
|
||||
* @param style_p pointer to a style
|
||||
*/
|
||||
void lv_draw_rect(const lv_area_t * cords_p, const lv_area_t * mask_p, const lv_style_t * style_p);
|
||||
#if LV_ANTIALIAS != 0
|
||||
|
||||
|
||||
/*Experimental use for 3D modeling*/
|
||||
#define USE_LV_TRIANGLE 0
|
||||
#if USE_LV_TRIANGLE != 0
|
||||
/**
|
||||
*
|
||||
* @param points pointer to an array with 3 points
|
||||
* @param mask_p the triangle will be drawn only in this mask
|
||||
* @param color color of the triangle
|
||||
* 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
|
||||
*/
|
||||
void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask_p, lv_color_t color);
|
||||
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
|
||||
|
||||
/**
|
||||
* Write a text
|
||||
* @param cords_p coordinates of the label
|
||||
* @param mask_p the label will be drawn only in this area
|
||||
* @param style_p pointer to a style
|
||||
* @param txt 0 terminated text to write
|
||||
* @param flags 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 * cords_p,const lv_area_t * mask_p, const lv_style_t * style_p,
|
||||
const char * txt, lv_txt_flag_t flag, lv_point_t * offset);
|
||||
|
||||
#if USE_LV_IMG
|
||||
/**
|
||||
* Draw an image
|
||||
* @param cords_p the coordinates of the image
|
||||
* @param mask_p the image will be drawn only in this area
|
||||
* @param map_p pointer to a lv_color_t array which contains the pixels of the image
|
||||
*/
|
||||
void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask,
|
||||
const lv_style_t * style, const void * src);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Draw a line
|
||||
* @param p1 first point of the line
|
||||
* @param p2 second point of the line
|
||||
* @param mask_pthe line will be drawn only on this area
|
||||
* @param style_p pointer to a style
|
||||
*/
|
||||
void lv_draw_line(const lv_point_t * p1, const lv_point_t * p2, const lv_area_t * mask_p,
|
||||
const lv_style_t * style_p);
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
extern void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);
|
||||
extern void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);
|
||||
extern void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa);
|
||||
extern void (*const map_fp)(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
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* POST INCLUDES
|
||||
*********************/
|
||||
#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" */
|
||||
|
@ -1,6 +1,12 @@
|
||||
CSRCS += lv_draw_vbasic.c
|
||||
CSRCS += lv_draw.c
|
||||
CSRCS += lv_draw_rbasic.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/lv_draw
|
||||
VPATH += :lvgl/lv_draw
|
||||
|
264
lv_draw/lv_draw_arc.c
Normal file
264
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);
|
||||
|
||||
fill_fp(&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);
|
||||
|
||||
fill_fp(&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
lv_draw/lv_draw_arc.h
Normal file
53
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*/
|
740
lv_draw/lv_draw_img.c
Normal file
740
lv_draw/lv_draw_img.c
Normal file
@ -0,0 +1,740 @@
|
||||
/**
|
||||
* @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 USE_LV_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 USE_LV_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_UNKOWN;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
switch(cf) {
|
||||
case LV_IMG_CF_UNKOWN:
|
||||
case LV_IMG_CF_RAW:
|
||||
return 0;
|
||||
case LV_IMG_CF_TRUE_COLOR:
|
||||
case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
|
||||
return LV_COLOR_SIZE;
|
||||
case LV_IMG_CF_TRUE_COLOR_ALPHA:
|
||||
return LV_IMG_PX_SIZE_ALPHA_BYTE;
|
||||
|
||||
case LV_IMG_CF_INDEXED_1BIT:
|
||||
case LV_IMG_CF_ALPHA_1BIT:
|
||||
return 1;
|
||||
|
||||
case LV_IMG_CF_INDEXED_2BIT:
|
||||
case LV_IMG_CF_ALPHA_2BIT:
|
||||
return 2;
|
||||
|
||||
case LV_IMG_CF_INDEXED_4BIT:
|
||||
case LV_IMG_CF_ALPHA_4BIT:
|
||||
return 4;
|
||||
|
||||
case LV_IMG_CF_INDEXED_8BIT:
|
||||
case LV_IMG_CF_ALPHA_8BIT:
|
||||
return 8;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf)
|
||||
{
|
||||
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:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool lv_img_color_format_has_alpha(lv_img_cf_t cf)
|
||||
{
|
||||
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:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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. SYMBOL_CLOSE)
|
||||
* @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN
|
||||
*/
|
||||
lv_img_src_t lv_img_src_get_type(const void * src)
|
||||
{
|
||||
if(src == NULL) return LV_IMG_SRC_UNKNOWN;
|
||||
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) {
|
||||
return LV_IMG_SRC_FILE; /*If it's an ASCII character then it's file name*/
|
||||
} else if(u8_p[0] >= 0x80) {
|
||||
return LV_IMG_SRC_SYMBOL; /*Symbols begins after 0x7F*/
|
||||
} else {
|
||||
return LV_IMG_SRC_VARIABLE; /*`lv_img_dsc_t` is design to the first byte < 0x20*/
|
||||
}
|
||||
|
||||
LV_LOG_WARN("lv_img_src_get_type: unknown image type");
|
||||
return LV_IMG_SRC_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
map_fp(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_SIZE + 1))];
|
||||
#else
|
||||
uint8_t buf[LV_HOR_RES * ((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;
|
||||
}
|
||||
map_fp(&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 USE_LV_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 USE_LV_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 USE_LV_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 USE_LV_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 USE_LV_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].red, palette_p[i].green, palette_p[i].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 USE_LV_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;
|
||||
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 USE_LV_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 USE_LV_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 USE_LV_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 USE_LV_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 USE_LV_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 USE_LV_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 USE_LV_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 USE_LV_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
lv_draw/lv_draw_img.h
Normal file
167
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_UNKOWN = 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. SYMBOL_CLOSE)
|
||||
* @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN
|
||||
*/
|
||||
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*/
|
236
lv_draw/lv_draw_label.c
Normal file
236
lv_draw/lv_draw_label.c
Normal file
@ -0,0 +1,236 @@
|
||||
/**
|
||||
* @file lv_draw_label.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_label.h"
|
||||
#include "lv_draw_rbasic.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;
|
||||
}
|
||||
|
||||
/*Init variables for the first line*/
|
||||
lv_coord_t line_width = 0;
|
||||
uint32_t line_start = 0;
|
||||
uint32_t line_end = lv_txt_get_next_line(txt, font, style->text.letter_space, w, flag);
|
||||
|
||||
lv_point_t pos;
|
||||
pos.x = coords->x1;
|
||||
pos.y = coords->y1;
|
||||
|
||||
/*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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*Real draw need a background color for higher bpp letter*/
|
||||
#if LV_VDB_SIZE == 0
|
||||
lv_rletter_set_background(style->body.main_color);
|
||||
#endif
|
||||
|
||||
/*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;
|
||||
|
||||
letter_fp(&pos, mask, font, letter, color, opa);
|
||||
letter_w = lv_font_get_width(font, letter);
|
||||
|
||||
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 += lv_font_get_height(font);
|
||||
pos.y += style->text.line_space;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* 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)
|
||||
{
|
||||
if(hex >= '0' && hex <= '9') {
|
||||
return hex - '0';
|
||||
}
|
||||
|
||||
if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/
|
||||
|
||||
switch(hex) {
|
||||
case 'A':
|
||||
return 10;
|
||||
case 'B':
|
||||
return 11;
|
||||
case 'C':
|
||||
return 12;
|
||||
case 'D':
|
||||
return 13;
|
||||
case 'E':
|
||||
return 14;
|
||||
case 'F':
|
||||
return 15;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
53
lv_draw/lv_draw_label.h
Normal file
53
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*/
|
562
lv_draw/lv_draw_line.c
Normal file
562
lv_draw/lv_draw_line.c
Normal file
@ -0,0 +1,562 @@
|
||||
/**
|
||||
* @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, 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 {
|
||||
line_draw_skew(&main_line, mask, style, opa_scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
static void line_draw_hor(line_draw_t * 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 = line->p1.x;
|
||||
act_area.x2 = line->p2.x;
|
||||
act_area.y1 = line->p1.y - width_half - width_1;
|
||||
act_area.y2 = 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);
|
||||
fill_fp(&draw_area, mask, style->line.color, opa);
|
||||
}
|
||||
|
||||
static void line_draw_ver(line_draw_t * 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 = line->p1.x - width_half;
|
||||
act_area.x2 = line->p2.x + width_half + width_1;
|
||||
act_area.y1 = line->p1.y;
|
||||
act_area.y2 = 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);
|
||||
fill_fp(&draw_area, mask, style->line.color, opa);
|
||||
}
|
||||
|
||||
static void line_draw_skew(line_draw_t * main_line, 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) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
pattern[0].x = 0;
|
||||
pattern[0].y = 0;
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
/* Make the coordinates relative to the center */
|
||||
for(i = 0; i < width; i++) {
|
||||
pattern[i].x -= pattern[width - 1].x / 2;
|
||||
pattern[i].y -= pattern[width - 1].y / 2;
|
||||
#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(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;
|
||||
fill_fp(&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) {
|
||||
px_fp(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;
|
||||
fill_fp(&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) {
|
||||
px_fp(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;
|
||||
|
||||
fill_fp(&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) {
|
||||
px_fp(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;
|
||||
|
||||
fill_fp(&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) {
|
||||
px_fp(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
lv_draw/lv_draw_line.h
Normal file
49
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*/
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_draw_rbasic.c
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
@ -66,25 +66,25 @@ void lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t col
|
||||
* @param color fill color
|
||||
* @param opa opacity (ignored, only for compatibility with lv_vfill)
|
||||
*/
|
||||
void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
{
|
||||
|
||||
(void)opa; /*Opa is used only for compatibility with lv_vfill*/
|
||||
|
||||
lv_area_t masked_area;
|
||||
bool union_ok = true;
|
||||
|
||||
|
||||
if(mask_p != NULL) {
|
||||
union_ok = lv_area_union(&masked_area, cords_p, mask_p);
|
||||
union_ok = lv_area_intersect(&masked_area, cords_p, mask_p);
|
||||
} else {
|
||||
lv_area_t scr_area;
|
||||
lv_area_set(&scr_area, 0, 0, LV_HOR_RES - 1, LV_VER_RES - 1);
|
||||
union_ok = lv_area_union(&masked_area, cords_p, &scr_area);
|
||||
union_ok = lv_area_intersect(&masked_area, cords_p, &scr_area);
|
||||
}
|
||||
|
||||
if(union_ok != false){
|
||||
lv_disp_fill(masked_area.x1, masked_area.y1, masked_area.x2, masked_area.y2, color);
|
||||
|
||||
if(union_ok != false) {
|
||||
lv_disp_fill(masked_area.x1, masked_area.y1, masked_area.x2, masked_area.y2, color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,39 +92,53 @@ void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
* Draw a letter to the display
|
||||
* @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 font_p pointer to font
|
||||
* @param letter a letter to draw
|
||||
* @param color color of letter
|
||||
* @param opa opacity of letter (ignored, only for compatibility with lv_vletter)
|
||||
*/
|
||||
void lv_rletter(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 lv_font_t * font_p, uint32_t letter,
|
||||
lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
(void)opa; /*Opa is used only for compatibility with lv_vletter*/
|
||||
|
||||
static uint8_t bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
|
||||
static uint8_t bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
|
||||
static 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};
|
||||
68, 85, 102, 119,
|
||||
136, 153, 170, 187,
|
||||
204, 221, 238, 255
|
||||
};
|
||||
|
||||
if(font_p == NULL) return;
|
||||
|
||||
uint8_t letter_w = lv_font_get_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)*/
|
||||
uint8_t *bpp_opa_table;
|
||||
uint8_t * bpp_opa_table;
|
||||
uint8_t mask_init;
|
||||
uint8_t mask;
|
||||
|
||||
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*/
|
||||
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);
|
||||
@ -133,7 +147,7 @@ void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
|
||||
|
||||
/*If the letter is completely out of mask don't draw it */
|
||||
if(pos_p->x + letter_w < mask_p->x1 || pos_p->x > mask_p->x2 ||
|
||||
pos_p->y + letter_h < mask_p->y1 || pos_p->y > mask_p->y2) return;
|
||||
pos_p->y + letter_h < mask_p->y1 || pos_p->y > mask_p->y2) return;
|
||||
|
||||
lv_coord_t col, row;
|
||||
uint8_t col_bit;
|
||||
@ -166,8 +180,7 @@ void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
|
||||
if(col_bit < 8 - bpp) {
|
||||
col_bit += bpp;
|
||||
mask = mask >> bpp;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
col_bit = 0;
|
||||
col_byte_cnt ++;
|
||||
mask = mask_init;
|
||||
@ -200,8 +213,8 @@ void lv_rletter_set_background(lv_color_t color)
|
||||
* @param recolor_opa the intense of recoloring
|
||||
*/
|
||||
void lv_rmap(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)
|
||||
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(alpha_byte) return; /*Pixel level opacity i not supported in real map drawing*/
|
||||
|
||||
@ -209,7 +222,7 @@ void lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
lv_area_t masked_a;
|
||||
bool union_ok;
|
||||
|
||||
union_ok = lv_area_union(&masked_a, cords_p, mask_p);
|
||||
union_ok = lv_area_intersect(&masked_a, cords_p, mask_p);
|
||||
|
||||
/*If there are common part of the mask and map then draw the map*/
|
||||
if(union_ok == false) return;
|
||||
@ -223,7 +236,7 @@ void lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
if(recolor_opa == LV_OPA_TRANSP && chroma_key == false) {
|
||||
lv_coord_t mask_w = lv_area_get_width(&masked_a) - 1;
|
||||
for(row = masked_a.y1; row <= masked_a.y2; row++) {
|
||||
lv_disp_map(masked_a.x1, row, masked_a.x1 + mask_w, row, (lv_color_t*)map_p);
|
||||
lv_disp_map(masked_a.x1, row, masked_a.x1 + mask_w, row, (lv_color_t *)map_p);
|
||||
map_p += map_width * sizeof(lv_color_t); /*Next row on the map*/
|
||||
}
|
||||
} else {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_draw_rbasic..h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_RBASIC_H
|
||||
@ -13,7 +13,12 @@ extern "C" {
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if USE_LV_REAL_DRAW != 0
|
||||
|
||||
#include "../lv_misc/lv_color.h"
|
||||
@ -42,7 +47,7 @@ void lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t col
|
||||
* @param opa opacity (ignored, only for compatibility with lv_vfill)
|
||||
*/
|
||||
void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
lv_color_t color, lv_opa_t opa);
|
||||
lv_color_t color, lv_opa_t opa);
|
||||
|
||||
/**
|
||||
* Draw a letter to the display
|
||||
@ -76,8 +81,8 @@ void lv_rletter_set_background(lv_color_t color);
|
||||
* @param recolor_opa the intense of recoloring
|
||||
*/
|
||||
void lv_rmap(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);
|
||||
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
|
||||
**********************/
|
||||
|
1435
lv_draw/lv_draw_rect.c
Normal file
1435
lv_draw/lv_draw_rect.c
Normal file
File diff suppressed because it is too large
Load Diff
48
lv_draw/lv_draw_rect.h
Normal file
48
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*/
|
168
lv_draw/lv_draw_triangle.c
Normal file
168
lv_draw/lv_draw_triangle.c
Normal file
@ -0,0 +1,168 @@
|
||||
/**
|
||||
* @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
|
||||
**********************/
|
||||
#if USE_LV_TRIANGLE != 0
|
||||
/**
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color)
|
||||
{
|
||||
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*/
|
||||
fill_fp(&draw_area, mask, color, LV_OPA_50);
|
||||
|
||||
/*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);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
#if USE_LV_TRIANGLE != 0
|
||||
/**
|
||||
* 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;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
51
lv_draw/lv_draw_triangle.h
Normal file
51
lv_draw/lv_draw_triangle.h
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @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
|
||||
**********************/
|
||||
/*Experimental use for 3D modeling*/
|
||||
#define USE_LV_TRIANGLE 1
|
||||
|
||||
#if USE_LV_TRIANGLE != 0
|
||||
/**
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_TRIANGLE_H*/
|
@ -1,9 +1,9 @@
|
||||
/**
|
||||
* @file lv_vdraw.c
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../lv_conf.h"
|
||||
#include "lv_draw_vbasic.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@ -13,6 +13,7 @@
|
||||
#include "../lv_misc/lv_area.h"
|
||||
#include "../lv_misc/lv_font.h"
|
||||
#include "../lv_misc/lv_color.h"
|
||||
#include "../lv_misc/lv_log.h"
|
||||
|
||||
#if LV_VDB_SIZE != 0
|
||||
|
||||
@ -39,6 +40,10 @@
|
||||
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
|
||||
**********************/
|
||||
@ -61,27 +66,42 @@ static void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_
|
||||
*/
|
||||
void lv_vpx(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;
|
||||
|
||||
lv_vdb_t * vdb_p = lv_vdb_get();
|
||||
if(!vdb_p) {
|
||||
LV_LOG_WARN("Invalid VDB pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
/*Pixel out of the mask*/
|
||||
if(x < mask_p->x1 || x > mask_p->x2 ||
|
||||
y < mask_p->y1 || y > mask_p->y2) {
|
||||
y < mask_p->y1 || y > mask_p->y2) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t vdb_width = lv_area_get_width(&vdb_p->area);
|
||||
|
||||
/*Make the coordinates relative to VDB*/
|
||||
x-=vdb_p->area.x1;
|
||||
y-=vdb_p->area.y1;
|
||||
lv_color_t * vdb_px_p = vdb_p->buf + y * vdb_width + x;
|
||||
if(opa == LV_OPA_COVER) {
|
||||
*vdb_px_p = color;
|
||||
}
|
||||
else {
|
||||
*vdb_px_p = lv_color_mix(color,*vdb_px_p, opa);
|
||||
}
|
||||
x -= vdb_p->area.x1;
|
||||
y -= vdb_p->area.y1;
|
||||
|
||||
lv_disp_t * disp = lv_disp_get_active();
|
||||
if(disp->driver.vdb_wr) {
|
||||
disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, x, y, color, opa);
|
||||
} else {
|
||||
lv_color_t * vdb_px_p = vdb_p->buf + 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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -92,18 +112,25 @@ void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t col
|
||||
* @param color fill color
|
||||
* @param opa opacity of the area (0..255)
|
||||
*/
|
||||
void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
lv_color_t color, lv_opa_t opa)
|
||||
void lv_vfill(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;
|
||||
lv_vdb_t * vdb_p = lv_vdb_get();
|
||||
|
||||
if(!vdb_p) {
|
||||
LV_LOG_WARN("Invalid VDB pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
/*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_union(&res_a, cords_p, mask_p);
|
||||
|
||||
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;
|
||||
|
||||
@ -126,22 +153,21 @@ void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
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_p->area, vdb_buf_tmp, &vdb_rel_a, color, opa);
|
||||
sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);
|
||||
}
|
||||
/*Not opaque fill*/
|
||||
else if(opa == LV_OPA_COVER) {
|
||||
/*Use hw fill if present*/
|
||||
if(lv_disp_is_mem_fill_supported()) {
|
||||
lv_coord_t row;
|
||||
for(row = vdb_rel_a.y1;row <= vdb_rel_a.y2; row++) {
|
||||
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
|
||||
lv_disp_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 &&
|
||||
lv_disp_is_mem_blend_supported())
|
||||
{
|
||||
lv_disp_is_mem_blend_supported()) {
|
||||
/*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;
|
||||
@ -153,7 +179,7 @@ void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
|
||||
/*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++) {
|
||||
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
|
||||
lv_disp_mem_blend(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa);
|
||||
vdb_buf_tmp += vdb_width;
|
||||
}
|
||||
@ -161,7 +187,7 @@ void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
}
|
||||
/*Else use sw fill if no better option*/
|
||||
else {
|
||||
sw_color_fill(&vdb_p->area, vdb_buf_tmp, &vdb_rel_a, color, opa);
|
||||
sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);
|
||||
}
|
||||
|
||||
}
|
||||
@ -178,7 +204,7 @@ void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
last_width = w;
|
||||
}
|
||||
lv_coord_t row;
|
||||
for(row = vdb_rel_a.y1;row <= vdb_rel_a.y2; row++) {
|
||||
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
|
||||
lv_disp_mem_blend(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa);
|
||||
vdb_buf_tmp += vdb_width;
|
||||
}
|
||||
@ -186,12 +212,12 @@ void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
}
|
||||
/*Use sw fill with opa if no better option*/
|
||||
else {
|
||||
sw_color_fill(&vdb_p->area, vdb_buf_tmp, &vdb_rel_a, color, opa);
|
||||
sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
sw_color_fill(&vdb_p->area, vdb_buf_tmp, &vdb_rel_a, color, opa);
|
||||
sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -199,38 +225,63 @@ void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
* 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 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_vletter(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)
|
||||
void lv_vletter(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)
|
||||
{
|
||||
|
||||
static uint8_t bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
|
||||
static uint8_t bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
|
||||
static uint8_t bpp4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
|
||||
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};
|
||||
204, 221, 238, 255
|
||||
};
|
||||
if(opa < LV_OPA_MIN) return;
|
||||
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
|
||||
|
||||
if(font_p == NULL) return;
|
||||
if(font_p == NULL) {
|
||||
LV_LOG_WARN("Font: character's bitmap not found");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t letter_w = lv_font_get_width(font_p, letter);
|
||||
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)*/
|
||||
uint8_t *bpp_opa_table;
|
||||
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*/
|
||||
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);
|
||||
@ -238,10 +289,15 @@ void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
|
||||
if(map_p == NULL) return;
|
||||
|
||||
/*If the letter is completely out of mask don't draw it */
|
||||
if(pos_p->x + letter_w < mask_p->x1 || pos_p->x > mask_p->x2 ||
|
||||
pos_p->y + letter_h < mask_p->y1 || pos_p->y > mask_p->y2) return;
|
||||
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_vdb_t * vdb_p = lv_vdb_get();
|
||||
if(!vdb_p) {
|
||||
LV_LOG_WARN("Invalid VDB pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_coord_t vdb_width = lv_area_get_width(&vdb_p->area);
|
||||
lv_color_t * vdb_buf_tmp = vdb_p->buf;
|
||||
lv_coord_t col, row;
|
||||
@ -253,14 +309,14 @@ void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
|
||||
if((letter_w * bpp) & 0x7) width_byte_bpp++;
|
||||
|
||||
/* Calculate the col/row start/end on the map*/
|
||||
lv_coord_t col_start = pos_p->x >= mask_p->x1 ? 0 : mask_p->x1 - pos_p->x;
|
||||
lv_coord_t col_end = pos_p->x + letter_w <= mask_p->x2 ? letter_w : mask_p->x2 - pos_p->x + 1;
|
||||
lv_coord_t row_start = pos_p->y >= mask_p->y1 ? 0 : mask_p->y1 - pos_p->y;
|
||||
lv_coord_t row_end = pos_p->y + letter_h <= mask_p->y2 ? letter_h : mask_p->y2 - pos_p->y + 1;
|
||||
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_p->y - vdb_p->area.y1) * vdb_width)
|
||||
+ pos_p->x - vdb_p->area.x1;
|
||||
vdb_buf_tmp += ((pos_y - vdb_p->area.y1) * vdb_width)
|
||||
+ pos_x - vdb_p->area.x1;
|
||||
|
||||
/*If the letter is partially out of mask the move there on VDB*/
|
||||
vdb_buf_tmp += (row_start * vdb_width) + col_start;
|
||||
@ -268,7 +324,10 @@ void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
|
||||
/*Move on the map too*/
|
||||
map_p += (row_start * width_byte_bpp) + ((col_start * bpp) >> 3);
|
||||
|
||||
lv_disp_t * disp = lv_disp_get_active();
|
||||
|
||||
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;
|
||||
@ -277,11 +336,23 @@ void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
|
||||
letter_px = (*map_p & mask) >> (8 - col_bit - bpp);
|
||||
if(letter_px != 0) {
|
||||
if(opa == LV_OPA_COVER) {
|
||||
*vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, bpp == 8 ? letter_px : bpp_opa_table[letter_px]);
|
||||
px_opa = bpp == 8 ? letter_px : bpp_opa_table[letter_px];
|
||||
} else {
|
||||
*vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, bpp == 8 ?
|
||||
(uint16_t)((uint16_t)letter_px * opa) >> 8 :
|
||||
(uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8);
|
||||
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.vdb_wr) {
|
||||
disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width,
|
||||
(col + pos_x) - vdb_p->area.x1, (row + pos_y) - vdb_p->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
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,8 +361,7 @@ void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
|
||||
if(col_bit < 8 - bpp) {
|
||||
col_bit += bpp;
|
||||
mask = mask >> bpp;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
col_bit = 0;
|
||||
col_byte_cnt ++;
|
||||
mask = mask_init;
|
||||
@ -315,18 +385,26 @@ void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
|
||||
* @param recolor mix the pixels with this color
|
||||
* @param recolor_opa the intense of recoloring
|
||||
*/
|
||||
void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
void lv_vmap(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;
|
||||
lv_vdb_t * vdb_p = lv_vdb_get();
|
||||
if(!vdb_p) {
|
||||
LV_LOG_WARN("Invalid VDB pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
/*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_union(&masked_a, cords_p, mask_p);
|
||||
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;
|
||||
@ -357,21 +435,37 @@ void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
lv_coord_t row;
|
||||
lv_coord_t map_useful_w = lv_area_get_width(&masked_a);
|
||||
|
||||
lv_disp_t * disp = lv_disp_get_active();
|
||||
|
||||
/*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) {
|
||||
|
||||
for(row = masked_a.y1; row <= masked_a.y2; row++) {
|
||||
#if USE_LV_GPU
|
||||
if(lv_disp_is_mem_blend_supported() == false) {
|
||||
sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
|
||||
} else {
|
||||
lv_disp_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
|
||||
/*Use the custom VDB write function is exists*/
|
||||
if(disp->driver.vdb_wr) {
|
||||
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) * ((lv_color_t *)&map_p[(uint32_t)col * px_size_byte]);
|
||||
disp->driver.vdb_wr((uint8_t *)vdb_p->buf, 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 USE_LV_GPU
|
||||
if(lv_disp_is_mem_blend_supported() == false) {
|
||||
sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
|
||||
} else {
|
||||
lv_disp_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);
|
||||
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*/
|
||||
map_p += map_width * px_size_byte; /*Next row on the map*/
|
||||
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -390,19 +484,18 @@ void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
/*Calculate with the pixel level alpha*/
|
||||
if(alpha_byte) {
|
||||
#if LV_COLOR_DEPTH == 8
|
||||
px_color.full = px_color_p[0];
|
||||
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 == 24
|
||||
px_color = *((lv_color_t*)px_color_p);
|
||||
/*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);
|
||||
} else {
|
||||
px_color = *((lv_color_t *)px_color_p);
|
||||
}
|
||||
|
||||
/*Handle chroma key*/
|
||||
@ -410,29 +503,57 @@ void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
|
||||
/*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);
|
||||
}
|
||||
|
||||
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);
|
||||
/*Handle custom VDB write is present*/
|
||||
if(disp->driver.vdb_wr) {
|
||||
disp->driver.vdb_wr((uint8_t *)vdb_p->buf, 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 {
|
||||
if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col] = px_color;
|
||||
else vdb_buf_tmp[col] = lv_color_mix(px_color, vdb_buf_tmp[col], opa_result);
|
||||
/*Handle custom VDB write is present*/
|
||||
if(disp->driver.vdb_wr) {
|
||||
disp->driver.vdb_wr((uint8_t *)vdb_p->buf, 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);
|
||||
// if(vdb_buf_tmp[col].alpha == LV_OPA_TRANSP) {
|
||||
// /* When it is the first visible pixel on the transparent screen
|
||||
// * simlply use this color and set the pixel opa as backrounds alpha*/
|
||||
// vdb_buf_tmp[col] = px_color;
|
||||
// vdb_buf_tmp[col].alpha = opa_result;
|
||||
// } else {
|
||||
// /* If already this pixel is already written then for performance reasons
|
||||
// * don't care with alpha channel
|
||||
// */
|
||||
// lv_opa_t bg_opa = vdb_buf_tmp[col].alpha;
|
||||
// vdb_buf_tmp[col] = lv_color_mix(px_color, vdb_buf_tmp[col], opa_result);
|
||||
//
|
||||
// uint16_t opa_tmp = (uint16_t)opa_result + ((bg_opa * (255 - opa_result)) >> 8);
|
||||
// vdb_buf_tmp[col].alpha = opa_tmp > 0xFF ? 0xFF : opa_tmp ;
|
||||
// }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*Next row on the map*/
|
||||
map_p += map_width * px_size_byte;
|
||||
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
|
||||
map_p += map_width * px_size_byte; /*Next row on the map*/
|
||||
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**********************
|
||||
@ -468,45 +589,115 @@ static void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t len
|
||||
*/
|
||||
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);
|
||||
|
||||
/*Run simpler function without opacity*/
|
||||
if(opa == LV_OPA_COVER) {
|
||||
/*Fill the first row with 'color'*/
|
||||
lv_disp_t * disp = lv_disp_get_active();
|
||||
if(disp->driver.vdb_wr) {
|
||||
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 {
|
||||
lv_color_t bg_tmp = LV_COLOR_BLACK;
|
||||
lv_color_t opa_tmp = lv_color_mix(color, bg_tmp, opa);
|
||||
for(row = fill_area->y1; row <= fill_area->y2; row++) {
|
||||
for(col = fill_area->x1; col <= fill_area->x2; col++) {
|
||||
/*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;
|
||||
for(row = fill_area->y1; row <= fill_area->y2; row++) {
|
||||
disp->driver.vdb_wr((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*/
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_draw_vbasic.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_VBASIC_H
|
||||
@ -13,7 +13,11 @@ extern "C" {
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if LV_VDB_SIZE != 0
|
||||
|
||||
@ -42,7 +46,7 @@ void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t col
|
||||
* @param opa opacity of the area (0..255)
|
||||
*/
|
||||
void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
|
||||
lv_color_t color, lv_opa_t opa);
|
||||
lv_color_t color, lv_opa_t opa);
|
||||
|
||||
/**
|
||||
* Draw a letter in the Virtual Display Buffer
|
||||
@ -69,8 +73,8 @@ void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
|
||||
* @param recolor_opa the intense of recoloring
|
||||
*/
|
||||
void lv_vmap(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);
|
||||
const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,
|
||||
lv_color_t recolor, lv_opa_t recolor_opa);
|
||||
|
||||
|
||||
/**
|
||||
|
165
lv_fonts/lv_font_builtin.c
Normal file
165
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 USE_LV_FONT_DEJAVU_10 != 0
|
||||
lv_font_add(&lv_font_dejavu_10, NULL);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_10_LATIN_SUP != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_10_CYRILLIC != 0
|
||||
#if USE_LV_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 USE_LV_FONT_SYMBOL_10 != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_20 != 0
|
||||
lv_font_add(&lv_font_dejavu_20, NULL);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_20_LATIN_SUP != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_20_CYRILLIC != 0
|
||||
#if USE_LV_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 USE_LV_FONT_SYMBOL_20 != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_30 != 0
|
||||
lv_font_add(&lv_font_dejavu_30, NULL);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_30_LATIN_SUP != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_30_CYRILLIC != 0
|
||||
#if USE_LV_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 USE_LV_FONT_SYMBOL_30 != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_40 != 0
|
||||
lv_font_add(&lv_font_dejavu_40, NULL);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_40_LATIN_SUP != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_40_CYRILLIC != 0
|
||||
#if USE_LV_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 USE_LV_FONT_SYMBOL_40 != 0
|
||||
#if USE_LV_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
lv_fonts/lv_font_builtin.h
Normal file
125
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 USE_LV_FONT_DEJAVU_10
|
||||
LV_FONT_DECLARE(lv_font_dejavu_10);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_10_LATIN_SUP
|
||||
LV_FONT_DECLARE(lv_font_dejavu_10_latin_sup);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_10_CYRILLIC
|
||||
LV_FONT_DECLARE(lv_font_dejavu_10_cyrillic);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_SYMBOL_10
|
||||
LV_FONT_DECLARE(lv_font_symbol_10);
|
||||
#endif
|
||||
|
||||
/*20 px */
|
||||
#if USE_LV_FONT_DEJAVU_20
|
||||
LV_FONT_DECLARE(lv_font_dejavu_20);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_20_LATIN_SUP
|
||||
LV_FONT_DECLARE(lv_font_dejavu_20_latin_sup);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_20_CYRILLIC
|
||||
LV_FONT_DECLARE(lv_font_dejavu_20_cyrillic);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_SYMBOL_20
|
||||
LV_FONT_DECLARE(lv_font_symbol_20);
|
||||
#endif
|
||||
|
||||
/*30 px */
|
||||
#if USE_LV_FONT_DEJAVU_30
|
||||
LV_FONT_DECLARE(lv_font_dejavu_30);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_30_LATIN_SUP
|
||||
LV_FONT_DECLARE(lv_font_dejavu_30_latin_sup);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_30_CYRILLIC
|
||||
LV_FONT_DECLARE(lv_font_dejavu_30_cyrillic);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_SYMBOL_30
|
||||
LV_FONT_DECLARE(lv_font_symbol_30);
|
||||
#endif
|
||||
|
||||
/*40 px */
|
||||
#if USE_LV_FONT_DEJAVU_40
|
||||
LV_FONT_DECLARE(lv_font_dejavu_40);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_40_LATIN_SUP
|
||||
LV_FONT_DECLARE(lv_font_dejavu_40_latin_sup);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_40_CYRILLIC
|
||||
LV_FONT_DECLARE(lv_font_dejavu_40_cyrillic);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_SYMBOL_40
|
||||
LV_FONT_DECLARE(lv_font_symbol_40);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_MONOSPACE_8
|
||||
LV_FONT_DECLARE(lv_font_monospace_8);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_FONT_BUILTIN_H*/
|
5380
lv_fonts/lv_font_dejavu_10.c
Normal file
5380
lv_fonts/lv_font_dejavu_10.c
Normal file
File diff suppressed because it is too large
Load Diff
3644
lv_fonts/lv_font_dejavu_10_cyrillic.c
Normal file
3644
lv_fonts/lv_font_dejavu_10_cyrillic.c
Normal file
File diff suppressed because it is too large
Load Diff
5436
lv_fonts/lv_font_dejavu_10_latin_sup.c
Normal file
5436
lv_fonts/lv_font_dejavu_10_latin_sup.c
Normal file
File diff suppressed because it is too large
Load Diff
9180
lv_fonts/lv_font_dejavu_20.c
Normal file
9180
lv_fonts/lv_font_dejavu_20.c
Normal file
File diff suppressed because it is too large
Load Diff
6204
lv_fonts/lv_font_dejavu_20_cyrillic.c
Normal file
6204
lv_fonts/lv_font_dejavu_20_cyrillic.c
Normal file
File diff suppressed because it is too large
Load Diff
9276
lv_fonts/lv_font_dejavu_20_latin_sup.c
Normal file
9276
lv_fonts/lv_font_dejavu_20_latin_sup.c
Normal file
File diff suppressed because it is too large
Load Diff
12980
lv_fonts/lv_font_dejavu_30.c
Normal file
12980
lv_fonts/lv_font_dejavu_30.c
Normal file
File diff suppressed because it is too large
Load Diff
8764
lv_fonts/lv_font_dejavu_30_cyrillic.c
Normal file
8764
lv_fonts/lv_font_dejavu_30_cyrillic.c
Normal file
File diff suppressed because it is too large
Load Diff
13116
lv_fonts/lv_font_dejavu_30_latin_sup.c
Normal file
13116
lv_fonts/lv_font_dejavu_30_latin_sup.c
Normal file
File diff suppressed because it is too large
Load Diff
16780
lv_fonts/lv_font_dejavu_40.c
Normal file
16780
lv_fonts/lv_font_dejavu_40.c
Normal file
File diff suppressed because it is too large
Load Diff
11323
lv_fonts/lv_font_dejavu_40_cyrillic.c
Normal file
11323
lv_fonts/lv_font_dejavu_40_cyrillic.c
Normal file
File diff suppressed because it is too large
Load Diff
16956
lv_fonts/lv_font_dejavu_40_latin_sup.c
Normal file
16956
lv_fonts/lv_font_dejavu_40_latin_sup.c
Normal file
File diff suppressed because it is too large
Load Diff
4619
lv_fonts/lv_font_monospace_8.c
Normal file
4619
lv_fonts/lv_font_monospace_8.c
Normal file
File diff suppressed because it is too large
Load Diff
2866
lv_fonts/lv_font_symbol_10.c
Normal file
2866
lv_fonts/lv_font_symbol_10.c
Normal file
File diff suppressed because it is too large
Load Diff
4866
lv_fonts/lv_font_symbol_20.c
Normal file
4866
lv_fonts/lv_font_symbol_20.c
Normal file
File diff suppressed because it is too large
Load Diff
6865
lv_fonts/lv_font_symbol_30.c
Normal file
6865
lv_fonts/lv_font_symbol_30.c
Normal file
File diff suppressed because it is too large
Load Diff
8866
lv_fonts/lv_font_symbol_40.c
Normal file
8866
lv_fonts/lv_font_symbol_40.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,4 @@
|
||||
CSRCS += lv_font_builtin.c
|
||||
CSRCS += lv_font_dejavu_10.c
|
||||
CSRCS += lv_font_dejavu_20.c
|
||||
CSRCS += lv_font_dejavu_30.c
|
||||
@ -15,7 +16,7 @@ CSRCS += lv_font_symbol_20.c
|
||||
CSRCS += lv_font_symbol_30.c
|
||||
CSRCS += lv_font_symbol_40.c
|
||||
|
||||
DEPPATH += --dep-path lvgl/lv_misc/lv_fonts
|
||||
VPATH += :lvgl/lv_misc/lv_fonts
|
||||
DEPPATH += --dep-path lvgl/lv_fonts
|
||||
VPATH += :lvgl/lv_fonts
|
||||
|
||||
CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_misc/lv_fonts"
|
||||
CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_fonts"
|
@ -30,8 +30,8 @@
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_disp_t *disp_list = NULL;
|
||||
static lv_disp_t *active;
|
||||
static lv_disp_t * disp_list = NULL;
|
||||
static lv_disp_t * active;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
@ -47,7 +47,7 @@ static lv_disp_t *active;
|
||||
* 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)
|
||||
void lv_disp_drv_init(lv_disp_drv_t * driver)
|
||||
{
|
||||
driver->disp_fill = NULL;
|
||||
driver->disp_map = NULL;
|
||||
@ -57,6 +57,10 @@ void lv_disp_drv_init(lv_disp_drv_t *driver)
|
||||
driver->mem_blend = NULL;
|
||||
driver->mem_fill = NULL;
|
||||
#endif
|
||||
|
||||
#if LV_VDB_SIZE
|
||||
driver->vdb_wr = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,18 +69,19 @@ void lv_disp_drv_init(lv_disp_drv_t *driver)
|
||||
* @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 * lv_disp_drv_register(lv_disp_drv_t * driver)
|
||||
{
|
||||
lv_disp_t *node;
|
||||
lv_disp_t * node;
|
||||
|
||||
node = lv_mem_alloc(sizeof(lv_disp_t));
|
||||
if (!node) return NULL;
|
||||
lv_mem_assert(node);
|
||||
if(node == NULL) return NULL;
|
||||
|
||||
memcpy(&node->driver,driver, sizeof(lv_disp_drv_t));
|
||||
memcpy(&node->driver, driver, sizeof(lv_disp_drv_t));
|
||||
node->next = NULL;
|
||||
|
||||
/* Set first display as active by default */
|
||||
if (disp_list == NULL) {
|
||||
if(disp_list == NULL) {
|
||||
disp_list = node;
|
||||
active = node;
|
||||
lv_obj_invalidate(lv_scr_act());
|
||||
@ -144,10 +149,18 @@ void lv_disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t col
|
||||
* @param y2 bottom coordinate of the rectangle
|
||||
* @param color_p pointer to an array of colors
|
||||
*/
|
||||
void lv_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t *color_p)
|
||||
void lv_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t * color_p)
|
||||
{
|
||||
if(active == NULL) return;
|
||||
if(active->driver.disp_flush != NULL) active->driver.disp_flush(x1, y1, x2, y2, color_p);
|
||||
if(active->driver.disp_flush != NULL) {
|
||||
|
||||
LV_LOG_TRACE("disp flush started");
|
||||
active->driver.disp_flush(x1, y1, x2, y2, color_p);
|
||||
LV_LOG_TRACE("disp flush ready");
|
||||
|
||||
} else {
|
||||
LV_LOG_WARN("disp flush function registered");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -215,6 +228,7 @@ bool lv_disp_is_mem_fill_supported(void)
|
||||
if(active->driver.mem_fill) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
|
@ -19,6 +19,7 @@ extern "C" {
|
||||
#include <stdbool.h>
|
||||
#include "lv_hal.h"
|
||||
#include "../lv_misc/lv_color.h"
|
||||
#include "../lv_misc/lv_area.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -41,6 +42,7 @@ typedef struct _disp_drv_t {
|
||||
/*Write pixel map (e.g. image) to the display*/
|
||||
void (*disp_map)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
|
||||
|
||||
/*Optional interface functions to use GPU*/
|
||||
#if USE_LV_GPU
|
||||
/*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);
|
||||
@ -49,6 +51,10 @@ typedef struct _disp_drv_t {
|
||||
void (*mem_fill)(lv_color_t * dest, uint32_t length, lv_color_t color);
|
||||
#endif
|
||||
|
||||
#if LV_VDB_SIZE
|
||||
/*Optional: Set a pixel in a buffer according to the requirements of the display*/
|
||||
void (*vdb_wr)(uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
|
||||
#endif
|
||||
} lv_disp_drv_t;
|
||||
|
||||
typedef struct _disp_t {
|
||||
|
@ -2,7 +2,7 @@
|
||||
* @file hal_indev.c
|
||||
*
|
||||
* @description Input device HAL interface
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
@ -22,7 +22,7 @@
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static lv_indev_t *indev_list = NULL;
|
||||
static lv_indev_t * indev_list = NULL;
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@ -42,7 +42,7 @@ static lv_indev_t *indev_list = NULL;
|
||||
* 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)
|
||||
void lv_indev_drv_init(lv_indev_drv_t * driver)
|
||||
{
|
||||
driver->read = NULL;
|
||||
driver->type = LV_INDEV_TYPE_NONE;
|
||||
@ -54,12 +54,12 @@ void lv_indev_drv_init(lv_indev_drv_t *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)
|
||||
lv_indev_t * lv_indev_drv_register(lv_indev_drv_t * driver)
|
||||
{
|
||||
lv_indev_t *node;
|
||||
lv_indev_t * node;
|
||||
|
||||
node = lv_mem_alloc(sizeof(lv_indev_t));
|
||||
if (!node) return NULL;
|
||||
if(!node) return NULL;
|
||||
|
||||
memset(node, 0, sizeof(lv_indev_t));
|
||||
memcpy(&node->driver, driver, sizeof(lv_indev_drv_t));
|
||||
@ -70,11 +70,11 @@ lv_indev_t * lv_indev_drv_register(lv_indev_drv_t *driver)
|
||||
node->group = NULL;
|
||||
node->btn_points = NULL;
|
||||
|
||||
if (indev_list == NULL) {
|
||||
if(indev_list == NULL) {
|
||||
indev_list = node;
|
||||
} else {
|
||||
lv_indev_t *last = indev_list;
|
||||
while (last->next)
|
||||
lv_indev_t * last = indev_list;
|
||||
while(last->next)
|
||||
last = last->next;
|
||||
|
||||
last->next = node;
|
||||
@ -105,14 +105,18 @@ lv_indev_t * lv_indev_next(lv_indev_t * indev)
|
||||
* @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 lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
{
|
||||
bool cont = false;
|
||||
|
||||
if(indev->driver.read) {
|
||||
data->user_data = indev->driver.user_data;
|
||||
|
||||
LV_LOG_TRACE("idnev read started");
|
||||
cont = indev->driver.read(data);
|
||||
LV_LOG_TRACE("idnev read finished");
|
||||
} else {
|
||||
LV_LOG_WARN("indev function registered");
|
||||
memset(data, 0, sizeof(lv_indev_data_t));
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* @file hal_indev.h
|
||||
*
|
||||
* @description Input Device HAL interface layer header file
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAL_INDEV_H
|
||||
@ -29,18 +29,21 @@ extern "C" {
|
||||
**********************/
|
||||
|
||||
/*Possible input device types*/
|
||||
typedef enum {
|
||||
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_hal_indev_type_t;
|
||||
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*/
|
||||
typedef enum {
|
||||
enum {
|
||||
LV_INDEV_STATE_REL = 0,
|
||||
LV_INDEV_STATE_PR
|
||||
}lv_indev_state_t;
|
||||
};
|
||||
typedef uint8_t lv_indev_state_t;
|
||||
|
||||
/*Data type when an input device is read */
|
||||
typedef struct {
|
||||
@ -48,17 +51,18 @@ 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; /*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_EVENT_REL or LV_INDEV_EVENT_PR*/
|
||||
void *user_data; /*'lv_indev_drv_t.priv' for this driver*/
|
||||
}lv_indev_data_t;
|
||||
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_hal_indev_type_t type; /*Input device type*/
|
||||
bool (*read)(lv_indev_data_t *data); /*Function pointer to read data. Return 'true' if there is still data to be read (buffered)*/
|
||||
void *user_data; /*Pointer to user defined data, passed in 'lv_indev_data_t' on read*/
|
||||
}lv_indev_drv_t;
|
||||
} lv_indev_drv_t;
|
||||
|
||||
struct _lv_obj_t;
|
||||
|
||||
@ -70,7 +74,7 @@ typedef struct _lv_indev_proc_t {
|
||||
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_sum; /*Count the dragged pixels to check LV_INDEV_DRAG_LIMIT*/
|
||||
struct _lv_obj_t * act_obj;
|
||||
struct _lv_obj_t * last_obj;
|
||||
|
||||
@ -92,7 +96,7 @@ typedef struct _lv_indev_proc_t {
|
||||
uint8_t long_pr_sent :1;
|
||||
uint8_t reset_query :1;
|
||||
uint8_t disabled :1;
|
||||
}lv_indev_proc_t;
|
||||
} lv_indev_proc_t;
|
||||
|
||||
|
||||
struct _lv_obj_t;
|
||||
|
@ -6,9 +6,18 @@
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include "lv_hal_tick.h"
|
||||
#include <stddef.h>
|
||||
#include "../../lv_conf.h"
|
||||
|
||||
#if LV_TICK_CUSTOM == 1
|
||||
#include LV_TICK_CUSTOM_INCLUDE
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -52,6 +61,7 @@ LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period)
|
||||
*/
|
||||
uint32_t lv_tick_get(void)
|
||||
{
|
||||
#if LV_TICK_CUSTOM == 0
|
||||
uint32_t result;
|
||||
do {
|
||||
tick_irq_flag = 1;
|
||||
@ -59,6 +69,9 @@ uint32_t lv_tick_get(void)
|
||||
} 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
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,17 +81,17 @@ uint32_t lv_tick_get(void)
|
||||
*/
|
||||
uint32_t lv_tick_elaps(uint32_t prev_tick)
|
||||
{
|
||||
uint32_t act_time = lv_tick_get();
|
||||
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;
|
||||
}
|
||||
/*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;
|
||||
return prev_tick;
|
||||
}
|
||||
|
||||
/**********************
|
||||
|
@ -13,6 +13,11 @@ extern "C" {
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../lv_conf.h"
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_ANIM_RESOLUTION 1024
|
||||
#define LV_ANIM_RESOLUTION 1024
|
||||
#define LV_ANIM_RES_SHIFT 10
|
||||
|
||||
/**********************
|
||||
@ -28,7 +28,7 @@
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void anim_task (void * param);
|
||||
static void anim_task(void * param);
|
||||
static bool anim_ready_handler(lv_anim_t * a);
|
||||
|
||||
/**********************
|
||||
@ -36,6 +36,7 @@ static bool anim_ready_handler(lv_anim_t * a);
|
||||
**********************/
|
||||
static lv_ll_t anim_ll;
|
||||
static uint32_t last_task_run;
|
||||
static bool anim_list_changed;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
@ -61,12 +62,14 @@ void lv_anim_init(void)
|
||||
*/
|
||||
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(&anim_ll);
|
||||
lv_mem_assert(new_anim);
|
||||
if(new_anim == NULL) return;
|
||||
|
||||
/*Initialize the animation descriptor*/
|
||||
anim_p->playback_now = 0;
|
||||
@ -74,6 +77,12 @@ void lv_anim_create(lv_anim_t * anim_p)
|
||||
|
||||
/*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")
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,9 +94,9 @@ void lv_anim_create(lv_anim_t * anim_p)
|
||||
*/
|
||||
bool lv_anim_del(void * var, lv_anim_fp_t fp)
|
||||
{
|
||||
bool del = false;
|
||||
lv_anim_t * a;
|
||||
lv_anim_t * a_next;
|
||||
bool del = false;
|
||||
a = lv_ll_get_head(&anim_ll);
|
||||
while(a != NULL) {
|
||||
/*'a' might be deleted, so get the next object while 'a' is valid*/
|
||||
@ -96,6 +105,7 @@ bool lv_anim_del(void * var, lv_anim_fp_t fp)
|
||||
if(a->var == var && (a->fp == fp || fp == NULL)) {
|
||||
lv_ll_rem(&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;
|
||||
}
|
||||
|
||||
@ -131,32 +141,55 @@ uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end)
|
||||
* @param a pointer to an animation
|
||||
* @return the current value to set
|
||||
*/
|
||||
int32_t lv_anim_path_linear(const lv_anim_t *a)
|
||||
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 id the time fully elapsed*/
|
||||
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 the current element of 'path_p'
|
||||
* and the 'start' and 'end' values*/
|
||||
/* 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 = (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 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 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)
|
||||
int32_t lv_anim_path_step(const lv_anim_t * a)
|
||||
{
|
||||
if(a->act_time >= a->time) return a->end;
|
||||
else return a->start;
|
||||
@ -170,40 +203,46 @@ int32_t lv_anim_path_step(const lv_anim_t *a)
|
||||
* Periodically handle the animations.
|
||||
* @param param unused
|
||||
*/
|
||||
static void anim_task (void * param)
|
||||
static void anim_task(void * param)
|
||||
{
|
||||
(void)param;
|
||||
|
||||
volatile uint32_t elaps;
|
||||
elaps = lv_tick_elaps(last_task_run);
|
||||
|
||||
lv_anim_t * a;
|
||||
lv_anim_t * a_next;
|
||||
LL_READ(anim_ll, a) {
|
||||
a->has_run = 0;
|
||||
}
|
||||
|
||||
uint32_t elaps = lv_tick_elaps(last_task_run);
|
||||
a = lv_ll_get_head(&anim_ll);
|
||||
|
||||
while(a != NULL) {
|
||||
/*'a' might be deleted, so get the next object while 'a' is valid*/
|
||||
a_next = lv_ll_get_next(&anim_ll, a);
|
||||
/*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;
|
||||
|
||||
a->act_time += elaps;
|
||||
if(a->act_time >= 0) {
|
||||
if(a->act_time > a->time) a->act_time = a->time;
|
||||
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);
|
||||
int32_t new_value;
|
||||
new_value = a->path(a);
|
||||
|
||||
if(a->fp != NULL) a->fp(a->var, new_value); /*Apply the calculated value*/
|
||||
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) {
|
||||
bool invalid;
|
||||
invalid = anim_ready_handler(a);
|
||||
if(invalid != false) {
|
||||
a_next = lv_ll_get_head(&anim_ll); /*a_next might be invalid if animation delete occurred*/
|
||||
/*If the time is elapsed the animation is ready*/
|
||||
if(a->act_time >= a->time) {
|
||||
anim_ready_handler(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a = a_next;
|
||||
/* 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(&anim_ll);
|
||||
else a = lv_ll_get_next(&anim_ll, a);
|
||||
}
|
||||
|
||||
last_task_run = lv_tick_get();
|
||||
@ -213,27 +252,25 @@ static void anim_task (void * param)
|
||||
* 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
|
||||
* @return true: animation delete occurred nnd the `anim_ll` has changed
|
||||
* */
|
||||
static bool anim_ready_handler(lv_anim_t * a)
|
||||
{
|
||||
bool invalid = false;
|
||||
|
||||
/*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 (*cb)(void *) = a->end_cb;
|
||||
void * p = a->var;
|
||||
lv_ll_rem(&anim_ll, a);
|
||||
lv_mem_free(a);
|
||||
|
||||
/*Call the callback function at the end*/
|
||||
/* 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);
|
||||
invalid = true;
|
||||
}
|
||||
/*If the animation is not deleted then restart it*/
|
||||
else {
|
||||
@ -244,7 +281,7 @@ static bool anim_ready_handler(lv_anim_t * a)
|
||||
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;
|
||||
a->playback_now = a->playback_now == 0 ? 1 : 0;
|
||||
/*Swap the start and end values*/
|
||||
int32_t tmp;
|
||||
tmp = a->start;
|
||||
@ -253,6 +290,6 @@ static bool anim_ready_handler(lv_anim_t * a)
|
||||
}
|
||||
}
|
||||
|
||||
return invalid;
|
||||
return anim_list_changed;
|
||||
}
|
||||
#endif
|
||||
|
@ -14,7 +14,12 @@ extern "C" {
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if USE_LV_ANIMATION
|
||||
|
||||
#include <stdint.h>
|
||||
@ -37,21 +42,22 @@ 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*/
|
||||
}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;
|
||||
@ -67,6 +73,7 @@ a.playback = 0;
|
||||
a.playback_pause = 0;
|
||||
a.repeat = 0;
|
||||
a.repeat_pause = 0;
|
||||
lv_anim_create(&a);
|
||||
*/
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
@ -108,6 +115,14 @@ uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end);
|
||||
*/
|
||||
int32_t lv_anim_path_linear(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 applying step characteristic.
|
||||
* (Set end value on the end of the animation)
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_area.c
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
@ -56,7 +56,7 @@ void lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2
|
||||
*/
|
||||
void lv_area_set_width(lv_area_t * area_p, lv_coord_t w)
|
||||
{
|
||||
area_p->x2 = area_p->x1 + w - 1;
|
||||
area_p->x2 = area_p->x1 + w - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,7 +66,7 @@ void lv_area_set_width(lv_area_t * area_p, lv_coord_t w)
|
||||
*/
|
||||
void lv_area_set_height(lv_area_t * area_p, lv_coord_t h)
|
||||
{
|
||||
area_p->y2 = area_p->y1 + h - 1;
|
||||
area_p->y2 = area_p->y1 + h - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,12 +77,12 @@ void lv_area_set_height(lv_area_t * area_p, lv_coord_t h)
|
||||
*/
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,40 +93,39 @@ void lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y)
|
||||
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);
|
||||
|
||||
|
||||
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 her
|
||||
* @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_union(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p)
|
||||
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))
|
||||
{
|
||||
(res_p->y1 > res_p->y2)) {
|
||||
union_ok = false;
|
||||
}
|
||||
|
||||
|
||||
return union_ok;
|
||||
}
|
||||
/**
|
||||
* Join two areas into a third which involves the other two
|
||||
* 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
|
||||
@ -148,29 +147,27 @@ void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t *
|
||||
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)))
|
||||
{
|
||||
((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 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))
|
||||
{
|
||||
(a1_p->x2 >= a2_p->x1) &&
|
||||
(a1_p->y1 <= a2_p->y2) &&
|
||||
(a1_p->y2 >= a2_p->y1)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -182,20 +179,19 @@ 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 in 'aholder_p'
|
||||
* @param aholder pointer to an area which could involve 'ain_p'
|
||||
* @return
|
||||
* @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)
|
||||
{
|
||||
ain_p->y1 >= aholder_p->y1 &&
|
||||
ain_p->x2 <= aholder_p->x2 &&
|
||||
ain_p->y2 <= aholder_p->y2) {
|
||||
is_in = true;
|
||||
}
|
||||
|
||||
|
||||
return is_in;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_area.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_AREA_H
|
||||
@ -33,15 +33,15 @@ typedef struct
|
||||
{
|
||||
lv_coord_t x;
|
||||
lv_coord_t y;
|
||||
}lv_point_t;
|
||||
} lv_point_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
lv_coord_t x1;
|
||||
lv_coord_t y1;
|
||||
lv_coord_t y1;
|
||||
lv_coord_t x2;
|
||||
lv_coord_t y2;
|
||||
}lv_area_t;
|
||||
lv_coord_t y2;
|
||||
} lv_area_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
@ -123,7 +123,7 @@ uint32_t lv_area_get_size(const lv_area_t * area_p);
|
||||
* @param a2_p pointer to the second area
|
||||
* @return false: the two area has NO common parts, res_p is invalid
|
||||
*/
|
||||
bool lv_area_union(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p);
|
||||
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
|
||||
|
@ -65,13 +65,13 @@ bool lv_circ_cont(lv_point_t * c)
|
||||
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
|
||||
|
||||
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
|
||||
}
|
||||
c->x--;
|
||||
(*tmp) += 2 * (c->y - c->x) + 1; // Change for y -> y+1, x -> x-1
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_circ.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_CIRC_H
|
||||
|
@ -53,8 +53,7 @@ lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v)
|
||||
|
||||
uint8_t region, remainder, p, q, t;
|
||||
|
||||
if (s == 0)
|
||||
{
|
||||
if(s == 0) {
|
||||
r = v;
|
||||
g = v;
|
||||
b = v;
|
||||
@ -68,25 +67,36 @@ lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v)
|
||||
q = (v * (255 - ((s * remainder) >> 8))) >> 8;
|
||||
t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
|
||||
|
||||
switch (region)
|
||||
{
|
||||
switch(region) {
|
||||
case 0:
|
||||
r = v; g = t; b = p;
|
||||
r = v;
|
||||
g = t;
|
||||
b = p;
|
||||
break;
|
||||
case 1:
|
||||
r = q; g = v; b = p;
|
||||
r = q;
|
||||
g = v;
|
||||
b = p;
|
||||
break;
|
||||
case 2:
|
||||
r = p; g = v; b = t;
|
||||
r = p;
|
||||
g = v;
|
||||
b = t;
|
||||
break;
|
||||
case 3:
|
||||
r = p; g = q; b = v;
|
||||
r = p;
|
||||
g = q;
|
||||
b = v;
|
||||
break;
|
||||
case 4:
|
||||
r = t; g = p; b = v;
|
||||
r = t;
|
||||
g = p;
|
||||
b = v;
|
||||
break;
|
||||
default:
|
||||
r = v; g = p; b = q;
|
||||
r = v;
|
||||
g = p;
|
||||
b = q;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -110,23 +120,21 @@ lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b)
|
||||
rgbMax = r > g ? (r > b ? r : b) : (g > b ? g : b);
|
||||
|
||||
hsv.v = rgbMax;
|
||||
if (hsv.v == 0)
|
||||
{
|
||||
if(hsv.v == 0) {
|
||||
hsv.h = 0;
|
||||
hsv.s = 0;
|
||||
return hsv;
|
||||
}
|
||||
|
||||
hsv.s = 255 * (long)(rgbMax - rgbMin) / hsv.v;
|
||||
if (hsv.s == 0)
|
||||
{
|
||||
if(hsv.s == 0) {
|
||||
hsv.h = 0;
|
||||
return hsv;
|
||||
}
|
||||
|
||||
if (rgbMax == r)
|
||||
if(rgbMax == r)
|
||||
hsv.h = 0 + 43 * (g - b) / (rgbMax - rgbMin);
|
||||
else if (rgbMax == g)
|
||||
else if(rgbMax == g)
|
||||
hsv.h = 85 + 43 * (b - r) / (rgbMax - rgbMin);
|
||||
else
|
||||
hsv.h = 171 + 43 * (r - g) / (rgbMax - rgbMin);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_color.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_COLOR_H
|
||||
@ -13,30 +13,48 @@ extern "C" {
|
||||
/*********************
|
||||
* 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_BLACK LV_COLOR_MAKE(0x00,0x00,0x00)
|
||||
#define LV_COLOR_WHITE LV_COLOR_MAKE(0xFF,0xFF,0xFF)
|
||||
#define LV_COLOR_RED LV_COLOR_MAKE(0xFF,0x00,0x00)
|
||||
#define LV_COLOR_LIME LV_COLOR_MAKE(0x00,0xFF,0x00)
|
||||
#define LV_COLOR_BLUE LV_COLOR_MAKE(0x00,0x00,0xFF)
|
||||
#define LV_COLOR_YELLOW LV_COLOR_MAKE(0xFF,0xFF,0x00)
|
||||
#define LV_COLOR_CYAN LV_COLOR_MAKE(0x00,0xFF,0xFF)
|
||||
#define LV_COLOR_AQUA LV_COLOR_CYAN
|
||||
#define LV_COLOR_MAGENTA LV_COLOR_MAKE(0xFF,0x00,0xFF)
|
||||
#define LV_COLOR_SILVER LV_COLOR_MAKE(0xC0,0xC0,0xC0)
|
||||
#define LV_COLOR_GRAY LV_COLOR_MAKE(0x80,0x80,0x80)
|
||||
#define LV_COLOR_MARRON LV_COLOR_MAKE(0x80,0x00,0x00)
|
||||
#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_PURPLE LV_COLOR_MAKE(0x80,0x00,0x80)
|
||||
#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)
|
||||
|
||||
#define LV_OPA_TRANSP 0
|
||||
@ -53,6 +71,20 @@ extern "C" {
|
||||
#define LV_OPA_100 255
|
||||
#define 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
|
||||
@ -64,7 +96,7 @@ typedef union
|
||||
uint8_t green :1;
|
||||
uint8_t red :1;
|
||||
uint8_t full :1;
|
||||
}lv_color1_t;
|
||||
} lv_color1_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
@ -75,18 +107,25 @@ typedef union
|
||||
uint8_t red :3;
|
||||
};
|
||||
uint8_t full;
|
||||
}lv_color8_t;
|
||||
} 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
|
||||
};
|
||||
uint16_t full;
|
||||
}lv_color16_t;
|
||||
} lv_color16_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
@ -98,7 +137,7 @@ typedef union
|
||||
uint8_t alpha;
|
||||
};
|
||||
uint32_t full;
|
||||
}lv_color24_t;
|
||||
} lv_color32_t;
|
||||
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
typedef uint8_t lv_color_int_t;
|
||||
@ -109,11 +148,11 @@ 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 == 24
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
typedef uint32_t lv_color_int_t;
|
||||
typedef lv_color24_t lv_color_t;
|
||||
typedef lv_color32_t lv_color_t;
|
||||
#else
|
||||
#error "Invalid LV_COLOR_DEPTH in misc_conf.h! Set it to 1, 8, 16 or 24!"
|
||||
#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!"
|
||||
#endif
|
||||
|
||||
typedef uint8_t lv_opa_t;
|
||||
@ -130,14 +169,14 @@ typedef struct
|
||||
**********************/
|
||||
|
||||
/*In color conversations:
|
||||
* - When converting to bigger color type the LSB weight of 1 LSB is calculated
|
||||
* - 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
|
||||
* E.g. 8 bit Red has 2 bits
|
||||
* 16 bit Red has 5 bits
|
||||
* ----------------------
|
||||
* Shift right with 5 - 3 = 2
|
||||
@ -146,30 +185,37 @@ typedef struct
|
||||
static inline uint8_t lv_color_to1(lv_color_t color)
|
||||
{
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
return color.full;
|
||||
return color.full;
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
if((color.red & 0x4) ||
|
||||
(color.green & 0x4) ||
|
||||
(color.blue & 0x2)) {
|
||||
return 1;
|
||||
(color.green & 0x4) ||
|
||||
(color.blue & 0x2)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
if((color.red & 0x10) ||
|
||||
(color.green & 0x20) ||
|
||||
(color.blue & 0x10)) {
|
||||
return 1;
|
||||
(color.green & 0x20) ||
|
||||
(color.blue & 0x10)) {
|
||||
return 1;
|
||||
# else
|
||||
if((color.red & 0x10) ||
|
||||
(color.green_h & 0x20) ||
|
||||
(color.blue & 0x10)) {
|
||||
return 1;
|
||||
# endif
|
||||
} else {
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
#elif LV_COLOR_DEPTH == 24
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
if((color.red & 0x80) ||
|
||||
(color.green & 0x80) ||
|
||||
(color.blue & 0x80)) {
|
||||
return 1;
|
||||
(color.green & 0x80) ||
|
||||
(color.blue & 0x80)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -182,12 +228,21 @@ static inline uint8_t lv_color_to8(lv_color_t color)
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
return color.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
lv_color8_t ret;
|
||||
ret.red = color.red >> 2; /* 5 - 3 = 2*/
|
||||
ret.green = color.green >> 3; /* 6 - 3 = 3*/
|
||||
ret.blue = color.blue >> 3; /* 5 - 2 = 3*/
|
||||
return ret.full;
|
||||
#elif LV_COLOR_DEPTH == 24
|
||||
# else
|
||||
lv_color8_t ret;
|
||||
ret.red = color.red >> 2; /* 5 - 3 = 2*/
|
||||
ret.green = color.green_h; /* 6 - 3 = 3*/
|
||||
ret.blue = color.blue >> 3; /* 5 - 2 = 3*/
|
||||
return ret.full;
|
||||
# endif
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
lv_color8_t ret;
|
||||
ret.red = color.red >> 5; /* 8 - 3 = 5*/
|
||||
ret.green = color.green >> 5; /* 8 - 3 = 5*/
|
||||
@ -203,41 +258,65 @@ static inline uint16_t lv_color_to16(lv_color_t color)
|
||||
else return 0xFFFF;
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
lv_color16_t ret;
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
ret.red = color.red * 4; /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/
|
||||
ret.green = color.green * 9; /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/
|
||||
ret.blue = color.blue * 10; /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/
|
||||
# else
|
||||
ret.red = color.red * 4;
|
||||
uint8_t g_tmp = color.green * 9;
|
||||
ret.green_h = (g_tmp & 0x1F) >> 3;
|
||||
ret.green_l = g_tmp & 0x07;
|
||||
ret.blue = color.blue * 10;
|
||||
# endif
|
||||
return ret.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
return color.full;
|
||||
#elif LV_COLOR_DEPTH == 24
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
lv_color16_t ret;
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
ret.red = color.red >> 3; /* 8 - 5 = 3*/
|
||||
ret.green = color.green >> 2; /* 8 - 6 = 2*/
|
||||
ret.blue = color.blue >> 3; /* 8 - 5 = 3*/
|
||||
# else
|
||||
ret.red = color.red >> 3;
|
||||
ret.green_h = (color.green & 0xE0) >> 5;
|
||||
ret.green_l = (color.green & 0x1C) >> 2;
|
||||
ret.blue = color.blue >> 3;
|
||||
# endif
|
||||
return ret.full;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t lv_color_to24(lv_color_t color)
|
||||
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_color24_t ret;
|
||||
lv_color32_t ret;
|
||||
ret.red = color.red * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/
|
||||
ret.green = color.green * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/
|
||||
ret.blue = color.blue * 85; /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/
|
||||
ret.alpha = 0xFF;
|
||||
return ret.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
lv_color24_t ret;
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
lv_color32_t ret;
|
||||
ret.red = color.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
|
||||
ret.green = color.green * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/
|
||||
ret.blue = color.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
|
||||
ret.alpha = 0xFF;
|
||||
return ret.full;
|
||||
#elif LV_COLOR_DEPTH == 24
|
||||
# else
|
||||
lv_color32_t ret;
|
||||
ret.red = color.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
|
||||
ret.green = ((color.green_h << 3) + color.green_l) * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/
|
||||
ret.blue = color.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
|
||||
ret.alpha = 0xFF;
|
||||
return ret.full;
|
||||
# endif
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
return color.full;
|
||||
#endif
|
||||
}
|
||||
@ -246,13 +325,24 @@ 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.red = (uint16_t)((uint16_t) c1.red * mix + (c2.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.green_h << 3) + c1.green_l;
|
||||
uint16_t g_2 = (c2.green_h << 3) + c2.green_l;
|
||||
uint16_t g_out = (uint16_t)((uint16_t) g_1 * mix + (g_2 * (255 - mix))) >> 8;
|
||||
ret.green_h = g_out >> 3;
|
||||
ret.green_l = g_out & 0x7;
|
||||
# else
|
||||
ret.green = (uint16_t)((uint16_t) c1.green * mix + (c2.green * (255 - mix))) >> 8;
|
||||
# endif
|
||||
ret.blue = (uint16_t)((uint16_t) c1.blue * mix + (c2.blue * (255 - mix))) >> 8;
|
||||
# if LV_COLOR_DEPTH == 24
|
||||
# if LV_COLOR_DEPTH == 32
|
||||
ret.alpha = 0xFF;
|
||||
# endif
|
||||
#else
|
||||
/*LV_COLOR_DEPTH == 1*/
|
||||
ret.full = mix > LV_OPA_50 ? c1.full : c2.full;
|
||||
#endif
|
||||
|
||||
@ -264,11 +354,11 @@ static inline lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix)
|
||||
* @param color a color
|
||||
* @return the brightness [0..255]
|
||||
*/
|
||||
static inline uint8_t lv_color_brightness(lv_color_t color)
|
||||
static inline uint8_t lv_color_brightness(lv_color_t color)
|
||||
{
|
||||
lv_color24_t c24;
|
||||
c24.full = lv_color_to24(color);
|
||||
uint16_t bright = 3 * c24.red + c24.blue + 4 * c24.green;
|
||||
lv_color32_t c32;
|
||||
c32.full = lv_color_to32(color);
|
||||
uint16_t bright = 3 * c32.red + c32.blue + 4 * c32.green;
|
||||
return (uint16_t) bright >> 3;
|
||||
}
|
||||
|
||||
@ -280,8 +370,12 @@ static inline uint8_t lv_color_brightness(lv_color_t color)
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 6, g8 >> 5, r8 >> 5}})
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 3, g8 >> 2, r8 >> 3}})
|
||||
#elif LV_COLOR_DEPTH == 24
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 3, g8 >> 2, r8 >> 3}})
|
||||
# else
|
||||
# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{g8 >> 5, r8 >> 3, b8 >> 3, (g8 >> 2) & 0x7}})
|
||||
# endif
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8, g8, r8, 0xff}}) /*Fix 0xff alpha*/
|
||||
#endif
|
||||
#else
|
||||
@ -291,7 +385,7 @@ static inline uint8_t lv_color_brightness(lv_color_t color)
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 6, g8 >> 5, b8 >> 5}})
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 3, g8 >> 2, b8 >> 3}})
|
||||
#elif LV_COLOR_DEPTH == 24
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{0xff, r8, g8, b8}}) /*Fix 0xff alpha*/
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1,15 +1,14 @@
|
||||
/**
|
||||
* @file lv_font.c
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../lv_conf.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include "lv_font.h"
|
||||
#include "lv_log.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -18,11 +17,6 @@
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct {
|
||||
uint32_t glyph_index;
|
||||
uint32_t unicode;
|
||||
uint8_t w_px;
|
||||
}asd_glyph_dsc_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
@ -45,132 +39,11 @@ typedef struct {
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the built-in fonts
|
||||
* Initialize the fonts
|
||||
*/
|
||||
void lv_font_init(void)
|
||||
{
|
||||
/*DEJAVU 10*/
|
||||
#if USE_LV_FONT_DEJAVU_10 != 0
|
||||
lv_font_add(&lv_font_dejavu_10, NULL);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_10_LATIN_SUP != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_10_CYRILLIC != 0
|
||||
#if USE_LV_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 USE_LV_FONT_SYMBOL_10 != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_20 != 0
|
||||
lv_font_add(&lv_font_dejavu_20, NULL);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_20_LATIN_SUP != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_20_CYRILLIC != 0
|
||||
#if USE_LV_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 USE_LV_FONT_SYMBOL_20 != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_30 != 0
|
||||
lv_font_add(&lv_font_dejavu_30, NULL);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_30_LATIN_SUP != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_30_CYRILLIC != 0
|
||||
#if USE_LV_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 USE_LV_FONT_SYMBOL_30 != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_40 != 0
|
||||
lv_font_add(&lv_font_dejavu_40, NULL);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_40_LATIN_SUP != 0
|
||||
#if USE_LV_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 USE_LV_FONT_DEJAVU_40_CYRILLIC != 0
|
||||
#if USE_LV_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 USE_LV_FONT_SYMBOL_40 != 0
|
||||
#if USE_LV_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
|
||||
|
||||
lv_font_builtin_init();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,7 +52,7 @@ void lv_font_init(void)
|
||||
* @param dsc_get_fp the font descriptor get function
|
||||
* @param parent add this font as charter set extension of 'parent'
|
||||
*/
|
||||
void lv_font_add(lv_font_t *child, lv_font_t *parent)
|
||||
void lv_font_add(lv_font_t * child, lv_font_t * parent)
|
||||
{
|
||||
if(parent == NULL) return;
|
||||
|
||||
@ -191,10 +64,34 @@ void lv_font_add(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)
|
||||
{
|
||||
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 a letter
|
||||
* @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)
|
||||
@ -211,12 +108,38 @@ 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
|
||||
* 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 a letter
|
||||
* @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;
|
||||
@ -240,13 +163,13 @@ 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;
|
||||
if(letter >= font_i->unicode_first && letter <= font_i->unicode_last) {
|
||||
return font_i->bpp;
|
||||
}
|
||||
font_i = font_i->next_page;
|
||||
}
|
||||
font_i = font_i->next_page;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_font.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_FONT_H
|
||||
@ -14,12 +14,17 @@ extern "C" {
|
||||
/*********************
|
||||
* 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_fonts/lv_symbol_def.h"
|
||||
#include "lv_symbol_def.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -33,34 +38,36 @@ typedef struct
|
||||
{
|
||||
uint32_t w_px :8;
|
||||
uint32_t glyph_index :24;
|
||||
}lv_font_glyph_dsc_t;
|
||||
} lv_font_glyph_dsc_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t unicode :21;
|
||||
uint32_t glyph_dsc_index :11;
|
||||
}lv_font_unicode_map_t;
|
||||
} lv_font_unicode_map_t;
|
||||
|
||||
typedef struct _lv_font_struct
|
||||
{
|
||||
uint32_t unicode_first;
|
||||
uint32_t unicode_last;
|
||||
uint8_t h_px;
|
||||
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*/
|
||||
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 bpp :4; /*Bit per pixel: 1, 2 or 4*/
|
||||
}lv_font_t;
|
||||
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 built-in fonts
|
||||
* Initialize the fonts
|
||||
*/
|
||||
void lv_font_init(void);
|
||||
|
||||
@ -71,14 +78,39 @@ void lv_font_init(void);
|
||||
*/
|
||||
void lv_font_add(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 a letter
|
||||
* @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
|
||||
@ -89,14 +121,6 @@ static inline uint8_t lv_font_get_height(const lv_font_t * font_p)
|
||||
return font_p->h_px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of a letter in a font
|
||||
* @param font_p pointer to a font
|
||||
* @param letter a letter
|
||||
* @return the width of a letter
|
||||
*/
|
||||
uint8_t lv_font_get_width(const lv_font_t * font_p, uint32_t letter);
|
||||
|
||||
/**
|
||||
* Get the bit-per-pixel of font
|
||||
* @param font pointer to font
|
||||
@ -139,78 +163,18 @@ 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;
|
||||
|
||||
/******************************
|
||||
* FONT DECLARATION INCLUDES
|
||||
*****************************/
|
||||
|
||||
/*10 px */
|
||||
#if USE_LV_FONT_DEJAVU_10
|
||||
LV_FONT_DECLARE(lv_font_dejavu_10);
|
||||
#endif
|
||||
/**********************
|
||||
* ADD BUILT IN FONTS
|
||||
**********************/
|
||||
#include "../lv_fonts/lv_font_builtin.h"
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_10_LATIN_SUP
|
||||
LV_FONT_DECLARE(lv_font_dejavu_10_latin_sup);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_10_CYRILLIC
|
||||
LV_FONT_DECLARE(lv_font_dejavu_10_cyrillic);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_SYMBOL_10
|
||||
LV_FONT_DECLARE(lv_font_symbol_10);
|
||||
#endif
|
||||
|
||||
/*20 px */
|
||||
#if USE_LV_FONT_DEJAVU_20
|
||||
LV_FONT_DECLARE(lv_font_dejavu_20);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_20_LATIN_SUP
|
||||
LV_FONT_DECLARE(lv_font_dejavu_20_latin_sup);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_20_CYRILLIC
|
||||
LV_FONT_DECLARE(lv_font_dejavu_20_cyrillic);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_SYMBOL_20
|
||||
LV_FONT_DECLARE(lv_font_symbol_20);
|
||||
#endif
|
||||
|
||||
/*30 px */
|
||||
#if USE_LV_FONT_DEJAVU_30
|
||||
LV_FONT_DECLARE(lv_font_dejavu_30);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_30_LATIN_SUP
|
||||
LV_FONT_DECLARE(lv_font_dejavu_30_latin_sup);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_30_CYRILLIC
|
||||
LV_FONT_DECLARE(lv_font_dejavu_30_cyrillic);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_SYMBOL_30
|
||||
LV_FONT_DECLARE(lv_font_symbol_30);
|
||||
#endif
|
||||
|
||||
/*40 px */
|
||||
#if USE_LV_FONT_DEJAVU_40
|
||||
LV_FONT_DECLARE(lv_font_dejavu_40);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_40_LATIN_SUP
|
||||
LV_FONT_DECLARE(lv_font_dejavu_40_latin_sup);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_DEJAVU_40_CYRILLIC
|
||||
LV_FONT_DECLARE(lv_font_dejavu_40_cyrillic);
|
||||
#endif
|
||||
|
||||
#if USE_LV_FONT_SYMBOL_40
|
||||
LV_FONT_DECLARE(lv_font_symbol_40);
|
||||
/*Declare the custom (user defined) fonts*/
|
||||
#ifdef LV_FONT_CUSTOM_DECLARE
|
||||
LV_FONT_CUSTOM_DECLARE
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,140 +0,0 @@
|
||||
#ifndef LV_SYMBOL_DEF_H
|
||||
#define LV_SYMBOL_DEF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../../../lv_conf.h"
|
||||
|
||||
/*
|
||||
* With no UTF-8 support (192-255)
|
||||
* - Basic symbols: 0xC0..0xCF
|
||||
* - Feedback symbols: 0xD0..0xDF
|
||||
* - File symbols: 0xE0..0xFF
|
||||
*
|
||||
* With UTF-8 support (in Supplemental Private Use Area-A)
|
||||
* - 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 SYMBOL_AUDIO "\xC0"
|
||||
#define SYMBOL_VIDEO "\xC1"
|
||||
#define SYMBOL_LIST "\xC2"
|
||||
#define SYMBOL_OK "\xC3"
|
||||
#define SYMBOL_CLOSE "\xC4"
|
||||
#define SYMBOL_POWER "\xC5"
|
||||
#define SYMBOL_SETTINGS "\xC6"
|
||||
#define SYMBOL_TRASH "\xC7"
|
||||
#define SYMBOL_HOME "\xC8"
|
||||
#define SYMBOL_DOWNLOAD "\xC9"
|
||||
#define SYMBOL_DRIVE "\xCA"
|
||||
#define SYMBOL_REFRESH "\xCB"
|
||||
#define SYMBOL_MUTE "\xCC"
|
||||
#define SYMBOL_VOLUME_MID "\xCD"
|
||||
#define SYMBOL_VOLUME_MAX "\xCE"
|
||||
#define SYMBOL_IMAGE "\xCF"
|
||||
#define SYMBOL_EDIT "\xD0"
|
||||
#define SYMBOL_PREV "\xD1"
|
||||
#define SYMBOL_PLAY "\xD2"
|
||||
#define SYMBOL_PAUSE "\xD3"
|
||||
#define SYMBOL_STOP "\xD4"
|
||||
#define SYMBOL_NEXT "\xD5"
|
||||
#define SYMBOL_EJECT "\xD6"
|
||||
#define SYMBOL_LEFT "\xD7"
|
||||
#define SYMBOL_RIGHT "\xD8"
|
||||
#define SYMBOL_PLUS "\xD9"
|
||||
#define SYMBOL_MINUS "\xDA"
|
||||
#define SYMBOL_WARNING "\xDB"
|
||||
#define SYMBOL_SHUFFLE "\xDC"
|
||||
#define SYMBOL_UP "\xDD"
|
||||
#define SYMBOL_DOWN "\xDE"
|
||||
#define SYMBOL_LOOP "\xDF"
|
||||
#define SYMBOL_DIRECTORY "\xE0"
|
||||
#define SYMBOL_UPLOAD "\xE1"
|
||||
#define SYMBOL_CALL "\xE2"
|
||||
#define SYMBOL_CUT "\xE3"
|
||||
#define SYMBOL_COPY "\xE4"
|
||||
#define SYMBOL_SAVE "\xE5"
|
||||
#define SYMBOL_CHARGE "\xE6"
|
||||
#define SYMBOL_BELL "\xE7"
|
||||
#define SYMBOL_KEYBOARD "\xE8"
|
||||
#define SYMBOL_GPS "\xE9"
|
||||
#define SYMBOL_FILE "\xEA"
|
||||
#define SYMBOL_WIFI "\xEB"
|
||||
#define SYMBOL_BATTERY_FULL "\xEC"
|
||||
#define SYMBOL_BATTERY_3 "\xED"
|
||||
#define SYMBOL_BATTERY_2 "\xEE"
|
||||
#define SYMBOL_BATTERY_1 "\xEF"
|
||||
#define SYMBOL_BATTERY_EMPTY "\xF0"
|
||||
#define SYMBOL_BLUETOOTH "\xF1"
|
||||
#else
|
||||
#define LV_SYMBOL_GLYPH_FIRST 0xF000
|
||||
|
||||
#define SYMBOL_AUDIO "\xEF\x80\x80"
|
||||
#define SYMBOL_VIDEO "\xEF\x80\x81"
|
||||
#define SYMBOL_LIST "\xEF\x80\x82"
|
||||
#define SYMBOL_OK "\xEF\x80\x83"
|
||||
#define SYMBOL_CLOSE "\xEF\x80\x84"
|
||||
#define SYMBOL_POWER "\xEF\x80\x85"
|
||||
#define SYMBOL_SETTINGS "\xEF\x80\x86"
|
||||
#define SYMBOL_TRASH "\xEF\x80\x87"
|
||||
#define SYMBOL_HOME "\xEF\x80\x88"
|
||||
#define SYMBOL_DOWNLOAD "\xEF\x80\x89"
|
||||
#define SYMBOL_DRIVE "\xEF\x80\x8A"
|
||||
#define SYMBOL_REFRESH "\xEF\x80\x8B"
|
||||
#define SYMBOL_MUTE "\xEF\x80\x8C"
|
||||
#define SYMBOL_VOLUME_MID "\xEF\x80\x8D"
|
||||
#define SYMBOL_VOLUME_MAX "\xEF\x80\x8E"
|
||||
#define SYMBOL_IMAGE "\xEF\x80\x8F"
|
||||
#define SYMBOL_EDIT "\xEF\x80\x90"
|
||||
#define SYMBOL_PREV "\xEF\x80\x91"
|
||||
#define SYMBOL_PLAY "\xEF\x80\x92"
|
||||
#define SYMBOL_PAUSE "\xEF\x80\x93"
|
||||
#define SYMBOL_STOP "\xEF\x80\x94"
|
||||
#define SYMBOL_NEXT "\xEF\x80\x95"
|
||||
#define SYMBOL_EJECT "\xEF\x80\x96"
|
||||
#define SYMBOL_LEFT "\xEF\x80\x97"
|
||||
#define SYMBOL_RIGHT "\xEF\x80\x98"
|
||||
#define SYMBOL_PLUS "\xEF\x80\x99"
|
||||
#define SYMBOL_MINUS "\xEF\x80\x9A"
|
||||
#define SYMBOL_WARNING "\xEF\x80\x9B"
|
||||
#define SYMBOL_SHUFFLE "\xEF\x80\x9C"
|
||||
#define SYMBOL_UP "\xEF\x80\x9D"
|
||||
#define SYMBOL_DOWN "\xEF\x80\x9E"
|
||||
#define SYMBOL_LOOP "\xEF\x80\x9F"
|
||||
#define SYMBOL_DIRECTORY "\xEF\x80\xA0"
|
||||
#define SYMBOL_UPLOAD "\xEF\x80\xA1"
|
||||
#define SYMBOL_CALL "\xEF\x80\xA2"
|
||||
#define SYMBOL_CUT "\xEF\x80\xA3"
|
||||
#define SYMBOL_COPY "\xEF\x80\xA4"
|
||||
#define SYMBOL_SAVE "\xEF\x80\xA5"
|
||||
#define SYMBOL_CHARGE "\xEF\x80\xA6"
|
||||
#define SYMBOL_BELL "\xEF\x80\xA7"
|
||||
#define SYMBOL_KEYBOARD "\xEF\x80\xA8"
|
||||
#define SYMBOL_GPS "\xEF\x80\xA9"
|
||||
#define SYMBOL_FILE "\xEF\x80\xAA"
|
||||
#define SYMBOL_WIFI "\xEF\x80\xAB"
|
||||
#define SYMBOL_BATTERY_FULL "\xEF\x80\xAC"
|
||||
#define SYMBOL_BATTERY_3 "\xEF\x80\xAD"
|
||||
#define SYMBOL_BATTERY_2 "\xEF\x80\xAE"
|
||||
#define SYMBOL_BATTERY_1 "\xEF\x80\xAF"
|
||||
#define SYMBOL_BATTERY_EMPTY "\xEF\x80\xB0"
|
||||
#define SYMBOL_BLUETOOTH "\xEF\x80\xB1"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*LV_SYMBOL_DEF_H*/
|
259
lv_misc/lv_fs.c
259
lv_misc/lv_fs.c
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_fs.c
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
@ -24,7 +24,7 @@
|
||||
* 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 lv_fs_drv_t * lv_fs_get_drv(char letter);
|
||||
|
||||
|
||||
/**********************
|
||||
@ -57,22 +57,22 @@ void lv_fs_init(void)
|
||||
* @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)
|
||||
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;
|
||||
@ -80,21 +80,24 @@ lv_fs_res_t lv_fs_open (lv_fs_file_t * file_p, const char * path, lv_fs_mode_t m
|
||||
return LV_FS_RES_HW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
file_p->file_d = lv_mem_alloc(file_p->drv->file_size);
|
||||
if(file_p->file_d == NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -106,23 +109,23 @@ lv_fs_res_t lv_fs_open (lv_fs_file_t * file_p, const char * path, lv_fs_mode_t m
|
||||
* @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)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -131,7 +134,7 @@ lv_fs_res_t lv_fs_close (lv_fs_file_t * file_p)
|
||||
* @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)
|
||||
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;
|
||||
@ -141,15 +144,15 @@ lv_fs_res_t lv_fs_remove (const char * path)
|
||||
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->ready() == false) return LV_FS_RES_HW_ERR;
|
||||
}
|
||||
|
||||
if(drv->remove == NULL) return LV_FS_RES_NOT_IMP;
|
||||
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);
|
||||
const char * real_path = lv_fs_get_real_path(path);
|
||||
lv_fs_res_t res = drv->remove(real_path);
|
||||
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,16 +163,16 @@ lv_fs_res_t lv_fs_remove (const char * path)
|
||||
* @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)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -181,22 +184,22 @@ lv_fs_res_t lv_fs_read (lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_
|
||||
* @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)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -206,18 +209,18 @@ lv_fs_res_t lv_fs_write (lv_fs_file_t * file_p, const void * buf, uint32_t btw,
|
||||
* @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)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -227,30 +230,50 @@ lv_fs_res_t lv_fs_seek (lv_fs_file_t * file_p, uint32_t pos)
|
||||
* @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)
|
||||
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)
|
||||
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;
|
||||
@ -266,6 +289,40 @@ lv_fs_res_t lv_fs_size (lv_fs_file_t * file_p, uint32_t * 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
|
||||
@ -277,50 +334,52 @@ 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);
|
||||
if(rddir_p->dir_d == NULL) {
|
||||
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.
|
||||
* 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)
|
||||
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;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -328,25 +387,25 @@ lv_fs_res_t lv_fs_dir_read (lv_fs_dir_t * rddir_p, char * fn)
|
||||
* @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)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -357,7 +416,7 @@ lv_fs_res_t lv_fs_dir_close (lv_fs_dir_t * rddir_p)
|
||||
* @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 (char letter, uint32_t * total_p, uint32_t * free_p)
|
||||
lv_fs_res_t lv_fs_free(char letter, uint32_t * total_p, uint32_t * free_p)
|
||||
{
|
||||
lv_fs_drv_t * drv = lv_fs_get_drv(letter);
|
||||
|
||||
@ -383,37 +442,38 @@ lv_fs_res_t lv_fs_free (char letter, uint32_t * total_p, uint32_t * free_p)
|
||||
|
||||
/**
|
||||
* Add a new drive
|
||||
* @param drv_p pointer to an lv_fs_drv_t structure which is inited with the
|
||||
* @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(&drv_ll);
|
||||
lv_mem_assert(new_drv);
|
||||
memcpy(new_drv, drv_p, sizeof(lv_fs_drv_t));
|
||||
|
||||
/*Save the new driver*/
|
||||
lv_fs_drv_t * new_drv;
|
||||
new_drv = lv_ll_ins_head(&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
|
||||
* 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)
|
||||
char * lv_fs_get_letters(char * buf)
|
||||
{
|
||||
lv_fs_drv_t* drv;
|
||||
uint8_t i = 0;
|
||||
|
||||
LL_READ(drv_ll, drv) {
|
||||
buf[i] = drv->letter;
|
||||
i++;
|
||||
}
|
||||
|
||||
buf[i] = '\0';
|
||||
|
||||
return buf;
|
||||
lv_fs_drv_t * drv;
|
||||
uint8_t i = 0;
|
||||
|
||||
LL_READ(drv_ll, drv) {
|
||||
buf[i] = drv->letter;
|
||||
i++;
|
||||
}
|
||||
|
||||
buf[i] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
@ -432,7 +492,7 @@ const char * lv_fs_get_ext(const char * fn)
|
||||
return ""; /*No extension if a '\' or '/' found*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ""; /*Empty string if no '.' in the file name. */
|
||||
}
|
||||
|
||||
@ -497,27 +557,26 @@ const char * lv_fs_get_last(const char * path)
|
||||
* 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)
|
||||
/**
|
||||
* 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"
|
||||
/* Example path: "S:/folder/file.txt"
|
||||
* Leave the letter and the : / \ characters*/
|
||||
|
||||
|
||||
path ++; /*Ignore the driver letter*/
|
||||
|
||||
while(*path != '\0') {
|
||||
if(*path == ':' || *path == '\\' || *path == '/'){
|
||||
|
||||
while(*path != '\0') {
|
||||
if(*path == ':' || *path == '\\' || *path == '/') {
|
||||
path ++;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@ -526,16 +585,16 @@ static const char * lv_fs_get_real_path(const char * path)
|
||||
* @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)
|
||||
static lv_fs_drv_t * lv_fs_get_drv(char letter)
|
||||
{
|
||||
lv_fs_drv_t* drv;
|
||||
|
||||
lv_fs_drv_t * drv;
|
||||
|
||||
LL_READ(drv_ll, drv) {
|
||||
if(drv->letter == letter) {
|
||||
return drv;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lv_fs.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_FS_H
|
||||
@ -10,11 +10,14 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if USE_LV_FILESYSTEM
|
||||
|
||||
@ -30,7 +33,7 @@ extern "C" {
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef enum
|
||||
enum
|
||||
{
|
||||
LV_FS_RES_OK = 0,
|
||||
LV_FS_RES_HW_ERR, /*Low level hardware error*/
|
||||
@ -45,28 +48,30 @@ typedef enum
|
||||
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*/
|
||||
}lv_fs_res_t;
|
||||
};
|
||||
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;
|
||||
} lv_fs_file_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void * dir_d;
|
||||
struct __lv_fs_drv_t * drv;
|
||||
}lv_fs_dir_t;
|
||||
} lv_fs_dir_t;
|
||||
|
||||
typedef enum
|
||||
enum
|
||||
{
|
||||
LV_FS_MODE_WR = 0x01,
|
||||
LV_FS_MODE_RD = 0x02,
|
||||
}lv_fs_mode_t;
|
||||
};
|
||||
typedef uint8_t lv_fs_mode_t;
|
||||
|
||||
typedef struct __lv_fs_drv_t
|
||||
{
|
||||
@ -74,7 +79,7 @@ typedef struct __lv_fs_drv_t
|
||||
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);
|
||||
@ -84,12 +89,13 @@ typedef struct __lv_fs_drv_t
|
||||
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) (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;
|
||||
} lv_fs_drv_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
@ -166,6 +172,14 @@ lv_fs_res_t lv_fs_seek (lv_fs_file_t * file_p, uint32_t pos);
|
||||
*/
|
||||
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
|
||||
@ -174,6 +188,14 @@ lv_fs_res_t lv_fs_tell (lv_fs_file_t * file_p, uint32_t * pos);
|
||||
*/
|
||||
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
|
||||
|
203
lv_misc/lv_ll.c
203
lv_misc/lv_ll.c
@ -27,8 +27,8 @@
|
||||
/**********************
|
||||
* 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 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
|
||||
@ -45,19 +45,27 @@ static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t* act, lv_ll_node_t* next)
|
||||
/**
|
||||
* Initialize linked list
|
||||
* @param ll_dsc pointer to ll_dsc variable
|
||||
* @param n_size the size of 1 node in bytes
|
||||
* @param n_size the size of 1 node in bytes
|
||||
*/
|
||||
void lv_ll_init(lv_ll_t * ll_p, uint32_t n_size)
|
||||
{
|
||||
ll_p->head = NULL;
|
||||
ll_p->tail = NULL;
|
||||
|
||||
if(n_size & 0x3) { /*Round up to 4*/
|
||||
n_size &= ~0x3;
|
||||
#ifdef LV_MEM_ENV64
|
||||
/*Round the size up to 8*/
|
||||
if(n_size & 0x7) {
|
||||
n_size = n_size & (~0x7);
|
||||
n_size += 8;
|
||||
}
|
||||
#else
|
||||
/*Round the size up to 4*/
|
||||
if(n_size & 0x3) {
|
||||
n_size = n_size & (~0x3);
|
||||
n_size += 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
ll_p->n_size = n_size;
|
||||
ll_p->n_size = n_size;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,24 +75,24 @@ void lv_ll_init(lv_ll_t * ll_p, uint32_t n_size)
|
||||
*/
|
||||
void * lv_ll_ins_head(lv_ll_t * ll_p)
|
||||
{
|
||||
lv_ll_node_t* n_new;
|
||||
|
||||
lv_ll_node_t * n_new;
|
||||
|
||||
n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
|
||||
|
||||
if(n_new != NULL) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -96,17 +104,17 @@ void * lv_ll_ins_head(lv_ll_t * ll_p)
|
||||
*/
|
||||
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;
|
||||
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);
|
||||
}
|
||||
else {
|
||||
if(n_new == NULL) return NULL;
|
||||
} else {
|
||||
n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
|
||||
lv_mem_assert(n_new);
|
||||
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);
|
||||
@ -124,30 +132,31 @@ void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act)
|
||||
* @return pointer to the new tail
|
||||
*/
|
||||
void * lv_ll_ins_tail(lv_ll_t * ll_p)
|
||||
{
|
||||
lv_ll_node_t* n_new;
|
||||
|
||||
{
|
||||
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.
|
||||
* Remove the node 'node_p' from 'll_p' linked list.
|
||||
* It Dose 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
|
||||
@ -159,26 +168,21 @@ void lv_ll_rem(lv_ll_t * ll_p, void * node_p)
|
||||
ll_p->head = lv_ll_get_next(ll_p, node_p);
|
||||
if(ll_p->head == NULL) {
|
||||
ll_p->tail = NULL;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
node_set_prev(ll_p, ll_p->head, NULL);
|
||||
}
|
||||
}
|
||||
else if(lv_ll_get_tail(ll_p) == node_p) {
|
||||
}
|
||||
} 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 {
|
||||
} 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);
|
||||
|
||||
} 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);
|
||||
}
|
||||
@ -190,20 +194,20 @@ void lv_ll_rem(lv_ll_t * ll_p, void * node_p)
|
||||
*/
|
||||
void lv_ll_clear(lv_ll_t * ll_p)
|
||||
{
|
||||
void * i;
|
||||
void * i_next;
|
||||
void * i;
|
||||
void * i_next;
|
||||
|
||||
i = lv_ll_get_head(ll_p);
|
||||
i_next = NULL;
|
||||
i = lv_ll_get_head(ll_p);
|
||||
i_next = NULL;
|
||||
|
||||
while(i != NULL) {
|
||||
i_next = lv_ll_get_next(ll_p, i);
|
||||
while(i != NULL) {
|
||||
i_next = lv_ll_get_next(ll_p, i);
|
||||
|
||||
lv_ll_rem(ll_p, i);
|
||||
lv_mem_free(i);
|
||||
lv_ll_rem(ll_p, i);
|
||||
lv_mem_free(i);
|
||||
|
||||
i = i_next;
|
||||
}
|
||||
i = i_next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -215,11 +219,11 @@ void lv_ll_clear(lv_ll_t * ll_p)
|
||||
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_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);
|
||||
}
|
||||
@ -233,16 +237,16 @@ 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'
|
||||
* @return pointer to the head of 'll_p'
|
||||
*/
|
||||
void * lv_ll_get_head(lv_ll_t * 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;
|
||||
}
|
||||
|
||||
@ -251,50 +255,50 @@ void * lv_ll_get_head(lv_ll_t * ll_p)
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the head of 'll_p'
|
||||
*/
|
||||
void * lv_ll_get_tail(lv_ll_t * 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'
|
||||
* 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
|
||||
* @param n_act pointer a node
|
||||
* @return pointer to the next node
|
||||
*/
|
||||
void * lv_ll_get_next(lv_ll_t * ll_p, void * n_act)
|
||||
void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act)
|
||||
{
|
||||
void * next = NULL;
|
||||
|
||||
|
||||
if(ll_p != NULL) {
|
||||
lv_ll_node_t* n_act_d = n_act;
|
||||
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'
|
||||
* 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
|
||||
* @param n_act pointer a node
|
||||
* @return pointer to the previous node
|
||||
*/
|
||||
void * lv_ll_get_prev(lv_ll_t * ll_p, void * n_act)
|
||||
void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act)
|
||||
{
|
||||
void * prev = NULL;
|
||||
|
||||
|
||||
if(ll_p != NULL) {
|
||||
lv_ll_node_t* n_act_d = n_act;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -316,20 +320,21 @@ 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*/
|
||||
|
||||
if(n_after == NULL) {
|
||||
void * n_before = lv_ll_get_tail(ll_p);
|
||||
node_set_next(ll_p, n_before, n_act);
|
||||
node_set_prev(ll_p, n_act, n_before);
|
||||
node_set_next(ll_p, n_act, NULL);
|
||||
ll_p->tail = n_act;
|
||||
} else {
|
||||
void * n_before = lv_ll_get_prev(ll_p, n_after);
|
||||
/*Move the node between `n_before` and `n_after`*/
|
||||
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);
|
||||
}
|
||||
|
||||
void * n_before = lv_ll_get_prev(ll_p, n_after);
|
||||
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;
|
||||
}
|
||||
|
||||
/**********************
|
||||
@ -337,24 +342,32 @@ void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after)
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set the 'pervious node pointer' of a node
|
||||
* 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)
|
||||
static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * prev)
|
||||
{
|
||||
memcpy(act + LL_PREV_P_OFFSET(ll_p), &prev, sizeof(lv_ll_node_t*));
|
||||
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
|
||||
* 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)
|
||||
static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * next)
|
||||
{
|
||||
memcpy(act + LL_NEXT_P_OFFSET(ll_p), &next, sizeof(lv_ll_node_t*));
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ typedef struct
|
||||
uint32_t n_size;
|
||||
lv_ll_node_t* head;
|
||||
lv_ll_node_t* tail;
|
||||
}lv_ll_t;
|
||||
} lv_ll_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
@ -97,14 +97,14 @@ void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node);
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the head of 'll_p'
|
||||
*/
|
||||
void * lv_ll_get_head(lv_ll_t * 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(lv_ll_t * ll_p);
|
||||
void * lv_ll_get_tail(const lv_ll_t * ll_p);
|
||||
|
||||
/**
|
||||
* Return with the pointer of the next node after 'n_act'
|
||||
@ -112,7 +112,7 @@ void * lv_ll_get_tail(lv_ll_t * ll_p);
|
||||
* @param n_act pointer a node
|
||||
* @return pointer to the next node
|
||||
*/
|
||||
void * lv_ll_get_next(lv_ll_t * ll_p, void * n_act);
|
||||
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'
|
||||
@ -120,7 +120,7 @@ void * lv_ll_get_next(lv_ll_t * ll_p, void * n_act);
|
||||
* @param n_act pointer a node
|
||||
* @return pointer to the previous node
|
||||
*/
|
||||
void * lv_ll_get_prev(lv_ll_t * ll_p, void * n_act);
|
||||
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
|
||||
|
76
lv_misc/lv_log.c
Normal file
76
lv_misc/lv_log.c
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @file lv_log.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_log.h"
|
||||
#if USE_LV_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, uint32_t 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 /*USE_LV_LOG*/
|
86
lv_misc/lv_log.h
Normal file
86
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 `USE_LV_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 uint8_t lv_log_level_t;
|
||||
|
||||
#if USE_LV_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, uint32_t 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 /*USE_LV_LOG*/
|
||||
|
||||
/*Do nothing if `USE_LV_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 /*USE_LV_LOG*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_LOG_H*/
|
@ -24,6 +24,18 @@
|
||||
/**********************
|
||||
* 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
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
@ -54,7 +66,7 @@ char * lv_math_num_to_str(int32_t num, char * buf)
|
||||
uint32_t output = 0;
|
||||
int8_t i;
|
||||
|
||||
for(i = 31; i >= 0; i--){
|
||||
for(i = 31; i >= 0; i--) {
|
||||
if((output & 0xF) >= 5)
|
||||
output += 3;
|
||||
if(((output & 0xF0) >> 4) >= 5)
|
||||
@ -90,6 +102,61 @@ char * lv_math_num_to_str(int32_t num, char * buf)
|
||||
return buf_ori;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = 179 - angle;
|
||||
ret = sin0_90_table[angle];
|
||||
} else if(angle >= 180 && angle < 270) {
|
||||
angle = angle - 180;
|
||||
ret = - sin0_90_table[angle];
|
||||
} else { /*angle >=270*/
|
||||
angle = 359 - 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
|
||||
**********************/
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file math_base.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_MATH_H
|
||||
@ -19,11 +19,16 @@ extern "C" {
|
||||
/*********************
|
||||
* 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
|
||||
**********************/
|
||||
@ -39,6 +44,24 @@ extern "C" {
|
||||
*/
|
||||
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
|
||||
**********************/
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user