Compare commits
545 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ead495903 | ||
|
|
75d44d0538 | ||
|
|
3403ec8332 | ||
|
|
1ddff88a81 | ||
|
|
3414433fd8 | ||
|
|
68b93ea002 | ||
|
|
320ee83dac | ||
|
|
def245f939 | ||
|
|
58483fc1aa | ||
|
|
36a4307930 | ||
|
|
40e2da1905 | ||
|
|
2cd3a5ac09 | ||
|
|
624a37c529 | ||
|
|
bc7efef537 | ||
|
|
79a65213d6 | ||
|
|
f960c75e3f | ||
|
|
84ed542b34 | ||
|
|
4bf228ca2c | ||
|
|
603786f969 | ||
|
|
0065992fcd | ||
|
|
e60439a9e7 | ||
|
|
6fbc9f3400 | ||
|
|
708d68eac1 | ||
|
|
cde12976ac | ||
|
|
0c093da924 | ||
|
|
eb44a75bf6 | ||
|
|
dde953f0e2 | ||
|
|
6b4ec1ee2e | ||
|
|
1765dde018 | ||
|
|
eb67692baa | ||
|
|
10b9c9b2f5 | ||
|
|
a53fca8c7f | ||
|
|
9b283981e8 | ||
|
|
70a2286f0f | ||
|
|
33f5448a38 | ||
|
|
03b0f7fc9a | ||
|
|
c75d868c2a | ||
|
|
ca84aaf6e8 | ||
|
|
51928059d2 | ||
|
|
f31ba6cf6f | ||
|
|
7afd70a005 | ||
|
|
492c9e4178 | ||
|
|
7d25f66060 | ||
|
|
9c599e1cc1 | ||
|
|
678fbd56d3 | ||
|
|
2c8ebb873e | ||
|
|
e5e68ac679 | ||
|
|
479012eb48 | ||
|
|
f8f308a72e | ||
|
|
40ed2b9e26 | ||
|
|
b9c8ee1794 | ||
|
|
26fdb159fe | ||
|
|
c400ba1bdb | ||
|
|
b7c6cf94c6 | ||
|
|
7cad0abb9f | ||
|
|
f4c172f56a | ||
|
|
2d203c8a41 | ||
|
|
ca576434e2 | ||
|
|
9aa535e30d | ||
|
|
9cc03b0122 | ||
|
|
47e29bed8e | ||
|
|
248868fef1 | ||
|
|
ef071d02a7 | ||
|
|
a010412fde | ||
|
|
7175231aab | ||
|
|
1441601e3e | ||
|
|
4405ab9cf7 | ||
|
|
1e4883ffc7 | ||
|
|
7567679a58 | ||
|
|
d7c74d6461 | ||
|
|
d6e4c2f50c | ||
|
|
30539a51ec | ||
|
|
b6b5b68d2c | ||
|
|
f54ecc470c | ||
|
|
cdc2cf90ce | ||
|
|
efeec7d3b6 | ||
|
|
fc29f58754 | ||
|
|
71be75b0ec | ||
|
|
da2ee84fbb | ||
|
|
842283d136 | ||
|
|
d7735410c9 | ||
|
|
f6f5f691f7 | ||
|
|
840f382b64 | ||
|
|
e8dd654ad6 | ||
|
|
17be0af46b | ||
|
|
f34598d810 | ||
|
|
d35e09bfcc | ||
|
|
1f2987a66b | ||
|
|
36082419d8 | ||
|
|
eb614c32b3 | ||
|
|
c23655a0d7 | ||
|
|
4037a68ccc | ||
|
|
6c8b0c44be | ||
|
|
6e8a4eeed4 | ||
|
|
0b12f934ec | ||
|
|
9083adb936 | ||
|
|
148478bf60 | ||
|
|
ec18ea42fe | ||
|
|
da8c604d14 | ||
|
|
bf5a8bc52f | ||
|
|
db7a22a01e | ||
|
|
a596462a49 | ||
|
|
dbb3630306 | ||
|
|
9ffdefd98a | ||
|
|
5612b22a4e | ||
|
|
64a56a2b0f | ||
|
|
bd049d1ac3 | ||
|
|
aafa6e7ccb | ||
|
|
c059025d42 | ||
|
|
14c407dad3 | ||
|
|
8bb67c0303 | ||
|
|
de48d1b558 | ||
|
|
b388c702e5 | ||
|
|
5f2e5e4d01 | ||
|
|
5f3374624e | ||
|
|
d17e7c7b76 | ||
|
|
926dafd3b5 | ||
|
|
a7bfaabfad | ||
|
|
f0863b4179 | ||
|
|
0422e662d9 | ||
|
|
12fa1ac788 | ||
|
|
ab0cad1b52 | ||
|
|
ef2bee1e42 | ||
|
|
9779513928 | ||
|
|
9a94f88885 | ||
|
|
b4b6a472fb | ||
|
|
9e74cdb145 | ||
|
|
810059e3ca | ||
|
|
5612856bca | ||
|
|
1ee7e1961e | ||
|
|
04ec2d17ec | ||
|
|
59743f7f90 | ||
|
|
197d95cf60 | ||
|
|
3452e60ec1 | ||
|
|
48f81d9f28 | ||
|
|
ca5940b693 | ||
|
|
ac28a13564 | ||
|
|
28cc431d95 | ||
|
|
bf5ea6658b | ||
|
|
57cf7ef7d6 | ||
|
|
98c4514852 | ||
|
|
b9f7883b0b | ||
|
|
575df77a02 | ||
|
|
bbf2c8247c | ||
|
|
de102f9d20 | ||
|
|
7814d31613 | ||
|
|
92f9af3113 | ||
|
|
9792a74413 | ||
|
|
060c27f54a | ||
|
|
1e4ce0b143 | ||
|
|
b7c3732da7 | ||
|
|
6ebaaa6fa8 | ||
|
|
db3d642096 | ||
|
|
97a83cdf5c | ||
|
|
3cd2120b60 | ||
|
|
79f403ddc5 | ||
|
|
8ac7bddaf7 | ||
|
|
afb47ebf56 | ||
|
|
49e105917e | ||
|
|
1764220deb | ||
|
|
bb91aeb64c | ||
|
|
f3b88a57ca | ||
|
|
23b58d598d | ||
|
|
90eeff7022 | ||
|
|
46eabd6cf0 | ||
|
|
8cf7824f82 | ||
|
|
c4f8d8cd5b | ||
|
|
183d849e84 | ||
|
|
57e2a6d983 | ||
|
|
6eaf8dd6d3 | ||
|
|
8dfcba6aa8 | ||
|
|
6f762bb7c7 | ||
|
|
96b9114a5a | ||
|
|
0130f3e5f2 | ||
|
|
a3a326c2ff | ||
|
|
45c6dbab62 | ||
|
|
647341426c | ||
|
|
86f44c974d | ||
|
|
a76e65db88 | ||
|
|
5441cf9998 | ||
|
|
74254975cd | ||
|
|
5d5a8b4894 | ||
|
|
6f57de051b | ||
|
|
769c1a8f8a | ||
|
|
c7a7d1adca | ||
|
|
f6829a17b2 | ||
|
|
9472d0d0c7 | ||
|
|
5222bf92c4 | ||
|
|
3c662670f0 | ||
|
|
8db8470a60 | ||
|
|
e0dee03233 | ||
|
|
982e2036cf | ||
|
|
b02bf9d804 | ||
|
|
fb9fb8d09e | ||
|
|
da7e67b381 | ||
|
|
0f1e5fba16 | ||
|
|
3da868a090 | ||
|
|
9baef1ef96 | ||
|
|
c86e2722bd | ||
|
|
cfb72d5b69 | ||
|
|
38ba12a866 | ||
|
|
dd100e5e07 | ||
|
|
8fe92bcd9a | ||
|
|
dd68877aae | ||
|
|
98b353879f | ||
|
|
6051e20b6c | ||
|
|
98a4d9b062 | ||
|
|
1c4695a21e | ||
|
|
9048e8072b | ||
|
|
081b2c2271 | ||
|
|
7f19fb53e6 | ||
|
|
57a8ee8e32 | ||
|
|
6df1fe190a | ||
|
|
372b133b18 | ||
|
|
f02d52a598 | ||
|
|
d5aabef42d | ||
|
|
4158334a40 | ||
|
|
f38b12ee6c | ||
|
|
437b34390c | ||
|
|
32689cb3e5 | ||
|
|
6f6c26b058 | ||
|
|
ddd7c1d30c | ||
|
|
a572d8a648 | ||
|
|
65252024bf | ||
|
|
69d7d53768 | ||
|
|
6aff9f65ed | ||
|
|
cfddd8df65 | ||
|
|
0634b11578 | ||
|
|
3264af9f0e | ||
|
|
901d108bae | ||
|
|
c241905d88 | ||
|
|
23ec092c14 | ||
|
|
246adc7b43 | ||
|
|
0bd200a36a | ||
|
|
f7c2512c76 | ||
|
|
ae006b2bc9 | ||
|
|
a11a06547f | ||
|
|
8694b3889b | ||
|
|
649e438f0d | ||
|
|
9a7b7f8511 | ||
|
|
4c944f4050 | ||
|
|
6cfb0af7c3 | ||
|
|
e1c46cb9bc | ||
|
|
f282c3bd08 | ||
|
|
c6b7cf130b | ||
|
|
04158b39cd | ||
|
|
92be109cba | ||
|
|
87d191e737 | ||
|
|
2e612c91bd | ||
|
|
770645ecd0 | ||
|
|
93a94bc4d5 | ||
|
|
c7b8626780 | ||
|
|
27c8a88c94 | ||
|
|
bd9695ab03 | ||
|
|
10b3463a5f | ||
|
|
bcdd680a2f | ||
|
|
6b5c89baf7 | ||
|
|
54e34c15b9 | ||
|
|
06746dfd63 | ||
|
|
f1c7e19985 | ||
|
|
9d2a2c58f9 | ||
|
|
de55986fc0 | ||
|
|
93ce1b9e1c | ||
|
|
0df7d0d996 | ||
|
|
7f5ce8ca37 | ||
|
|
dcc287c936 | ||
|
|
bd402605da | ||
|
|
c2b3976d5a | ||
|
|
6d93057532 | ||
|
|
bae1cb6ae0 | ||
|
|
7325a3cdde | ||
|
|
641117e896 | ||
|
|
fe35307d9f | ||
|
|
6f001958ce | ||
|
|
c747f29664 | ||
|
|
cadf2bd97d | ||
|
|
7f7abe9a93 | ||
|
|
aa1d5080e4 | ||
|
|
8af6043e75 | ||
|
|
7a0728fc3c | ||
|
|
a12bbfe0d2 | ||
|
|
1016b8bb47 | ||
|
|
0257fbcd5a | ||
|
|
eeabd32b9e | ||
|
|
68c752ab50 | ||
|
|
34e133586e | ||
|
|
b06ef2620a | ||
|
|
6190763382 | ||
|
|
99fd136758 | ||
|
|
2117c4dab2 | ||
|
|
beafc32594 | ||
|
|
dbccceea51 | ||
|
|
80448a1d54 | ||
|
|
e0ca7581ef | ||
|
|
05f23d5ff0 | ||
|
|
92b9141788 | ||
|
|
02755339bc | ||
|
|
34faac98a7 | ||
|
|
d1d3ef4305 | ||
|
|
68c39030a6 | ||
|
|
61dfb56648 | ||
|
|
ca9c4c8fda | ||
|
|
c74e6a6207 | ||
|
|
abb480f988 | ||
|
|
de96092537 | ||
|
|
3753265f56 | ||
|
|
8fb484ab91 | ||
|
|
dd87cb8ef4 | ||
|
|
e4bd622c78 | ||
|
|
dab042fe06 | ||
|
|
6d52976a16 | ||
|
|
0d31e63a1e | ||
|
|
b49edd91a2 | ||
|
|
994057b578 | ||
|
|
8fc9b12c64 | ||
|
|
434ef7e667 | ||
|
|
d4196c7534 | ||
|
|
e8625aaf65 | ||
|
|
11d5fcb9ae | ||
|
|
786eabe1c7 | ||
|
|
10d90a8baa | ||
|
|
eda607d824 | ||
|
|
2600c1c3d9 | ||
|
|
c64dc1d645 | ||
|
|
8cb508dfec | ||
|
|
af7b2857ee | ||
|
|
98d29cdcd1 | ||
|
|
974e4a245e | ||
|
|
333812ba7a | ||
|
|
5e7edc30be | ||
|
|
c190374c79 | ||
|
|
a5de64f93c | ||
|
|
a35a79ba4e | ||
|
|
93d2d422b8 | ||
|
|
1339d92ccd | ||
|
|
bf9ed06bac | ||
|
|
3a5293fa32 | ||
|
|
ab2114e4e7 | ||
|
|
1a3d61e074 | ||
|
|
1a5001d7a3 | ||
|
|
a50e597942 | ||
|
|
c1e0faf440 | ||
|
|
3f89a91d9c | ||
|
|
e94f8e3cfc | ||
|
|
3aac71b16e | ||
|
|
7ac2aff982 | ||
|
|
280c291db7 | ||
|
|
ac269ebaad | ||
|
|
a3b61e72fc | ||
|
|
5370543e95 | ||
|
|
f00c24f312 | ||
|
|
85ffe5f974 | ||
|
|
c5e7fbd953 | ||
|
|
8476692731 | ||
|
|
25d4991683 | ||
|
|
d3962fc26c | ||
|
|
96e64ad6fc | ||
|
|
0a9eeba4e4 | ||
|
|
ede392b7c9 | ||
|
|
8e7bd571af | ||
|
|
4d44d16b2e | ||
|
|
8dcb1ff21c | ||
|
|
6e9f10451d | ||
|
|
46dead9ab9 | ||
|
|
e9941eaf4c | ||
|
|
8ce6c32415 | ||
|
|
e9b6fcd58d | ||
|
|
53a1188f7c | ||
|
|
c4e9f69868 | ||
|
|
93cef9e121 | ||
|
|
0b4e7629b8 | ||
|
|
5660181b81 | ||
|
|
a7dc9e852c | ||
|
|
3dfbc5c85d | ||
|
|
366f958e1a | ||
|
|
7ef624054a | ||
|
|
bddf31824c | ||
|
|
4479a22696 | ||
|
|
2c5c4abdce | ||
|
|
62c6ede15e | ||
|
|
bebd2dd896 | ||
|
|
6d81b453b3 | ||
|
|
9f978cb087 | ||
|
|
87c3296d92 | ||
|
|
f341ad9b60 | ||
|
|
e4bcade975 | ||
|
|
cf1fed89e0 | ||
|
|
305ac5ff69 | ||
|
|
fc1b5c682d | ||
|
|
b67f40ed39 | ||
|
|
12ee870e2c | ||
|
|
7f565f419a | ||
|
|
3dc57783ad | ||
|
|
9c8e0f0552 | ||
|
|
a611160636 | ||
|
|
88bda09f5f | ||
|
|
f190c78195 | ||
|
|
915046d3ba | ||
|
|
a031af4f1e | ||
|
|
8e5e33d746 | ||
|
|
eefd9c4e0d | ||
|
|
ffd4708ac3 | ||
|
|
49c2bbedbb | ||
|
|
8efba76073 | ||
|
|
78125b66db | ||
|
|
f15bd1c59b | ||
|
|
2a4ba5042e | ||
|
|
b1047f4b59 | ||
|
|
54a9ea6179 | ||
|
|
1ff1e31ed8 | ||
|
|
74d5ac5553 | ||
|
|
cfc86713ce | ||
|
|
3eb06252e9 | ||
|
|
a5d89e6ece | ||
|
|
c0180b05b4 | ||
|
|
248c3a51ea | ||
|
|
94c95bc9e4 | ||
|
|
941409f3f9 | ||
|
|
7ea67301d7 | ||
|
|
d5d8eb5afd | ||
|
|
bbb0d2f60e | ||
|
|
71e950614f | ||
|
|
c35c84c7d0 | ||
|
|
49afd3f46c | ||
|
|
7c90b84560 | ||
|
|
5e8a3e180e | ||
|
|
18eb517cff | ||
|
|
d4a22cb713 | ||
|
|
ba1fba1f10 | ||
|
|
e53a30381a | ||
|
|
9a69d142fe | ||
|
|
677e25397b | ||
|
|
5c735c0fc8 | ||
|
|
bdce05e20f | ||
|
|
7f653e6924 | ||
|
|
22aee91fc2 | ||
|
|
ebb29f09fb | ||
|
|
d845cd73b0 | ||
|
|
1efff93dda | ||
|
|
17111843a0 | ||
|
|
1f4f333a01 | ||
|
|
3eeb104463 | ||
|
|
6bb86f0963 | ||
|
|
8ad5aa36dd | ||
|
|
ec63826d53 | ||
|
|
ff853105d9 | ||
|
|
8361a9c23d | ||
|
|
f5dca830c4 | ||
|
|
6a65f6e5d9 | ||
|
|
4f0393f704 | ||
|
|
7a73cb00a5 | ||
|
|
786e793634 | ||
|
|
a9ec60b5cd | ||
|
|
3cfe72c0fb | ||
|
|
a4c6d511b7 | ||
|
|
fd6d7119f5 | ||
|
|
0ab5e6e65c | ||
|
|
6d2bbf2862 | ||
|
|
2093b43045 | ||
|
|
ebeeb28e85 | ||
|
|
5a9904fa12 | ||
|
|
28505b09e6 | ||
|
|
29b145ffb2 | ||
|
|
bf2453ce0e | ||
|
|
c519b73ae2 | ||
|
|
5d44e66d42 | ||
|
|
04be7cc6a6 | ||
|
|
3977a33ac4 | ||
|
|
c5f69ca3b1 | ||
|
|
aa2f70fabc | ||
|
|
465bd3edd9 | ||
|
|
639409b881 | ||
|
|
9401353ccb | ||
|
|
196da100b1 | ||
|
|
24c17a9e5f | ||
|
|
d1bc187ec6 | ||
|
|
884b0b8025 | ||
|
|
9f333d50d7 | ||
|
|
1c859fc3d6 | ||
|
|
cd0d311531 | ||
|
|
33b4072138 | ||
|
|
da3785240a | ||
|
|
ea00b24cdf | ||
|
|
d7fd9eca35 | ||
|
|
27db08eb23 | ||
|
|
93357446a4 | ||
|
|
f55abd4e97 | ||
|
|
a421547774 | ||
|
|
4a036d8c28 | ||
|
|
362378b4e4 | ||
|
|
0c8794d557 | ||
|
|
2cead48cd5 | ||
|
|
5312875972 | ||
|
|
fca1a1d434 | ||
|
|
1618930f9b | ||
|
|
014850e73a | ||
|
|
1a7e7ef125 | ||
|
|
f984c35875 | ||
|
|
dec310a78d | ||
|
|
a568a131d6 | ||
|
|
5f9324cec5 | ||
|
|
40c86ea34e | ||
|
|
df91d5bcad | ||
|
|
2f29a9f361 | ||
|
|
7bacac488e | ||
|
|
e792352f45 | ||
|
|
b4b4c764a3 | ||
|
|
1dfded27d4 | ||
|
|
3654253472 | ||
|
|
95149e466f | ||
|
|
1d53e5eaec | ||
|
|
91f8755690 | ||
|
|
5ae4b62f4d | ||
|
|
8e9764532d | ||
|
|
03f18260a9 | ||
|
|
9023588fef | ||
|
|
89bc24a7d9 | ||
|
|
f66b21433c | ||
|
|
c021de5968 | ||
|
|
2dce4407c7 | ||
|
|
6989a9c797 | ||
|
|
471ff8a5b5 | ||
|
|
55740d2a96 | ||
|
|
6c59216b46 | ||
|
|
3a8a004e8b | ||
|
|
a78d0489f5 | ||
|
|
507c220d3f | ||
|
|
f2f024b610 | ||
|
|
4f77d8fc1a | ||
|
|
3eb14e198a | ||
|
|
63b070164f | ||
|
|
6eb9975966 | ||
|
|
0f24ef3666 | ||
|
|
50d134fa8c | ||
|
|
5b9d969fa4 | ||
|
|
27155720d5 | ||
|
|
90a3edd218 | ||
|
|
9ad51e529e | ||
|
|
0dde2937d7 | ||
|
|
b0870156c8 | ||
|
|
f7b8e5d415 | ||
|
|
7b0b28f5a7 | ||
|
|
38cbc2fdea | ||
|
|
28e321f223 | ||
|
|
86c28355ab |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
custom: ["https://littlevgl.com/donate"]
|
||||
2
.github/ISSUE_TEMPLATE/bug-report.md
vendored
2
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@@ -7,6 +7,8 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
> # Important: issues that don't use this template will be ignored/closed.
|
||||
|
||||
**Describe the bug**
|
||||
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
323
README.md
323
README.md
@@ -1,8 +1,10 @@
|
||||
<h1 align="center"> LittlevGL - Open-source Embedded GUI Library</h1>
|
||||
<p align="center">
|
||||
<a href="https://github.com/littlevgl/lvgl/blob/master/LICENCE.txt"><img src="https://img.shields.io/badge/licence-MIT-blue.svg"></a>
|
||||
<a href="https://github.com/littlevgl/lvgl/releases/tag/v5.3"><img src="https://img.shields.io/badge/version-5.3-blue.svg"></a>
|
||||
<br>
|
||||
<a href="https://github.com/littlevgl/lvgl/releases/tag/v6.0"><img src="https://img.shields.io/badge/version-6.0-blue.svg"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://littlevgl.com/github/cover_ori_reduced_2.gif">
|
||||
</p>
|
||||
|
||||
@@ -13,21 +15,29 @@ LittlevGL provides everything you need to create a Graphical User Interface (GUI
|
||||
<h4 align="center">
|
||||
<a href="https://littlevgl.com">Website </a> ·
|
||||
<a href="https://littlevgl.com/live-demo">Live demo</a> ·
|
||||
<a href="https://docs.littlevgl.com/#PC-simulator">Simulator</a> ·
|
||||
<a href="https://docs.littlevgl.com/en/html/get-started/pc-simulator.html">Simulator</a> ·
|
||||
<a href="https://forum.littlevgl.com">Forum</a> ·
|
||||
<a href="https://docs.littlevgl.com/">Docs</a> ·
|
||||
<a href="https://blog.littlevgl.com/">Blog</a>
|
||||
</h4>
|
||||
|
||||
<!--
|
||||
<p align="center">
|
||||
:star: Star the project if you like it! And share with your friends <a href="https://twitter.com/intent/tweet?text=LittlevGL%20is%20a%20free%20and%20open%20source%20embedded%20GUI%20library%20with%20easy-to-use%20graphical%20elements,%20beautiful%20visual%20effects%20and%20low%20memory%20footprint.&url=https://littlevgl.com/&hashtags=littlevgl,embedded,gui,free,opensource"><img src="https://img.shields.io/twitter/url/http/shields.io.svg?style=social"></a>
|
||||
</p>
|
||||
-->
|
||||
---
|
||||
|
||||
### Features
|
||||
- [Features](#features)
|
||||
- [Supported devices](#supported-devices)
|
||||
- [Quick start in a simulator](#quick-start-in-a-simulator)
|
||||
- [Add LittlevGL to your project](#add-littlevgl-to-your-project)
|
||||
- [Learn the basics](#learn-the-basics)
|
||||
- [Examples](#examples)
|
||||
- [Contributing](#contributing)
|
||||
- [Donate](#donate)
|
||||
|
||||
|
||||
## Features
|
||||
* **Powerful building blocks** buttons, charts, lists, sliders, images, etc.
|
||||
* **Advanced graphics** with animations, anti-aliasing, opacity, smooth scrolling
|
||||
* **Various input devices** touch pad, mouse, keyboard, encoder, buttons, etc.
|
||||
* **Simultaneously use various input devices** touchscreen, mouse, keyboard, encoder, buttons, etc.
|
||||
* **Simultaneously use multiple displays** i.e. monochrome and color display
|
||||
* **Multi-language support** with UTF-8 encoding
|
||||
* **Fully customizable** graphical elements
|
||||
* **Hardware independent** to use with any microcontroller or display
|
||||
@@ -38,15 +48,22 @@ LittlevGL provides everything you need to create a Graphical User Interface (GUI
|
||||
* **Micropython Binding** exposes [LittlevGL API in Micropython](https://blog.littlevgl.com/2019-02-20/micropython-bindings)
|
||||
* **Simulator** to develop on PC without embedded hardware
|
||||
* **Tutorials, examples, themes** for rapid development
|
||||
* **Documentation** and API references online
|
||||
* **Documentation** and API references
|
||||
|
||||
### Supported devices
|
||||
## Supported devices
|
||||
Basically, every modern controller - which is able to drive a display - is suitable to run LittlevGL. The minimal requirements:
|
||||
- **16, 32 or 64-bit** microcontroller or processor
|
||||
- **> 16 MHz** clock speed
|
||||
- **> 8 kB RAM for static data** and **> 2 KB RAM for dynamic data** (graphical objects)
|
||||
- **> 64 kB flash** program memory
|
||||
- **Optionally ~1/10 screen sized memory** for buffered drawing (on 240 × 320, 16-bit colors it's 15 kB)
|
||||
- 16, 32 or 64 bit microcontroller or processor
|
||||
- > 16 MHz clock speed is recommended
|
||||
- Flash/ROM: > 64 kB for the very essential components (> 180 kB is recommended)
|
||||
- RAM:
|
||||
- Static RAM usage: ~8..16 kB depending on the used features and objects types
|
||||
- Stack: > 2kB (> 4 kB is recommended)
|
||||
- Dynamic data (heap): > 4 KB (> 16 kB is recommended if using several objects).
|
||||
Set by `LV_MEM_SIZE` in *lv_conf.h*.
|
||||
- Display buffer: > *"Horizontal resolution"* pixels (> 10 × *"Horizontal resolution"* is recommended)
|
||||
- C99 or newer compiler
|
||||
|
||||
*Note that the memory usage might vary depending on the architecture, compiler and build options.*
|
||||
|
||||
Just to mention some **platforms**:
|
||||
- STM32F1, STM32F3, [STM32F4](https://blog.littlevgl.com/2017-07-15/stm32f429_disco_port), [STM32F7](https://github.com/littlevgl/stm32f746_disco_no_os_sw4stm32)
|
||||
@@ -58,7 +75,7 @@ Just to mention some **platforms**:
|
||||
- Nordic nrf52
|
||||
- Quectell M66
|
||||
|
||||
### Quick start in a simulator
|
||||
## Quick start in a simulator
|
||||
The easiest way to get started with LittlevGL is to run it in a simulator on your PC without any embedded hardware.
|
||||
|
||||
Choose a project with your favourite IDE:
|
||||
@@ -66,27 +83,32 @@ Choose a project with your favourite IDE:
|
||||
| Eclipse | CodeBlocks | Visual Studio | PlatformIO | Qt Creator |
|
||||
|-------------|-------------|---------------|-----------|------------|
|
||||
| [](https://github.com/littlevgl/pc_simulator_sdl_eclipse) | [](https://github.com/littlevgl/pc_simulator_win_codeblocks) | [](https://github.com/littlevgl/visual_studio_2017_sdl_x64) | [](https://github.com/littlevgl/pc_simulator_sdl_platformio) | [](https://blog.littlevgl.com/2019-01-03/qt-creator) |
|
||||
| Cross-platform<br>with SDL | Native Windows | Cross-platform<br>with SDL | Cross-platform<br>with SDL | Cross-platform<br>with SDL |
|
||||
| Cross-platform<br>with SDL<br>(Recommended on<br>Linux and Mac) | Native Windows | Windows<br>with SDL | Cross-platform<br>with SDL | Cross-platform<br>with SDL |
|
||||
|
||||
### Porting to an embedded hardware
|
||||
In the most simple case you need to do these steps:
|
||||
1. Copy `lv_conf_templ.h` as `lv_conf.h` next to `lvgl` and set at least `LV_HOR_RES`, `LV_VER_RES` and `LV_COLOR_DEPTH`.
|
||||
2. Call `lv_tick_inc(x)` every `x` milliseconds **in a Timer or Task** (`x` should be between 1 and 10). It is required for the internal timing of LittlevGL. **It's very important that you don't call `lv_task_handler` in the same loop.**
|
||||
3. Call `lv_init()`
|
||||
4. Create a buffer for LittlevGL
|
||||
|
||||
## Add LittlevGL to your project
|
||||
|
||||
The steps below show how to setup LittlevGL on an embedded system with a display and a touchpad.
|
||||
You can use the [Simulators](https://docs.littlevgl.com/en/html/get-started/pc-simulator) to get ready to use projects which can be run on your PC.
|
||||
|
||||
1. [Download](https://littlevgl.com/download) or [Clone](https://github.com/littlevgl/lvgl) the library
|
||||
2. Copy the `lvgl` folder into your project
|
||||
3. Copy `lvgl/lv_conf_template.h` as `lv_conf.h` next to the `lvgl` folder and set at least `LV_HOR_RES_MAX`, `LV_VER_RES_MAX` and `LV_COLOR_DEPTH`.
|
||||
4. Include `lvgl/lvgl.h` where you need to use LittlevGL related functions.
|
||||
5. Call `lv_tick_inc(x)` every `x` milliseconds **in a Timer or Task** (`x` should be between 1 and 10). It is required for the internal timing of LittlevGL.
|
||||
6. Call `lv_init()`
|
||||
7. Create a display buffer for LittlevGL
|
||||
```c
|
||||
static lv_disp_buf_t disp_buf;
|
||||
static lv_color_t buf[LV_HOR_RES_MAX * 10]; /*Declare a buffer for 10 lines*/
|
||||
lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10); /*Initialize the display buffer*/
|
||||
```
|
||||
4. Implement and register a function which can **copy a pixel array** to an area of your diplay:
|
||||
8. Implement and register a function which can **copy a pixel array** to an area of your display:
|
||||
```c
|
||||
lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
|
||||
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
||||
disp_drv.hor_res = 480; /*Set the horizontal resolution*/
|
||||
disp_drv.ver_res = 320; /*Set the vertical resolution*/
|
||||
disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/
|
||||
disp_drv.buffer = &disp_buf; /*Assign the buffer to teh display*/
|
||||
disp_drv.buffer = &disp_buf; /*Assign the buffer to the display*/
|
||||
lv_disp_drv_register(&disp_drv); /*Finally register the driver*/
|
||||
|
||||
void my_disp_flush(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p)
|
||||
@@ -99,18 +121,18 @@ void my_disp_flush(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_
|
||||
}
|
||||
}
|
||||
|
||||
lv_disp_flush_ready(disp); /* Tell you are ready with the flushing*/
|
||||
lv_disp_flush_ready(disp); /* Indicate you are ready with the flushing*/
|
||||
}
|
||||
|
||||
```
|
||||
5. Register a function which can **read an input device**. E.g. for a touch pad:
|
||||
9. Implement and register a function which can **read an input device**. E.g. for a touch pad:
|
||||
```c
|
||||
lv_indev_drv_init(&indev_drv); /*Descriptor of a input device driver*/
|
||||
indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/
|
||||
indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/
|
||||
lv_indev_drv_register(&indev_drv); /*Finally register the driver*/
|
||||
|
||||
bool my_touchpad_read(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data)
|
||||
{
|
||||
static lv_coord_t last_x = 0;
|
||||
static lv_coord_t last_y = 0;
|
||||
@@ -126,68 +148,222 @@ bool my_touchpad_read(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
return false; /*Return `false` because we are not buffering and no more data to read*/
|
||||
}
|
||||
```
|
||||
6. Call `lv_task_handler()` periodically every few milliseconds in the main `while(1)` loop, in Timer interrupt or in an Operation system task. It will redraw the screen if required, handle input devices etc. **It's very important that you don't call `lv_tick_inc` in the same loop.**
|
||||
10. Call `lv_task_handler()` periodically every few milliseconds in the main `while(1)` loop, in Timer interrupt or in an Operation system task.
|
||||
It will redraw the screen if required, handle input devices etc.
|
||||
|
||||
For a detailed description check the [Documentation](https://docs.littlevgl.com/#Porting) or the [Porting examples](https://github.com/littlevgl/lvgl/tree/multi-disp/lv_porting).
|
||||
|
||||
|
||||
### Code examples
|
||||
#### Create a button with a label and assign a click callback
|
||||
|
||||
## Learn the basics
|
||||
|
||||
### Objects (Widgets)
|
||||
|
||||
The graphical elements like Buttons, Labels, Sliders, Charts etc are called objects in LittelvGL. Go to [Object types](https://docs.littlevgl.com/en/html/object-types/index) to see the full list of available types.
|
||||
|
||||
Every object has a parent object. The child object moves with the parent and if you delete the parent the children will be deleted too. Children can be visible only on their parent.
|
||||
|
||||
The *screen* are the "root" parents. To get the current screen call `lv_scr_act()`.
|
||||
|
||||
You can create a new object with `lv_<type>_create(parent, obj_to_copy)`. It will return an `lv_obj_t *` variable which should be used as a reference to the object to set its parameters.
|
||||
The first parameter is the desired *parent*, te second parameters can be an object to copy (`NULL` is unused).
|
||||
For example:
|
||||
```c
|
||||
lv_obj_t * slider1 = lv_slider_create(lv_scr_act(), NULL);
|
||||
```
|
||||
|
||||
To set some basic attribute `lv_obj_set_<paramters_name>(obj, <value>)` function can be used. For example:
|
||||
```c
|
||||
lv_obj_set_x(btn1, 30);
|
||||
lv_obj_set_y(btn1, 10);
|
||||
lv_obj_set_size(btn1, 200, 50);
|
||||
```
|
||||
|
||||
The objects has type specific parameters too which can be set by `lv_<type>_set_<paramters_name>(obj, <value>)` functions. For example:
|
||||
```c
|
||||
lv_slider_set_value(slider1, 70, LV_ANIM_ON);
|
||||
```
|
||||
|
||||
To see the full API visit the documentation of the object types or the related header file (e.g. `lvgl/src/lv_objx/lv_slider.h`).
|
||||
|
||||
### Styles
|
||||
Styles can be assigned to the objects to changed their appearance. A style describes the appearance of rectangle-like objects (like a button or slider), texts, images and lines at once.
|
||||
|
||||
You can create a new style like this:
|
||||
```c
|
||||
static lv_style_t style1; /*Declare a new style. Should be `static`*/
|
||||
lv_style_copy(&style1, &lv_style_plain); /*Copy a built-in style*/
|
||||
style1.body.main_color = LV_COLOR_RED; /*Main color*/
|
||||
style1.body.grad_color = lv_color_hex(0xffd83c) /*Gradient color (orange)*/
|
||||
style1.body.radius = 3;
|
||||
style1.text.color = lv_color_hex3(0x0F0) /*Label color (green)*/
|
||||
style1.text.font = &lv_font_dejavu_22; /*Change font*/
|
||||
...
|
||||
```
|
||||
|
||||
To set a new style for an object use the `lv_<type>set_style(obj, LV_<TYPE>_STYLE_<NAME>, &my_style)` functions. For example:
|
||||
```c
|
||||
lv_slider_set_style(slider1, LV_SLIDER_STYLE_BG, &slider_bg_style);
|
||||
lv_slider_set_style(slider1, LV_SLIDER_STYLE_INDIC, &slider_indic_style);
|
||||
lv_slider_set_style(slider1, LV_SLIDER_STYLE_KNOB, &slider_knob_style);
|
||||
```
|
||||
|
||||
If an object's style is `NULL` then it will inherit its parent's style. For example, the labels' style are `NULL` by default. If you place them on a button then they will use the `style.text` properties from the button's style.
|
||||
|
||||
Learn more in [Style overview](https://docs.littlevgl.com/en/html/overview/style) section.
|
||||
|
||||
### Events
|
||||
Events are used to inform the user if something has happened with an object. You can assign a callback to an object which will be called if the object is clicked, released, dragged, being deleted etc. It should look like this:
|
||||
|
||||
```c
|
||||
lv_obj_set_event_cb(btn, btn_event_cb); /*Assign a callback to the button*/
|
||||
|
||||
...
|
||||
|
||||
void btn_event_cb(lv_obj_t * btn, lv_event_t event)
|
||||
{
|
||||
if(event == LV_EVENT_CLICKED) {
|
||||
printf("Clicked\n");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about the events in the [Event overview](https://docs.littlevgl.com/en/html/overview/event) section.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
### Button with label
|
||||
```c
|
||||
lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL); /*Add a button the current screen*/
|
||||
lv_obj_set_pos(btn, 10, 10); /*Set its position*/
|
||||
lv_obj_set_size(btn, 100, 50); /*Set its size*/
|
||||
lv_obj_set_event_cb(btn, btn_event_cb); /*Assign a callback to the button*/
|
||||
|
||||
lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, btn_action);/*Assign a callback to the button*/
|
||||
lv_obj_t * label = lv_label_create(btn, NULL); /*Add a label to the button*/
|
||||
lv_label_set_text(label, "Button"); /*Set the labels text*/
|
||||
|
||||
lv_res_t btn_action(lv_obj_t * btn)
|
||||
...
|
||||
|
||||
void btn_event_cb(lv_obj_t * btn, lv_event_t event)
|
||||
{
|
||||
printf("Clicked\n");
|
||||
return LV_RES_OK;
|
||||
if(event == LV_EVENT_CLICKED) {
|
||||
printf("Clicked\n");
|
||||
}
|
||||
}
|
||||
```
|
||||

|
||||

|
||||
|
||||
#### Modify the styles
|
||||
### Button with styles
|
||||
Add styles to the previously button from the previous example
|
||||
```c
|
||||
static lv_style_t style_btn_rel; /*A variable to store the released style*/
|
||||
lv_style_copy(&style_btn_rel, &lv_style_plain); /*Initialize from a built-in style*/
|
||||
style_btn_rel.body.border.color = LV_COLOR_HEX3(0x269);
|
||||
style_btn_rel.body.border.color = lv_color_hex3(0x269);
|
||||
style_btn_rel.body.border.width = 1;
|
||||
style_btn_rel.body.main_color = LV_COLOR_HEX3(0xADF);
|
||||
style_btn_rel.body.grad_color = LV_COLOR_HEX3(0x46B);
|
||||
style_btn_rel.body.main_color = lv_color_hex3(0xADF);
|
||||
style_btn_rel.body.grad_color = lv_color_hex3(0x46B);
|
||||
style_btn_rel.body.shadow.width = 4;
|
||||
style_btn_rel.body.shadow.type = LV_SHADOW_BOTTOM;
|
||||
style_btn_rel.body.radius = LV_RADIUS_CIRCLE;
|
||||
style_btn_rel.text.color = LV_COLOR_HEX3(0xDEF);
|
||||
style_btn_rel.text.color = lv_color_hex3(0xDEF);
|
||||
|
||||
static lv_style_t style_btn_pr; /*A variable to store the pressed style*/
|
||||
lv_style_copy(&style_btn_pr, &style_btn_rel); /*Initialize from the released style*/
|
||||
style_btn_pr.body.border.color = LV_COLOR_HEX3(0x46B);
|
||||
style_btn_pr.body.main_color = LV_COLOR_HEX3(0x8BD);
|
||||
style_btn_pr.body.grad_color = LV_COLOR_HEX3(0x24A);
|
||||
style_btn_pr.body.border.color = lv_color_hex3(0x46B);
|
||||
style_btn_pr.body.main_color = lv_color_hex3(0x8BD);
|
||||
style_btn_pr.body.grad_color = lv_color_hex3(0x24A);
|
||||
style_btn_pr.body.shadow.width = 2;
|
||||
style_btn_pr.text.color = LV_COLOR_HEX3(0xBCD);
|
||||
style_btn_pr.text.color = lv_color_hex3(0xBCD);
|
||||
|
||||
lv_btn_set_style(btn, LV_BTN_STYLE_REL, &style_btn_rel); /*Set the button's released style*/
|
||||
lv_btn_set_style(btn, LV_BTN_STYLE_PR, &style_btn_pr); /*Set the button's pressed style*/
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
#### Enable a fancy effect
|
||||
### Slider and object alignment
|
||||
```c
|
||||
/*Add some effects when the button is clicked*/
|
||||
lv_btn_set_ink_in_time(btn, 300);
|
||||
lv_btn_set_ink_wait_time(btn, 100);
|
||||
lv_btn_set_ink_out_time(btn, 300);
|
||||
lv_obj_t * label;
|
||||
|
||||
...
|
||||
|
||||
/* Create a slider in the center of the display */
|
||||
lv_obj_t * slider = lv_slider_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_width(slider, 200); /*Set the width*/
|
||||
lv_obj_align(slider, NULL, LV_ALIGN_CENTER, 0, 0); /*Align to the center of the parent (screen)*/
|
||||
lv_obj_set_event_cb(slider, slider_event_cb); /*Assign an event function*/
|
||||
|
||||
/* Create a label below the slider */
|
||||
label = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_label_set_text(label, "0");
|
||||
lv_obj_set_auto_realign(slider, true);
|
||||
lv_obj_align(label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
|
||||
|
||||
...
|
||||
|
||||
void slider_event_cb(lv_obj_t * slider, lv_event_t event)
|
||||
{
|
||||
if(event == LV_EVENT_VALUE_CHANGED) {
|
||||
static char buf[4]; /* max 3 bytes for number plus 1 null terminating byte */
|
||||
snprintf(buf, 4, "%u", lv_slider_get_value(slider));
|
||||
lv_label_set_text(slider_label, buf); /*Refresh the text*/
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
#### Use LittlevGL from Micropython
|
||||
### List and themes
|
||||
```c
|
||||
/*Texts of the list elements*/
|
||||
const char * txts[] = {"First", "Second", "Third", "Forth", "Fifth", "Sixth", NULL};
|
||||
|
||||
/* Initialize and set a theme. `LV_THEME_NIGHT` needs to enabled in lv_conf.h. */
|
||||
lv_theme_t * th = lv_theme_night_init(20, NULL);
|
||||
lv_theme_set_current(th);
|
||||
|
||||
/*Create a list*/
|
||||
lv_obj_t* list = lv_list_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_size(list, 120, 180);
|
||||
lv_obj_set_pos(list, 10, 10);
|
||||
|
||||
/*Add buttons*/
|
||||
uint8_t i;
|
||||
for(i = 0; txts[i]; i++) {
|
||||
lv_obj_t * btn = lv_list_add_btn(list, LV_SYMBOL_FILE, txts[i]);
|
||||
lv_obj_set_event_cb(btn, list_event); /*Assign event function*/
|
||||
lv_btn_set_toggle(btn, true); /*Enable on/off states*/
|
||||
}
|
||||
|
||||
/* Initialize and set an other theme. `LV_THEME_MATERIAL` needs to enabled in lv_conf.h.
|
||||
* If `LV_TEHE_LIVE_UPDATE 1` then the previous list's style will be updated too.*/
|
||||
th = lv_theme_material_init(210, NULL);
|
||||
lv_theme_set_current(th);
|
||||
|
||||
/*Create an other list*/
|
||||
list = lv_list_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_size(list, 120, 180);
|
||||
lv_obj_set_pos(list, 150, 10);
|
||||
|
||||
/*Add buttons with the same texts*/
|
||||
for(i = 0; txts[i]; i++) {
|
||||
lv_obj_t * btn = lv_list_add_btn(list, LV_SYMBOL_FILE, txts[i]);
|
||||
lv_obj_set_event_cb(btn, list_event);
|
||||
lv_btn_set_toggle(btn, true);
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
static void list_event(lv_obj_t * btn, lv_event_t e)
|
||||
{
|
||||
if(e == LV_EVENT_CLICKED) {
|
||||
printf("%s\n", lv_list_get_btn_text(btn));
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||

|
||||
|
||||
### Use LittlevGL from Micropython
|
||||
Learn more about [Micropython](https://docs.littlevgl.com/en/html/get-started/micropython).
|
||||
```python
|
||||
# Create a Button and a Label
|
||||
scr = lv.obj()
|
||||
@@ -200,22 +376,23 @@ label.set_text("Button")
|
||||
lv.scr_load(scr)
|
||||
```
|
||||
|
||||
Check out the [Documentation](https://docs.littlevgl.com/) for more!
|
||||
|
||||
### Contributing
|
||||
## Contributing
|
||||
To ask questions please use the [Forum](https://forum.littlevgl.com).
|
||||
FOr development related things (bug reports, feature suggestions) use [GitHub's Issue tracker](https://github.com/littlevgl/lvgl/issues).
|
||||
You can contribute in several ways:
|
||||
- **Answer other's question** in the Forum
|
||||
- **Report and/or fix bugs** using the issue tracker and in Pull-request
|
||||
- **Suggest and/or implement new features** using the issue tracker and in Pull-request
|
||||
- **Improve and/or translate the documentation** learn more [here](https://github.com/littlevgl/docs)
|
||||
- **Write a blog post about your experiences** learn more [here](https://github.com/littlevgl/blog)
|
||||
- **Upload your project or product as a reference** to [this site](https://blog.littlevgl.com/2018-12-26/references)
|
||||
For development-related things (bug reports, feature suggestions) use [GitHub's Issue tracker](https://github.com/littlevgl/lvgl/issues).
|
||||
|
||||
Before contributing, please read [CONTRIBUTING.md](https://github.com/littlevgl/lvgl/blob/master/docs/CONTRIBUTING.md).
|
||||
If you are interested in contributing to LittlevGL you can
|
||||
- **Help others** in the [Forum](https://forum.littlevgl.com).
|
||||
- **Inspire people** by speaking about your project in [My project](https://forum.littlevgl.com/c/my-projects) category in the Forum or add it to the [References](https://blog.littlevgl.com/2018-12-26/references) post
|
||||
- **Improve and/or translate the documentation.** Go to the [Documentation](https://github.com/littlevgl/docs) repository to learn more
|
||||
- **Write a blog post** about your experiences. See how to do it in the [Blog](https://github.com/littlevgl/blog) repository
|
||||
- **Report and/or fix bugs** in [GitHub's issue tracker](https://github.com/littlevgl/lvgl/issues)
|
||||
- **Help in the developement**. Check the [Open issues](https://github.com/littlevgl/lvgl/issues) especially the ones with [Help wanted](https://github.com/littlevgl/lvgl/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) label and tell your ideas about a topic or implement a feature.
|
||||
|
||||
### Donate
|
||||
It should be useful to read the
|
||||
- [Contributing guide](https://blog.littlevgl.com/2018-12-06/contributing)
|
||||
- [Coding style guide](https://github.com/littlevgl/lvgl/blob/master/docs/CODING_STYLE.md)
|
||||
|
||||
## Donate
|
||||
If you are pleased with the library, found it useful, or you are happy with the support you got, please help its further development:
|
||||
|
||||
[](https://littlevgl.com/donate)
|
||||
|
||||
94
docs/CODING_STYLE.md
Normal file
94
docs/CODING_STYLE.md
Normal file
@@ -0,0 +1,94 @@
|
||||
|
||||
## File format
|
||||
Use [lv_misc/lv_templ.c](https://github.com/littlevgl/lvgl/blob/master/src/lv_misc/lv_templ.c) and [lv_misc/lv_templ.h](https://github.com/littlevgl/lvgl/blob/master/src/lv_misc/lv_templ.h)
|
||||
|
||||
## Naming conventions
|
||||
* 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):
|
||||
* starts with *lv*
|
||||
* followed by module name: *btn*, *label*, *style* etc.
|
||||
* followed by the action (for functions): *set*, *get*, *refr* etc.
|
||||
* closed with the subject: *name*, *size*, *state* etc.
|
||||
* Typedefs
|
||||
* prefer `typedef struct` and `typedef enum` instead of `struct name` and `enum name`
|
||||
* always end `typedef struct` and `typedef enum` type names with `_t`
|
||||
* Abbreviations:
|
||||
* 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 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)
|
||||
* Declare variables when needed (not all at function start)
|
||||
* Use the smallest required scope
|
||||
* Variables in a file (outside functions) are always *static*
|
||||
* Do not use global variables (use functions to set/get static variables)
|
||||
|
||||
## Comments
|
||||
Before every function have a comment like this:
|
||||
|
||||
```c
|
||||
/**
|
||||
* Return with the screen of an object
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to a screen
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_scr(lv_obj_t * obj);
|
||||
```
|
||||
|
||||
Always use `/* Something */` format and NOT `//Something`
|
||||
|
||||
Write readable code to avoid descriptive comments like:
|
||||
`x++; /* Add 1 to x */`.
|
||||
The code should show clearly what you are doing.
|
||||
|
||||
You should write **why** have you done this:
|
||||
`x++; /*Because of closing '\0' of the string */`
|
||||
|
||||
Short "code summaries" of a few lines are accepted. E.g. `/*Calculate the new coordinates*/`
|
||||
|
||||
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:
|
||||
```c
|
||||
/**
|
||||
* Set a new text for a label. Memory will be allocated to store the text by the label.
|
||||
* @param label pointer to a label object
|
||||
* @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 brackets of functions in new line*/
|
||||
|
||||
if(label == NULL) return; /*No bracket only if the command is inline with the if statement*/
|
||||
|
||||
lv_obj_inv(label);
|
||||
|
||||
lv_label_ext_t * ext = lv_obj_get_ext(label);
|
||||
|
||||
/*Comment before a section */
|
||||
if(text == ext->txt || text == NULL) { /*Bracket of statements start inline*/
|
||||
lv_label_refr_text(label);
|
||||
return;
|
||||
}
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
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,95 +1,96 @@
|
||||
# Contributing to Littlev Graphics Library
|
||||
|
||||
**Welcome! It's glad to see that you are interested in contributing to LittlevGL! There are several types of task where you can help to build a better library! Let's see how to get started!**
|
||||
**Do you have some free time to spend with programming?
|
||||
Are you working on an Embedded GUI project with LittlevGL?
|
||||
See how can you help to improve the graphics library!**
|
||||
|
||||
|
||||
There are many different possibilities to join the community. If you have some time to work with us I'm sure you will find something that fits you! You can:
|
||||
- answer other's questions
|
||||
- report and/or fix bugs
|
||||
- suggest and/or implement new features
|
||||
There are many ways to join the community. If you have some time to work with us I'm sure you will find something that fits you! You can:
|
||||
- help others in the [Forum](https://forum.littlevgl.com/)
|
||||
- improve and/or translate the documentation
|
||||
- write a blog post about your experiences
|
||||
- report and/or fix bugs
|
||||
- suggest and/or implement new features
|
||||
|
||||
But first, start with the most Frequently Asked Questions.
|
||||
|
||||
## FAQ about contributing
|
||||
# FAQ about contributing
|
||||
|
||||
### What license does my code need to be under?
|
||||
## Where can I write my question and remarks?
|
||||
|
||||
Any code added to LittlevGL must be licensed under [MIT](https://choosealicense.com/licenses/mit/) or another license that is fully compatible. Contributions under other licenses are highly likely to be rejected.
|
||||
We use the [Forum](https://forum.littlevgl.com/) to ask and answer questions and [GitHub's issue tracker](https://github.com/littlevgl/lvgl/issues) for development-related discussion.
|
||||
|
||||
If you borrow code from another project, please make sure to add their copyright notice to your contribution.
|
||||
|
||||
### Where do I ask questions, give feedback, or report bugs?
|
||||
|
||||
We use the [forum](http://forum.littlevgl.com/) for questions, feature suggestions, and discussions.
|
||||
|
||||
We use [GitHub's issue tracker](https://github.com/littlevgl/lvgl/issues) to report bugs.
|
||||
|
||||
For both of these there are some rules:
|
||||
But there are some simple rules:
|
||||
- Be kind and friendly.
|
||||
- Speak about one thing in one issue.
|
||||
- Give feedback and close the issue if your question is answered.
|
||||
- Explain exactly what you experience or expect. _"The button is not working"_ is not enough info to get help.
|
||||
- For most issues you should send an absolute minimal code example in order to reproduce the issue. Ideally this should be easily usable in the PC simulator.
|
||||
- Speak about one thing in one issue/topic.
|
||||
- Give feedback and close the issue or mark the topic as solved if your question is answered.
|
||||
- Tell what you experience or expect. _"The button is not working"_ is not enough info to get help.
|
||||
- If possible send an absolute minimal code example in order to reproduce the issue
|
||||
- Use [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) to format your post.
|
||||
- If you don't get any answer in a week write a comment like "Can somebody help?". Maybe your issue wasn't noticed.
|
||||
|
||||
### How can I send fixes and improvements?
|
||||
Merging new code happens via Pull Requests. If you are still not familiar with the Pull Requests (PR for short) here is a quick guide about them:
|
||||
## How can I send fixes and improvements?
|
||||
|
||||
Merging new code happens via Pull Requests. If you are still not familiar with the Pull Requests (PR for short) here is a quick guide:
|
||||
1. **Fork** the [lvgl repository](https://github.com/littlevgl/lvgl). To do this click the "Fork" button in the top right corner. It will "copy" the `lvgl` repository to your GitHub account (`https://github.com/your_name?tab=repositories`)
|
||||
2. **Clone** the forked repository and add your updates
|
||||
3. **Create a PR** on the GitHub on the page of you `lvgl` repository(`https://github.com/your_name/lvgl`) by hitting the "New pull request" button
|
||||
4. **Set the base branch**. It means where you want to merge your update. Bugfixes for the last release go to `master`, new features to the actual `dev-x.y` branch.
|
||||
2. **Clone** the forked repository and add your changes
|
||||
3. **Create a PR** on GitHub from the page of your `lvgl` repository (`https://github.com/your_name/lvgl`) by hitting the "New pull request" button
|
||||
4. **Set the base branch**. It means where you want to merge your update. Fixes go to `master`, new features to the actual `dev-x.y` branch.
|
||||
5. **Describe** what is in the update. An example code is welcome if applicable.
|
||||
|
||||
Some advice:
|
||||
- If you are not sure about your fix or feature it's better to open an issue first, and discuss the details there.
|
||||
- If you are not sure about your fix or feature it's better to open an issue first and discuss the details there.
|
||||
- Maybe your fix or update won't be perfect at first. Don't be afraid, just improve it and push the new commits. The PR will be updated accordingly.
|
||||
- If your update needs some extra work it's okay to say: _"I'm busy now and I will improve it soon"_ or _"Sorry, I don't have time to improve it, I hope it helps in this form too"_. So it's better to say don't have time to continue then saying nothing.
|
||||
- Please read and follow this [guide about the coding style](https://docs.littlevgl.com/#Coding-Style-Guide)
|
||||
- If your update needs some extra work it's okay to say: _"I'm busy now and I will improve it soon"_ or _"Sorry, I don't have time to improve it, I hope it helps in this form too"_.
|
||||
So it's better to say don't have time to continue than saying nothing.
|
||||
- Please read and follow this [guide about the coding style](https://github.com/littlevgl/lvgl/blob/master/docs/CODING_STYLE.md)
|
||||
|
||||
|
||||
### Where is the documentation?
|
||||
## Where is the documentation?
|
||||
|
||||
You can read the documentation here: https://docs.littlevgl.com/
|
||||
You can edit the documentation here: https://github.com/littlevgl/doc
|
||||
You can read the documentation here: <https://docs.littlevgl.com/>
|
||||
You can edit the documentation here: <https://github.com/littlevgl/doc>
|
||||
|
||||
### Where is the blog?
|
||||
## Where is the blog?
|
||||
|
||||
You can read the blog here: https://blog.littlevgl.com/
|
||||
You can edit the blog here: https://github.com/littlevgl/blog
|
||||
You can read the blog here: <https://blog.littlevgl.com/>
|
||||
You can edit the blog here: <https://github.com/littlevgl/blog>
|
||||
|
||||
# So how and where can you contribute?
|
||||
|
||||
## Help others in the Forum
|
||||
|
||||
It's a great way to contribute to the library if you already use it.
|
||||
Just go to [https://forum.littlevgl.com/](https://forum.littlevgl.com/) a register (Google and GitHub login also works).
|
||||
Log in, read the titles and if you are already familiar with a topic, don't be shy, and write your suggestion.
|
||||
|
||||
## Improving and/or translating the documentation
|
||||
|
||||
If you would like to contribute to LittlevGL the documentation is the best place to start.
|
||||
|
||||
### Fix typos, add missing parts
|
||||
|
||||
If you find a typo, an obscure sentence or something which is not explained well enough in the [English documentation](https://docs.littlevgl.com/en/html/index.html)
|
||||
click the *"Edit on GitHub"* button in the top right corner and fix the issue by sending a Pull Request.
|
||||
|
||||
### Translate the documentation
|
||||
|
||||
If you have time and interest you can translate the documentation to your native language or any language you speak.
|
||||
You can join others to work on an already existing language or you can start a new one.
|
||||
|
||||
To translate the documentation we use [Zanata](https://zanata.org) which is an online translation platform.
|
||||
You will find the LittlevGL project here: [LittlevGL on Zanata](https://translate.zanata.org/iteration/view/littlevgl-docs/v6.0-doc1?dswid=3430)
|
||||
|
||||
To get started you need to:
|
||||
- register at [Zanata](https://zanata.org) which is an online translation platform.
|
||||
- comment to [this post](https://forum.littlevgl.com/t/translate-the-documentation/238?u=kisvegabor)
|
||||
- tell your username at *Zanata* and your selected language(s) to get permission the edit the translations
|
||||
|
||||
Note that a translation will be added to the documentation only if at least the [Porting section](https://docs.littlevgl.com/en/html/porting/index.html) is translated.
|
||||
|
||||
|
||||
## So how and where can I contribute?
|
||||
## Writing a blog post about your experiences
|
||||
|
||||
### Answering other's questions
|
||||
|
||||
It's a great way to contribute to the library if you already use it. Just go the [issue tracker](https://github.com/littlevgl/lvgl/issues), read the titles and if you are already familiar with a topic, don't be shy, and write your suggestion.
|
||||
|
||||
### Reporting and/or fixing bugs
|
||||
For simple bugfixes (typos, missing error handling, fixing a warning) is fine to send a Pull request directly. However, for more complex bugs it's better to open an issue first. In the issue, you should describe how to reproduce the bug and even add the minimal code snippet.
|
||||
|
||||
### Suggesting and/or implementing new features
|
||||
If you have a good idea don't hesitate to share with us. It's even better if you have time to deal with its implementation. Don't be afraid if you still don't know LittlevGL well enough. We will help you to get started.
|
||||
|
||||
During the implementation don't forget the [Code style guide](https://docs.littlevgl.com/#Coding-Style-Guide).
|
||||
|
||||
### Improving and/or translating the documentation
|
||||
|
||||
The documentation of LittlevGL is written in Markdown and available [here](https://github.com/littlevgl/doc) for editing. If you find some parts of the documentation obscure or insufficient just search the related `.md` file, hit the edit icon and add your updates. This way a new Pull request will be generated automatically.
|
||||
|
||||
If you can devote more time to improve the documentation you can translate it!
|
||||
1. Just copy the English `.md` files from the root folder to `locale/LANGUAGE_CODE` (language code is e.g. DE, FR, ES etc)
|
||||
2. Append the language code the end of files (e.g. Welcome_fr.md)
|
||||
3. Update the filenames in `_Sidebar.md`
|
||||
4. Translate the page(s) you want
|
||||
5. Create a Pull request
|
||||
|
||||
### Writing a blog post about your experiences
|
||||
|
||||
Have ported LittlevGL to a new platform? Have you created a fancy GUI? Do you know a great trick?
|
||||
You can share your knowledge on LittelvGL's blog! It's super easy to add your own post:
|
||||
Have you ported LittlevGL to a new platform? Have you created a fancy GUI? Do you know a great trick?
|
||||
You can share your knowledge on LittlevGL's blog! It's super easy to add your own post:
|
||||
- Fork and clone the [blog repository](https://github.com/littlevgl/blog)
|
||||
- Add your post in Markdown to the `_posts` folder.
|
||||
- Store the images and other resources in a dedicated folder in `assets`
|
||||
@@ -97,7 +98,14 @@ You can share your knowledge on LittelvGL's blog! It's super easy to add your ow
|
||||
|
||||
The blog uses [Jekyll](https://jekyllrb.com/) to convert the `.md` files to a webpage. You can easily [run Jekyll offline](https://jekyllrb.com/docs/) to check your post before creating the Pull request
|
||||
|
||||
## Summary
|
||||
## Reporting and/or fixing bugs
|
||||
For simple bugfixes (typos, missing error handling, fixing a warning) is fine to send a Pull request directly. However, for more complex bugs it's better to open an issue first. In the issue, you should describe how to reproduce the bug and even add the minimal code snippet.
|
||||
|
||||
I hope you have taken a liking to contribute to LittelvGL. A helpful and friendly community is waiting for you! :)
|
||||
## Suggesting and/or implementing new features
|
||||
If you have a good idea don't hesitate to share with us. It's even better if you have time to deal with its implementation. Don't be afraid if you still don't know LittlevGL well enough. We will help you to get started.
|
||||
|
||||
During the implementation don't forget the [Code style guide](https://github.com/littlevgl/lvgl/blob/master/docs/CODING_STYLE.md).
|
||||
|
||||
# Summary
|
||||
|
||||
I hope you have taken a liking to contribute to LittlevGL. A helpful and friendly community is waiting for you! :)
|
||||
|
||||
14
library.json
Normal file
14
library.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "lvgl",
|
||||
"version": "v6.1.2",
|
||||
"keywords": "graphics, gui, embedded, littlevgl",
|
||||
"description": "Graphics library to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint. It offers anti-aliasing, opacity, and animations using only one frame buffer.",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/littlevgl/lvgl.git"
|
||||
},
|
||||
"build": {
|
||||
"includeDir": "."
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,9 @@
|
||||
/*Images pixels with this color will not be drawn (with chroma keying)*/
|
||||
#define LV_COLOR_TRANSP LV_COLOR_LIME /*LV_COLOR_LIME: pure green*/
|
||||
|
||||
/* Enable chroma keying for indexed images. */
|
||||
#define LV_INDEXED_CHROMA 1
|
||||
|
||||
/* Enable anti-aliasing (lines, and radiuses will be smoothed) */
|
||||
#define LV_ANTIALIAS 1
|
||||
|
||||
@@ -152,7 +155,7 @@ typedef void * lv_fs_drv_user_data_t;
|
||||
#endif
|
||||
|
||||
/*1: Add a `user_data` to drivers and objects*/
|
||||
#define LV_USE_USER_DATA 1
|
||||
#define LV_USE_USER_DATA 0
|
||||
|
||||
/*========================
|
||||
* Image decoder and cache
|
||||
@@ -193,6 +196,14 @@ typedef void * lv_img_decoder_user_data_t;
|
||||
* font's bitmaps */
|
||||
#define LV_ATTRIBUTE_LARGE_CONST
|
||||
|
||||
/* Export integer constant to binding.
|
||||
* This macro is used with constants in the form of LV_<CONST> that
|
||||
* should also appear on lvgl binding API such as Micropython
|
||||
*
|
||||
* The default value just prevents a GCC warning.
|
||||
*/
|
||||
#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning
|
||||
|
||||
/*===================
|
||||
* HAL settings
|
||||
*==================*/
|
||||
@@ -213,21 +224,58 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the i
|
||||
*===============*/
|
||||
|
||||
/*1: Enable the log module*/
|
||||
#define LV_USE_LOG 1
|
||||
#define LV_USE_LOG 0
|
||||
#if LV_USE_LOG
|
||||
/* How important log should be added:
|
||||
* LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
|
||||
* LV_LOG_LEVEL_INFO Log important events
|
||||
* LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem
|
||||
* LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
|
||||
* LV_LOG_LEVEL_NONE Do not log anything
|
||||
*/
|
||||
# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN
|
||||
|
||||
/* 1: Print the log with 'printf';
|
||||
* 0: user need to register a callback with `lv_log_register_print`*/
|
||||
* 0: user need to register a callback with `lv_log_register_print_cb`*/
|
||||
# define LV_LOG_PRINTF 0
|
||||
#endif /*LV_USE_LOG*/
|
||||
|
||||
/*=================
|
||||
* Debug settings
|
||||
*================*/
|
||||
|
||||
/* If Debug is enabled LittelvGL validates the parameters of the functions.
|
||||
* If an invalid parameter is found an error log message is printed and
|
||||
* the MCU halts at the error. (`LV_USE_LOG` should be enabled)
|
||||
* If you are debugging the MCU you can pause
|
||||
* the debugger to see exactly where the issue is.
|
||||
*
|
||||
* The behavior of asserts can be overwritten by redefining them here.
|
||||
* E.g. #define LV_ASSERT_MEM(p) <my_assert_code>
|
||||
*/
|
||||
#define LV_USE_DEBUG 1
|
||||
#if LV_USE_DEBUG
|
||||
|
||||
/*Check if the parameter is NULL. (Quite fast) */
|
||||
#define LV_USE_ASSERT_NULL 1
|
||||
|
||||
/*Checks is the memory is successfully allocated or no. (Quite fast)*/
|
||||
#define LV_USE_ASSERT_MEM 1
|
||||
|
||||
/* Check the strings.
|
||||
* Search for NULL, very long strings, invalid characters, and unnatural repetitions. (Slow)
|
||||
* If disabled `LV_USE_ASSERT_NULL` will be performed instead (if it's enabled) */
|
||||
#define LV_USE_ASSERT_STR 0
|
||||
|
||||
/* Check NULL, the object's type and existence (e.g. not deleted). (Quite slow)
|
||||
* If disabled `LV_USE_ASSERT_NULL` will be performed instead (if it's enabled) */
|
||||
#define LV_USE_ASSERT_OBJ 0
|
||||
|
||||
/*Check if the styles are properly initialized. (Fast)*/
|
||||
#define LV_USE_ASSERT_STYLE 1
|
||||
|
||||
#endif /*LV_USE_DEBUG*/
|
||||
|
||||
/*================
|
||||
* THEME USAGE
|
||||
*================*/
|
||||
@@ -259,6 +307,10 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the i
|
||||
#define LV_FONT_ROBOTO_22 0
|
||||
#define LV_FONT_ROBOTO_28 0
|
||||
|
||||
/* Demonstrate special features */
|
||||
#define LV_FONT_ROBOTO_12_SUBPX 1
|
||||
#define LV_FONT_ROBOTO_28_COMPRESSED 1 /*bpp = 3*/
|
||||
|
||||
/*Pixel perfect monospace font
|
||||
* http://pelulamu.net/unscii/ */
|
||||
#define LV_FONT_UNSCII_8 0
|
||||
@@ -274,6 +326,17 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the i
|
||||
/*Always set a default font from the built-in fonts*/
|
||||
#define LV_FONT_DEFAULT &lv_font_roboto_16
|
||||
|
||||
/* Enable it if you have fonts with a lot of characters.
|
||||
* The limit depends on the font size, font face and bpp
|
||||
* but with > 10,000 characters if you see issues probably you need to enable it.*/
|
||||
#define LV_FONT_FMT_TXT_LARGE 0
|
||||
|
||||
/* Set the pixel order of the display.
|
||||
* Important only if "subpx fonts" are used.
|
||||
* With "normal" font it doesn't matter.
|
||||
*/
|
||||
#define LV_FONT_SUBPX_BGR 0
|
||||
|
||||
/*Declare the type of the user data of fonts (can be e.g. `void *`, `int`, `struct`)*/
|
||||
typedef void * lv_font_user_data_t;
|
||||
|
||||
@@ -291,6 +354,42 @@ typedef void * lv_font_user_data_t;
|
||||
/*Can break (wrap) texts on these chars*/
|
||||
#define LV_TXT_BREAK_CHARS " ,.;:-_"
|
||||
|
||||
/* If a word is at least this long, will break wherever "prettiest"
|
||||
* To disable, set to a value <= 0 */
|
||||
#define LV_TXT_LINE_BREAK_LONG_LEN 12
|
||||
|
||||
/* Minimum number of characters in a long word to put on a line before a break.
|
||||
* Depends on LV_TXT_LINE_BREAK_LONG_LEN. */
|
||||
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3
|
||||
|
||||
/* Minimum number of characters in a long word to put on a line after a break.
|
||||
* Depends on LV_TXT_LINE_BREAK_LONG_LEN. */
|
||||
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3
|
||||
|
||||
/* The control character to use for signalling text recoloring. */
|
||||
#define LV_TXT_COLOR_CMD "#"
|
||||
|
||||
/* Support bidirectional texts.
|
||||
* Allows mixing Left-to-Right and Right-to-Left texts.
|
||||
* The direction will be processed according to the Unicode Bidirectioanl Algorithm:
|
||||
* https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/
|
||||
#define LV_USE_BIDI 0
|
||||
#if LV_USE_BIDI
|
||||
/* Set the default direction. Supported values:
|
||||
* `LV_BIDI_DIR_LTR` Left-to-Right
|
||||
* `LV_BIDI_DIR_RTL` Right-to-Left
|
||||
* `LV_BIDI_DIR_AUTO` detect texts base direction */
|
||||
#define LV_BIDI_BASE_DIR_DEF LV_BIDI_DIR_AUTO
|
||||
#endif
|
||||
|
||||
/*Change the built in (v)snprintf functions*/
|
||||
#define LV_SPRINTF_CUSTOM 0
|
||||
#if LV_SPRINTF_CUSTOM
|
||||
# define LV_SPRINTF_INCLUDE <stdio.h>
|
||||
# define lv_snprintf snprintf
|
||||
# define lv_vsnprintf vsnprintf
|
||||
#endif /*LV_SPRINTF_CUSTOM*/
|
||||
|
||||
/*===================
|
||||
* LV_OBJ SETTINGS
|
||||
*==================*/
|
||||
@@ -325,7 +424,7 @@ typedef void * lv_obj_user_data_t;
|
||||
#define LV_USE_BTN 1
|
||||
#if LV_USE_BTN != 0
|
||||
/*Enable button-state animations - draw a circle on click (dependencies: LV_USE_ANIMATION)*/
|
||||
# define LV_BTN_INK_EFFECT 1
|
||||
# define LV_BTN_INK_EFFECT 0
|
||||
#endif
|
||||
|
||||
/*Button matrix (dependencies: -)*/
|
||||
@@ -349,6 +448,9 @@ typedef void * lv_obj_user_data_t;
|
||||
/*Container (dependencies: -*/
|
||||
#define LV_USE_CONT 1
|
||||
|
||||
/*Color picker (dependencies: -*/
|
||||
#define LV_USE_CPICKER 1
|
||||
|
||||
/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/
|
||||
#define LV_USE_DDLIST 1
|
||||
#if LV_USE_DDLIST != 0
|
||||
|
||||
6
lvgl.h
6
lvgl.h
@@ -19,19 +19,24 @@ extern "C" {
|
||||
#include "src/lv_misc/lv_log.h"
|
||||
#include "src/lv_misc/lv_task.h"
|
||||
#include "src/lv_misc/lv_math.h"
|
||||
#include "src/lv_misc/lv_async.h"
|
||||
|
||||
#include "src/lv_hal/lv_hal.h"
|
||||
|
||||
#include "src/lv_core/lv_obj.h"
|
||||
#include "src/lv_core/lv_group.h"
|
||||
#include "src/lv_core/lv_indev.h"
|
||||
|
||||
#include "src/lv_core/lv_refr.h"
|
||||
#include "src/lv_core/lv_disp.h"
|
||||
#include "src/lv_core/lv_debug.h"
|
||||
|
||||
#include "src/lv_themes/lv_theme.h"
|
||||
|
||||
#include "src/lv_font/lv_font.h"
|
||||
#include "src/lv_font/lv_font_fmt_txt.h"
|
||||
#include "src/lv_misc/lv_bidi.h"
|
||||
#include "src/lv_misc/lv_printf.h"
|
||||
|
||||
#include "src/lv_objx/lv_btn.h"
|
||||
#include "src/lv_objx/lv_imgbtn.h"
|
||||
@@ -44,6 +49,7 @@ extern "C" {
|
||||
#include "src/lv_objx/lv_chart.h"
|
||||
#include "src/lv_objx/lv_table.h"
|
||||
#include "src/lv_objx/lv_cb.h"
|
||||
#include "src/lv_objx/lv_cpicker.h"
|
||||
#include "src/lv_objx/lv_bar.h"
|
||||
#include "src/lv_objx/lv_slider.h"
|
||||
#include "src/lv_objx/lv_led.h"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_port_disp_templ.h"
|
||||
#include "lv_port_disp_template.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -26,8 +26,9 @@ static void disp_init(void);
|
||||
|
||||
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||
#if LV_USE_GPU
|
||||
static void gpu_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);
|
||||
static void gpu_fill(lv_color_t * dest, uint32_t length, lv_color_t color);
|
||||
static void gpu_blend(lv_disp_drv_t * disp_drv, lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);
|
||||
static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
|
||||
const lv_area_t * fill_area, lv_color_t color);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
@@ -112,10 +113,10 @@ void lv_port_disp_init(void)
|
||||
/*Optionally add functions to access the GPU. (Only in buffered mode, LV_VDB_SIZE != 0)*/
|
||||
|
||||
/*Blend two color array using opacity*/
|
||||
disp_drv.gpu_blend = gpu_blend;
|
||||
disp_drv.gpu_blend_cb = gpu_blend;
|
||||
|
||||
/*Fill a memory array with a color*/
|
||||
disp_drv.gpu_fill = gpu_fill;
|
||||
disp_drv.gpu_fill_cb = gpu_fill;
|
||||
#endif
|
||||
|
||||
/*Finally register the driver*/
|
||||
@@ -151,7 +152,7 @@ static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_colo
|
||||
|
||||
/* IMPORTANT!!!
|
||||
* Inform the graphics library that you are ready with the flushing*/
|
||||
lv_disp_flush_ready(disp);
|
||||
lv_disp_flush_ready(disp_drv);
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +164,6 @@ static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_colo
|
||||
static void gpu_blend(lv_disp_drv_t * disp_drv, lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa)
|
||||
{
|
||||
/*It's an example code which should be done by your GPU*/
|
||||
|
||||
uint32_t i;
|
||||
for(i = 0; i < length; i++) {
|
||||
dest[i] = lv_color_mix(dest[i], src[i], opa);
|
||||
@@ -172,11 +172,11 @@ static void gpu_blend(lv_disp_drv_t * disp_drv, lv_color_t * dest, const lv_colo
|
||||
|
||||
/* If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color
|
||||
* It can be used only in buffered mode (LV_VDB_SIZE != 0 in lv_conf.h)*/
|
||||
static void gpu_fill_cb(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
|
||||
const lv_area_t * fill_area, lv_color_t color);
|
||||
static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
|
||||
const lv_area_t * fill_area, lv_color_t color)
|
||||
{
|
||||
/*It's an example code which should be done by your GPU*/
|
||||
uint32_t x, y;
|
||||
int32_t x, y;
|
||||
dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
|
||||
|
||||
for(y = fill_area->y1; y < fill_area->y2; y++) {
|
||||
@@ -185,12 +185,6 @@ static void gpu_fill_cb(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coor
|
||||
}
|
||||
dest_buf+=dest_width; /*Go to the next line*/
|
||||
}
|
||||
|
||||
|
||||
uint32_t i;
|
||||
for(i = 0; i < length; i++) {
|
||||
dest[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GPU*/
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_port_fs_templ.h"
|
||||
#include "lv_port_fs_template.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -42,20 +42,20 @@ typedef struct {
|
||||
**********************/
|
||||
static void fs_init(void);
|
||||
|
||||
static lv_fs_res_t fs_open (void * file_p, const char * path, lv_fs_mode_t mode);
|
||||
static lv_fs_res_t fs_close (void * file_p);
|
||||
static lv_fs_res_t fs_read (void * file_p, void * buf, uint32_t btr, uint32_t * br);
|
||||
static lv_fs_res_t fs_write(void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
|
||||
static lv_fs_res_t fs_seek (void * file_p, uint32_t pos);
|
||||
static lv_fs_res_t fs_size (void * file_p, uint32_t * size_p);
|
||||
static lv_fs_res_t fs_tell (void * file_p, uint32_t * pos_p);
|
||||
static lv_fs_res_t fs_remove (const char *path);
|
||||
static lv_fs_res_t fs_trunc (void * file_p);
|
||||
static lv_fs_res_t fs_rename (const char * oldname, const char * newname);
|
||||
static lv_fs_res_t fs_free (uint32_t * total_p, uint32_t * free_p);
|
||||
static lv_fs_res_t fs_dir_open (void * rddir_p, const char *path);
|
||||
static lv_fs_res_t fs_dir_read (void * rddir_p, char *fn);
|
||||
static lv_fs_res_t fs_dir_close (void * rddir_p);
|
||||
static lv_fs_res_t fs_open (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode);
|
||||
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p);
|
||||
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
|
||||
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
|
||||
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos);
|
||||
static lv_fs_res_t fs_size (lv_fs_drv_t * drv, void * file_p, uint32_t * size_p);
|
||||
static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
|
||||
static lv_fs_res_t fs_remove (lv_fs_drv_t * drv, const char *path);
|
||||
static lv_fs_res_t fs_trunc (lv_fs_drv_t * drv, void * file_p);
|
||||
static lv_fs_res_t fs_rename (lv_fs_drv_t * drv, const char * oldname, const char * newname);
|
||||
static lv_fs_res_t fs_free (lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p);
|
||||
static lv_fs_res_t fs_dir_open (lv_fs_drv_t * drv, void * rddir_p, const char *path);
|
||||
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * rddir_p, char *fn);
|
||||
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * rddir_p);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -85,30 +85,30 @@ void lv_port_fs_init(void)
|
||||
*--------------------------------------------------*/
|
||||
|
||||
/* Add a simple drive to open images */
|
||||
lv_fs_drv_t fs_drv; /*A driver descriptor*/
|
||||
memset(&fs_drv, 0, sizeof(lv_fs_drv_t)); /*Initialization*/
|
||||
lv_fs_drv_t fs_drv;
|
||||
lv_fs_drv_init(&fs_drv);
|
||||
|
||||
/*Set up fields...*/
|
||||
fs_drv.file_size = sizeof(file_t);
|
||||
fs_drv.letter = 'P';
|
||||
fs_drv.open = fs_open;
|
||||
fs_drv.close = fs_close;
|
||||
fs_drv.read = fs_read;
|
||||
fs_drv.write = fs_write;
|
||||
fs_drv.seek = fs_seek;
|
||||
fs_drv.tell = fs_tell;
|
||||
fs_drv.free = fs_free;
|
||||
fs_drv.size = fs_size;
|
||||
fs_drv.remove = fs_remove;
|
||||
fs_drv.rename = fs_rename;
|
||||
fs_drv.trunc = fs_trunc;
|
||||
fs_drv.open_cb = fs_open;
|
||||
fs_drv.close_cb = fs_close;
|
||||
fs_drv.read_cb = fs_read;
|
||||
fs_drv.write_cb = fs_write;
|
||||
fs_drv.seek_cb = fs_seek;
|
||||
fs_drv.tell_cb = fs_tell;
|
||||
fs_drv.free_space_cb = fs_free;
|
||||
fs_drv.size_cb = fs_size;
|
||||
fs_drv.remove_cb = fs_remove;
|
||||
fs_drv.rename_cb = fs_rename;
|
||||
fs_drv.trunc_cb = fs_trunc;
|
||||
|
||||
fs_drv.rddir_size = sizeof(dir_t);
|
||||
fs_drv.dir_close = fs_dir_close;
|
||||
fs_drv.dir_open = fs_dir_open;
|
||||
fs_drv.dir_read = fs_dir_read;
|
||||
fs_drv.dir_close_cb = fs_dir_close;
|
||||
fs_drv.dir_open_cb = fs_dir_open;
|
||||
fs_drv.dir_read_cb = fs_dir_read;
|
||||
|
||||
lv_fs_add_drv(&fs_drv);
|
||||
lv_fs_drv_register(&fs_drv);
|
||||
}
|
||||
|
||||
/**********************
|
||||
@@ -125,12 +125,13 @@ static void fs_init(void)
|
||||
|
||||
/**
|
||||
* Open a file
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @param file_p pointer to a file_t variable
|
||||
* @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
|
||||
* @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
static lv_fs_res_t fs_open (void * file_p, const char * path, lv_fs_mode_t mode)
|
||||
static lv_fs_res_t fs_open (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -159,11 +160,12 @@ static lv_fs_res_t fs_open (void * file_p, const char * path, lv_fs_mode_t mode)
|
||||
|
||||
/**
|
||||
* Close an opened file
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open)
|
||||
* @return LV_FS_RES_OK: no error, the file is read
|
||||
* any error from lv_fs_res_t enum
|
||||
*/
|
||||
static lv_fs_res_t fs_close (void * file_p)
|
||||
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -174,6 +176,7 @@ static lv_fs_res_t fs_close (void * file_p)
|
||||
|
||||
/**
|
||||
* Read data from an opened file
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @param file_p pointer to a file_t variable.
|
||||
* @param buf pointer to a memory block where to store the read data
|
||||
* @param btr number of Bytes To Read
|
||||
@@ -181,7 +184,7 @@ static lv_fs_res_t fs_close (void * file_p)
|
||||
* @return LV_FS_RES_OK: no error, the file is read
|
||||
* any error from lv_fs_res_t enum
|
||||
*/
|
||||
static lv_fs_res_t fs_read (void * file_p, void * buf, uint32_t btr, uint32_t * br)
|
||||
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -192,13 +195,14 @@ static lv_fs_res_t fs_read (void * file_p, void * buf, uint32_t btr, uint32_t *
|
||||
|
||||
/**
|
||||
* Write into a file
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @param file_p pointer to a file_t variable
|
||||
* @param buf pointer to a buffer with the bytes to write
|
||||
* @param btr Bytes To Write
|
||||
* @param br the number of real written bytes (Bytes Written). NULL if unused.
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
static lv_fs_res_t fs_write(void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
|
||||
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -209,12 +213,13 @@ static lv_fs_res_t fs_write(void * file_p, const void * buf, uint32_t btw, uint3
|
||||
|
||||
/**
|
||||
* Set the read write pointer. Also expand the file size if necessary.
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open )
|
||||
* @param pos the new position of read write pointer
|
||||
* @return LV_FS_RES_OK: no error, the file is read
|
||||
* any error from lv_fs_res_t enum
|
||||
*/
|
||||
static lv_fs_res_t fs_seek (void * file_p, uint32_t pos)
|
||||
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -225,11 +230,12 @@ static lv_fs_res_t fs_seek (void * file_p, uint32_t pos)
|
||||
|
||||
/**
|
||||
* Give the size of a file bytes
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @param file_p pointer to a 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
|
||||
*/
|
||||
static lv_fs_res_t fs_size (void * file_p, uint32_t * size_p)
|
||||
static lv_fs_res_t fs_size (lv_fs_drv_t * drv, void * file_p, uint32_t * size_p)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -239,12 +245,13 @@ static lv_fs_res_t fs_size (void * file_p, uint32_t * size_p)
|
||||
}
|
||||
/**
|
||||
* Give the position of the read write pointer
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @param file_p pointer to a file_t variable.
|
||||
* @param pos_p pointer to to store the result
|
||||
* @return LV_FS_RES_OK: no error, the file is read
|
||||
* any error from lv_fs_res_t enum
|
||||
*/
|
||||
static lv_fs_res_t fs_tell (void * file_p, uint32_t * pos_p)
|
||||
static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -255,10 +262,11 @@ static lv_fs_res_t fs_tell (void * file_p, uint32_t * pos_p)
|
||||
|
||||
/**
|
||||
* Delete a file
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @param path path of the file to delete
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
static lv_fs_res_t fs_remove (const char *path)
|
||||
static lv_fs_res_t fs_remove (lv_fs_drv_t * drv, const char *path)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -269,11 +277,12 @@ static lv_fs_res_t fs_remove (const char *path)
|
||||
|
||||
/**
|
||||
* Truncate the file size to the current position of the read write pointer
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @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
|
||||
*/
|
||||
static lv_fs_res_t fs_trunc (void * file_p)
|
||||
static lv_fs_res_t fs_trunc (lv_fs_drv_t * drv, void * file_p)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -284,11 +293,12 @@ static lv_fs_res_t fs_trunc (void * file_p)
|
||||
|
||||
/**
|
||||
* Rename a file
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @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'
|
||||
*/
|
||||
static lv_fs_res_t fs_rename (const char * oldname, const char * newname)
|
||||
static lv_fs_res_t fs_rename (lv_fs_drv_t * drv, const char * oldname, const char * newname)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -299,12 +309,13 @@ static lv_fs_res_t fs_rename (const char * oldname, const char * newname)
|
||||
|
||||
/**
|
||||
* Get the free and total size of a driver in kB
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @param letter the driver letter
|
||||
* @param total_p pointer to store the total size [kB]
|
||||
* @param free_p pointer to store the free size [kB]
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
static lv_fs_res_t fs_free (uint32_t * total_p, uint32_t * free_p)
|
||||
static lv_fs_res_t fs_free (lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -315,11 +326,12 @@ static lv_fs_res_t fs_free (uint32_t * total_p, uint32_t * free_p)
|
||||
|
||||
/**
|
||||
* Initialize a 'fs_read_dir_t' variable for directory reading
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @param rddir_p pointer to a 'fs_read_dir_t' variable
|
||||
* @param path path to a directory
|
||||
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
|
||||
*/
|
||||
static lv_fs_res_t fs_dir_open (void * rddir_p, const char *path)
|
||||
static lv_fs_res_t fs_dir_open (lv_fs_drv_t * drv, void * rddir_p, const char *path)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -331,11 +343,12 @@ static lv_fs_res_t fs_dir_open (void * rddir_p, const char *path)
|
||||
/**
|
||||
* Read the next filename form a directory.
|
||||
* The name of the directories will begin with '/'
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @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
|
||||
*/
|
||||
static lv_fs_res_t fs_dir_read (void * rddir_p, char *fn)
|
||||
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * rddir_p, char *fn)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
@@ -346,10 +359,11 @@ static lv_fs_res_t fs_dir_read (void * rddir_p, char *fn)
|
||||
|
||||
/**
|
||||
* Close the directory reading
|
||||
* @param drv pointer to a driver where this function belongs
|
||||
* @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
|
||||
*/
|
||||
static lv_fs_res_t fs_dir_close (void * rddir_p)
|
||||
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * rddir_p)
|
||||
{
|
||||
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_port_indev_templ.h"
|
||||
#include "lv_port_indev_template.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
|
||||
@@ -724,7 +724,7 @@ CITE_BIB_FILES =
|
||||
# messages are off.
|
||||
# The default value is: NO.
|
||||
|
||||
QUIET = NO
|
||||
QUIET = YES
|
||||
|
||||
# The WARNINGS tag can be used to turn on/off the warning messages that are
|
||||
# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
|
||||
@@ -733,14 +733,14 @@ QUIET = NO
|
||||
# Tip: Turn warnings on while writing the documentation.
|
||||
# The default value is: YES.
|
||||
|
||||
WARNINGS = YES
|
||||
WARNINGS = NO
|
||||
|
||||
# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
|
||||
# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
|
||||
# will automatically be disabled.
|
||||
# The default value is: YES.
|
||||
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
|
||||
# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
|
||||
# potential errors in the documentation, such as not documenting some parameters
|
||||
@@ -748,7 +748,7 @@ WARN_IF_UNDOCUMENTED = YES
|
||||
# markup commands wrongly.
|
||||
# The default value is: YES.
|
||||
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_IF_DOC_ERROR = NO
|
||||
|
||||
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
|
||||
# are documented, but have no documentation for their parameters or return
|
||||
|
||||
Binary file not shown.
BIN
scripts/built_in_font/FontAwesome5-Solid+Brands+Regular.woff
Normal file
BIN
scripts/built_in_font/FontAwesome5-Solid+Brands+Regular.woff
Normal file
Binary file not shown.
@@ -40,8 +40,8 @@ else:
|
||||
compr = ""
|
||||
|
||||
#Built in symbols
|
||||
syms = "61441,61448,61451,61452,61453,61457,61459,61460,61461,61465,61468,61473,61478,61479,61480,61502,61504,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61671,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62099"
|
||||
syms = "61441,61448,61451,61452,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650"
|
||||
|
||||
#Run the command
|
||||
cmd = "lv_font_conv {} --bpp {} --size {} --font ./Roboto-Regular.woff -r {} --font FontAwesome.ttf -r {} --format lvgl -o {} --force-fast-kern-format".format(compr, args.bpp, args.size, args.range[0], syms, args.output)
|
||||
cmd = "lv_font_conv {} --bpp {} --size {} --font Roboto-Regular.woff -r {} --font FontAwesome5-Solid+Brands+Regular.woff -r {} --format lvgl -o {} --force-fast-kern-format".format(compr, args.bpp, args.size, args.range[0], syms, args.output)
|
||||
os.system(cmd)
|
||||
|
||||
6
scripts/lv_conf_checker.py
Normal file → Executable file
6
scripts/lv_conf_checker.py
Normal file → Executable file
@@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env python3.6
|
||||
|
||||
'''
|
||||
Generates a checker file for lv_conf.h from lv_conf_templ.h define all the not defined values
|
||||
'''
|
||||
@@ -34,9 +36,11 @@ for i in fin.read().splitlines():
|
||||
if '/*--END OF LV_CONF_H--*/' in i: break
|
||||
|
||||
r = re.search(r'^ *# *define ([^\s]+).*$', i)
|
||||
|
||||
if r:
|
||||
line = re.sub('\(.*?\)', '', r[1], 1) #remove parentheses from macros
|
||||
fout.write(
|
||||
f'#ifndef {r[1]}\n'
|
||||
f'#ifndef {line}\n'
|
||||
f'{i}\n'
|
||||
'#endif\n'
|
||||
)
|
||||
|
||||
189
scripts/release_patch.py
Normal file
189
scripts/release_patch.py
Normal file
@@ -0,0 +1,189 @@
|
||||
import re
|
||||
import os
|
||||
lastNum = re.compile(r'(?:[^\d]*(\d+)[^\d]*)+')
|
||||
|
||||
|
||||
def title(t):
|
||||
print("\n---------------------------------")
|
||||
print(t)
|
||||
print("---------------------------------")
|
||||
|
||||
|
||||
def cmd(c):
|
||||
print("\n" + c)
|
||||
os.system(c)
|
||||
|
||||
|
||||
def increment(s):
|
||||
""" look for the last sequence of number(s) in a string and increment """
|
||||
m = lastNum.search(s)
|
||||
if m:
|
||||
next = str(int(m.group(1))+1)
|
||||
start, end = m.span(1)
|
||||
s = s[:max(end-len(next), start)] + next + s[end:]
|
||||
return s, str(next)
|
||||
|
||||
|
||||
def lvgl_clone():
|
||||
title("lvgl: Clone")
|
||||
cmd("git clone https://github.com/littlevgl/lvgl.git")
|
||||
os.chdir("./lvgl")
|
||||
cmd("git co master")
|
||||
|
||||
def lvgl_update_version():
|
||||
title("lvgl: Update version number")
|
||||
|
||||
f = open("./src/lv_version.h", "r")
|
||||
|
||||
outbuf = ""
|
||||
major_ver = -1
|
||||
minor_ver = -1
|
||||
patch_ver = -1
|
||||
|
||||
for i in f.read().splitlines():
|
||||
r = re.search(r'^#define LVGL_VERSION_MAJOR ', i)
|
||||
if r:
|
||||
m = lastNum.search(i)
|
||||
if m: major_ver = m.group(1)
|
||||
|
||||
r = re.search(r'^#define LVGL_VERSION_MINOR ', i)
|
||||
if r:
|
||||
m = lastNum.search(i)
|
||||
if m: minor_ver = m.group(1)
|
||||
|
||||
r = re.search(r'^#define LVGL_VERSION_PATCH ', i)
|
||||
if r:
|
||||
i, patch_ver = increment(i)
|
||||
|
||||
|
||||
r = re.search(r'^#define LVGL_VERSION_INFO ', i)
|
||||
if r:
|
||||
i = "#define LVGL_VERSION_INFO \"\""
|
||||
|
||||
outbuf += i + '\n'
|
||||
|
||||
f.close()
|
||||
|
||||
f = open("./src/lv_version", "w")
|
||||
|
||||
f.write(outbuf)
|
||||
f.close()
|
||||
|
||||
s = "v" + str(major_ver) + "." + str(minor_ver) + "." + str(patch_ver)
|
||||
print("New version:" + s)
|
||||
return s
|
||||
|
||||
|
||||
|
||||
def lvgl_update_library_json(v):
|
||||
title("lvgl: Update version number in library.json")
|
||||
|
||||
f = open("./library.json", "r")
|
||||
|
||||
outbuf = ""
|
||||
|
||||
for i in f.read().splitlines():
|
||||
r = re.search(r'"version": ', i)
|
||||
if r:
|
||||
i = ' "version": "' + v + '",'
|
||||
|
||||
outbuf += i + '\n'
|
||||
|
||||
f.close()
|
||||
|
||||
f = open("./library.json", "w")
|
||||
|
||||
f.write(outbuf)
|
||||
f.close()
|
||||
|
||||
def lvgl_commit_push(v):
|
||||
title("lvgl: commit and push release")
|
||||
|
||||
cmd('git ci -am "Release ' + v + '"')
|
||||
cmd('git tag -a ' + v + ' -m "Release ' + v +'"')
|
||||
cmd('git push origin master')
|
||||
cmd('git push origin ' + v)
|
||||
|
||||
def lvgl_update_api_docs():
|
||||
title("lvgl: Update API with Doxygen")
|
||||
|
||||
cmd("cd scripts; doxygen");
|
||||
|
||||
|
||||
def docs_clone():
|
||||
title("docs: Clone")
|
||||
os.chdir("../")
|
||||
cmd("git clone --recursive https://github.com/littlevgl/docs.git")
|
||||
os.chdir("./docs")
|
||||
cmd("git co master")
|
||||
|
||||
def docs_get_api():
|
||||
title("docs: Get API files")
|
||||
|
||||
cmd("rm -rf xml");
|
||||
cmd("cp -r ../lvgl/docs/api_doc/xml .");
|
||||
|
||||
|
||||
def docs_update_version(v):
|
||||
title("docs: Update version number")
|
||||
|
||||
f = open("./conf.py", "r")
|
||||
|
||||
outbuf = ""
|
||||
|
||||
for i in f.read().splitlines():
|
||||
r = re.search(r'^version = ', i)
|
||||
if r:
|
||||
i = "version = '" + v + "'"
|
||||
|
||||
r = re.search(r'^release = ', i)
|
||||
if r:
|
||||
i = "version = '" + v + "'"
|
||||
|
||||
outbuf += i + '\n'
|
||||
|
||||
f.close()
|
||||
|
||||
f = open("./conf.py", "w")
|
||||
|
||||
f.write(outbuf)
|
||||
f.close()
|
||||
|
||||
def docs_update_trans():
|
||||
title("docs: Update translations")
|
||||
cmd("cd en && ./trans_push.py && ./trans_pull.py")
|
||||
|
||||
def docs_build():
|
||||
title("docs: Build")
|
||||
cmd("./build.py clean")
|
||||
|
||||
|
||||
def docs_commit_push(v):
|
||||
title("docs: Commit release")
|
||||
|
||||
cmd('git add .')
|
||||
cmd('git ci -am "Release ' + v + '"')
|
||||
cmd('git tag -a ' + v + ' -m "Release ' + v +'"')
|
||||
cmd('git push origin master')
|
||||
cmd('git push origin ' + v)
|
||||
|
||||
def clean_up():
|
||||
title("Clean up repos")
|
||||
os.chdir("..")
|
||||
cmd("rm -rf lvgl docs")
|
||||
|
||||
lvgl_clone()
|
||||
lvgl_update_api_docs()
|
||||
ver_str = lvgl_update_version()
|
||||
lvgl_update_library_json(ver_str)
|
||||
lvgl_commit_push(ver_str)
|
||||
|
||||
docs_clone()
|
||||
docs_get_api()
|
||||
docs_update_version(ver_str)
|
||||
docs_update_trans()
|
||||
docs_build()
|
||||
docs_commit_push(ver_str)
|
||||
|
||||
clean_up()
|
||||
|
||||
@@ -50,6 +50,11 @@
|
||||
#define LV_COLOR_TRANSP LV_COLOR_LIME /*LV_COLOR_LIME: pure green*/
|
||||
#endif
|
||||
|
||||
/* Enable chroma keying for indexed images. */
|
||||
#ifndef LV_INDEXED_CHROMA
|
||||
#define LV_INDEXED_CHROMA 1
|
||||
#endif
|
||||
|
||||
/* Enable anti-aliasing (lines, and radiuses will be smoothed) */
|
||||
#ifndef LV_ANTIALIAS
|
||||
#define LV_ANTIALIAS 1
|
||||
@@ -206,7 +211,7 @@
|
||||
|
||||
/*1: Add a `user_data` to drivers and objects*/
|
||||
#ifndef LV_USE_USER_DATA
|
||||
#define LV_USE_USER_DATA 1
|
||||
#define LV_USE_USER_DATA 0
|
||||
#endif
|
||||
|
||||
/*========================
|
||||
@@ -261,6 +266,16 @@
|
||||
#define LV_ATTRIBUTE_LARGE_CONST
|
||||
#endif
|
||||
|
||||
/* Export integer constant to binding.
|
||||
* This macro is used with constants in the form of LV_<CONST> that
|
||||
* should also appear on lvgl binding API such as Micropython
|
||||
*
|
||||
* The default value just prevents a GCC warning.
|
||||
*/
|
||||
#ifndef LV_EXPORT_CONST_INT
|
||||
#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning
|
||||
#endif
|
||||
|
||||
/*===================
|
||||
* HAL settings
|
||||
*==================*/
|
||||
@@ -286,7 +301,7 @@
|
||||
|
||||
/*1: Enable the log module*/
|
||||
#ifndef LV_USE_LOG
|
||||
#define LV_USE_LOG 1
|
||||
#define LV_USE_LOG 0
|
||||
#endif
|
||||
#if LV_USE_LOG
|
||||
/* How important log should be added:
|
||||
@@ -294,18 +309,67 @@
|
||||
* LV_LOG_LEVEL_INFO Log important events
|
||||
* LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem
|
||||
* LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
|
||||
* LV_LOG_LEVEL_NONE Do not log anything
|
||||
*/
|
||||
#ifndef LV_LOG_LEVEL
|
||||
# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN
|
||||
#endif
|
||||
|
||||
/* 1: Print the log with 'printf';
|
||||
* 0: user need to register a callback with `lv_log_register_print`*/
|
||||
* 0: user need to register a callback with `lv_log_register_print_cb`*/
|
||||
#ifndef LV_LOG_PRINTF
|
||||
# define LV_LOG_PRINTF 0
|
||||
#endif
|
||||
#endif /*LV_USE_LOG*/
|
||||
|
||||
/*=================
|
||||
* Debug settings
|
||||
*================*/
|
||||
|
||||
/* If Debug is enabled LittelvGL validates the parameters of the functions.
|
||||
* If an invalid parameter is found an error log message is printed and
|
||||
* the MCU halts at the error. (`LV_USE_LOG` should be enabled)
|
||||
* If you are debugging the MCU you can pause
|
||||
* the debugger to see exactly where the issue is.
|
||||
*
|
||||
* The behavior of asserts can be overwritten by redefining them here.
|
||||
* E.g. #define LV_ASSERT_MEM(p) <my_assert_code>
|
||||
*/
|
||||
#ifndef LV_USE_DEBUG
|
||||
#define LV_USE_DEBUG 1
|
||||
#endif
|
||||
#if LV_USE_DEBUG
|
||||
|
||||
/*Check if the parameter is NULL. (Quite fast) */
|
||||
#ifndef LV_USE_ASSERT_NULL
|
||||
#define LV_USE_ASSERT_NULL 1
|
||||
#endif
|
||||
|
||||
/*Checks is the memory is successfully allocated or no. (Quite fast)*/
|
||||
#ifndef LV_USE_ASSERT_MEM
|
||||
#define LV_USE_ASSERT_MEM 1
|
||||
#endif
|
||||
|
||||
/* Check the strings.
|
||||
* Search for NULL, very long strings, invalid characters, and unnatural repetitions. (Slow)
|
||||
* If disabled `LV_USE_ASSERT_NULL` will be performed instead (if it's enabled) */
|
||||
#ifndef LV_USE_ASSERT_STR
|
||||
#define LV_USE_ASSERT_STR 0
|
||||
#endif
|
||||
|
||||
/* Check NULL, the object's type and existence (e.g. not deleted). (Quite slow)
|
||||
* If disabled `LV_USE_ASSERT_NULL` will be performed instead (if it's enabled) */
|
||||
#ifndef LV_USE_ASSERT_OBJ
|
||||
#define LV_USE_ASSERT_OBJ 0
|
||||
#endif
|
||||
|
||||
/*Check if the styles are properly initialized. (Fast)*/
|
||||
#ifndef LV_USE_ASSERT_STYLE
|
||||
#define LV_USE_ASSERT_STYLE 1
|
||||
#endif
|
||||
|
||||
#endif /*LV_USE_DEBUG*/
|
||||
|
||||
/*================
|
||||
* THEME USAGE
|
||||
*================*/
|
||||
@@ -363,6 +427,14 @@
|
||||
#define LV_FONT_ROBOTO_28 0
|
||||
#endif
|
||||
|
||||
/* Demonstrate special features */
|
||||
#ifndef LV_FONT_ROBOTO_12_SUBPX
|
||||
#define LV_FONT_ROBOTO_12_SUBPX 1
|
||||
#endif
|
||||
#ifndef LV_FONT_ROBOTO_28_COMPRESSED
|
||||
#define LV_FONT_ROBOTO_28_COMPRESSED 1 /*bpp = 3*/
|
||||
#endif
|
||||
|
||||
/*Pixel perfect monospace font
|
||||
* http://pelulamu.net/unscii/ */
|
||||
#ifndef LV_FONT_UNSCII_8
|
||||
@@ -384,6 +456,21 @@
|
||||
#define LV_FONT_DEFAULT &lv_font_roboto_16
|
||||
#endif
|
||||
|
||||
/* Enable it if you have fonts with a lot of characters.
|
||||
* The limit depends on the font size, font face and bpp
|
||||
* but with > 10,000 characters if you see issues probably you need to enable it.*/
|
||||
#ifndef LV_FONT_FMT_TXT_LARGE
|
||||
#define LV_FONT_FMT_TXT_LARGE 0
|
||||
#endif
|
||||
|
||||
/* Set the pixel order of the display.
|
||||
* Important only if "subpx fonts" are used.
|
||||
* With "normal" font it doesn't matter.
|
||||
*/
|
||||
#ifndef LV_FONT_SUBPX_BGR
|
||||
#define LV_FONT_SUBPX_BGR 0
|
||||
#endif
|
||||
|
||||
/*Declare the type of the user data of fonts (can be e.g. `void *`, `int`, `struct`)*/
|
||||
|
||||
/*=================
|
||||
@@ -404,6 +491,62 @@
|
||||
#define LV_TXT_BREAK_CHARS " ,.;:-_"
|
||||
#endif
|
||||
|
||||
/* If a word is at least this long, will break wherever "prettiest"
|
||||
* To disable, set to a value <= 0 */
|
||||
#ifndef LV_TXT_LINE_BREAK_LONG_LEN
|
||||
#define LV_TXT_LINE_BREAK_LONG_LEN 12
|
||||
#endif
|
||||
|
||||
/* Minimum number of characters in a long word to put on a line before a break.
|
||||
* Depends on LV_TXT_LINE_BREAK_LONG_LEN. */
|
||||
#ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN
|
||||
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3
|
||||
#endif
|
||||
|
||||
/* Minimum number of characters in a long word to put on a line after a break.
|
||||
* Depends on LV_TXT_LINE_BREAK_LONG_LEN. */
|
||||
#ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN
|
||||
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3
|
||||
#endif
|
||||
|
||||
/* The control character to use for signalling text recoloring. */
|
||||
#ifndef LV_TXT_COLOR_CMD
|
||||
#define LV_TXT_COLOR_CMD "#"
|
||||
#endif
|
||||
|
||||
/* Support bidirectional texts.
|
||||
* Allows mixing Left-to-Right and Right-to-Left texts.
|
||||
* The direction will be processed according to the Unicode Bidirectioanl Algorithm:
|
||||
* https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/
|
||||
#ifndef LV_USE_BIDI
|
||||
#define LV_USE_BIDI 0
|
||||
#endif
|
||||
#if LV_USE_BIDI
|
||||
/* Set the default direction. Supported values:
|
||||
* `LV_BIDI_DIR_LTR` Left-to-Right
|
||||
* `LV_BIDI_DIR_RTL` Right-to-Left
|
||||
* `LV_BIDI_DIR_AUTO` detect texts base direction */
|
||||
#ifndef LV_BIDI_BASE_DIR_DEF
|
||||
#define LV_BIDI_BASE_DIR_DEF LV_BIDI_DIR_AUTO
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Change the built in (v)snprintf functions*/
|
||||
#ifndef LV_SPRINTF_CUSTOM
|
||||
#define LV_SPRINTF_CUSTOM 0
|
||||
#endif
|
||||
#if LV_SPRINTF_CUSTOM
|
||||
#ifndef LV_SPRINTF_INCLUDE
|
||||
# define LV_SPRINTF_INCLUDE <stdio.h>
|
||||
#endif
|
||||
#ifndef lv_snprintf
|
||||
# define lv_snprintf snprintf
|
||||
#endif
|
||||
#ifndef lv_vsnprintf
|
||||
# define lv_vsnprintf vsnprintf
|
||||
#endif
|
||||
#endif /*LV_SPRINTF_CUSTOM*/
|
||||
|
||||
/*===================
|
||||
* LV_OBJ SETTINGS
|
||||
*==================*/
|
||||
@@ -448,7 +591,7 @@
|
||||
#if LV_USE_BTN != 0
|
||||
/*Enable button-state animations - draw a circle on click (dependencies: LV_USE_ANIMATION)*/
|
||||
#ifndef LV_BTN_INK_EFFECT
|
||||
# define LV_BTN_INK_EFFECT 1
|
||||
# define LV_BTN_INK_EFFECT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -487,6 +630,11 @@
|
||||
#define LV_USE_CONT 1
|
||||
#endif
|
||||
|
||||
/*Color picker (dependencies: -*/
|
||||
#ifndef LV_USE_CPICKER
|
||||
#define LV_USE_CPICKER 1
|
||||
#endif
|
||||
|
||||
/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/
|
||||
#ifndef LV_USE_DDLIST
|
||||
#define LV_USE_DDLIST 1
|
||||
|
||||
@@ -4,6 +4,7 @@ CSRCS += lv_disp.c
|
||||
CSRCS += lv_obj.c
|
||||
CSRCS += lv_refr.c
|
||||
CSRCS += lv_style.c
|
||||
CSRCS += lv_debug.c
|
||||
|
||||
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/src/lv_core
|
||||
VPATH += :$(LVGL_DIR)/lvgl/src/lv_core
|
||||
|
||||
193
src/lv_core/lv_debug.c
Normal file
193
src/lv_core/lv_debug.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* @file lv_debug.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj.h"
|
||||
#include "lv_debug.h"
|
||||
|
||||
#if LV_USE_DEBUG
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#ifndef LV_DEBUG_STR_MAX_LENGTH
|
||||
#define LV_DEBUG_STR_MAX_LENGTH (1024 * 8)
|
||||
#endif
|
||||
|
||||
#ifndef LV_DEBUG_STR_MAX_REPEAT
|
||||
#define LV_DEBUG_STR_MAX_REPEAT 8
|
||||
#endif
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_find);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
bool lv_debug_check_null(const void * p)
|
||||
{
|
||||
if(p) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lv_debug_check_obj_type(const lv_obj_t * obj, const char * obj_type)
|
||||
{
|
||||
if(obj_type[0] == '\0') return true;
|
||||
|
||||
lv_obj_type_t types;
|
||||
lv_obj_get_type((lv_obj_t *)obj, &types);
|
||||
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM; i++) {
|
||||
if(strcmp(types.type[i], obj_type) == 0) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lv_debug_check_obj_valid(const lv_obj_t * obj)
|
||||
{
|
||||
lv_disp_t * disp = lv_disp_get_next(NULL);
|
||||
while(disp) {
|
||||
lv_obj_t * scr;
|
||||
LV_LL_READ(disp->scr_ll, scr) {
|
||||
|
||||
if(scr == obj) return true;
|
||||
bool found = obj_valid_child(scr, obj);
|
||||
if(found) return true;
|
||||
}
|
||||
|
||||
disp = lv_disp_get_next(disp);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lv_debug_check_style(const lv_style_t * style)
|
||||
{
|
||||
if(style == NULL) return true; /*NULL style is still valid*/
|
||||
|
||||
#if LV_USE_ASSERT_STYLE
|
||||
if(style->debug_sentinel != LV_STYLE_DEGUG_SENTINEL_VALUE) {
|
||||
LV_LOG_WARN("Invalid style (local variable or not initialized?)");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lv_debug_check_str(const void * str)
|
||||
{
|
||||
const uint8_t * s = (const uint8_t *)str;
|
||||
uint8_t last_byte = 0;
|
||||
uint32_t rep = 0;
|
||||
uint32_t i;
|
||||
|
||||
for(i = 0; s[i] != '\0' && i < LV_DEBUG_STR_MAX_LENGTH; i++) {
|
||||
if(s[i] != last_byte) {
|
||||
last_byte = s[i];
|
||||
rep = 1;
|
||||
} else if(s[i] > 0x7F){
|
||||
rep++;
|
||||
if(rep > LV_DEBUG_STR_MAX_REPEAT) {
|
||||
LV_LOG_WARN("lv_debug_check_str: a non-ASCII char has repeated more than LV_DEBUG_STR_MAX_REPEAT times)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(s[i] < 10) {
|
||||
LV_LOG_WARN("lv_debug_check_str: invalid char in the string (< 10 value)");
|
||||
return false; /*Shouldn't occur in strings*/
|
||||
}
|
||||
}
|
||||
|
||||
if(s[i] == '\0') return true;
|
||||
|
||||
LV_LOG_WARN("lv_debug_check_str: string is longer than LV_DEBUG_STR_MAX_LENGTH");
|
||||
return false;
|
||||
}
|
||||
|
||||
void lv_debug_log_error(const char * msg, uint64_t value)
|
||||
{
|
||||
static const char hex[] = "0123456789ABCDEF";
|
||||
|
||||
size_t msg_len = strlen(msg);
|
||||
uint32_t value_len = sizeof(unsigned long int);
|
||||
|
||||
if(msg_len < 230) {
|
||||
char buf[255];
|
||||
char * bufp = buf;
|
||||
|
||||
/*Add the function name*/
|
||||
memcpy(bufp, msg, msg_len);
|
||||
bufp += msg_len;
|
||||
|
||||
/*Add value in hey*/
|
||||
*bufp = ' ';
|
||||
bufp ++;
|
||||
*bufp = '(';
|
||||
bufp ++;
|
||||
*bufp = '0';
|
||||
bufp ++;
|
||||
*bufp = 'x';
|
||||
bufp ++;
|
||||
|
||||
int8_t i;
|
||||
for(i = value_len * 2 - 1; i >= 0; i--) {
|
||||
uint8_t x = (unsigned long int)((unsigned long int)value >> (i * 4)) & 0xF;
|
||||
|
||||
*bufp = hex[x];
|
||||
bufp++;
|
||||
}
|
||||
|
||||
*bufp = ')';
|
||||
bufp ++;
|
||||
|
||||
*bufp = '\0';
|
||||
LV_LOG_ERROR(buf);
|
||||
} else {
|
||||
LV_LOG_ERROR(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_find)
|
||||
{
|
||||
/*Check all children of `parent`*/
|
||||
lv_obj_t * child;
|
||||
LV_LL_READ(parent->child_ll, child) {
|
||||
if(child == obj_to_find) return true;
|
||||
|
||||
/*Check the children*/
|
||||
bool found = obj_valid_child(child, obj_to_find);
|
||||
if(found) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DEBUG*/
|
||||
|
||||
154
src/lv_core/lv_debug.h
Normal file
154
src/lv_core/lv_debug.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* @file lv_debug.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DEBUG_H
|
||||
#define LV_DEBUG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj.h"
|
||||
|
||||
#if LV_USE_DEBUG
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
bool lv_debug_check_null(const void * p);
|
||||
|
||||
bool lv_debug_check_obj_type(const lv_obj_t * obj, const char * obj_type);
|
||||
|
||||
bool lv_debug_check_obj_valid(const lv_obj_t * obj);
|
||||
|
||||
bool lv_debug_check_style(const lv_style_t * style);
|
||||
|
||||
bool lv_debug_check_str(const void * str);
|
||||
|
||||
void lv_debug_log_error(const char * msg, uint64_t value);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifndef LV_DEBUG_ASSERT
|
||||
#define LV_DEBUG_ASSERT(expr, msg, value) \
|
||||
{ \
|
||||
if(!(expr)) { \
|
||||
LV_LOG_ERROR(__func__); \
|
||||
lv_debug_log_error(msg, (uint64_t)((uintptr_t)value)); \
|
||||
while(1); \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
/*----------------
|
||||
* CHECKS
|
||||
*----------------*/
|
||||
|
||||
#ifndef LV_DEBUG_IS_NULL
|
||||
#define LV_DEBUG_IS_NULL(p) (lv_debug_check_null(p))
|
||||
#endif
|
||||
|
||||
#ifndef LV_DEBUG_IS_STR
|
||||
#define LV_DEBUG_IS_STR(str) (lv_debug_check_null(str) && \
|
||||
lv_debug_check_str(str))
|
||||
#endif
|
||||
|
||||
#ifndef LV_DEBUG_IS_OBJ
|
||||
#define LV_DEBUG_IS_OBJ(obj_p, obj_type) (lv_debug_check_null(obj_p) && \
|
||||
lv_debug_check_obj_valid(obj_p) && \
|
||||
lv_debug_check_obj_type(obj_p, obj_type))
|
||||
#endif
|
||||
|
||||
#ifndef LV_DEBUG_IS_STYLE
|
||||
#define LV_DEBUG_IS_STYLE(style_p) (lv_debug_check_style(style_p))
|
||||
#endif
|
||||
|
||||
/*-----------------
|
||||
* ASSERTS
|
||||
*-----------------*/
|
||||
|
||||
/*clang-format off*/
|
||||
|
||||
#if LV_USE_ASSERT_NULL
|
||||
# ifndef LV_ASSERT_NULL
|
||||
# define LV_ASSERT_NULL(p) LV_DEBUG_ASSERT(LV_DEBUG_IS_NULL(p), "NULL pointer", p);
|
||||
# endif
|
||||
#else
|
||||
# define LV_ASSERT_NULL(p) true
|
||||
#endif
|
||||
|
||||
#if LV_USE_ASSERT_MEM
|
||||
# ifndef LV_ASSERT_MEM
|
||||
# define LV_ASSERT_MEM(p) LV_DEBUG_ASSERT(LV_DEBUG_IS_NULL(p), "Out of memory", p);
|
||||
# endif
|
||||
#else
|
||||
# define LV_ASSERT_MEM(p) true
|
||||
#endif
|
||||
|
||||
#if LV_USE_ASSERT_STR
|
||||
# ifndef LV_ASSERT_STR
|
||||
# define LV_ASSERT_STR(str) LV_DEBUG_ASSERT(LV_DEBUG_IS_STR(str), "Strange or invalid string", str);
|
||||
# endif
|
||||
#else /* LV_USE_ASSERT_OBJ == 0 */
|
||||
# if LV_USE_ASSERT_NULL /*Use at least LV_ASSERT_NULL if enabled*/
|
||||
# define LV_ASSERT_STR(str) LV_ASSERT_NULL(str)
|
||||
# else
|
||||
# define LV_ASSERT_STR(str) true
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#if LV_USE_ASSERT_OBJ
|
||||
# ifndef LV_ASSERT_OBJ
|
||||
# define LV_ASSERT_OBJ(obj_p, obj_type) LV_DEBUG_ASSERT(LV_DEBUG_IS_OBJ(obj_p, obj_type), "Invalid object", obj_p);
|
||||
# endif
|
||||
#else /* LV_USE_ASSERT_OBJ == 0 */
|
||||
# if LV_USE_ASSERT_NULL /*Use at least LV_ASSERT_NULL if enabled*/
|
||||
# define LV_ASSERT_OBJ(obj_p, obj_type) LV_ASSERT_NULL(obj_p)
|
||||
# else
|
||||
# define LV_ASSERT_OBJ(obj_p, obj_type) true
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#if LV_USE_ASSERT_STYLE
|
||||
# ifndef LV_ASSERT_STYLE
|
||||
# define LV_ASSERT_STYLE(style_p) LV_DEBUG_ASSERT(LV_DEBUG_IS_STYLE(style_p), "Invalid style", style_p);
|
||||
# endif
|
||||
#else
|
||||
# define LV_ASSERT_STYLE(style) true
|
||||
#endif
|
||||
|
||||
#else /* LV_USE_DEBUG == 0 */
|
||||
|
||||
#define LV_DEBUG_ASSERT(expr, msg, value) do{}while(0)
|
||||
|
||||
#define LV_ASSERT_NULL(p) true
|
||||
#define LV_ASSERT_MEM(p) true
|
||||
#define LV_ASSERT_STR(p) true
|
||||
#define LV_ASSERT_OBJ(obj, obj_type) true
|
||||
#define LV_ASSERT_STYLE(p) true
|
||||
|
||||
#endif /* LV_USE_DEBUG */
|
||||
/*clang-format on*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_DEBUG_H*/
|
||||
@@ -109,7 +109,7 @@ static inline lv_obj_t * lv_layer_top(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the active screen of the deafult display
|
||||
* Get the active screen of the default display
|
||||
* @return pointer to the sys layer
|
||||
*/
|
||||
static inline lv_obj_t * lv_layer_sys(void)
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
*********************/
|
||||
#include "lv_group.h"
|
||||
#if LV_USE_GROUP != 0
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
#include <stddef.h>
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
#include "../lv_misc/lv_gc.h"
|
||||
|
||||
#if defined(LV_GC_INCLUDE)
|
||||
@@ -62,7 +63,7 @@ void lv_group_init(void)
|
||||
lv_group_t * lv_group_create(void)
|
||||
{
|
||||
lv_group_t * group = lv_ll_ins_head(&LV_GC_ROOT(_lv_group_ll));
|
||||
lv_mem_assert(group);
|
||||
LV_ASSERT_MEM(group);
|
||||
if(group == NULL) return NULL;
|
||||
lv_ll_init(&group->obj_ll, sizeof(lv_obj_t *));
|
||||
|
||||
@@ -138,7 +139,7 @@ void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj)
|
||||
|
||||
obj->group_p = group;
|
||||
lv_obj_t ** next = lv_ll_ins_tail(&group->obj_ll);
|
||||
lv_mem_assert(next);
|
||||
LV_ASSERT_MEM(next);
|
||||
if(next == NULL) return;
|
||||
*next = obj;
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ void lv_indev_enable(lv_indev_t * indev, bool en)
|
||||
{
|
||||
if(!indev) return;
|
||||
|
||||
indev->proc.disabled = en ? 1 : 0;
|
||||
indev->proc.disabled = en ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -687,12 +687,14 @@ static void indev_proc_press(lv_indev_proc_t * proc)
|
||||
if(proc->wait_until_release != 0) return;
|
||||
|
||||
lv_disp_t * disp = indev_act->driver.disp;
|
||||
bool new_obj_searched = false;
|
||||
|
||||
/*If there is no last object then search*/
|
||||
if(indev_obj_act == NULL) {
|
||||
indev_obj_act = indev_search_obj(proc, lv_disp_get_layer_sys(disp));
|
||||
if(indev_obj_act == NULL) indev_obj_act = indev_search_obj(proc, lv_disp_get_layer_top(disp));
|
||||
if(indev_obj_act == NULL) indev_obj_act = indev_search_obj(proc, lv_disp_get_scr_act(disp));
|
||||
new_obj_searched = true;
|
||||
}
|
||||
/*If there is last object but it is not dragged and not protected also search*/
|
||||
else if(proc->types.pointer.drag_in_prog == 0 &&
|
||||
@@ -700,14 +702,21 @@ static void indev_proc_press(lv_indev_proc_t * proc)
|
||||
indev_obj_act = indev_search_obj(proc, lv_disp_get_layer_sys(disp));
|
||||
if(indev_obj_act == NULL) indev_obj_act = indev_search_obj(proc, lv_disp_get_layer_top(disp));
|
||||
if(indev_obj_act == NULL) indev_obj_act = indev_search_obj(proc, lv_disp_get_scr_act(disp));
|
||||
new_obj_searched = true;
|
||||
}
|
||||
/*If a dragable or a protected object was the last then keep it*/
|
||||
else {
|
||||
}
|
||||
|
||||
/*The last object might have drag throw. Stop it manually*/
|
||||
if(new_obj_searched && proc->types.pointer.last_obj) {
|
||||
proc->types.pointer.drag_throw_vect.x = 0;
|
||||
proc->types.pointer.drag_throw_vect.y = 0;
|
||||
indev_drag_throw(proc);
|
||||
}
|
||||
|
||||
/*If a new object was found reset some variables and send a pressed signal*/
|
||||
if(indev_obj_act != proc->types.pointer.act_obj) {
|
||||
|
||||
proc->types.pointer.last_point.x = proc->types.pointer.act_point.x;
|
||||
proc->types.pointer.last_point.y = proc->types.pointer.act_point.y;
|
||||
|
||||
@@ -720,6 +729,7 @@ static void indev_proc_press(lv_indev_proc_t * proc)
|
||||
if(indev_reset_check(proc)) return;
|
||||
lv_event_send(last_obj, LV_EVENT_PRESS_LOST, NULL);
|
||||
if(indev_reset_check(proc)) return;
|
||||
|
||||
}
|
||||
|
||||
proc->types.pointer.act_obj = indev_obj_act; /*Save the pressed object*/
|
||||
@@ -868,8 +878,10 @@ static void indev_proc_release(lv_indev_proc_t * proc)
|
||||
if(indev_reset_check(proc)) return;
|
||||
}
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL);
|
||||
if(indev_reset_check(proc)) return;
|
||||
if(proc->types.pointer.drag_in_prog == 0) {
|
||||
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL);
|
||||
if(indev_reset_check(proc)) return;
|
||||
}
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL);
|
||||
if(indev_reset_check(proc)) return;
|
||||
@@ -1106,20 +1118,9 @@ static void indev_drag(lv_indev_proc_t * state)
|
||||
lv_obj_set_y(drag_obj, act_y + state->types.pointer.vect.y);
|
||||
}
|
||||
|
||||
/*Set the drag in progress flag*/
|
||||
/*Send the drag begin signal on first move*/
|
||||
if(state->types.pointer.drag_in_prog == 0) {
|
||||
drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_BEGIN, indev_act);
|
||||
if(indev_reset_check(state)) return;
|
||||
lv_event_send(drag_obj, LV_EVENT_DRAG_BEGIN, NULL);
|
||||
if(indev_reset_check(state)) return;
|
||||
}
|
||||
|
||||
state->types.pointer.drag_in_prog = 1;
|
||||
|
||||
/*If the object didn't moved then clear the invalidated areas*/
|
||||
if(drag_obj->coords.x1 == prev_x && drag_obj->coords.y1 == prev_y) {
|
||||
state->types.pointer.drag_in_prog = 0;
|
||||
// state->types.pointer.drag_in_prog = 0;
|
||||
/*In a special case if the object is moved on a page and
|
||||
* the scrollable has fit == true and the object is dragged of the page then
|
||||
* while its coordinate is not changing only the parent's size is reduced */
|
||||
@@ -1129,6 +1130,16 @@ static void indev_drag(lv_indev_proc_t * state)
|
||||
uint16_t new_inv_buf_size = lv_disp_get_inv_buf_size(indev_act->driver.disp);
|
||||
lv_disp_pop_from_inv_buf(indev_act->driver.disp, new_inv_buf_size - inv_buf_size);
|
||||
}
|
||||
} else {
|
||||
state->types.pointer.drag_in_prog = 1;
|
||||
/*Set the drag in progress flag*/
|
||||
/*Send the drag begin signal on first move*/
|
||||
if(drag_just_started) {
|
||||
drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_BEGIN, indev_act);
|
||||
if(indev_reset_check(state)) return;
|
||||
lv_event_send(drag_obj, LV_EVENT_DRAG_BEGIN, NULL);
|
||||
if(indev_reset_check(state)) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,7 @@ extern "C" {
|
||||
#include "../lv_misc/lv_ll.h"
|
||||
#include "../lv_misc/lv_color.h"
|
||||
#include "../lv_misc/lv_log.h"
|
||||
#include "../lv_misc/lv_bidi.h"
|
||||
#include "../lv_hal/lv_hal.h"
|
||||
|
||||
/*********************
|
||||
@@ -111,7 +112,8 @@ enum {
|
||||
LV_SIGNAL_CHILD_CHG, /**< Child was removed/added */
|
||||
LV_SIGNAL_CORD_CHG, /**< Object coordinates/size have changed */
|
||||
LV_SIGNAL_PARENT_SIZE_CHG, /**< Parent's size has changed */
|
||||
LV_SIGNAL_STYLE_CHG, /**< Object's style has changed */
|
||||
LV_SIGNAL_STYLE_CHG, /**< Object's style has changed */
|
||||
LV_SIGNAL_BASE_DIR_CHG, /**<The base dir has changed*/
|
||||
LV_SIGNAL_REFR_EXT_DRAW_PAD, /**< Object's extra padding has changed */
|
||||
LV_SIGNAL_GET_TYPE, /**< LittlevGL needs to retrieve the object's type */
|
||||
|
||||
@@ -123,7 +125,8 @@ enum {
|
||||
LV_SIGNAL_LONG_PRESS, /**< Object has been pressed for at least `LV_INDEV_LONG_PRESS_TIME`. Not called if dragged.*/
|
||||
LV_SIGNAL_LONG_PRESS_REP, /**< Called after `LV_INDEV_LONG_PRESS_TIME` in every `LV_INDEV_LONG_PRESS_REP_TIME` ms. Not called if dragged.*/
|
||||
LV_SIGNAL_DRAG_BEGIN,
|
||||
LV_SIGNAL_DRAG_END,
|
||||
LV_SIGNAL_DRAG_END,
|
||||
|
||||
/*Group related*/
|
||||
LV_SIGNAL_FOCUS,
|
||||
LV_SIGNAL_DEFOCUS,
|
||||
@@ -218,7 +221,8 @@ typedef struct _lv_obj_t
|
||||
uint8_t opa_scale_en : 1; /**< 1: opa_scale is set*/
|
||||
uint8_t parent_event : 1; /**< 1: Send the object's events to the parent too. */
|
||||
lv_drag_dir_t drag_dir : 2; /**< Which directions the object can be dragged in */
|
||||
uint8_t reserved : 6; /**< Reserved for future use*/
|
||||
lv_bidi_dir_t base_dir : 2; /**< Base direction of texts related to this object */
|
||||
uint8_t reserved : 3; /**< Reserved for future use*/
|
||||
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*/
|
||||
@@ -265,6 +269,15 @@ typedef struct
|
||||
*/
|
||||
void lv_init(void);
|
||||
|
||||
|
||||
/**
|
||||
* Deinit the 'lv' library
|
||||
* Currently only implemented when not using custorm allocators, or GC is enabled.
|
||||
*/
|
||||
#if LV_ENABLE_GC || !LV_MEM_CUSTOM
|
||||
void lv_deinit(void);
|
||||
#endif
|
||||
|
||||
/*--------------------
|
||||
* Create and delete
|
||||
*-------------------*/
|
||||
@@ -285,12 +298,29 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy);
|
||||
*/
|
||||
lv_res_t lv_obj_del(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Helper function for asynchronously deleting objects.
|
||||
* Useful for cases where you can't delete an object directly in an `LV_EVENT_DELETE` handler (i.e. parent).
|
||||
* @param obj object to delete
|
||||
* @see lv_async_call
|
||||
*/
|
||||
void lv_obj_del_async(struct _lv_obj_t *obj);
|
||||
|
||||
/**
|
||||
* Delete all children of an object
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_clean(lv_obj_t * obj);
|
||||
|
||||
|
||||
/**
|
||||
* Mark an area of an object as invalid.
|
||||
* This area will be redrawn by 'lv_refr_task'
|
||||
* @param obj pointer to an object
|
||||
* @param area the area to redraw
|
||||
*/
|
||||
void lv_obj_invalidate_area(const lv_obj_t * obj, const lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task'
|
||||
* @param obj pointer to an object
|
||||
@@ -502,6 +532,7 @@ void lv_obj_set_drag_parent(lv_obj_t * obj, bool en);
|
||||
*/
|
||||
void lv_obj_set_parent_event(lv_obj_t * obj, bool en);
|
||||
|
||||
void lv_obj_set_base_dir(lv_obj_t * obj, lv_bidi_dir_t dir);
|
||||
/**
|
||||
* Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`)
|
||||
* @param obj pointer to an object
|
||||
@@ -510,7 +541,10 @@ void lv_obj_set_parent_event(lv_obj_t * obj, bool en);
|
||||
void lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Set the opa scale of an object
|
||||
* Set the opa scale of an object.
|
||||
* The opacity of this object and all it's children will be scaled down with this factor.
|
||||
* `lv_obj_set_opa_scale_enable(obj, true)` needs to be called to enable it.
|
||||
* (not for all children just for the parent where to start the opa scaling)
|
||||
* @param obj pointer to an object
|
||||
* @param opa_scale a factor to scale down opacity [0..255]
|
||||
*/
|
||||
@@ -716,21 +750,21 @@ lv_coord_t lv_obj_get_height(const lv_obj_t * obj);
|
||||
* @param obj pointer to an object
|
||||
* @return the width which still fits into the container
|
||||
*/
|
||||
lv_coord_t lv_obj_get_width_fit(lv_obj_t * obj);
|
||||
lv_coord_t lv_obj_get_width_fit(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get that height reduced by the top an bottom padding.
|
||||
* @param obj pointer to an object
|
||||
* @return the height which still fits into the container
|
||||
*/
|
||||
lv_coord_t lv_obj_get_height_fit(lv_obj_t * obj);
|
||||
lv_coord_t lv_obj_get_height_fit(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the automatic realign property of the object.
|
||||
* @param obj pointer to an object
|
||||
* @return true: auto realign is enabled; false: auto realign is disabled
|
||||
*/
|
||||
bool lv_obj_get_auto_realign(lv_obj_t * obj);
|
||||
bool lv_obj_get_auto_realign(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the left padding of extended clickable area
|
||||
@@ -838,6 +872,9 @@ bool lv_obj_get_drag_parent(const lv_obj_t * obj);
|
||||
*/
|
||||
bool lv_obj_get_parent_event(const lv_obj_t * obj);
|
||||
|
||||
|
||||
lv_bidi_dir_t lv_obj_get_base_dir(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the opa scale enable parameter
|
||||
* @param obj pointer to an object
|
||||
@@ -906,7 +943,7 @@ void * lv_obj_get_ext_attr(const lv_obj_t * obj);
|
||||
* @param obj pointer to an object which type should be get
|
||||
* @param buf pointer to an `lv_obj_type_t` buffer to store the types
|
||||
*/
|
||||
void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf);
|
||||
void lv_obj_get_type(const lv_obj_t * obj, lv_obj_type_t * buf);
|
||||
|
||||
#if LV_USE_USER_DATA
|
||||
/**
|
||||
@@ -914,14 +951,14 @@ void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf);
|
||||
* @param obj pointer to an object
|
||||
* @return user data
|
||||
*/
|
||||
lv_obj_user_data_t lv_obj_get_user_data(lv_obj_t * obj);
|
||||
lv_obj_user_data_t lv_obj_get_user_data(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get a pointer to the object's user data
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to the user data
|
||||
*/
|
||||
lv_obj_user_data_t * lv_obj_get_user_data_ptr(lv_obj_t * obj);
|
||||
lv_obj_user_data_t * lv_obj_get_user_data_ptr(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the object's user data. The data will be copied.
|
||||
@@ -949,6 +986,18 @@ bool lv_obj_is_focused(const lv_obj_t * obj);
|
||||
|
||||
#endif
|
||||
|
||||
/*-------------------
|
||||
* OTHER FUNCTIONS
|
||||
*------------------*/
|
||||
|
||||
/**
|
||||
* Used in the signal callback to handle `LV_SIGNAL_GET_TYPE` signal
|
||||
* @param buf pointer to `lv_obj_type_t`. (`param` in the signal callback)
|
||||
* @param name name of the object. E.g. "lv_btn". (Only the pointer is saved)
|
||||
* @return LV_RES_OK
|
||||
*/
|
||||
lv_res_t lv_obj_handle_get_type_signal(lv_obj_type_t * buf, const char * name);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -115,7 +115,7 @@ void lv_inv_area(lv_disp_t * disp, const lv_area_t * area_p)
|
||||
|
||||
/*The area is truncated to the screen*/
|
||||
if(suc != false) {
|
||||
if(disp->driver.rounder_cb) disp->driver.rounder_cb(&disp_refr->driver, &com_area);
|
||||
if(disp->driver.rounder_cb) disp->driver.rounder_cb(&disp->driver, &com_area);
|
||||
|
||||
/*Save only if this area is not in one of the saved areas*/
|
||||
uint16_t i;
|
||||
@@ -318,19 +318,19 @@ static void lv_refr_area(const lv_area_t * area_p)
|
||||
tmp.x2 = 0;
|
||||
tmp.y1 = 0;
|
||||
|
||||
lv_coord_t y_tmp = max_row - 1;
|
||||
lv_coord_t h_tmp = max_row;
|
||||
do {
|
||||
tmp.y2 = y_tmp;
|
||||
tmp.y2 = h_tmp - 1;
|
||||
disp_refr->driver.rounder_cb(&disp_refr->driver, &tmp);
|
||||
|
||||
/*If this height fits into `max_row` then fine*/
|
||||
if(lv_area_get_height(&tmp) <= max_row) break;
|
||||
|
||||
/*Decrement the height of the area until it fits into `max_row` after rounding*/
|
||||
y_tmp--;
|
||||
} while(y_tmp != 0);
|
||||
h_tmp--;
|
||||
} while(h_tmp > 0);
|
||||
|
||||
if(y_tmp == 0) {
|
||||
if(h_tmp <= 0) {
|
||||
LV_LOG_WARN("Can't set VDB height using the round function. (Wrong round_cb or to "
|
||||
"small VDB)");
|
||||
return;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj.h"
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
#include "../lv_misc/lv_anim.h"
|
||||
|
||||
@@ -106,6 +107,12 @@ void lv_style_init(void)
|
||||
lv_style_scr.line.width = 2;
|
||||
lv_style_scr.line.rounded = 0;
|
||||
|
||||
#if LV_USE_DEBUG
|
||||
#if LV_USE_ASSERT_STYLE
|
||||
lv_style_scr.debug_sentinel = LV_STYLE_DEGUG_SENTINEL_VALUE;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Plain style (by default near the same as the screen style)*/
|
||||
lv_style_copy(&lv_style_plain, &lv_style_scr);
|
||||
lv_style_plain.body.padding.left = LV_DPI / 20;
|
||||
@@ -287,7 +294,7 @@ void lv_style_anim_init(lv_anim_t * a)
|
||||
|
||||
lv_style_anim_dsc_t * dsc;
|
||||
dsc = lv_mem_alloc(sizeof(lv_style_anim_dsc_t));
|
||||
lv_mem_assert(dsc);
|
||||
LV_ASSERT_MEM(dsc);
|
||||
if(dsc == NULL) return;
|
||||
dsc->ready_cb = NULL;
|
||||
dsc->style_anim = NULL;
|
||||
|
||||
@@ -23,6 +23,9 @@ extern "C" {
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_RADIUS_CIRCLE (LV_COORD_MAX) /**< A very big radius to always draw as circle*/
|
||||
#define LV_STYLE_DEGUG_SENTINEL_VALUE 0x12345678
|
||||
|
||||
LV_EXPORT_CONST_INT(LV_RADIUS_CIRCLE);
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -119,6 +122,13 @@ typedef struct
|
||||
lv_opa_t opa;
|
||||
uint8_t rounded : 1; /**< 1: rounded line endings*/
|
||||
} line;
|
||||
|
||||
#if LV_USE_DEBUG
|
||||
#if LV_USE_ASSERT_STYLE
|
||||
uint32_t debug_sentinel; /**<Should `LV_STYLE_DEGUG_SENTINEL_VALUE` to indicate that the style is valid*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
} lv_style_t;
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
@@ -186,7 +196,7 @@ void lv_style_anim_set_styles(lv_anim_t * a, lv_style_t * to_anim, const lv_styl
|
||||
* @param duration duration of the animation in milliseconds
|
||||
* @param delay delay before the animation in milliseconds
|
||||
*/
|
||||
static inline void lv_style_anim_set_time(lv_anim_t * a, uint16_t duration, uint16_t delay)
|
||||
static inline void lv_style_anim_set_time(lv_anim_t * a, uint16_t duration, int16_t delay)
|
||||
{
|
||||
lv_anim_set_time(a, duration, delay);
|
||||
}
|
||||
@@ -240,36 +250,6 @@ static inline void lv_style_anim_clear_repeat(lv_anim_t * a)
|
||||
lv_anim_clear_repeat(a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a user specific data for the animation
|
||||
* @param a pointer to an initialized `lv_anim_t` variable
|
||||
* @param user_data the user data
|
||||
*/
|
||||
static inline void lv_style_anim_set_user_data(lv_anim_t * a, lv_anim_user_data_t user_data)
|
||||
{
|
||||
lv_anim_set_user_data(a, user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user data
|
||||
* @param a pointer to an initialized `lv_anim_t` variable
|
||||
* @return the user data
|
||||
*/
|
||||
static inline lv_anim_user_data_t lv_style_anim_get_user_data(lv_anim_t * a)
|
||||
{
|
||||
return lv_anim_get_user_data(a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pointer to the user data
|
||||
* @param a pointer to an initialized `lv_anim_t` variable
|
||||
* @return pointer to the user data
|
||||
*/
|
||||
static inline lv_anim_user_data_t * lv_style_anim_get_user_data_ptr(lv_anim_t * a)
|
||||
{
|
||||
return lv_anim_get_user_data_ptr(a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an animation
|
||||
* @param a an initialized 'anim_t' variable. Not required after call.
|
||||
@@ -302,6 +282,18 @@ extern lv_style_t lv_style_btn_ina;
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create and initialize a `static` style
|
||||
* Example:
|
||||
* LV_STYLE_CREATE(my_style, &lv_style_plain);
|
||||
* is equivalent to
|
||||
* static lv_style_t my_style;
|
||||
* lv_style_copy(my_style, &lv_style_plain);
|
||||
*
|
||||
* If the style to copy is `NULL` `lv_style_plain` will be used.
|
||||
*/
|
||||
#define LV_STYLE_CREATE(name, copy_p) static lv_style_t name; lv_style_copy(&name, copy_p == NULL ? &lv_style_plain : copy_p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -10,10 +10,16 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "lv_draw.h"
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
#include "../lv_misc/lv_log.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
#include "../lv_misc/lv_gc.h"
|
||||
|
||||
#if defined(LV_GC_INCLUDE)
|
||||
#include LV_GC_INCLUDE
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -30,7 +36,6 @@
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static void * draw_buf = NULL;
|
||||
static uint32_t draw_buf_size = 0;
|
||||
|
||||
/**********************
|
||||
@@ -48,21 +53,21 @@ static uint32_t draw_buf_size = 0;
|
||||
*/
|
||||
void * lv_draw_get_buf(uint32_t size)
|
||||
{
|
||||
if(size <= draw_buf_size) return draw_buf;
|
||||
if(size <= draw_buf_size) return LV_GC_ROOT(_lv_draw_buf);
|
||||
|
||||
LV_LOG_TRACE("lv_draw_get_buf: allocate");
|
||||
|
||||
draw_buf_size = size;
|
||||
|
||||
if(draw_buf == NULL) {
|
||||
draw_buf = lv_mem_alloc(size);
|
||||
lv_mem_assert(draw_buf);
|
||||
return draw_buf;
|
||||
if(LV_GC_ROOT(_lv_draw_buf) == NULL) {
|
||||
LV_GC_ROOT(_lv_draw_buf) = lv_mem_alloc(size);
|
||||
LV_ASSERT_MEM(LV_GC_ROOT(_lv_draw_buf));
|
||||
return LV_GC_ROOT(_lv_draw_buf);
|
||||
}
|
||||
|
||||
draw_buf = lv_mem_realloc(draw_buf, size);
|
||||
lv_mem_assert(draw_buf);
|
||||
return draw_buf;
|
||||
LV_GC_ROOT(_lv_draw_buf) = lv_mem_realloc(LV_GC_ROOT(_lv_draw_buf), size);
|
||||
LV_ASSERT_MEM(LV_GC_ROOT(_lv_draw_buf));
|
||||
return LV_GC_ROOT(_lv_draw_buf);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,9 +75,9 @@ void * lv_draw_get_buf(uint32_t size)
|
||||
*/
|
||||
void lv_draw_free_buf(void)
|
||||
{
|
||||
if(draw_buf) {
|
||||
lv_mem_free(draw_buf);
|
||||
draw_buf = NULL;
|
||||
if(LV_GC_ROOT(_lv_draw_buf)) {
|
||||
lv_mem_free(LV_GC_ROOT(_lv_draw_buf));
|
||||
LV_GC_ROOT(_lv_draw_buf) = NULL;
|
||||
draw_buf_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
/**********************
|
||||
* 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,
|
||||
@@ -57,6 +56,11 @@ void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, cons
|
||||
lv_coord_t thickness = style->line.width;
|
||||
if(thickness > radius) thickness = radius;
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
thickness--;
|
||||
radius--;
|
||||
#endif
|
||||
|
||||
lv_coord_t r_out = radius;
|
||||
lv_coord_t r_in = r_out - thickness;
|
||||
int16_t deg_base;
|
||||
@@ -73,17 +77,26 @@ void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, cons
|
||||
else
|
||||
deg_test = deg_test_inv;
|
||||
|
||||
int middle_r_out = r_out;
|
||||
#if !LV_ANTIALIAS
|
||||
thickness--;
|
||||
middle_r_out = r_out - 1;
|
||||
#endif
|
||||
if(deg_test(270, start_angle, end_angle))
|
||||
hor_line(center_x - r_out + 1, center_y, mask, thickness - 1, color, opa); // Left Middle
|
||||
hor_line(center_x - middle_r_out, center_y, mask, thickness, 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
|
||||
hor_line(center_x + r_in, center_y, mask, thickness, 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
|
||||
ver_line(center_x, center_y - middle_r_out, mask, thickness, 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
|
||||
ver_line(center_x, center_y + r_in, mask, thickness, color, opa); /*Bottom middle*/
|
||||
|
||||
uint32_t r_out_sqr = r_out * r_out;
|
||||
uint32_t r_in_sqr = r_in * r_in;
|
||||
#if LV_ANTIALIAS
|
||||
uint32_t r_out_aa_sqr = (r_out + 1) * (r_out + 1);
|
||||
uint32_t r_in_aa_sqr = (r_in - 1) * (r_in - 1);
|
||||
#endif
|
||||
int16_t xi;
|
||||
int16_t yi;
|
||||
for(yi = -r_out; yi < 0; yi++) {
|
||||
@@ -95,12 +108,55 @@ void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, cons
|
||||
x_end[1] = LV_COORD_MIN;
|
||||
x_end[2] = LV_COORD_MIN;
|
||||
x_end[3] = LV_COORD_MIN;
|
||||
int xe = 0;
|
||||
for(xi = -r_out; xi < 0; xi++) {
|
||||
|
||||
uint32_t r_act_sqr = xi * xi + yi * yi;
|
||||
#if LV_ANTIALIAS
|
||||
if(r_act_sqr > r_out_aa_sqr) {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
if(r_act_sqr > r_out_sqr) continue;
|
||||
#endif
|
||||
|
||||
deg_base = fast_atan2(xi, yi) - 180;
|
||||
deg_base = lv_atan2(xi, yi) - 180;
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
int opa2 = -1;
|
||||
if(r_act_sqr > r_out_sqr) {
|
||||
opa2 = LV_OPA_100 * (r_out + 1) - lv_sqrt(LV_OPA_100 * LV_OPA_100 * r_act_sqr);
|
||||
if(opa2 < LV_OPA_0)
|
||||
opa2 = LV_OPA_0;
|
||||
else if(opa2 > LV_OPA_100)
|
||||
opa2 = LV_OPA_100;
|
||||
} else if(r_act_sqr < r_in_sqr) {
|
||||
if(xe == 0) xe = xi;
|
||||
opa2 = lv_sqrt(LV_OPA_100 * LV_OPA_100 * r_act_sqr) - LV_OPA_100 * (r_in - 1);
|
||||
if(opa2 < LV_OPA_0)
|
||||
opa2 = LV_OPA_0;
|
||||
else if(opa2 > LV_OPA_100)
|
||||
opa2 = LV_OPA_100;
|
||||
if(r_act_sqr < r_in_aa_sqr)
|
||||
break; /*No need to continue the iteration in x once we found the inner edge of the
|
||||
arc*/
|
||||
}
|
||||
if(opa2 != -1) {
|
||||
if(deg_test(180 + deg_base, start_angle, end_angle)) {
|
||||
lv_draw_px(center_x + xi, center_y + yi, mask, color, opa2);
|
||||
}
|
||||
if(deg_test(360 - deg_base, start_angle, end_angle)) {
|
||||
lv_draw_px(center_x + xi, center_y - yi, mask, color, opa2);
|
||||
}
|
||||
if(deg_test(180 - deg_base, start_angle, end_angle)) {
|
||||
lv_draw_px(center_x - xi, center_y + yi, mask, color, opa2);
|
||||
}
|
||||
if(deg_test(deg_base, start_angle, end_angle)) {
|
||||
lv_draw_px(center_x - xi, center_y - yi, mask, color, opa2);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
deg = 180 + deg_base;
|
||||
if(deg_test(deg, start_angle, end_angle)) {
|
||||
@@ -130,113 +186,35 @@ void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, cons
|
||||
x_end[3] = xi - 1;
|
||||
}
|
||||
|
||||
if(r_act_sqr < r_in_sqr)
|
||||
if(r_act_sqr < r_in_sqr) {
|
||||
xe = xi;
|
||||
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;
|
||||
if(x_end[0] == LV_COORD_MIN) x_end[0] = xe - 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;
|
||||
if(x_end[1] == LV_COORD_MIN) x_end[1] = xe - 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;
|
||||
if(x_end[2] == LV_COORD_MIN) x_end[2] = xe - 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;
|
||||
if(x_end[3] == LV_COORD_MIN) x_end[3] = xe - 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
|
||||
**********************/
|
||||
|
||||
@@ -45,7 +45,9 @@ static void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t len
|
||||
static void sw_color_fill(lv_color_t * mem, lv_coord_t mem_width, const lv_area_t * fill_area, lv_color_t color,
|
||||
lv_opa_t opa);
|
||||
|
||||
#if LV_COLOR_DEPTH == 32 && 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
|
||||
@@ -90,7 +92,7 @@ void lv_draw_px(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t
|
||||
disp->driver.set_px_cb(&disp->driver, (uint8_t *)vdb->buf_act, vdb_width, x, y, color, opa);
|
||||
} else {
|
||||
bool scr_transp = false;
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
#if LV_COLOR_DEPTH == 32 && LV_COLOR_SCREEN_TRANSP
|
||||
scr_transp = disp->driver.screen_transp;
|
||||
#endif
|
||||
|
||||
@@ -104,7 +106,7 @@ void lv_draw_px(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t
|
||||
*vdb_px_p = lv_color_mix(color, *vdb_px_p, opa);
|
||||
}
|
||||
} else {
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
#if LV_COLOR_DEPTH == 32 && LV_COLOR_SCREEN_TRANSP
|
||||
*vdb_px_p = color_mix_2_alpha(*vdb_px_p, (*vdb_px_p).ch.alpha, color, opa);
|
||||
#endif
|
||||
}
|
||||
@@ -250,6 +252,7 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, const lv
|
||||
bool g_ret = lv_font_get_glyph_dsc(font_p, &g, letter, '\0');
|
||||
if(g_ret == false) return;
|
||||
|
||||
|
||||
lv_coord_t pos_x = pos_p->x + g.ofs_x;
|
||||
lv_coord_t pos_y = pos_p->y + (font_p->line_height - font_p->base_line) - g.box_h - g.ofs_y;
|
||||
|
||||
@@ -257,6 +260,9 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, const lv
|
||||
uint8_t bitmask_init;
|
||||
uint8_t bitmask;
|
||||
|
||||
/*bpp = 3 should be converted to bpp = 4 in lv_font_get_glyph_bitmap */
|
||||
if(g.bpp == 3) g.bpp = 4;
|
||||
|
||||
switch(g.bpp) {
|
||||
case 1:
|
||||
bpp_opa_table = bpp1_opa_table;
|
||||
@@ -295,63 +301,131 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, const lv
|
||||
if(g.box_w & 0x7) width_byte_scr++;
|
||||
uint16_t width_bit = g.box_w * g.bpp; /*Letter width in bits*/
|
||||
|
||||
bool subpx = font_p->subpx == LV_FONT_SUBPX_NONE ? false : true;
|
||||
|
||||
/* Calculate the col/row start/end on the map*/
|
||||
lv_coord_t col_start = pos_x >= mask_p->x1 ? 0 : mask_p->x1 - pos_x;
|
||||
lv_coord_t col_end = pos_x + g.box_w <= mask_p->x2 ? g.box_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 + g.box_h <= mask_p->y2 ? g.box_h : mask_p->y2 - pos_y + 1;
|
||||
lv_coord_t col_start;
|
||||
lv_coord_t col_end;
|
||||
lv_coord_t row_start;
|
||||
lv_coord_t row_end;
|
||||
|
||||
if(subpx == false) {
|
||||
col_start = pos_x >= mask_p->x1 ? 0 : mask_p->x1 - pos_x;
|
||||
col_end = pos_x + g.box_w <= mask_p->x2 ? g.box_w : mask_p->x2 - pos_x + 1;
|
||||
row_start = pos_y >= mask_p->y1 ? 0 : mask_p->y1 - pos_y;
|
||||
row_end = pos_y + g.box_h <= mask_p->y2 ? g.box_h : mask_p->y2 - pos_y + 1;
|
||||
} else {
|
||||
col_start = pos_x >= mask_p->x1 ? 0 : (mask_p->x1 - pos_x) * 3;
|
||||
col_end = pos_x + g.box_w / 3 <= mask_p->x2 ? g.box_w : (mask_p->x2 - pos_x + 1) * 3;
|
||||
row_start = pos_y >= mask_p->y1 ? 0 : mask_p->y1 - pos_y;
|
||||
row_end = pos_y + g.box_h <= mask_p->y2 ? g.box_h : mask_p->y2 - pos_y + 1;
|
||||
}
|
||||
|
||||
/*Set a pointer on VDB to the first pixel of the letter*/
|
||||
vdb_buf_tmp += ((pos_y - vdb->area.y1) * vdb_width) + pos_x - vdb->area.x1;
|
||||
|
||||
/*If the letter is partially out of mask the move there on VDB*/
|
||||
vdb_buf_tmp += (row_start * vdb_width) + col_start;
|
||||
if(subpx) vdb_buf_tmp += (row_start * vdb_width) + col_start / 3;
|
||||
else vdb_buf_tmp += (row_start * vdb_width) + col_start;
|
||||
|
||||
/*Move on the map too*/
|
||||
uint32_t bit_ofs = (row_start * width_bit) + (col_start * g.bpp);
|
||||
map_p += bit_ofs >> 3;
|
||||
|
||||
uint8_t letter_px;
|
||||
lv_opa_t px_opa;
|
||||
lv_opa_t px_opa = 0;
|
||||
uint16_t col_bit;
|
||||
col_bit = bit_ofs & 0x7; /* "& 0x7" equals to "% 8" just faster */
|
||||
|
||||
bool scr_transp = false;
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
#if LV_COLOR_DEPTH == 32 && LV_COLOR_SCREEN_TRANSP
|
||||
scr_transp = disp->driver.screen_transp;
|
||||
#endif
|
||||
|
||||
uint8_t font_rgb[3];
|
||||
uint8_t txt_rgb[3] = {LV_COLOR_GET_R(color), LV_COLOR_GET_G(color), LV_COLOR_GET_B(color)};
|
||||
|
||||
for(row = row_start; row < row_end; row++) {
|
||||
bitmask = bitmask_init >> col_bit;
|
||||
uint8_t sub_px_cnt = 0;
|
||||
for(col = col_start; col < col_end; col++) {
|
||||
letter_px = (*map_p & bitmask) >> (8 - col_bit - g.bpp);
|
||||
if(letter_px != 0) {
|
||||
if(opa == LV_OPA_COVER) {
|
||||
px_opa = g.bpp == 8 ? letter_px : bpp_opa_table[letter_px];
|
||||
} else {
|
||||
px_opa = g.bpp == 8 ? (uint16_t)((uint16_t)letter_px * opa) >> 8
|
||||
: (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8;
|
||||
}
|
||||
|
||||
if(disp->driver.set_px_cb) {
|
||||
disp->driver.set_px_cb(&disp->driver, (uint8_t *)vdb->buf_act, vdb_width,
|
||||
(col + pos_x) - vdb->area.x1, (row + pos_y) - vdb->area.y1, color, px_opa);
|
||||
} else if(vdb_buf_tmp->full != color.full) {
|
||||
if(px_opa > LV_OPA_MAX)
|
||||
*vdb_buf_tmp = color;
|
||||
else if(px_opa > LV_OPA_MIN) {
|
||||
if(scr_transp == false) {
|
||||
*vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, px_opa);
|
||||
} else {
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
*vdb_buf_tmp = color_mix_2_alpha(*vdb_buf_tmp, (*vdb_buf_tmp).ch.alpha, color, px_opa);
|
||||
/*subpx == 0*/
|
||||
if(subpx == false) {
|
||||
if(letter_px != 0) {
|
||||
if(opa == LV_OPA_COVER) {
|
||||
px_opa = g.bpp == 8 ? letter_px : bpp_opa_table[letter_px];
|
||||
} else {
|
||||
px_opa = g.bpp == 8 ? (uint16_t)((uint16_t)letter_px * opa) >> 8
|
||||
: (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8;
|
||||
}
|
||||
|
||||
if(disp->driver.set_px_cb) {
|
||||
disp->driver.set_px_cb(&disp->driver, (uint8_t *)vdb->buf_act, vdb_width,
|
||||
(col + pos_x) - vdb->area.x1, (row + pos_y) - vdb->area.y1, color, px_opa);
|
||||
} else if(vdb_buf_tmp->full != color.full) {
|
||||
if(px_opa > LV_OPA_MAX) {
|
||||
*vdb_buf_tmp = color;
|
||||
} else if(px_opa > LV_OPA_MIN) {
|
||||
if(scr_transp == false) {
|
||||
*vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, px_opa);
|
||||
} else {
|
||||
#if LV_COLOR_DEPTH == 32 && LV_COLOR_SCREEN_TRANSP
|
||||
*vdb_buf_tmp = color_mix_2_alpha(*vdb_buf_tmp, (*vdb_buf_tmp).ch.alpha, color, px_opa);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
vdb_buf_tmp++;
|
||||
}
|
||||
/*Handle subpx drawing*/
|
||||
else {
|
||||
if(letter_px != 0) {
|
||||
if(opa == LV_OPA_COVER) {
|
||||
px_opa = g.bpp == 8 ? letter_px : bpp_opa_table[letter_px];
|
||||
} else {
|
||||
px_opa = g.bpp == 8 ? (uint16_t)((uint16_t)letter_px * opa) >> 8
|
||||
: (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8;
|
||||
}
|
||||
|
||||
font_rgb[sub_px_cnt] = px_opa;
|
||||
} else {
|
||||
font_rgb[sub_px_cnt] = 0;
|
||||
}
|
||||
sub_px_cnt ++;
|
||||
|
||||
if(sub_px_cnt == 3) {
|
||||
lv_color_t res_color;
|
||||
|
||||
if(font_rgb[0] == 0 && font_rgb[1] == 0 && font_rgb[2] == 0) {
|
||||
res_color = *vdb_buf_tmp;
|
||||
} else {
|
||||
|
||||
uint8_t bg_rgb[3] = {LV_COLOR_GET_R(*vdb_buf_tmp), LV_COLOR_GET_G(*vdb_buf_tmp), LV_COLOR_GET_B(*vdb_buf_tmp)};
|
||||
|
||||
#if LV_FONT_SUBPX_BGR
|
||||
LV_COLOR_SET_B(res_color, (uint16_t)((uint16_t)txt_rgb[0] * font_rgb[0] + (bg_rgb[2] * (255 - font_rgb[0]))) >> 8);
|
||||
LV_COLOR_SET_R(res_color, (uint16_t)((uint16_t)txt_rgb[2] * font_rgb[2] + (bg_rgb[0] * (255 - font_rgb[2]))) >> 8);
|
||||
#else
|
||||
LV_COLOR_SET_R(res_color, (uint16_t)((uint16_t)txt_rgb[0] * font_rgb[0] + (bg_rgb[0] * (255 - font_rgb[0]))) >> 8);
|
||||
LV_COLOR_SET_B(res_color, (uint16_t)((uint16_t)txt_rgb[2] * font_rgb[2] + (bg_rgb[2] * (255 - font_rgb[2]))) >> 8);
|
||||
#endif
|
||||
LV_COLOR_SET_G(res_color, (uint16_t)((uint16_t)txt_rgb[1] * font_rgb[1] + (bg_rgb[1] * (255 - font_rgb[1]))) >> 8);
|
||||
}
|
||||
if(scr_transp == false) {
|
||||
vdb_buf_tmp->full = res_color.full;
|
||||
#if LV_COLOR_DEPTH == 32 && LV_COLOR_SCREEN_TRANSP
|
||||
} else {
|
||||
*vdb_buf_tmp = color_mix_2_alpha(*vdb_buf_tmp, (*vdb_buf_tmp).ch.alpha, color, px_opa);
|
||||
#endif
|
||||
}
|
||||
sub_px_cnt = 0;
|
||||
vdb_buf_tmp++;
|
||||
}
|
||||
}
|
||||
|
||||
vdb_buf_tmp++;
|
||||
|
||||
if(col_bit < 8 - g.bpp) {
|
||||
col_bit += g.bpp;
|
||||
@@ -362,11 +436,15 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, const lv
|
||||
map_p++;
|
||||
}
|
||||
}
|
||||
|
||||
col_bit += ((g.box_w - col_end) + col_start) * g.bpp;
|
||||
|
||||
map_p += (col_bit >> 3);
|
||||
col_bit = col_bit & 0x7;
|
||||
vdb_buf_tmp += vdb_width - (col_end - col_start); /*Next row in VDB*/
|
||||
|
||||
/*Next row in VDB*/
|
||||
if(subpx) vdb_buf_tmp += vdb_width - (col_end - col_start) / 3;
|
||||
else vdb_buf_tmp += vdb_width - (col_end - col_start);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,7 +507,7 @@ void lv_draw_map(const lv_area_t * cords_p, const lv_area_t * mask_p, const uint
|
||||
lv_coord_t map_useful_w = lv_area_get_width(&masked_a);
|
||||
|
||||
bool scr_transp = false;
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
#if LV_COLOR_DEPTH == 32 && LV_COLOR_SCREEN_TRANSP
|
||||
scr_transp = disp->driver.screen_transp;
|
||||
#endif
|
||||
|
||||
@@ -535,7 +613,7 @@ void lv_draw_map(const lv_area_t * cords_p, const lv_area_t * mask_p, const uint
|
||||
if(scr_transp == false) {
|
||||
vdb_buf_tmp[col] = lv_color_mix(px_color, vdb_buf_tmp[col], opa_result);
|
||||
} else {
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
#if LV_COLOR_DEPTH == 32 && LV_COLOR_SCREEN_TRANSP
|
||||
vdb_buf_tmp[col] = color_mix_2_alpha(vdb_buf_tmp[col], vdb_buf_tmp[col].ch.alpha,
|
||||
px_color, opa_result);
|
||||
#endif
|
||||
@@ -620,7 +698,7 @@ static void sw_color_fill(lv_color_t * mem, lv_coord_t mem_width, const lv_area_
|
||||
/*Calculate with alpha too*/
|
||||
else {
|
||||
bool scr_transp = false;
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
#if LV_COLOR_DEPTH == 32 && LV_COLOR_SCREEN_TRANSP
|
||||
scr_transp = disp->driver.screen_transp;
|
||||
#endif
|
||||
|
||||
@@ -638,7 +716,7 @@ static void sw_color_fill(lv_color_t * mem, lv_coord_t mem_width, const lv_area_
|
||||
mem[col] = opa_tmp;
|
||||
|
||||
} else {
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
#if LV_COLOR_DEPTH == 32 && LV_COLOR_SCREEN_TRANSP
|
||||
mem[col] = color_mix_2_alpha(mem[col], mem[col].ch.alpha, color, opa);
|
||||
#endif
|
||||
}
|
||||
@@ -649,6 +727,7 @@ static void sw_color_fill(lv_color_t * mem, lv_coord_t mem_width, const lv_area_
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_COLOR_DEPTH == 32 && LV_COLOR_SCREEN_TRANSP
|
||||
/**
|
||||
* Mix two colors. Both color can have alpha value. It requires ARGB888 colors.
|
||||
* @param bg_color background color
|
||||
@@ -659,8 +738,6 @@ static void sw_color_fill(lv_color_t * mem, lv_coord_t mem_width, const lv_area_
|
||||
*/
|
||||
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)
|
||||
{
|
||||
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
/* Pick the foreground if it's fully opaque or the Background is fully transparent*/
|
||||
if(fg_opa > LV_OPA_MAX || bg_opa <= LV_OPA_MIN) {
|
||||
fg_color.ch.alpha = fg_opa;
|
||||
@@ -702,13 +779,5 @@ static inline lv_color_t color_mix_2_alpha(lv_color_t bg_color, lv_opa_t bg_opa,
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#else
|
||||
(void)bg_color; /*Unused*/
|
||||
(void)fg_color; /*Unused*/
|
||||
(void)bg_opa; /*Unused*/
|
||||
(void)fg_opa; /*Unused*/
|
||||
|
||||
return LV_COLOR_BLACK;
|
||||
|
||||
#endif /*LV_COLOR_SCREEN_TRANSP*/
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "lv_draw_img.h"
|
||||
#include "lv_img_cache.h"
|
||||
#include "../lv_misc/lv_log.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -50,7 +51,7 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void *
|
||||
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, -1, -1, NULL);
|
||||
lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, "No\ndata", LV_TXT_FLAG_NONE, NULL, NULL, NULL, LV_BIDI_DIR_LTR);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,7 +61,7 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void *
|
||||
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, -1, -1, NULL);
|
||||
lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, "No\ndata", LV_TXT_FLAG_NONE, NULL, NULL, NULL, LV_BIDI_DIR_LTR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -78,7 +79,7 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void *
|
||||
lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, const lv_style_t * style)
|
||||
{
|
||||
lv_color_t p_color = LV_COLOR_BLACK;
|
||||
if(x >= dsc->header.w) {
|
||||
if(x >= (lv_coord_t)dsc->header.w) {
|
||||
x = dsc->header.w - 1;
|
||||
LV_LOG_WARN("lv_canvas_get_px: x is too large (out of canvas)");
|
||||
} else if(x < 0) {
|
||||
@@ -86,7 +87,7 @@ lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t
|
||||
LV_LOG_WARN("lv_canvas_get_px: x is < 0 (out of canvas)");
|
||||
}
|
||||
|
||||
if(y >= dsc->header.h) {
|
||||
if(y >= (lv_coord_t)dsc->header.h) {
|
||||
y = dsc->header.h - 1;
|
||||
LV_LOG_WARN("lv_canvas_get_px: y is too large (out of canvas)");
|
||||
} else if(y < 0) {
|
||||
@@ -109,21 +110,30 @@ lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t
|
||||
uint8_t bit = x & 0x7;
|
||||
x = x >> 3;
|
||||
|
||||
uint32_t px = (dsc->header.w >> 3) * y + x;
|
||||
/* Get the current pixel.
|
||||
* dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
|
||||
* so the possible real width are 8, 16, 24 ...*/
|
||||
uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
|
||||
p_color.full = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit);
|
||||
} else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) {
|
||||
buf_u8 += 4 * 4;
|
||||
uint8_t bit = (x & 0x3) * 2;
|
||||
x = x >> 2;
|
||||
|
||||
uint32_t px = (dsc->header.w >> 2) * y + x;
|
||||
/* Get the current pixel.
|
||||
* dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned
|
||||
* so the possible real width are 4, 8, 12 ...*/
|
||||
uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
|
||||
p_color.full = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit);
|
||||
} else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) {
|
||||
buf_u8 += 4 * 16;
|
||||
uint8_t bit = (x & 0x1) * 4;
|
||||
x = x >> 1;
|
||||
|
||||
uint32_t px = (dsc->header.w >> 1) * y + x;
|
||||
/* Get the current pixel.
|
||||
* dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned
|
||||
* so the possible real width are 2, 4, 6 ...*/
|
||||
uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
|
||||
p_color.full = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit);
|
||||
} else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
|
||||
buf_u8 += 4 * 256;
|
||||
@@ -148,7 +158,7 @@ lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t
|
||||
*/
|
||||
lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y)
|
||||
{
|
||||
if(x >= dsc->header.w) {
|
||||
if(x >= (lv_coord_t)dsc->header.w) {
|
||||
x = dsc->header.w - 1;
|
||||
LV_LOG_WARN("lv_canvas_get_px: x is too large (out of canvas)");
|
||||
} else if(x < 0) {
|
||||
@@ -156,7 +166,7 @@ lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y)
|
||||
LV_LOG_WARN("lv_canvas_get_px: x is < 0 (out of canvas)");
|
||||
}
|
||||
|
||||
if(y >= dsc->header.h) {
|
||||
if(y >= (lv_coord_t)dsc->header.h) {
|
||||
y = dsc->header.h - 1;
|
||||
LV_LOG_WARN("lv_canvas_get_px: y is too large (out of canvas)");
|
||||
} else if(y < 0) {
|
||||
@@ -173,7 +183,10 @@ lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y)
|
||||
uint8_t bit = x & 0x7;
|
||||
x = x >> 3;
|
||||
|
||||
uint32_t px = (dsc->header.w >> 3) * y + x;
|
||||
/* Get the current pixel.
|
||||
* dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
|
||||
* so the possible real width are 8 ,16, 24 ...*/
|
||||
uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
|
||||
uint8_t px_opa = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit);
|
||||
return px_opa ? LV_OPA_TRANSP : LV_OPA_COVER;
|
||||
} else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) {
|
||||
@@ -182,7 +195,10 @@ lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y)
|
||||
uint8_t bit = (x & 0x3) * 2;
|
||||
x = x >> 2;
|
||||
|
||||
uint32_t px = (dsc->header.w >> 2) * y + x;
|
||||
/* Get the current pixel.
|
||||
* dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned
|
||||
* so the possible real width are 4 ,8, 12 ...*/
|
||||
uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
|
||||
uint8_t px_opa = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit);
|
||||
return opa_table[px_opa];
|
||||
} else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) {
|
||||
@@ -192,7 +208,10 @@ lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y)
|
||||
uint8_t bit = (x & 0x1) * 4;
|
||||
x = x >> 1;
|
||||
|
||||
uint32_t px = (dsc->header.w >> 1) * y + x;
|
||||
/* Get the current pixel.
|
||||
* dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned
|
||||
* so the possible real width are 2 ,4, 6 ...*/
|
||||
uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
|
||||
uint8_t px_opa = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit);
|
||||
return opa_table[px_opa];
|
||||
} else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
|
||||
@@ -227,7 +246,11 @@ void lv_img_buf_set_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_
|
||||
|
||||
uint8_t bit = x & 0x7;
|
||||
x = x >> 3;
|
||||
uint32_t px = (dsc->header.w >> 3) * y + x;
|
||||
|
||||
/* Get the current pixel.
|
||||
* dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
|
||||
* so the possible real width are 8 ,16, 24 ...*/
|
||||
uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
|
||||
buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit));
|
||||
buf_u8[px] = buf_u8[px] | ((c.full & 0x1) << (7 - bit));
|
||||
} else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) {
|
||||
@@ -235,7 +258,10 @@ void lv_img_buf_set_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_
|
||||
uint8_t bit = (x & 0x3) * 2;
|
||||
x = x >> 2;
|
||||
|
||||
uint32_t px = (dsc->header.w >> 2) * y + x;
|
||||
/* Get the current pixel.
|
||||
* dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned
|
||||
* so the possible real width are 4, 8 ,12 ...*/
|
||||
uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
|
||||
|
||||
buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit));
|
||||
buf_u8[px] = buf_u8[px] | ((c.full & 0x3) << (6 - bit));
|
||||
@@ -244,7 +270,10 @@ void lv_img_buf_set_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_
|
||||
uint8_t bit = (x & 0x1) * 4;
|
||||
x = x >> 1;
|
||||
|
||||
uint32_t px = (dsc->header.w >> 1) * y + x;
|
||||
/* Get the current pixel.
|
||||
* dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned
|
||||
* so the possible real width are 2 ,4, 6 ...*/
|
||||
uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
|
||||
buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit));
|
||||
buf_u8[px] = buf_u8[px] | ((c.full & 0xF) << (4 - bit));
|
||||
} else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
|
||||
@@ -273,14 +302,22 @@ void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_
|
||||
opa = opa >> 7; /*opa -> [0,1]*/
|
||||
uint8_t bit = x & 0x7;
|
||||
x = x >> 3;
|
||||
uint32_t px = (dsc->header.w >> 3) * y + x;
|
||||
|
||||
/* Get the current pixel.
|
||||
* dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
|
||||
* so the possible real width are 8 ,16, 24 ...*/
|
||||
uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
|
||||
buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit));
|
||||
buf_u8[px] = buf_u8[px] | ((opa & 0x1) << (7 - bit));
|
||||
} else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) {
|
||||
opa = opa >> 6; /*opa -> [0,3]*/
|
||||
uint8_t bit = (x & 0x3) * 2;
|
||||
x = x >> 2;
|
||||
uint32_t px = (dsc->header.w >> 2) * y + x;
|
||||
|
||||
/* Get the current pixel.
|
||||
* dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned
|
||||
* so the possible real width are 4 ,8, 12 ...*/
|
||||
uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
|
||||
buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit));
|
||||
buf_u8[px] = buf_u8[px] | ((opa & 0x3) << (6 - bit));
|
||||
} else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) {
|
||||
@@ -288,7 +325,10 @@ void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_
|
||||
uint8_t bit = (x & 0x1) * 4;
|
||||
x = x >> 1;
|
||||
|
||||
uint32_t px = (dsc->header.w >> 1) * y + x;
|
||||
/* Get the current pixel.
|
||||
* dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned
|
||||
* so the possible real width are 2 ,4, 6 ...*/
|
||||
uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
|
||||
buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit));
|
||||
buf_u8[px] = buf_u8[px] | ((opa & 0xF) << (4 - bit));
|
||||
} else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
|
||||
@@ -362,10 +402,14 @@ 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:
|
||||
#if LV_INDEXED_CHROMA
|
||||
case LV_IMG_CF_INDEXED_1BIT:
|
||||
case LV_IMG_CF_INDEXED_2BIT:
|
||||
case LV_IMG_CF_INDEXED_4BIT:
|
||||
case LV_IMG_CF_INDEXED_8BIT: is_chroma_keyed = true; break;
|
||||
case LV_IMG_CF_INDEXED_8BIT:
|
||||
#endif
|
||||
is_chroma_keyed = true; break;
|
||||
|
||||
default: is_chroma_keyed = false; break;
|
||||
}
|
||||
|
||||
@@ -384,6 +428,10 @@ 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_INDEXED_1BIT:
|
||||
case LV_IMG_CF_INDEXED_2BIT:
|
||||
case LV_IMG_CF_INDEXED_4BIT:
|
||||
case LV_IMG_CF_INDEXED_8BIT:
|
||||
case LV_IMG_CF_ALPHA_1BIT:
|
||||
case LV_IMG_CF_ALPHA_2BIT:
|
||||
case LV_IMG_CF_ALPHA_4BIT:
|
||||
@@ -425,6 +473,66 @@ lv_img_src_t lv_img_src_get_type(const void * src)
|
||||
return img_src_type;
|
||||
}
|
||||
|
||||
lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
|
||||
{
|
||||
/* Allocate image descriptor */
|
||||
lv_img_dsc_t *dsc = lv_mem_alloc(sizeof(lv_img_dsc_t));
|
||||
if(dsc == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(dsc, 0, sizeof(lv_img_dsc_t));
|
||||
|
||||
/* Get image data size */
|
||||
dsc->data_size = lv_img_buf_get_img_size(w, h, cf);
|
||||
if(dsc->data_size == 0) {
|
||||
lv_mem_free(dsc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate raw buffer */
|
||||
dsc->data = lv_mem_alloc(dsc->data_size);
|
||||
if(dsc->data == NULL) {
|
||||
lv_mem_free(dsc);
|
||||
return NULL;
|
||||
}
|
||||
memset((uint8_t *)dsc->data, 0, dsc->data_size);
|
||||
|
||||
/* Fill in header */
|
||||
dsc->header.always_zero = 0;
|
||||
dsc->header.w = w;
|
||||
dsc->header.h = h;
|
||||
dsc->header.cf = cf;
|
||||
return dsc;
|
||||
}
|
||||
|
||||
void lv_img_buf_free(lv_img_dsc_t *dsc)
|
||||
{
|
||||
if(dsc != NULL) {
|
||||
if(dsc->data != NULL)
|
||||
lv_mem_free(dsc->data);
|
||||
|
||||
lv_mem_free(dsc);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
|
||||
{
|
||||
switch(cf) {
|
||||
case LV_IMG_CF_TRUE_COLOR: return LV_IMG_BUF_SIZE_TRUE_COLOR(w, h);
|
||||
case LV_IMG_CF_TRUE_COLOR_ALPHA: return LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h);
|
||||
case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: return LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h);
|
||||
case LV_IMG_CF_ALPHA_1BIT: return LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h);
|
||||
case LV_IMG_CF_ALPHA_2BIT: return LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h);
|
||||
case LV_IMG_CF_ALPHA_4BIT: return LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h);
|
||||
case LV_IMG_CF_ALPHA_8BIT: return LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h);
|
||||
case LV_IMG_CF_INDEXED_1BIT: return LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h);
|
||||
case LV_IMG_CF_INDEXED_2BIT: return LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h);
|
||||
case LV_IMG_CF_INDEXED_4BIT: return LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h);
|
||||
case LV_IMG_CF_INDEXED_8BIT: return LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -454,8 +562,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas
|
||||
if(cdsc->dec_dsc.error_msg != NULL) {
|
||||
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, cdsc->dec_dsc.error_msg, LV_TXT_FLAG_NONE, NULL, -1,
|
||||
-1, NULL);
|
||||
lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, cdsc->dec_dsc.error_msg, LV_TXT_FLAG_NONE, NULL, NULL, NULL, LV_BIDI_DIR_LTR);
|
||||
}
|
||||
/* The decoder open could open the image and gave the entire uncompressed image.
|
||||
* Just draw it!*/
|
||||
@@ -467,7 +574,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas
|
||||
else {
|
||||
lv_coord_t width = lv_area_get_width(&mask_com);
|
||||
|
||||
uint8_t * buf = lv_draw_get_buf(lv_area_get_width(&mask_com) * ((LV_COLOR_DEPTH >> 3) + 1)); /*+1 because of the possible alpha byte*/
|
||||
uint8_t * buf = lv_draw_get_buf(lv_area_get_width(&mask_com) * LV_IMG_PX_SIZE_ALPHA_BYTE); /*space for the possible alpha byte*/
|
||||
|
||||
lv_area_t line;
|
||||
lv_area_copy(&line, &mask_com);
|
||||
|
||||
@@ -20,6 +20,26 @@ extern "C" {
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#define LV_IMG_BUF_SIZE_TRUE_COLOR(w, h) ((LV_COLOR_SIZE / 8) * w * h)
|
||||
#define LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) ((LV_COLOR_SIZE / 8) * w * h)
|
||||
#define LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) (LV_IMG_PX_SIZE_ALPHA_BYTE * w * h)
|
||||
|
||||
/*+ 1: to be sure no fractional row*/
|
||||
#define LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) ((((w / 8) + 1) * h))
|
||||
#define LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) ((((w / 4) + 1) * h))
|
||||
#define LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) ((((w / 2) + 1) * h))
|
||||
#define LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) ((w * h))
|
||||
|
||||
/*4 * X: for palette*/
|
||||
#define LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) + 4 * 2)
|
||||
#define LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) + 4 * 4)
|
||||
#define LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) + 4 * 16)
|
||||
#define LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) + 4 * 256)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
@@ -120,9 +140,30 @@ 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
|
||||
**********************/
|
||||
/**
|
||||
* Allocate an image buffer in RAM
|
||||
* @param w width of image
|
||||
* @param h height of image
|
||||
* @param cf a color format (`LV_IMG_CF_...`)
|
||||
* @return an allocated image, or NULL on failure
|
||||
*/
|
||||
lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf);
|
||||
|
||||
/**
|
||||
* Free an allocated image buffer
|
||||
* @param dsc image buffer to free
|
||||
*/
|
||||
void lv_img_buf_free(lv_img_dsc_t *dsc);
|
||||
|
||||
/**
|
||||
* Get the memory consumption of a raw bitmap, given color format and dimensions.
|
||||
* @param w width
|
||||
* @param h height
|
||||
* @param cf color format
|
||||
* @return size in bytes
|
||||
*/
|
||||
uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*********************/
|
||||
#include "lv_draw_label.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
#include "../lv_misc/lv_bidi.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -51,15 +52,18 @@ static uint8_t hex_char_to_num(char hex);
|
||||
* @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)
|
||||
* @param sel_start start index of selected area (`LV_LABEL_TXT_SEL_OFF` if none)
|
||||
* @param sel_end end index of selected area (`LV_LABEL_TXT_SEL_OFF` if none)
|
||||
* @param sel make the text selected in the range by drawing a background there
|
||||
*/
|
||||
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, uint16_t sel_start, uint16_t sel_end,
|
||||
lv_draw_label_hint_t * hint)
|
||||
const char * txt, lv_txt_flag_t flag, lv_point_t * offset, lv_draw_label_txt_sel_t * sel,
|
||||
lv_draw_label_hint_t * hint, lv_bidi_dir_t bidi_dir)
|
||||
{
|
||||
const lv_font_t * font = style->text.font;
|
||||
lv_coord_t w;
|
||||
|
||||
/*No need to waste processor time if string is empty*/
|
||||
if (txt[0] == '\0') return;
|
||||
|
||||
if((flag & LV_TXT_FLAG_EXPAND) == 0) {
|
||||
/*Normally use the label's width as width*/
|
||||
w = lv_area_get_width(coords);
|
||||
@@ -67,7 +71,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
|
||||
/*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);
|
||||
flag);
|
||||
w = p.x;
|
||||
}
|
||||
|
||||
@@ -91,7 +95,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
|
||||
int32_t last_line_start = -1;
|
||||
|
||||
/*Check the hint to use the cached info*/
|
||||
if(hint && y_ofs == 0) {
|
||||
if(hint && y_ofs == 0 && coords->y1 < 0) {
|
||||
/*If the label changed too much recalculate the hint.*/
|
||||
if(LV_MATH_ABS(hint->coord_y - coords->y1) > LV_LABEL_HINT_UPDATE_TH - 2 * line_height) {
|
||||
hint->line_start = -1;
|
||||
@@ -105,6 +109,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
|
||||
pos.y += hint->y;
|
||||
}
|
||||
|
||||
|
||||
uint32_t line_end = line_start + lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag);
|
||||
|
||||
/*Go the first visible line*/
|
||||
@@ -139,6 +144,18 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
|
||||
|
||||
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->text.opa : (uint16_t)((uint16_t)style->text.opa * opa_scale) >> 8;
|
||||
|
||||
uint16_t sel_start = 0xFFFF;
|
||||
uint16_t sel_end = 0xFFFF;
|
||||
if(sel) {
|
||||
sel_start = sel->start;
|
||||
sel_end = sel->end;
|
||||
if(sel_start > sel_end) {
|
||||
uint16_t tmp = sel_start;
|
||||
sel_start = sel_end;
|
||||
sel_end = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
cmd_state_t cmd_state = CMD_STATE_WAIT;
|
||||
uint32_t i;
|
||||
uint16_t par_start = 0;
|
||||
@@ -155,12 +172,32 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
|
||||
}
|
||||
/*Write all letter of a line*/
|
||||
cmd_state = CMD_STATE_WAIT;
|
||||
i = line_start;
|
||||
i = 0;
|
||||
uint32_t letter;
|
||||
uint32_t letter_next;
|
||||
while(i < line_end) {
|
||||
letter = lv_txt_encoded_next(txt, &i);
|
||||
letter_next = lv_txt_encoded_next(&txt[i], NULL);
|
||||
#if LV_USE_BIDI
|
||||
char *bidi_txt = lv_draw_get_buf(line_end - line_start + 1);
|
||||
lv_bidi_process_paragraph(txt + line_start, bidi_txt, line_end - line_start, bidi_dir, NULL, 0);
|
||||
#else
|
||||
(void)bidi_dir;
|
||||
const char *bidi_txt = txt + line_start;
|
||||
#endif
|
||||
|
||||
while(i < line_end - line_start) {
|
||||
uint16_t logical_char_pos = 0;
|
||||
if(sel_start != 0xFFFF && sel_end != 0xFFFF) {
|
||||
#if LV_USE_BIDI
|
||||
logical_char_pos = lv_txt_encoded_get_char_id(txt, line_start);
|
||||
uint16_t t = lv_txt_encoded_get_char_id(bidi_txt, i);
|
||||
logical_char_pos += lv_bidi_get_logical_pos(bidi_txt, NULL, line_end - line_start, bidi_dir, t, NULL);
|
||||
#else
|
||||
logical_char_pos = lv_txt_encoded_get_char_id(txt, line_start + i);
|
||||
#endif
|
||||
}
|
||||
|
||||
letter = lv_txt_encoded_next(bidi_txt, &i);
|
||||
letter_next = lv_txt_encoded_next(&bidi_txt[i], NULL);
|
||||
|
||||
|
||||
/*Handle the re-color command*/
|
||||
if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
|
||||
@@ -183,7 +220,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
|
||||
/*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);
|
||||
memcpy(buf, &bidi_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]);
|
||||
@@ -206,9 +243,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
|
||||
letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
|
||||
if(sel_start != 0xFFFF && sel_end != 0xFFFF) {
|
||||
int char_ind = lv_encoded_get_char_id(txt, i);
|
||||
/*Do not draw the rectangle on the character at `sel_start`.*/
|
||||
if(char_ind > sel_start && char_ind <= sel_end) {
|
||||
if(logical_char_pos >= sel_start && logical_char_pos < sel_end) {
|
||||
lv_area_t sel_coords;
|
||||
sel_coords.x1 = pos.x;
|
||||
sel_coords.y1 = pos.y;
|
||||
@@ -217,6 +252,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
|
||||
lv_draw_rect(&sel_coords, mask, &sel_style, opa);
|
||||
}
|
||||
}
|
||||
|
||||
lv_draw_letter(&pos, mask, font, letter, color, opa);
|
||||
|
||||
if(letter_w > 0) {
|
||||
@@ -231,7 +267,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
|
||||
/*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);
|
||||
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;
|
||||
|
||||
@@ -239,7 +275,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
|
||||
/*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);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -269,13 +305,13 @@ static uint8_t hex_char_to_num(char hex)
|
||||
if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/
|
||||
|
||||
switch(hex) {
|
||||
case 'A': result = 10; break;
|
||||
case 'B': result = 11; break;
|
||||
case 'C': result = 12; break;
|
||||
case 'D': result = 13; break;
|
||||
case 'E': result = 14; break;
|
||||
case 'F': result = 15; break;
|
||||
default: result = 0; break;
|
||||
case 'A': result = 10; break;
|
||||
case 'B': result = 11; break;
|
||||
case 'C': result = 12; break;
|
||||
case 'D': result = 13; break;
|
||||
case 'E': result = 14; break;
|
||||
case 'F': result = 15; break;
|
||||
default: result = 0; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,15 +14,24 @@ extern "C" {
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw.h"
|
||||
#include "../lv_misc/lv_bidi.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_DRAW_LABEL_NO_TXT_SEL (0xFFFF)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t start;
|
||||
uint16_t end;
|
||||
}lv_draw_label_txt_sel_t;
|
||||
|
||||
|
||||
/** Store some info to speed up drawing of very large texts
|
||||
* It takes a lot of time to get the first visible character because
|
||||
* all the previous characters needs to be checked to calculate the positions.
|
||||
@@ -54,11 +63,11 @@ typedef struct {
|
||||
* @param flag settings for the text from 'txt_flag_t' enum
|
||||
* @param offset text offset in x and y direction (NULL if unused)
|
||||
* @param sel_start start index of selected area (`LV_LABEL_TXT_SEL_OFF` if none)
|
||||
* @param sel_end end index of selected area (`LV_LABEL_TXT_SEL_OFF` if none)
|
||||
* @param bidi_dir base direction of the text
|
||||
*/
|
||||
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, uint16_t sel_start, uint16_t sel_end,
|
||||
lv_draw_label_hint_t * hint);
|
||||
const char * txt, lv_txt_flag_t flag, lv_point_t * offset, lv_draw_label_txt_sel_t * sel,
|
||||
lv_draw_label_hint_t * hint, lv_bidi_dir_t bidi_dir);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
|
||||
@@ -83,10 +83,10 @@ void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv
|
||||
if(point1->x == point2->x && point1->y == point2->y) return;
|
||||
|
||||
/*Return if the points are out of the mask*/
|
||||
if(point1->x < mask->x1 && point2->x < mask->x1) return;
|
||||
if(point1->x > mask->x2 && point2->x > mask->x2) return;
|
||||
if(point1->y < mask->y1 && point2->y < mask->y1) return;
|
||||
if(point1->y > mask->y2 && point2->y > mask->y2) return;
|
||||
if(point1->x < mask->x1 - style->line.width && point2->x < mask->x1 - style->line.width) return;
|
||||
if(point1->x > mask->x2 + style->line.width && point2->x > mask->x2 + style->line.width) return;
|
||||
if(point1->y < mask->y1 - style->line.width && point2->y < mask->y1 - style->line.width) return;
|
||||
if(point1->y > mask->y2 + style->line.width && point2->y > mask->y2 + style->line.width) return;
|
||||
|
||||
line_draw_t main_line;
|
||||
lv_point_t p1;
|
||||
@@ -263,7 +263,8 @@ static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_
|
||||
/* 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*/
|
||||
|
||||
lv_point_t * pattern = lv_draw_get_buf(width * 2 * sizeof(lv_point_t));
|
||||
lv_coord_t pattern_size = width * 2;
|
||||
lv_point_t * pattern = lv_draw_get_buf(pattern_size * sizeof(lv_point_t));
|
||||
lv_coord_t i = 0;
|
||||
|
||||
/*Create a perpendicular pattern (a small line)*/
|
||||
@@ -274,7 +275,7 @@ static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_
|
||||
|
||||
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++) {
|
||||
for(i = 0; i < (lv_coord_t)pattern_size - 1; i++) {
|
||||
pattern[i].x = pattern_line.p_act.x;
|
||||
pattern[i].y = pattern_line.p_act.y;
|
||||
|
||||
|
||||
@@ -45,8 +45,7 @@ static void point_swap(lv_point_t * p1, lv_point_t * p2);
|
||||
*/
|
||||
void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
|
||||
{
|
||||
|
||||
/*Return is the triangle is degenerated*/
|
||||
/*Return if the triangle is degenerated*/
|
||||
if(points[0].x == points[1].x && points[0].y == points[1].y) return;
|
||||
if(points[1].x == points[2].x && points[1].y == points[2].y) return;
|
||||
if(points[0].x == points[2].x && points[0].y == points[2].y) return;
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "lv_img_cache.h"
|
||||
#include "lv_img_decoder.h"
|
||||
#include "lv_draw_img.h"
|
||||
#include "../lv_hal/lv_hal_tick.h"
|
||||
#include "../lv_misc/lv_gc.h"
|
||||
|
||||
@@ -79,7 +82,15 @@ lv_img_cache_entry_t * lv_img_cache_open(const void * src, const lv_style_t * st
|
||||
/*Is the image cached?*/
|
||||
lv_img_cache_entry_t * cached_src = NULL;
|
||||
for(i = 0; i < entry_cnt; i++) {
|
||||
if(cache[i].dec_dsc.src == src) {
|
||||
bool match = false;
|
||||
lv_img_src_t src_type = lv_img_src_get_type(cache[i].dec_dsc.src);
|
||||
if(src_type == LV_IMG_SRC_VARIABLE) {
|
||||
if(cache[i].dec_dsc.src == src && cache[i].dec_dsc.style == style) match = true;
|
||||
} else if(src_type == LV_IMG_SRC_FILE) {
|
||||
if(strcmp(cache[i].dec_dsc.src, src) == 0) match = true;
|
||||
}
|
||||
|
||||
if(match) {
|
||||
/* If opened increment its life.
|
||||
* Image difficult to open should live longer to keep avoid frequent their recaching.
|
||||
* Therefore increase `life` with `time_to_open`*/
|
||||
@@ -152,7 +163,7 @@ void lv_img_cache_set_size(uint16_t new_entry_cnt)
|
||||
|
||||
/*Reallocate the cache*/
|
||||
LV_GC_ROOT(_lv_img_cache_array) = lv_mem_alloc(sizeof(lv_img_cache_entry_t) * new_entry_cnt);
|
||||
lv_mem_assert(LV_GC_ROOT(_lv_img_cache_array));
|
||||
LV_ASSERT_MEM(LV_GC_ROOT(_lv_img_cache_array));
|
||||
if(LV_GC_ROOT(_lv_img_cache_array) == NULL) {
|
||||
entry_cnt = 0;
|
||||
return;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_img_decoder.h"
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_draw/lv_draw_img.h"
|
||||
#include "../lv_misc/lv_ll.h"
|
||||
#include "../lv_misc/lv_color.h"
|
||||
@@ -19,6 +20,8 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define CF_BUILT_IN_FIRST LV_IMG_CF_TRUE_COLOR
|
||||
#define CF_BUILT_IN_LAST LV_IMG_CF_ALPHA_8BIT
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -29,17 +32,12 @@ typedef struct
|
||||
lv_fs_file_t * f;
|
||||
#endif
|
||||
lv_color_t * palette;
|
||||
lv_opa_t * opa;
|
||||
} lv_img_decoder_built_in_data_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);
|
||||
static lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
|
||||
static lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x,
|
||||
lv_coord_t y, lv_coord_t len, uint8_t * buf);
|
||||
static void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
|
||||
static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
|
||||
lv_coord_t len, uint8_t * buf);
|
||||
static lv_res_t lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
|
||||
@@ -72,7 +70,7 @@ void lv_img_decoder_init(void)
|
||||
decoder = lv_img_decoder_create();
|
||||
if(decoder == NULL) {
|
||||
LV_LOG_WARN("lv_img_decoder_init: out of memory");
|
||||
lv_mem_assert(decoder);
|
||||
LV_ASSERT_MEM(decoder);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -122,10 +120,17 @@ lv_res_t lv_img_decoder_get_info(const char * src, lv_img_header_t * header)
|
||||
lv_res_t lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, const lv_style_t * style)
|
||||
{
|
||||
dsc->style = style;
|
||||
dsc->src = src;
|
||||
dsc->src_type = lv_img_src_get_type(src);
|
||||
dsc->user_data = NULL;
|
||||
|
||||
if(dsc->src_type == LV_IMG_SRC_FILE) {
|
||||
size_t fnlen = strlen(src);
|
||||
dsc->src = lv_mem_alloc(fnlen + 1);
|
||||
strcpy((char *)dsc->src, src);
|
||||
} else {
|
||||
dsc->src = src;
|
||||
}
|
||||
|
||||
lv_res_t res = LV_RES_INV;
|
||||
|
||||
lv_img_decoder_t * d;
|
||||
@@ -177,7 +182,14 @@ lv_res_t lv_img_decoder_read_line(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_c
|
||||
*/
|
||||
void lv_img_decoder_close(lv_img_decoder_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->decoder->close_cb) dsc->decoder->close_cb(dsc->decoder, dsc);
|
||||
if(dsc->decoder) {
|
||||
if(dsc->decoder->close_cb) dsc->decoder->close_cb(dsc->decoder, dsc);
|
||||
|
||||
if(dsc->src_type == LV_IMG_SRC_FILE) {
|
||||
lv_mem_free(dsc->src);
|
||||
dsc->src = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,7 +200,7 @@ lv_img_decoder_t * lv_img_decoder_create(void)
|
||||
{
|
||||
lv_img_decoder_t * decoder;
|
||||
decoder = lv_ll_ins_head(&LV_GC_ROOT(_lv_img_defoder_ll));
|
||||
lv_mem_assert(decoder);
|
||||
LV_ASSERT_MEM(decoder);
|
||||
if(decoder == NULL) return NULL;
|
||||
|
||||
memset(decoder, 0, sizeof(lv_img_decoder_t));
|
||||
@@ -246,16 +258,22 @@ void lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder, lv_img_decoder_clos
|
||||
decoder->close_cb = close_cb;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
|
||||
/**
|
||||
* Get info about a built-in image
|
||||
* @param decoder the decoder where this function belongs
|
||||
* @param src the image source: pointer to an `lv_img_dsc_t` variable, a file path or a symbol
|
||||
* @param header store the image data here
|
||||
* @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error.
|
||||
*/
|
||||
lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
|
||||
{
|
||||
(void)decoder; /*Unused*/
|
||||
|
||||
lv_img_src_t src_type = lv_img_src_get_type(src);
|
||||
if(src_type == LV_IMG_SRC_VARIABLE) {
|
||||
lv_img_cf_t cf = ((lv_img_dsc_t *)src)->header.cf;
|
||||
if(cf < CF_BUILT_IN_FIRST || cf > CF_BUILT_IN_LAST) return LV_RES_INV;
|
||||
|
||||
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;
|
||||
@@ -271,13 +289,8 @@ static lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const v
|
||||
lv_fs_close(&file);
|
||||
}
|
||||
|
||||
/*Create a dummy header on fs error*/
|
||||
if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) {
|
||||
header->w = LV_DPI;
|
||||
header->h = LV_DPI;
|
||||
header->cf = LV_IMG_CF_UNKNOWN;
|
||||
return LV_RES_INV;
|
||||
}
|
||||
if(header->cf < CF_BUILT_IN_FIRST || header->cf > CF_BUILT_IN_LAST) return LV_RES_INV;
|
||||
|
||||
}
|
||||
#endif
|
||||
else if(src_type == LV_IMG_SRC_SYMBOL) {
|
||||
@@ -295,7 +308,13 @@ static lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const v
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
static lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
|
||||
/**
|
||||
* Open a built in image
|
||||
* @param decoder the decoder where this function belongs
|
||||
* @param dsc pointer to decoder descriptor. `src`, `style` are already initialized in it.
|
||||
* @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error.
|
||||
*/
|
||||
lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
|
||||
{
|
||||
/*Open the file if it's a file*/
|
||||
if(dsc->src_type == LV_IMG_SRC_FILE) {
|
||||
@@ -316,7 +335,7 @@ static lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_
|
||||
dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t));
|
||||
if(dsc->user_data == NULL) {
|
||||
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
|
||||
lv_mem_assert(dsc->user_data);
|
||||
LV_ASSERT_MEM(dsc->user_data);
|
||||
}
|
||||
memset(dsc->user_data, 0, sizeof(lv_img_decoder_built_in_data_t));
|
||||
}
|
||||
@@ -325,7 +344,7 @@ static lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_
|
||||
user_data->f = lv_mem_alloc(sizeof(f));
|
||||
if(user_data->f == NULL) {
|
||||
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
|
||||
lv_mem_assert(user_data->f);
|
||||
LV_ASSERT_MEM(user_data->f);
|
||||
}
|
||||
|
||||
memcpy(user_data->f, &f, sizeof(f));
|
||||
@@ -363,17 +382,18 @@ static lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_
|
||||
dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t));
|
||||
if(dsc->user_data == NULL) {
|
||||
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
|
||||
lv_mem_assert(dsc->user_data);
|
||||
LV_ASSERT_MEM(dsc->user_data);
|
||||
}
|
||||
memset(dsc->user_data, 0, sizeof(lv_img_decoder_built_in_data_t));
|
||||
}
|
||||
|
||||
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
|
||||
user_data->palette = lv_mem_alloc(palette_size * sizeof(lv_color_t));
|
||||
if(user_data->palette == NULL) {
|
||||
user_data->opa = lv_mem_alloc(palette_size * sizeof(lv_opa_t));
|
||||
if(user_data->palette == NULL || user_data->opa == NULL) {
|
||||
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
|
||||
#if LV_USE_FILESYSTEM
|
||||
lv_mem_assert(user_data->f);
|
||||
LV_ASSERT_MEM(user_data->f);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -381,7 +401,13 @@ static lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_
|
||||
/*Read the palette from file*/
|
||||
#if LV_USE_FILESYSTEM
|
||||
lv_fs_seek(user_data->f, 4); /*Skip the header*/
|
||||
lv_fs_read(user_data->f, user_data->palette, palette_size * sizeof(lv_color_t), NULL);
|
||||
lv_color32_t cur_color;
|
||||
uint32_t i;
|
||||
for(i = 0; i < palette_size; i++) {
|
||||
lv_fs_read(user_data->f, &cur_color, sizeof(lv_color32_t), NULL);
|
||||
user_data->palette[i] = lv_color_make(cur_color.ch.red, cur_color.ch.green, cur_color.ch.blue);
|
||||
user_data->opa[i] = cur_color.ch.alpha;
|
||||
}
|
||||
#else
|
||||
LV_LOG_WARN("Image built-in decoder can read the palette because LV_USE_FILESYSTEM = 0");
|
||||
return LV_RES_INV;
|
||||
@@ -393,6 +419,7 @@ static lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_
|
||||
uint32_t i;
|
||||
for(i = 0; i < palette_size; i++) {
|
||||
user_data->palette[i] = lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue);
|
||||
user_data->opa[i] = palette_p[i].ch.alpha;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,7 +451,18 @@ static lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_
|
||||
}
|
||||
}
|
||||
|
||||
static lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x,
|
||||
/**
|
||||
* 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 decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
* @param x start x coordinate
|
||||
* @param y start 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
|
||||
*/
|
||||
lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x,
|
||||
lv_coord_t y, lv_coord_t len, uint8_t * buf)
|
||||
{
|
||||
(void)decoder; /*Unused*/
|
||||
@@ -453,7 +491,12 @@ static lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv
|
||||
return res;
|
||||
}
|
||||
|
||||
static void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
|
||||
/**
|
||||
* Close the pending decoding. Free resources etc.
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
*/
|
||||
void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
|
||||
{
|
||||
(void)decoder; /*Unused*/
|
||||
|
||||
@@ -466,6 +509,7 @@ static void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_dec
|
||||
}
|
||||
#endif
|
||||
if(user_data->palette) lv_mem_free(user_data->palette);
|
||||
if(user_data->opa) lv_mem_free(user_data->opa);
|
||||
|
||||
lv_mem_free(user_data);
|
||||
|
||||
@@ -473,6 +517,11 @@ static void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_dec
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
|
||||
lv_coord_t len, uint8_t * buf)
|
||||
{
|
||||
@@ -673,13 +722,24 @@ static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc,
|
||||
#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] = user_data->palette[val_act];
|
||||
val_act = (*data_tmp & (mask << pos)) >> pos;
|
||||
|
||||
lv_color_t color = user_data->palette[val_act];
|
||||
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = 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] = color.full & 0xFF;
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (color.full >> 8) & 0xFF;
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
*((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = color.full;
|
||||
#else
|
||||
#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
|
||||
#endif
|
||||
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = user_data->opa[val_act];
|
||||
|
||||
pos -= px_size;
|
||||
if(pos < 0) {
|
||||
|
||||
@@ -93,6 +93,25 @@ enum {
|
||||
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*/
|
||||
|
||||
LV_IMG_CF_RESERVED_15, /**< Reserved for further use. */
|
||||
LV_IMG_CF_RESERVED_16, /**< Reserved for further use. */
|
||||
LV_IMG_CF_RESERVED_17, /**< Reserved for further use. */
|
||||
LV_IMG_CF_RESERVED_18, /**< Reserved for further use. */
|
||||
LV_IMG_CF_RESERVED_19, /**< Reserved for further use. */
|
||||
LV_IMG_CF_RESERVED_20, /**< Reserved for further use. */
|
||||
LV_IMG_CF_RESERVED_21, /**< Reserved for further use. */
|
||||
LV_IMG_CF_RESERVED_22, /**< Reserved for further use. */
|
||||
LV_IMG_CF_RESERVED_23, /**< Reserved for further use. */
|
||||
|
||||
LV_IMG_CF_USER_ENCODED_0, /**< User holder encoding format. */
|
||||
LV_IMG_CF_USER_ENCODED_1, /**< User holder encoding format. */
|
||||
LV_IMG_CF_USER_ENCODED_2, /**< User holder encoding format. */
|
||||
LV_IMG_CF_USER_ENCODED_3, /**< User holder encoding format. */
|
||||
LV_IMG_CF_USER_ENCODED_4, /**< User holder encoding format. */
|
||||
LV_IMG_CF_USER_ENCODED_5, /**< User holder encoding format. */
|
||||
LV_IMG_CF_USER_ENCODED_6, /**< User holder encoding format. */
|
||||
LV_IMG_CF_USER_ENCODED_7, /**< User holder encoding format. */
|
||||
};
|
||||
typedef uint8_t lv_img_cf_t;
|
||||
|
||||
@@ -287,6 +306,46 @@ void lv_img_decoder_set_read_line_cb(lv_img_decoder_t * decoder, lv_img_decoder_
|
||||
*/
|
||||
void lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder, lv_img_decoder_close_f_t close_cb);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get info about a built-in image
|
||||
* @param decoder the decoder where this function belongs
|
||||
* @param src the image source: pointer to an `lv_img_dsc_t` variable, a file path or a symbol
|
||||
* @param header store the image data here
|
||||
* @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error.
|
||||
*/
|
||||
lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);
|
||||
|
||||
/**
|
||||
* Open a built in image
|
||||
* @param decoder the decoder where this function belongs
|
||||
* @param dsc pointer to decoder descriptor. `src`, `style` are already initialized in it.
|
||||
* @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error.
|
||||
*/
|
||||
lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* 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 decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
* @param x start x coordinate
|
||||
* @param y start 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
|
||||
*/
|
||||
lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x,
|
||||
lv_coord_t y, lv_coord_t len, uint8_t * buf);
|
||||
|
||||
/**
|
||||
* Close the pending decoding. Free resources etc.
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
*/
|
||||
void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -53,7 +53,18 @@ typedef struct
|
||||
uint8_t bpp; /**< Bit-per-pixel: 1, 2, 4, 8*/
|
||||
}lv_font_glyph_dsc_t;
|
||||
|
||||
/*Describe the properties of a font*/
|
||||
|
||||
/** The bitmaps might be upscaled by 3 to achieve subpixel rendering. */
|
||||
enum {
|
||||
LV_FONT_SUBPX_NONE,
|
||||
LV_FONT_SUBPX_HOR,
|
||||
LV_FONT_SUBPX_VER,
|
||||
LV_FONT_SUBPX_BOTH,
|
||||
};
|
||||
|
||||
typedef uint8_t lv_font_subpx_t;
|
||||
|
||||
/** Describe the properties of a font*/
|
||||
typedef struct _lv_font_struct
|
||||
{
|
||||
/** Get a glyph's descriptor from a font*/
|
||||
@@ -64,11 +75,14 @@ typedef struct _lv_font_struct
|
||||
|
||||
/*Pointer to the font in a font pack (must have the same line height)*/
|
||||
uint8_t line_height; /**< The real line height where any text fits*/
|
||||
uint8_t base_line; /**< Base line measured from the top of the line_height*/
|
||||
void * dsc; /**< Store implementation specific data here*/
|
||||
int8_t base_line; /**< Base line measured from the top of the line_height*/
|
||||
uint8_t subpx :2; /**< An element of `lv_font_subpx_t`*/
|
||||
void * dsc; /**< Store implementation specific or run_time data or caching here*/
|
||||
#if LV_USE_USER_DATA
|
||||
lv_font_user_data_t user_data; /**< Custom user data for font. */
|
||||
#endif
|
||||
|
||||
|
||||
} lv_font_t;
|
||||
|
||||
/**********************
|
||||
|
||||
@@ -4,6 +4,7 @@ CSRCS += lv_font_roboto_12.c
|
||||
CSRCS += lv_font_roboto_16.c
|
||||
CSRCS += lv_font_roboto_22.c
|
||||
CSRCS += lv_font_roboto_28.c
|
||||
CSRCS += lv_font_unscii_8.c
|
||||
|
||||
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/src/lv_font
|
||||
VPATH += :$(LVGL_DIR)/lvgl/src/lv_font
|
||||
|
||||
@@ -6,11 +6,14 @@
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_font.h"
|
||||
#include "lv_font_fmt_txt.h"
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_misc/lv_types.h"
|
||||
#include "../lv_misc/lv_log.h"
|
||||
#include "../lv_misc/lv_utils.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -19,6 +22,11 @@
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef enum {
|
||||
RLE_STATE_SINGLE = 0,
|
||||
RLE_STATE_REPEATE,
|
||||
RLE_STATE_COUNTER,
|
||||
}rle_state_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
@@ -29,10 +37,25 @@ static int32_t unicode_list_compare(const void * ref, const void * element);
|
||||
static int32_t kern_pair_8_compare(const void * ref, const void * element);
|
||||
static int32_t kern_pair_16_compare(const void * ref, const void * element);
|
||||
|
||||
static void decompress(const uint8_t * in, uint8_t * out, lv_coord_t w, lv_coord_t h, uint8_t bpp);
|
||||
static void decompress_line(uint8_t * out, lv_coord_t w);
|
||||
static uint8_t get_bits(const uint8_t * in, uint32_t bit_pos, uint8_t len);
|
||||
static void bits_write(uint8_t * out, uint32_t bit_pos, uint8_t val, uint8_t len);
|
||||
static void rle_init(const uint8_t * in, uint8_t bpp);
|
||||
static uint8_t rle_next(void);
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static uint32_t rle_rdp;
|
||||
static const uint8_t * rle_in;
|
||||
static uint8_t rle_bpp;
|
||||
static uint8_t rle_prev_v;
|
||||
static uint8_t rle_cnt;
|
||||
static rle_state_t rle_state;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
@@ -55,11 +78,38 @@ const uint8_t * lv_font_get_bitmap_fmt_txt(const lv_font_t * font, uint32_t unic
|
||||
{
|
||||
lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
|
||||
uint32_t gid = get_glyph_dsc_id(font, unicode_letter);
|
||||
if(!gid) return false;
|
||||
if(!gid) return NULL;
|
||||
|
||||
const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid];
|
||||
|
||||
if(gdsc) return &fdsc->glyph_bitmap[gdsc->bitmap_index];
|
||||
if(fdsc->bitmap_format == LV_FONT_FMT_TXT_PLAIN) {
|
||||
if(gdsc) return &fdsc->glyph_bitmap[gdsc->bitmap_index];
|
||||
}
|
||||
/*Handle compressed bitmap*/
|
||||
else
|
||||
{
|
||||
static uint8_t * buf = NULL;
|
||||
|
||||
uint32_t gsize = gdsc->box_w * gdsc->box_h;
|
||||
if(gsize == 0) return NULL;
|
||||
|
||||
uint32_t buf_size = gsize;
|
||||
switch(fdsc->bpp) {
|
||||
case 1: buf_size = gsize >> 3; break;
|
||||
case 2: buf_size = gsize >> 2; break;
|
||||
case 3: buf_size = gsize >> 1; break;
|
||||
case 4: buf_size = gsize >> 1; break;
|
||||
}
|
||||
|
||||
if(lv_mem_get_size(buf) < buf_size) {
|
||||
buf = lv_mem_realloc(buf, buf_size);
|
||||
LV_ASSERT_MEM(buf);
|
||||
if(buf == NULL) return NULL;
|
||||
}
|
||||
|
||||
decompress(&fdsc->glyph_bitmap[gdsc->bitmap_index], buf, gdsc->box_w , gdsc->box_h, (uint8_t)fdsc->bpp);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*If not returned earlier then the letter is not found in this font*/
|
||||
return NULL;
|
||||
@@ -90,7 +140,9 @@ bool lv_font_get_glyph_dsc_fmt_txt(const lv_font_t * font, lv_font_glyph_dsc_t *
|
||||
/*Put together a glyph dsc*/
|
||||
const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid];
|
||||
|
||||
uint32_t adv_w = gdsc->adv_w + ((int32_t)((int32_t)kvalue * fdsc->kern_scale) >> 4);
|
||||
int32_t kv = ((int32_t)((int32_t)kvalue * fdsc->kern_scale) >> 4);
|
||||
|
||||
uint32_t adv_w = gdsc->adv_w + kv;
|
||||
adv_w = (adv_w + (1 << 3)) >> 4;
|
||||
|
||||
dsc_out->adv_w = adv_w;
|
||||
@@ -98,7 +150,7 @@ bool lv_font_get_glyph_dsc_fmt_txt(const lv_font_t * font, lv_font_glyph_dsc_t *
|
||||
dsc_out->box_w = gdsc->box_w;
|
||||
dsc_out->ofs_x = gdsc->ofs_x;
|
||||
dsc_out->ofs_y = gdsc->ofs_y;
|
||||
dsc_out->bpp = fdsc->bpp;
|
||||
dsc_out->bpp = (uint8_t)fdsc->bpp;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -113,7 +165,7 @@ static uint32_t get_glyph_dsc_id(const lv_font_t * font, uint32_t letter)
|
||||
|
||||
lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
|
||||
|
||||
/*Check the chacge first*/
|
||||
/*Check the cache first*/
|
||||
if(letter == fdsc->last_letter) return fdsc->last_glyph_id;
|
||||
|
||||
uint16_t i;
|
||||
@@ -134,7 +186,7 @@ static uint32_t get_glyph_dsc_id(const lv_font_t * font, uint32_t letter)
|
||||
uint8_t * p = lv_utils_bsearch(&rcp, fdsc->cmaps[i].unicode_list, fdsc->cmaps[i].list_length, sizeof(fdsc->cmaps[i].unicode_list[0]), unicode_list_compare);
|
||||
|
||||
if(p) {
|
||||
uint32_t ofs = (uintptr_t)p - (uintptr_t) fdsc->cmaps[i].unicode_list;
|
||||
lv_uintptr_t ofs = (lv_uintptr_t)(p - (uint8_t *) fdsc->cmaps[i].unicode_list);
|
||||
ofs = ofs >> 1; /*The list stores `uint16_t` so the get the index divide by 2*/
|
||||
glyph_id = fdsc->cmaps[i].glyph_id_start + ofs;
|
||||
}
|
||||
@@ -143,7 +195,7 @@ static uint32_t get_glyph_dsc_id(const lv_font_t * font, uint32_t letter)
|
||||
uint8_t * p = lv_utils_bsearch(&rcp, fdsc->cmaps[i].unicode_list, fdsc->cmaps[i].list_length, sizeof(fdsc->cmaps[i].unicode_list[0]), unicode_list_compare);
|
||||
|
||||
if(p) {
|
||||
uint32_t ofs = (uintptr_t)p - (uintptr_t) fdsc->cmaps[i].unicode_list;
|
||||
lv_uintptr_t ofs = (lv_uintptr_t)(p - (uint8_t*) fdsc->cmaps[i].unicode_list);
|
||||
ofs = ofs >> 1; /*The list stores `uint16_t` so the get the index divide by 2*/
|
||||
const uint8_t * gid_ofs_16 = fdsc->cmaps[i].glyph_id_ofs_list;
|
||||
glyph_id = fdsc->cmaps[i].glyph_id_start + gid_ofs_16[ofs];
|
||||
@@ -180,7 +232,7 @@ static int8_t get_kern_value(const lv_font_t * font, uint32_t gid_left, uint32_t
|
||||
|
||||
/*If the `g_id_both` were found get its index from the pointer*/
|
||||
if(kid_p) {
|
||||
uintptr_t ofs = (uintptr_t)kid_p - (uintptr_t)g_ids;
|
||||
lv_uintptr_t ofs = (lv_uintptr_t)(kid_p - g_ids);
|
||||
ofs = ofs >> 1; /*ofs is for pair, divide by 2 to refer as a single value*/
|
||||
value = kdsc->values[ofs];
|
||||
}
|
||||
@@ -188,12 +240,12 @@ static int8_t get_kern_value(const lv_font_t * font, uint32_t gid_left, uint32_t
|
||||
/* Use binary search to find the kern value.
|
||||
* The pairs are ordered left_id first, then right_id secondly. */
|
||||
const uint16_t * g_ids = kdsc->glyph_ids;
|
||||
uint32_t g_id_both = (uint32_t)((uint32_t)gid_right << 8) + gid_left; /*Create one number from the ids*/
|
||||
lv_uintptr_t g_id_both = (uint32_t)((uint32_t)gid_right << 8) + gid_left; /*Create one number from the ids*/
|
||||
uint8_t * kid_p = lv_utils_bsearch(&g_id_both, g_ids, kdsc->pair_cnt, 4, kern_pair_16_compare);
|
||||
|
||||
/*If the `g_id_both` were found get its index from the pointer*/
|
||||
if(kid_p) {
|
||||
uintptr_t ofs = (uintptr_t)kid_p - (uintptr_t)g_ids;
|
||||
lv_uintptr_t ofs = (lv_uintptr_t) (kid_p - (const uint8_t *)g_ids);
|
||||
ofs = ofs >> 4; /*ofs is 4 byte pairs, divide by 4 to refer as a single value*/
|
||||
value = kdsc->values[ofs];
|
||||
}
|
||||
@@ -205,7 +257,7 @@ static int8_t get_kern_value(const lv_font_t * font, uint32_t gid_left, uint32_t
|
||||
/*Kern classes*/
|
||||
const lv_font_fmt_txt_kern_classes_t * kdsc = fdsc->kern_dsc;
|
||||
uint8_t left_class = kdsc->left_class_mapping[gid_left];
|
||||
uint8_t right_class = kdsc->left_class_mapping[gid_right];
|
||||
uint8_t right_class = kdsc->right_class_mapping[gid_right];
|
||||
|
||||
/* If class = 0, kerning not exist for that glyph
|
||||
* else got the value form `class_pair_values` 2D array*/
|
||||
@@ -238,6 +290,176 @@ static int32_t kern_pair_16_compare(const void * ref, const void * element)
|
||||
else return (int32_t) ref16_p[1] - element16_p[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* The compress a glyph's bitmap
|
||||
* @param in the compressed bitmap
|
||||
* @param out buffer to store the result
|
||||
* @param px_num number of pixels in the glyph (width * height)
|
||||
* @param bpp bit per pixel (bpp = 3 will be converted to bpp = 4)
|
||||
*/
|
||||
static void decompress(const uint8_t * in, uint8_t * out, lv_coord_t w, lv_coord_t h, uint8_t bpp)
|
||||
{
|
||||
uint32_t wrp = 0;
|
||||
uint8_t wr_size = bpp;
|
||||
if(bpp == 3) wr_size = 4;
|
||||
|
||||
rle_init(in, bpp);
|
||||
|
||||
uint8_t * line_buf = lv_draw_get_buf(w * 2);
|
||||
uint8_t * line_buf1 = line_buf;
|
||||
uint8_t * line_buf2 = line_buf + w;
|
||||
|
||||
decompress_line(line_buf1, w);
|
||||
|
||||
lv_coord_t y;
|
||||
lv_coord_t x;
|
||||
for(x = 0; x < w; x++) {
|
||||
bits_write(out,wrp, line_buf1[x], bpp);
|
||||
wrp += wr_size;
|
||||
}
|
||||
|
||||
for(y = 1; y < h; y++) {
|
||||
decompress_line(line_buf2, w);
|
||||
|
||||
for(x = 0; x < w; x++) {
|
||||
line_buf1[x] = line_buf2[x] ^ line_buf1[x];
|
||||
bits_write(out,wrp, line_buf1[x], bpp);
|
||||
wrp += wr_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompress one line. Store one pixel per byte
|
||||
* @param out output buffer
|
||||
* @param w width of the line in pixel count
|
||||
*/
|
||||
static void decompress_line(uint8_t * out, lv_coord_t w)
|
||||
{
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < w; i++) {
|
||||
out[i] = rle_next();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read bits from an input buffer. The read can cross byte boundary.
|
||||
* @param in the input buffer to read from.
|
||||
* @param bit_pos index of teh first bit to read.
|
||||
* @param len number of bits to read (must be <= 8).
|
||||
* @return the read bits
|
||||
*/
|
||||
static uint8_t get_bits(const uint8_t * in, uint32_t bit_pos, uint8_t len)
|
||||
{
|
||||
uint8_t res = 0;
|
||||
uint32_t byte_pos = bit_pos >> 3;
|
||||
bit_pos = bit_pos & 0x7;
|
||||
uint8_t bit_mask = (uint16_t)((uint16_t) 1 << len) - 1;
|
||||
uint16_t in16 = (in[byte_pos] << 8) + in[byte_pos + 1];
|
||||
|
||||
res = (in16 >> (16 - bit_pos - len)) & bit_mask;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `val` data to `bit_pos` position of `out`. The write can NOT cross byte boundary.
|
||||
* @param out buffer where to write
|
||||
* @param bit_pos bit index to write
|
||||
* @param val value to write
|
||||
* @param len length of bits to write from `val`. (Counted from the LSB).
|
||||
* @note `len == 3` will be converted to `len = 4` and `val` will be upscaled too
|
||||
*/
|
||||
static void bits_write(uint8_t * out, uint32_t bit_pos, uint8_t val, uint8_t len)
|
||||
{
|
||||
if(len == 3) {
|
||||
len = 4;
|
||||
switch(val) {
|
||||
case 0: val = 0; break;
|
||||
case 1: val = 2; break;
|
||||
case 2: val = 4; break;
|
||||
case 3: val = 6; break;
|
||||
case 4: val = 9; break;
|
||||
case 5: val = 11; break;
|
||||
case 6: val = 13; break;
|
||||
case 7: val = 15; break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t byte_pos = bit_pos >> 3;
|
||||
bit_pos = bit_pos & 0x7;
|
||||
bit_pos = 8 - bit_pos - len;
|
||||
|
||||
uint8_t bit_mask = (uint16_t)((uint16_t) 1 << len) - 1;
|
||||
out[byte_pos] &= ((~bit_mask) << bit_pos);
|
||||
out[byte_pos] |= (val << bit_pos);
|
||||
}
|
||||
|
||||
static void rle_init(const uint8_t * in, uint8_t bpp)
|
||||
{
|
||||
rle_in = in;
|
||||
rle_bpp = bpp;
|
||||
rle_state = RLE_STATE_SINGLE;
|
||||
rle_rdp = 0;
|
||||
rle_prev_v = 0;
|
||||
rle_cnt = 0;
|
||||
}
|
||||
|
||||
static uint8_t rle_next(void)
|
||||
{
|
||||
uint8_t v = 0;
|
||||
uint8_t ret = 0;
|
||||
|
||||
if(rle_state == RLE_STATE_SINGLE) {
|
||||
ret = get_bits(rle_in, rle_rdp, rle_bpp);
|
||||
if(rle_rdp != 0 && rle_prev_v == ret) {
|
||||
rle_cnt = 0;
|
||||
rle_state = RLE_STATE_REPEATE;
|
||||
}
|
||||
|
||||
rle_prev_v = ret;
|
||||
rle_rdp += rle_bpp;
|
||||
}
|
||||
else if(rle_state == RLE_STATE_REPEATE) {
|
||||
v = get_bits(rle_in, rle_rdp, 1);
|
||||
rle_cnt++;
|
||||
rle_rdp += 1;
|
||||
if(v == 1) {
|
||||
ret = rle_prev_v;
|
||||
if(rle_cnt == 11) {
|
||||
rle_cnt = get_bits(rle_in, rle_rdp, 6);
|
||||
rle_rdp += 6;
|
||||
if(rle_cnt != 0) {
|
||||
rle_state = RLE_STATE_COUNTER;
|
||||
} else {
|
||||
ret = get_bits(rle_in, rle_rdp, rle_bpp);
|
||||
rle_prev_v = ret;
|
||||
rle_rdp += rle_bpp;
|
||||
rle_state = RLE_STATE_SINGLE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = get_bits(rle_in, rle_rdp, rle_bpp);
|
||||
rle_prev_v = ret;
|
||||
rle_rdp += rle_bpp;
|
||||
rle_state = RLE_STATE_SINGLE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if(rle_state == RLE_STATE_COUNTER) {
|
||||
ret = rle_prev_v;
|
||||
rle_cnt--;
|
||||
if(rle_cnt == 0) {
|
||||
ret = get_bits(rle_in, rle_rdp, rle_bpp);
|
||||
rle_prev_v = ret;
|
||||
rle_rdp += rle_bpp;
|
||||
rle_state = RLE_STATE_SINGLE;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Code Comparator.
|
||||
*
|
||||
* Compares the value of both input arguments.
|
||||
@@ -253,5 +475,5 @@ static int32_t kern_pair_16_compare(const void * ref, const void * element)
|
||||
*/
|
||||
static int32_t unicode_list_compare(const void * ref, const void * element)
|
||||
{
|
||||
return (*(uint16_t *)ref) - (*(uint16_t *)element);
|
||||
return ((int32_t)(*(uint16_t *)ref)) - ((int32_t)(*(uint16_t *)element));
|
||||
}
|
||||
|
||||
@@ -35,23 +35,29 @@ extern "C" {
|
||||
/** This describes a glyph. */
|
||||
typedef struct
|
||||
{
|
||||
#if LV_FONT_FMT_TXT_LARGE == 0
|
||||
uint32_t bitmap_index : 20; /**< Start index of the bitmap. A font can be max 1 MB. */
|
||||
uint32_t adv_w :12; /**< Draw the next glyph after this width. 12.4 format (real_value * 16 is stored). */
|
||||
|
||||
uint32_t adv_w :12; /**< Draw the next glyph after this width. 8.4 format (real_value * 16 is stored). */
|
||||
#else
|
||||
uint32_t bitmap_index; /**< Start index of the bitmap. A font can be max 4 GB. */
|
||||
uint32_t adv_w; /**< Draw the next glyph after this width. 28.4 format (real_value * 16 is stored). */
|
||||
#endif
|
||||
uint8_t box_w; /**< Width of the glyph's bounding box*/
|
||||
uint8_t box_h; /**< Height of the glyph's bounding box*/
|
||||
int8_t ofs_x; /**< x offset of the bounding box*/
|
||||
uint8_t ofs_y; /**< y offset of the bounding box. Measured from the top of the line*/
|
||||
int8_t ofs_y; /**< y offset of the bounding box. Measured from the top of the line*/
|
||||
}lv_font_fmt_txt_glyph_dsc_t;
|
||||
|
||||
|
||||
/** Format of font character map. */
|
||||
typedef enum {
|
||||
enum {
|
||||
LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY,
|
||||
LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL,
|
||||
LV_FONT_FMT_TXT_CMAP_SPARSE_TINY,
|
||||
LV_FONT_FMT_TXT_CMAP_SPARSE_FULL,
|
||||
}lv_font_fmt_txt_cmap_type_t;
|
||||
};
|
||||
|
||||
typedef uint8_t lv_font_fmt_txt_cmap_type_t;
|
||||
|
||||
|
||||
/* Map codepoints to a `glyph_dsc`s
|
||||
@@ -96,7 +102,7 @@ typedef struct {
|
||||
glyph_id = glyph_id_start + glyph_id_ofs_list[search(unicode_list, rcp)]
|
||||
*/
|
||||
|
||||
uint16_t * unicode_list;
|
||||
const uint16_t * unicode_list;
|
||||
|
||||
/** if(type == LV_FONT_FMT_TXT_CMAP_FORMAT0_...) it's `uint8_t *`
|
||||
* if(type == LV_FONT_FMT_TXT_CMAP_SPARSE_...) it's `uint16_t *`
|
||||
@@ -107,7 +113,7 @@ typedef struct {
|
||||
uint16_t list_length;
|
||||
|
||||
/** Type of this character map*/
|
||||
lv_font_fmt_txt_cmap_type_t type :2;
|
||||
lv_font_fmt_txt_cmap_type_t type;
|
||||
}lv_font_fmt_txt_cmap_t;
|
||||
|
||||
/** A simple mapping of kern values from pairs*/
|
||||
@@ -135,7 +141,7 @@ typedef struct {
|
||||
3. value = class_pair_values[(left_class-1)*right_class_cnt + (righ_class-1)]
|
||||
*/
|
||||
|
||||
const uint8_t * class_pair_values; /*left_class_num * right_class_num value*/
|
||||
const int8_t * class_pair_values; /*left_class_num * right_class_num value*/
|
||||
const uint8_t * left_class_mapping; /*Map the glyph_ids to classes: index -> glyph_id -> class_id*/
|
||||
const uint8_t * right_class_mapping; /*Map the glyph_ids to classes: index -> glyph_id -> class_id*/
|
||||
uint8_t left_class_cnt;
|
||||
@@ -174,7 +180,7 @@ typedef struct {
|
||||
/*Number of cmap tables*/
|
||||
uint16_t cmap_num :10;
|
||||
|
||||
/*Bit per pixel: 1, 2, 4 or 8*/
|
||||
/*Bit per pixel: 1, 2, 3, 4*/
|
||||
uint16_t bpp :3;
|
||||
|
||||
/*Type of `kern_dsc`*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
3419
src/lv_font/lv_font_roboto_12_subpx.c
Normal file
3419
src/lv_font/lv_font_roboto_12_subpx.c
Normal file
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
2451
src/lv_font/lv_font_roboto_28_compressed.c
Normal file
2451
src/lv_font/lv_font_roboto_28_compressed.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
#include "lvgl/lvgl.h"
|
||||
#include "../../lvgl.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Size: 8 px
|
||||
@@ -311,7 +311,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = {
|
||||
* GLYPH DESCRIPTION
|
||||
*--------------------*/
|
||||
|
||||
static lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 0, .adv_w = 0, .box_h = 0, .box_w = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
|
||||
{.bitmap_index = 0, .adv_w = 128, .box_h = 0, .box_w = 0, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 0, .adv_w = 128, .box_h = 7, .box_w = 1, .ofs_x = 3, .ofs_y = -1},
|
||||
@@ -460,4 +460,3 @@ lv_font_t lv_font_unscii_8 = {
|
||||
};
|
||||
|
||||
#endif /*#if LV_FONT_UNSCII_8*/
|
||||
|
||||
|
||||
@@ -11,57 +11,72 @@ extern "C" {
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
/* In the font converter use this list as range:
|
||||
61441, 61448, 61451, 61452, 61453, 61457, 61459, 61461, 61465, 61468,
|
||||
61473, 61478, 61479, 61480, 61502, 61512, 61515, 61516, 61517, 61521,
|
||||
61522, 61523, 61524, 61543, 61544, 61550, 61552, 61553, 61556, 61559,
|
||||
61560, 61561, 61563, 61587, 61589, 61636, 61637, 61639, 61671, 61674,
|
||||
61683, 61724, 61732, 61787, 61931, 62016, 62017, 62018, 62019, 62020,
|
||||
62087, 62099, 62212, 62189, 62810, 63426, 63650
|
||||
*/
|
||||
|
||||
#define LV_SYMBOL_AUDIO "\xef\x80\x81"
|
||||
#define LV_SYMBOL_VIDEO "\xef\x80\x88"
|
||||
#define LV_SYMBOL_LIST "\xef\x80\x8b"
|
||||
#define LV_SYMBOL_OK "\xef\x80\x8c"
|
||||
#define LV_SYMBOL_CLOSE "\xef\x80\x8d"
|
||||
#define LV_SYMBOL_POWER "\xef\x80\x91"
|
||||
#define LV_SYMBOL_SETTINGS "\xef\x80\x93"
|
||||
#define LV_SYMBOL_TRASH "\xef\x80\x94"
|
||||
#define LV_SYMBOL_HOME "\xef\x80\x95"
|
||||
#define LV_SYMBOL_DOWNLOAD "\xef\x80\x99"
|
||||
#define LV_SYMBOL_DRIVE "\xef\x80\x9c"
|
||||
#define LV_SYMBOL_REFRESH "\xef\x80\xa1"
|
||||
#define LV_SYMBOL_MUTE "\xef\x80\xa6"
|
||||
#define LV_SYMBOL_VOLUME_MID "\xef\x80\xa7"
|
||||
#define LV_SYMBOL_VOLUME_MAX "\xef\x80\xa8"
|
||||
#define LV_SYMBOL_IMAGE "\xef\x80\xbe"
|
||||
#define LV_SYMBOL_EDIT "\xef\x81\x80"
|
||||
#define LV_SYMBOL_PREV "\xef\x81\x88"
|
||||
#define LV_SYMBOL_PLAY "\xef\x81\x8b"
|
||||
#define LV_SYMBOL_PAUSE "\xef\x81\x8c"
|
||||
#define LV_SYMBOL_STOP "\xef\x81\x8d"
|
||||
#define LV_SYMBOL_NEXT "\xef\x81\x91"
|
||||
#define LV_SYMBOL_EJECT "\xef\x81\x92"
|
||||
#define LV_SYMBOL_LEFT "\xef\x81\x93"
|
||||
#define LV_SYMBOL_RIGHT "\xef\x81\x94"
|
||||
#define LV_SYMBOL_PLUS "\xef\x81\xa7"
|
||||
#define LV_SYMBOL_MINUS "\xef\x81\xa8"
|
||||
#define LV_SYMBOL_WARNING "\xef\x81\xb1"
|
||||
#define LV_SYMBOL_SHUFFLE "\xef\x81\xb4"
|
||||
#define LV_SYMBOL_UP "\xef\x81\xb7"
|
||||
#define LV_SYMBOL_DOWN "\xef\x81\xb8"
|
||||
#define LV_SYMBOL_LOOP "\xef\x81\xb9"
|
||||
#define LV_SYMBOL_DIRECTORY "\xef\x81\xbb"
|
||||
#define LV_SYMBOL_UPLOAD "\xef\x82\x93"
|
||||
#define LV_SYMBOL_CALL "\xef\x82\x95"
|
||||
#define LV_SYMBOL_CUT "\xef\x83\x84"
|
||||
#define LV_SYMBOL_COPY "\xef\x83\x85"
|
||||
#define LV_SYMBOL_SAVE "\xef\x83\x87"
|
||||
#define LV_SYMBOL_CHARGE "\xef\x83\xa7"
|
||||
#define LV_SYMBOL_BELL "\xef\x83\xb3"
|
||||
#define LV_SYMBOL_KEYBOARD "\xef\x84\x9c"
|
||||
#define LV_SYMBOL_GPS "\xef\x84\xa4"
|
||||
#define LV_SYMBOL_FILE "\xef\x85\x9b"
|
||||
#define LV_SYMBOL_WIFI "\xef\x87\xab"
|
||||
#define LV_SYMBOL_BATTERY_FULL "\xef\x89\x80"
|
||||
#define LV_SYMBOL_BATTERY_3 "\xef\x89\x81"
|
||||
#define LV_SYMBOL_BATTERY_2 "\xef\x89\x82"
|
||||
#define LV_SYMBOL_BATTERY_1 "\xef\x89\x83"
|
||||
#define LV_SYMBOL_BATTERY_EMPTY "\xef\x89\x84"
|
||||
#define LV_SYMBOL_BLUETOOTH "\xef\x8a\x93"
|
||||
#define LV_SYMBOL_AUDIO "\xef\x80\x81" /*61441, 0xF001*/
|
||||
#define LV_SYMBOL_VIDEO "\xef\x80\x88" /*61448, 0xF008*/
|
||||
#define LV_SYMBOL_LIST "\xef\x80\x8b" /*61451, 0xF00B*/
|
||||
#define LV_SYMBOL_OK "\xef\x80\x8c" /*61452, 0xF00C*/
|
||||
#define LV_SYMBOL_CLOSE "\xef\x80\x8d" /*61453, 0xF00D*/
|
||||
#define LV_SYMBOL_POWER "\xef\x80\x91" /*61457, 0xF011*/
|
||||
#define LV_SYMBOL_SETTINGS "\xef\x80\x93" /*61459, 0xF013*/
|
||||
#define LV_SYMBOL_HOME "\xef\x80\x95" /*61461, 0xF015*/
|
||||
#define LV_SYMBOL_DOWNLOAD "\xef\x80\x99" /*61465, 0xF019*/
|
||||
#define LV_SYMBOL_DRIVE "\xef\x80\x9c" /*61468, 0xF01C*/
|
||||
#define LV_SYMBOL_REFRESH "\xef\x80\xa1" /*61473, 0xF021*/
|
||||
#define LV_SYMBOL_MUTE "\xef\x80\xa6" /*61478, 0xF026*/
|
||||
#define LV_SYMBOL_VOLUME_MID "\xef\x80\xa7" /*61479, 0xF027*/
|
||||
#define LV_SYMBOL_VOLUME_MAX "\xef\x80\xa8" /*61480, 0xF028*/
|
||||
#define LV_SYMBOL_IMAGE "\xef\x80\xbe" /*61502, 0xF03E*/
|
||||
#define LV_SYMBOL_EDIT "\xef\x8C\x84" /*62212, 0xF304*/
|
||||
#define LV_SYMBOL_PREV "\xef\x81\x88" /*61512, 0xF048*/
|
||||
#define LV_SYMBOL_PLAY "\xef\x81\x8b" /*61515, 0xF04B*/
|
||||
#define LV_SYMBOL_PAUSE "\xef\x81\x8c" /*61516, 0xF04C*/
|
||||
#define LV_SYMBOL_STOP "\xef\x81\x8d" /*61517, 0xF04D*/
|
||||
#define LV_SYMBOL_NEXT "\xef\x81\x91" /*61521, 0xF051*/
|
||||
#define LV_SYMBOL_EJECT "\xef\x81\x92" /*61522, 0xF052*/
|
||||
#define LV_SYMBOL_LEFT "\xef\x81\x93" /*61523, 0xF053*/
|
||||
#define LV_SYMBOL_RIGHT "\xef\x81\x94" /*61524, 0xF054*/
|
||||
#define LV_SYMBOL_PLUS "\xef\x81\xa7" /*61543, 0xF067*/
|
||||
#define LV_SYMBOL_MINUS "\xef\x81\xa8" /*61544, 0xF068*/
|
||||
#define LV_SYMBOL_EYE_OPEN "\xef\x81\xae" /*61550, 0xF06E*/
|
||||
#define LV_SYMBOL_EYE_CLOSE "\xef\x81\xb0" /*61552, 0xF070*/
|
||||
#define LV_SYMBOL_WARNING "\xef\x81\xb1" /*61553, 0xF071*/
|
||||
#define LV_SYMBOL_SHUFFLE "\xef\x81\xb4" /*61556, 0xF074*/
|
||||
#define LV_SYMBOL_UP "\xef\x81\xb7" /*61559, 0xF077*/
|
||||
#define LV_SYMBOL_DOWN "\xef\x81\xb8" /*61560, 0xF078*/
|
||||
#define LV_SYMBOL_LOOP "\xef\x81\xb9" /*61561, 0xF079*/
|
||||
#define LV_SYMBOL_DIRECTORY "\xef\x81\xbb" /*61563, 0xF07B*/
|
||||
#define LV_SYMBOL_UPLOAD "\xef\x82\x93" /*61587, 0xF093*/
|
||||
#define LV_SYMBOL_CALL "\xef\x82\x95" /*61589, 0xF095*/
|
||||
#define LV_SYMBOL_CUT "\xef\x83\x84" /*61636, 0xF0C4*/
|
||||
#define LV_SYMBOL_COPY "\xef\x83\x85" /*61637, 0xF0C5*/
|
||||
#define LV_SYMBOL_SAVE "\xef\x83\x87" /*61639, 0xF0C7*/
|
||||
#define LV_SYMBOL_CHARGE "\xef\x83\xa7" /*61671, 0xF0E7*/
|
||||
#define LV_SYMBOL_PASTE "\xef\x83\xAA" /*61674, 0xF0EA*/
|
||||
#define LV_SYMBOL_BELL "\xef\x83\xb3" /*61683, 0xF0F3*/
|
||||
#define LV_SYMBOL_KEYBOARD "\xef\x84\x9c" /*61724, 0xF11C*/
|
||||
#define LV_SYMBOL_GPS "\xef\x84\xa4" /*61732, 0xF124*/
|
||||
#define LV_SYMBOL_FILE "\xef\x85\x9b" /*61787, 0xF158*/
|
||||
#define LV_SYMBOL_WIFI "\xef\x87\xab" /*61931, 0xF1EB*/
|
||||
#define LV_SYMBOL_BATTERY_FULL "\xef\x89\x80" /*62016, 0xF240*/
|
||||
#define LV_SYMBOL_BATTERY_3 "\xef\x89\x81" /*62017, 0xF241*/
|
||||
#define LV_SYMBOL_BATTERY_2 "\xef\x89\x82" /*62018, 0xF242*/
|
||||
#define LV_SYMBOL_BATTERY_1 "\xef\x89\x83" /*62019, 0xF243*/
|
||||
#define LV_SYMBOL_BATTERY_EMPTY "\xef\x89\x84" /*62020, 0xF244*/
|
||||
#define LV_SYMBOL_USB "\xef\x8a\x87" /*62087, 0xF287*/
|
||||
#define LV_SYMBOL_BLUETOOTH "\xef\x8a\x93" /*62099, 0xF293*/
|
||||
#define LV_SYMBOL_TRASH "\xef\x8B\xAD" /*62189, 0xF2ED*/
|
||||
#define LV_SYMBOL_BACKSPACE "\xef\x95\x9A" /*62810, 0xF55A*/
|
||||
#define LV_SYMBOL_SD_CARD "\xef\x9F\x82" /*63426, 0xF7C2*/
|
||||
#define LV_SYMBOL_NEW_LINE "\xef\xA2\xA2" /*63650, 0xF8A2*/
|
||||
|
||||
/** Invalid symbol at (U+F8FF). If written before a string then `lv_img` will show it as a label*/
|
||||
#define LV_SYMBOL_DUMMY "\xEF\xA3\xBF"
|
||||
@@ -78,7 +93,6 @@ enum {
|
||||
_LV_STR_SYMBOL_CLOSE,
|
||||
_LV_STR_SYMBOL_POWER,
|
||||
_LV_STR_SYMBOL_SETTINGS,
|
||||
_LV_STR_SYMBOL_TRASH,
|
||||
_LV_STR_SYMBOL_HOME,
|
||||
_LV_STR_SYMBOL_DOWNLOAD,
|
||||
_LV_STR_SYMBOL_DRIVE,
|
||||
@@ -98,6 +112,8 @@ enum {
|
||||
_LV_STR_SYMBOL_RIGHT,
|
||||
_LV_STR_SYMBOL_PLUS,
|
||||
_LV_STR_SYMBOL_MINUS,
|
||||
_LV_STR_SYMBOL_EYE_OPEN,
|
||||
_LV_STR_SYMBOL_EYE_CLOSE,
|
||||
_LV_STR_SYMBOL_WARNING,
|
||||
_LV_STR_SYMBOL_SHUFFLE,
|
||||
_LV_STR_SYMBOL_UP,
|
||||
@@ -110,6 +126,7 @@ enum {
|
||||
_LV_STR_SYMBOL_COPY,
|
||||
_LV_STR_SYMBOL_SAVE,
|
||||
_LV_STR_SYMBOL_CHARGE,
|
||||
_LV_STR_SYMBOL_PASTE,
|
||||
_LV_STR_SYMBOL_BELL,
|
||||
_LV_STR_SYMBOL_KEYBOARD,
|
||||
_LV_STR_SYMBOL_GPS,
|
||||
@@ -120,7 +137,12 @@ enum {
|
||||
_LV_STR_SYMBOL_BATTERY_2,
|
||||
_LV_STR_SYMBOL_BATTERY_1,
|
||||
_LV_STR_SYMBOL_BATTERY_EMPTY,
|
||||
_LV_STR_SYMBOL_USB,
|
||||
_LV_STR_SYMBOL_BLUETOOTH,
|
||||
_LV_STR_SYMBOL_TRASH,
|
||||
_LV_STR_SYMBOL_BACKSPACE,
|
||||
_LV_STR_SYMBOL_SD_CARD,
|
||||
_LV_STR_SYMBOL_NEW_LINE,
|
||||
_LV_STR_SYMBOL_DUMMY,
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "lv_hal.h"
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
#include "../lv_core/lv_obj.h"
|
||||
#include "../lv_core/lv_refr.h"
|
||||
@@ -118,7 +119,7 @@ lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver)
|
||||
{
|
||||
lv_disp_t * disp = lv_ll_ins_head(&LV_GC_ROOT(_lv_disp_ll));
|
||||
if(!disp) {
|
||||
lv_mem_assert(disp);
|
||||
LV_ASSERT_MEM(disp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -126,6 +127,7 @@ lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver)
|
||||
memset(&disp->inv_area_joined, 0, sizeof(disp->inv_area_joined));
|
||||
memset(&disp->inv_areas, 0, sizeof(disp->inv_areas));
|
||||
lv_ll_init(&disp->scr_ll, sizeof(lv_obj_t));
|
||||
disp->last_activity_time = 0;
|
||||
|
||||
if(disp_def == NULL) disp_def = disp;
|
||||
|
||||
@@ -137,7 +139,7 @@ lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver)
|
||||
|
||||
disp->act_scr = lv_obj_create(NULL, NULL); /*Create a default screen on the display*/
|
||||
disp->top_layer = lv_obj_create(NULL, NULL); /*Create top layer on the display*/
|
||||
disp->sys_layer = lv_obj_create(NULL, NULL); /*Create top layer on the display*/
|
||||
disp->sys_layer = lv_obj_create(NULL, NULL); /*Create sys layer on the display*/
|
||||
lv_obj_set_style(disp->top_layer, &lv_style_transp);
|
||||
lv_obj_set_style(disp->sys_layer, &lv_style_transp);
|
||||
|
||||
@@ -147,7 +149,7 @@ lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver)
|
||||
|
||||
/*Create a refresh task*/
|
||||
disp->refr_task = lv_task_create(lv_disp_refr_task, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, disp);
|
||||
lv_mem_assert(disp->refr_task);
|
||||
LV_ASSERT_MEM(disp->refr_task);
|
||||
if(disp->refr_task == NULL) return NULL;
|
||||
|
||||
lv_task_ready(disp->refr_task); /*Be sure the screen will be refreshed immediately on start up*/
|
||||
@@ -267,14 +269,14 @@ bool lv_disp_get_antialiasing(lv_disp_t * disp)
|
||||
*/
|
||||
LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_drv_t * disp_drv)
|
||||
{
|
||||
disp_drv->buffer->flushing = 0;
|
||||
|
||||
/*If the screen is transparent initialize it when the flushing is ready*/
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
if(disp_drv->screen_transp) {
|
||||
memset(disp_drv->buffer->buf_act, 0x00, disp_drv->buffer->size * sizeof(lv_color32_t));
|
||||
}
|
||||
#endif
|
||||
|
||||
disp_drv->buffer->flushing = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_hal/lv_hal_indev.h"
|
||||
#include "../lv_core/lv_indev.h"
|
||||
#include "../lv_misc/lv_mem.h"
|
||||
@@ -77,7 +78,7 @@ lv_indev_t * lv_indev_drv_register(lv_indev_drv_t * driver)
|
||||
|
||||
lv_indev_t * indev = lv_ll_ins_head(&LV_GC_ROOT(_lv_indev_ll));
|
||||
if(!indev) {
|
||||
lv_mem_assert(indev);
|
||||
LV_ASSERT_MEM(indev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#if LV_USE_ANIMATION
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_hal/lv_hal_tick.h"
|
||||
#include "lv_task.h"
|
||||
#include "lv_math.h"
|
||||
@@ -89,7 +90,7 @@ void lv_anim_create(lv_anim_t * a)
|
||||
|
||||
/*Add the new animation to the animation linked list*/
|
||||
lv_anim_t * new_anim = lv_ll_ins_head(&LV_GC_ROOT(_lv_anim_ll));
|
||||
lv_mem_assert(new_anim);
|
||||
LV_ASSERT_MEM(new_anim);
|
||||
if(new_anim == NULL) return;
|
||||
|
||||
/*Initialize the animation descriptor*/
|
||||
|
||||
@@ -129,10 +129,10 @@ static inline void lv_anim_set_exec_cb(lv_anim_t * a, void * var, lv_anim_exec_x
|
||||
* @param duration duration of the animation in milliseconds
|
||||
* @param delay delay before the animation in milliseconds
|
||||
*/
|
||||
static inline void lv_anim_set_time(lv_anim_t * a, uint16_t duration, uint16_t delay)
|
||||
static inline void lv_anim_set_time(lv_anim_t * a, uint16_t duration, int16_t delay)
|
||||
{
|
||||
a->time = duration;
|
||||
a->act_time = -delay;
|
||||
a->act_time = (int16_t)(-delay);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,36 +222,6 @@ static inline void lv_anim_clear_repeat(lv_anim_t * a)
|
||||
a->repeat = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a user specific data for the animation
|
||||
* @param a pointer to an initialized `lv_anim_t` variable
|
||||
* @param user_data the user data
|
||||
*/
|
||||
static inline void lv_anim_set_user_data(lv_anim_t * a, lv_anim_user_data_t user_data)
|
||||
{
|
||||
memcpy(&a->user_data, &user_data, sizeof(user_data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user data
|
||||
* @param a pointer to an initialized `lv_anim_t` variable
|
||||
* @return the user data
|
||||
*/
|
||||
static inline lv_anim_user_data_t lv_anim_get_user_data(lv_anim_t * a)
|
||||
{
|
||||
return a->user_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pointer to the user data
|
||||
* @param a pointer to an initialized `lv_anim_t` variable
|
||||
* @return pointer to the user data
|
||||
*/
|
||||
static inline lv_anim_user_data_t * lv_anim_get_user_data_ptr(lv_anim_t * a)
|
||||
{
|
||||
return &a->user_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an animation
|
||||
* @param a an initialized 'anim_t' variable. Not required after call.
|
||||
|
||||
@@ -192,6 +192,19 @@ bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p)
|
||||
return is_in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment or decrement an area's size by a single amount
|
||||
* @param a_p pointer to an area to grow
|
||||
* @param amount amount to increment the area, or negative to decrement
|
||||
*/
|
||||
void lv_area_increment(lv_area_t * a_p, const lv_coord_t amount)
|
||||
{
|
||||
a_p->x1 -= amount;
|
||||
a_p->y1 -= amount;
|
||||
a_p->x2 += amount;
|
||||
a_p->y2 += amount;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
@@ -29,6 +29,9 @@ extern "C" {
|
||||
#define LV_COORD_MAX ((lv_coord_t)((uint32_t)((uint32_t)1 << (8 * sizeof(lv_coord_t) - 1)) - 1000))
|
||||
#define LV_COORD_MIN (-LV_COORD_MAX)
|
||||
|
||||
LV_EXPORT_CONST_INT(LV_COORD_MAX);
|
||||
LV_EXPORT_CONST_INT(LV_COORD_MIN);
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
@@ -82,7 +85,7 @@ inline static void lv_area_copy(lv_area_t * dest, const lv_area_t * src)
|
||||
*/
|
||||
static inline lv_coord_t lv_area_get_width(const lv_area_t * area_p)
|
||||
{
|
||||
return area_p->x2 - area_p->x1 + 1;
|
||||
return (lv_coord_t)(area_p->x2 - area_p->x1 + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +95,7 @@ static inline lv_coord_t lv_area_get_width(const lv_area_t * area_p)
|
||||
*/
|
||||
static inline lv_coord_t lv_area_get_height(const lv_area_t * area_p)
|
||||
{
|
||||
return area_p->y2 - area_p->y1 + 1;
|
||||
return (lv_coord_t)(area_p->y2 - area_p->y1 + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,6 +168,13 @@ bool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p);
|
||||
*/
|
||||
bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p);
|
||||
|
||||
/**
|
||||
* Increment or decrement an area's size by a single amount
|
||||
* @param a_p pointer to an area to grow
|
||||
* @param amount amount to increment the area, or negative to decrement
|
||||
*/
|
||||
void lv_area_increment(lv_area_t * a_p, const lv_coord_t amount);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
75
src/lv_misc/lv_async.c
Normal file
75
src/lv_misc/lv_async.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @file lv_async.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_async.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void lv_async_task_cb(lv_task_t *task);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_res_t lv_async_call(lv_async_cb_t async_xcb, void * user_data)
|
||||
{
|
||||
/*Allocate an info structure */
|
||||
lv_async_info_t *info = lv_mem_alloc(sizeof(lv_async_info_t));
|
||||
|
||||
if(info == NULL)
|
||||
return LV_RES_INV;
|
||||
|
||||
/* Create a new task */
|
||||
/* Use highest priority so that it will run before a refresh */
|
||||
lv_task_t *task = lv_task_create(lv_async_task_cb, 0, LV_TASK_PRIO_HIGHEST, info);
|
||||
|
||||
if(task == NULL) {
|
||||
lv_mem_free(info);
|
||||
return LV_RES_INV;
|
||||
}
|
||||
|
||||
info->cb = async_xcb;
|
||||
info->user_data = user_data;
|
||||
|
||||
/* Set the task's user data */
|
||||
task->user_data = info;
|
||||
lv_task_once(task);
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void lv_async_task_cb(lv_task_t *task)
|
||||
{
|
||||
lv_async_info_t *info = (lv_async_info_t *)task->user_data;
|
||||
|
||||
info->cb(info->user_data);
|
||||
|
||||
lv_mem_free(info);
|
||||
}
|
||||
62
src/lv_misc/lv_async.h
Normal file
62
src/lv_misc/lv_async.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @file lv_async.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_ASYNC_H
|
||||
#define LV_ASYNC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_task.h"
|
||||
#include "lv_types.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Type for async callback.
|
||||
*/
|
||||
typedef void (*lv_async_cb_t)(void *);
|
||||
|
||||
typedef struct _lv_async_info_t {
|
||||
lv_async_cb_t cb;
|
||||
void *user_data;
|
||||
} lv_async_info_t;
|
||||
|
||||
struct _lv_obj_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Call an asynchronous function the next time lv_task_handler() is run. This function is likely to return
|
||||
* **before** the call actually happens!
|
||||
* @param task_xcb a callback which is the task itself.
|
||||
* (the 'x' in the argument name indicates that its not a fully generic function because it not follows
|
||||
* the `func_name(object, callback, ...)` convention)
|
||||
* @param user_data custom parameter
|
||||
*/
|
||||
lv_res_t lv_async_call(lv_async_cb_t async_xcb, void * user_data);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_TEMPL_H*/
|
||||
544
src/lv_misc/lv_bidi.c
Normal file
544
src/lv_misc/lv_bidi.c
Normal file
@@ -0,0 +1,544 @@
|
||||
/**
|
||||
* @file lv_bidi.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stddef.h>
|
||||
#include "lv_bidi.h"
|
||||
#include "lv_txt.h"
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
|
||||
#if LV_USE_BIDI
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_BIDI_BRACKLET_DEPTH 4
|
||||
|
||||
// Highest bit of the 16-bit pos_conv value specifies whether this pos is RTL or not
|
||||
#define GET_POS(x) ((x) & 0x7FFF)
|
||||
#define IS_RTL_POS(x) (((x) & 0x8000) != 0)
|
||||
#define SET_RTL_POS(x, is_rtl) (GET_POS(x) | ((is_rtl)? 0x8000: 0))
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t bracklet_pos;
|
||||
lv_bidi_dir_t dir;
|
||||
}bracket_stack_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t max_len, uint32_t * len, uint16_t * pos_conv_len);
|
||||
static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t *pos_conv_out, uint16_t pos_conv_rd_base, uint16_t pos_conv_len);
|
||||
static uint32_t char_change_to_pair(uint32_t letter);
|
||||
static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32_t len, uint32_t letter, lv_bidi_dir_t base_dir);
|
||||
static void fill_pos_conv(uint16_t * out, uint16_t len, uint16_t index);
|
||||
static uint32_t get_txt_len(const char * txt, uint32_t max_len);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static const uint8_t bracket_left[] = {"<({["};
|
||||
static const uint8_t bracket_right[] = {">)}]"};
|
||||
static bracket_stack_t br_stack[LV_BIDI_BRACKLET_DEPTH];
|
||||
static uint8_t br_stack_p;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir)
|
||||
{
|
||||
if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(str_in);
|
||||
|
||||
uint32_t par_start = 0;
|
||||
uint32_t par_len;
|
||||
|
||||
while(str_in[par_start] == '\n' || str_in[par_start] == '\r') {
|
||||
str_out[par_start] = str_in[par_start];
|
||||
par_start ++;
|
||||
}
|
||||
|
||||
while(str_in[par_start] != '\0') {
|
||||
par_len = lv_bidi_get_next_paragraph(&str_in[par_start]);
|
||||
lv_bidi_process_paragraph(&str_in[par_start], &str_out[par_start], par_len, base_dir, NULL, 0);
|
||||
par_start += par_len;
|
||||
|
||||
while(str_in[par_start] == '\n' || str_in[par_start] == '\r') {
|
||||
str_out[par_start] = str_in[par_start];
|
||||
par_start ++;
|
||||
}
|
||||
}
|
||||
|
||||
str_out[par_start] = '\0';
|
||||
}
|
||||
|
||||
lv_bidi_dir_t lv_bidi_detect_base_dir(const char * txt)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t letter;
|
||||
while(txt[i] != '\0') {
|
||||
letter = lv_txt_encoded_next(txt, &i);
|
||||
|
||||
lv_bidi_dir_t dir;
|
||||
dir = lv_bidi_get_letter_dir(letter);
|
||||
if(dir == LV_BIDI_DIR_RTL || dir == LV_BIDI_DIR_LTR) return dir;
|
||||
}
|
||||
|
||||
/*If there were no strong char earlier return with the default base dir */
|
||||
if(LV_BIDI_BASE_DIR_DEF == LV_BIDI_DIR_AUTO) return LV_BIDI_DIR_LTR;
|
||||
else return LV_BIDI_BASE_DIR_DEF;
|
||||
}
|
||||
|
||||
lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter)
|
||||
{
|
||||
if(lv_bidi_letter_is_rtl(letter)) return LV_BIDI_DIR_RTL;
|
||||
if(lv_bidi_letter_is_neutral(letter)) return LV_BIDI_DIR_NEUTRAL;
|
||||
if(lv_bidi_letter_is_weak(letter)) return LV_BIDI_DIR_WEAK;
|
||||
|
||||
return LV_BIDI_DIR_LTR;
|
||||
}
|
||||
|
||||
bool lv_bidi_letter_is_weak(uint32_t letter)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
static const char weaks[] = "0123456789";
|
||||
|
||||
do {
|
||||
uint32_t x = lv_txt_encoded_next(weaks, &i);
|
||||
if(letter == x) {
|
||||
return true;
|
||||
}
|
||||
} while(weaks[i] != '\0');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lv_bidi_letter_is_rtl(uint32_t letter)
|
||||
{
|
||||
if(letter >= 0x5d0 && letter <= 0x5ea) return true;
|
||||
if(letter == 0x202E) return true; /*Unicode of LV_BIDI_RLO*/
|
||||
// if(letter >= 'a' && letter <= 'z') return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lv_bidi_letter_is_neutral(uint32_t letter)
|
||||
{
|
||||
uint16_t i;
|
||||
static const char neutrals[] = " \t\n\r.,:;'\"`!?%/\\-=()[]{}<>@#&$|";
|
||||
for(i = 0; neutrals[i] != '\0'; i++) {
|
||||
if(letter == (uint32_t)neutrals[i]) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t lv_bidi_get_logical_pos(const char * str_in, char **bidi_txt, uint32_t len, lv_bidi_dir_t base_dir, uint32_t visual_pos, bool *is_rtl)
|
||||
{
|
||||
uint32_t pos_conv_len = get_txt_len(str_in, len);
|
||||
uint32_t txt_buf_size = len + 1;
|
||||
txt_buf_size = (txt_buf_size + 3) & (~0x3);
|
||||
void *buf = lv_draw_get_buf(txt_buf_size + pos_conv_len * sizeof(uint16_t));
|
||||
if (bidi_txt) *bidi_txt = buf;
|
||||
uint16_t *pos_conv_buf = (uint16_t*) ((char*)buf + txt_buf_size);
|
||||
lv_bidi_process_paragraph(str_in, bidi_txt? *bidi_txt: NULL, len, base_dir, pos_conv_buf, pos_conv_len);
|
||||
if (is_rtl) *is_rtl = IS_RTL_POS(pos_conv_buf[visual_pos]);
|
||||
return GET_POS(pos_conv_buf[visual_pos]);
|
||||
}
|
||||
|
||||
uint16_t lv_bidi_get_visual_pos(const char * str_in, char **bidi_txt, uint16_t len, lv_bidi_dir_t base_dir, uint32_t logical_pos, bool *is_rtl)
|
||||
{
|
||||
uint32_t pos_conv_len = get_txt_len(str_in, len);
|
||||
uint32_t txt_buf_size = len + 1;
|
||||
txt_buf_size = (txt_buf_size + 3) & (~0x3);
|
||||
void *buf = lv_draw_get_buf(txt_buf_size + pos_conv_len * sizeof(uint16_t));
|
||||
if (bidi_txt) *bidi_txt = buf;
|
||||
uint16_t *pos_conv_buf = (uint16_t*) ((char*)buf + txt_buf_size);
|
||||
lv_bidi_process_paragraph(str_in, bidi_txt? *bidi_txt: NULL, len, base_dir, pos_conv_buf, pos_conv_len);
|
||||
for (uint16_t i = 0; i < pos_conv_len; i++){
|
||||
if (GET_POS(pos_conv_buf[i]) == logical_pos){
|
||||
if (is_rtl) *is_rtl = IS_RTL_POS(pos_conv_buf[i]);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return (uint16_t) -1;
|
||||
}
|
||||
|
||||
void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir, uint16_t *pos_conv_out, uint16_t pos_conv_len)
|
||||
{
|
||||
uint32_t run_len = 0;
|
||||
lv_bidi_dir_t run_dir;
|
||||
uint32_t rd = 0;
|
||||
uint32_t wr;
|
||||
uint16_t pos_conv_run_len = 0;
|
||||
uint16_t pos_conv_rd = 0;
|
||||
uint16_t pos_conv_wr;
|
||||
|
||||
if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(str_in);
|
||||
if(base_dir == LV_BIDI_DIR_RTL) {
|
||||
wr = len;
|
||||
pos_conv_wr = pos_conv_len;
|
||||
}
|
||||
else {
|
||||
wr = 0;
|
||||
pos_conv_wr = 0;
|
||||
}
|
||||
|
||||
if (str_out) str_out[len] = '\0';
|
||||
|
||||
lv_bidi_dir_t dir = base_dir;
|
||||
|
||||
/*Empty the bracket stack*/
|
||||
br_stack_p = 0;
|
||||
|
||||
/*Process neutral chars in the beginning*/
|
||||
while(rd < len) {
|
||||
uint32_t letter = lv_txt_encoded_next(str_in, &rd);
|
||||
pos_conv_rd++;
|
||||
dir = lv_bidi_get_letter_dir(letter);
|
||||
if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(str_in, rd, len, letter, base_dir);
|
||||
if(dir != LV_BIDI_DIR_NEUTRAL && dir != LV_BIDI_DIR_WEAK) break;
|
||||
}
|
||||
|
||||
if(rd && str_in[rd] != '\0') {
|
||||
lv_txt_encoded_prev(str_in, &rd);
|
||||
pos_conv_rd--;
|
||||
}
|
||||
|
||||
if(rd) {
|
||||
if(base_dir == LV_BIDI_DIR_LTR) {
|
||||
if (str_out) {
|
||||
memcpy(&str_out[wr], str_in, rd);
|
||||
wr += rd;
|
||||
}
|
||||
if (pos_conv_out) {
|
||||
fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_rd, 0);
|
||||
pos_conv_wr += pos_conv_rd;
|
||||
}
|
||||
} else {
|
||||
wr -= rd;
|
||||
pos_conv_wr -= pos_conv_rd;
|
||||
rtl_reverse(str_out? &str_out[wr]: NULL, str_in, rd, pos_conv_out? &pos_conv_out[pos_conv_wr]: NULL, 0, pos_conv_rd);
|
||||
}
|
||||
}
|
||||
|
||||
/*Get and process the runs*/
|
||||
|
||||
while(rd < len && str_in[rd]) {
|
||||
run_dir = get_next_run(&str_in[rd], base_dir, len - rd, &run_len, &pos_conv_run_len);
|
||||
|
||||
if(base_dir == LV_BIDI_DIR_LTR) {
|
||||
if(run_dir == LV_BIDI_DIR_LTR) {
|
||||
if (str_out) memcpy(&str_out[wr], &str_in[rd], run_len);
|
||||
if (pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_run_len, pos_conv_rd);
|
||||
}
|
||||
else rtl_reverse(str_out? &str_out[wr]: NULL, &str_in[rd], run_len, pos_conv_out? &pos_conv_out[pos_conv_wr] : NULL, pos_conv_rd, pos_conv_run_len);
|
||||
wr += run_len;
|
||||
pos_conv_wr += pos_conv_run_len;
|
||||
} else {
|
||||
wr -= run_len;
|
||||
pos_conv_wr -= pos_conv_run_len;
|
||||
if(run_dir == LV_BIDI_DIR_LTR) {
|
||||
if (str_out) memcpy(&str_out[wr], &str_in[rd], run_len);
|
||||
if (pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_run_len, pos_conv_rd);
|
||||
}
|
||||
else rtl_reverse(str_out? &str_out[wr]: NULL, &str_in[rd], run_len, pos_conv_out? &pos_conv_out[pos_conv_wr] : NULL, pos_conv_rd, pos_conv_run_len);
|
||||
}
|
||||
|
||||
rd += run_len;
|
||||
pos_conv_rd += pos_conv_run_len;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t lv_bidi_get_next_paragraph(const char * txt)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
|
||||
lv_txt_encoded_next(txt, &i);
|
||||
|
||||
while(txt[i] != '\0' && txt[i] != '\n' && txt[i] != '\r') {
|
||||
lv_txt_encoded_next(txt, &i);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static uint32_t get_txt_len(const char * txt, uint32_t max_len)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
uint32_t i = 0;
|
||||
|
||||
while(i < max_len && txt[i] != '\0') {
|
||||
lv_txt_encoded_next(txt, &i);
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void fill_pos_conv(uint16_t * out, uint16_t len, uint16_t index)
|
||||
{
|
||||
for (uint16_t i = 0; i < len; i++)
|
||||
{
|
||||
out[i] = SET_RTL_POS(index, false);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t max_len, uint32_t * len, uint16_t * pos_conv_len)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t letter;
|
||||
|
||||
uint16_t pos_conv_i = 0;
|
||||
|
||||
letter = lv_txt_encoded_next(txt, NULL);
|
||||
lv_bidi_dir_t dir = lv_bidi_get_letter_dir(letter);
|
||||
if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(txt, 0, max_len, letter, base_dir);
|
||||
|
||||
/*Find the first strong char. Skip the neutrals*/
|
||||
while(dir == LV_BIDI_DIR_NEUTRAL || dir == LV_BIDI_DIR_WEAK) {
|
||||
letter = lv_txt_encoded_next(txt, &i);
|
||||
pos_conv_i++;
|
||||
dir = lv_bidi_get_letter_dir(letter);
|
||||
if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(txt, i, max_len, letter, base_dir);
|
||||
|
||||
if(i >= max_len || txt[i] == '\0' || txt[i] == '\n' || txt[i] == '\r') {
|
||||
*len = i;
|
||||
*pos_conv_len = pos_conv_i;
|
||||
return base_dir;
|
||||
}
|
||||
}
|
||||
|
||||
lv_bidi_dir_t run_dir = dir;
|
||||
|
||||
uint32_t i_prev = i;
|
||||
uint32_t i_last_strong = i;
|
||||
uint16_t pos_conv_i_prev = pos_conv_i;
|
||||
uint16_t pos_conv_i_last_strong = pos_conv_i;
|
||||
|
||||
/*Find the next char which has different direction*/
|
||||
lv_bidi_dir_t next_dir = base_dir;
|
||||
while(i_prev < max_len && txt[i] != '\0' && txt[i] != '\n' && txt[i] != '\r') {
|
||||
letter = lv_txt_encoded_next(txt, &i);
|
||||
pos_conv_i++;
|
||||
next_dir = lv_bidi_get_letter_dir(letter);
|
||||
if(next_dir == LV_BIDI_DIR_NEUTRAL) next_dir = bracket_process(txt, i, max_len, letter, base_dir);
|
||||
|
||||
/*New dir found?*/
|
||||
if((next_dir == LV_BIDI_DIR_RTL || next_dir == LV_BIDI_DIR_LTR) && next_dir != run_dir) {
|
||||
/*Include neutrals if `run_dir == base_dir` */
|
||||
if(run_dir == base_dir) {
|
||||
*len = i_prev;
|
||||
*pos_conv_len = pos_conv_i_prev;
|
||||
}
|
||||
/*Exclude neutrals if `run_dir != base_dir` */
|
||||
else {
|
||||
*len = i_last_strong;
|
||||
*pos_conv_len = pos_conv_i_last_strong;
|
||||
}
|
||||
|
||||
return run_dir;
|
||||
}
|
||||
|
||||
if(next_dir != LV_BIDI_DIR_NEUTRAL) {
|
||||
i_last_strong = i;
|
||||
pos_conv_i_last_strong = pos_conv_i;
|
||||
}
|
||||
|
||||
i_prev = i;
|
||||
pos_conv_i_prev = pos_conv_i;
|
||||
}
|
||||
|
||||
/*Handle end of of string. Apply `base_dir` on trailing neutrals*/
|
||||
|
||||
/*Include neutrals if `run_dir == base_dir` */
|
||||
if(run_dir == base_dir) {
|
||||
*len = i_prev;
|
||||
*pos_conv_len = pos_conv_i_prev;
|
||||
}
|
||||
/*Exclude neutrals if `run_dir != base_dir` */
|
||||
else {
|
||||
*len = i_last_strong;
|
||||
*pos_conv_len = pos_conv_i_last_strong;
|
||||
}
|
||||
|
||||
return run_dir;
|
||||
}
|
||||
|
||||
static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t *pos_conv_out, uint16_t pos_conv_rd_base, uint16_t pos_conv_len)
|
||||
{
|
||||
uint32_t i = len;
|
||||
uint32_t wr = 0;
|
||||
uint16_t pos_conv_i = pos_conv_len;
|
||||
uint16_t pos_conv_wr = 0;
|
||||
|
||||
while(i) {
|
||||
uint32_t letter = lv_txt_encoded_prev(src, &i);
|
||||
uint16_t pos_conv_letter = --pos_conv_i;
|
||||
|
||||
/*Keep weak letters (numbers) as LTR*/
|
||||
if(lv_bidi_letter_is_weak(letter)) {
|
||||
uint32_t last_weak = i;
|
||||
uint32_t first_weak = i;
|
||||
uint16_t pos_conv_last_weak = pos_conv_i;
|
||||
uint16_t pos_conv_first_weak = pos_conv_i;
|
||||
while(i) {
|
||||
letter = lv_txt_encoded_prev(src, &i);
|
||||
pos_conv_letter = --pos_conv_i;
|
||||
|
||||
/*No need to call `char_change_to_pair` because there not such chars here*/
|
||||
|
||||
/*Finish on non-weak char */
|
||||
/*but treat number and currency related chars as weak*/
|
||||
if (lv_bidi_letter_is_weak(letter) == false && letter != '.' && letter != ',' && letter != '$' && letter != '%') {
|
||||
lv_txt_encoded_next(src, &i); /*Rewind one letter*/
|
||||
pos_conv_i++;
|
||||
first_weak = i;
|
||||
pos_conv_first_weak = pos_conv_i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i == 0) {
|
||||
first_weak = 0;
|
||||
pos_conv_first_weak = 0;
|
||||
}
|
||||
|
||||
if (dest) memcpy(&dest[wr], &src[first_weak], last_weak - first_weak + 1);
|
||||
if (pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_last_weak - pos_conv_first_weak + 1, pos_conv_rd_base + pos_conv_first_weak);
|
||||
wr += last_weak - first_weak + 1;
|
||||
pos_conv_wr += pos_conv_last_weak - pos_conv_first_weak + 1;
|
||||
}
|
||||
|
||||
/*Simply store in reversed order*/
|
||||
else {
|
||||
uint32_t letter_size = lv_txt_encoded_size((const char *)&src[i]);
|
||||
/*Swap arithmetical symbols*/
|
||||
if(letter_size == 1) {
|
||||
uint32_t new_letter = letter = char_change_to_pair(letter);
|
||||
if (dest) dest[wr] = (uint8_t)new_letter;
|
||||
if (pos_conv_out) pos_conv_out[pos_conv_wr] = SET_RTL_POS(pos_conv_rd_base + pos_conv_letter, true);
|
||||
wr++;
|
||||
pos_conv_wr++;
|
||||
}
|
||||
/*Just store the letter*/
|
||||
else {
|
||||
if (dest) memcpy(&dest[wr], &src[i], letter_size);
|
||||
if (pos_conv_out) pos_conv_out[pos_conv_wr] = SET_RTL_POS(pos_conv_rd_base + pos_conv_i, true);
|
||||
wr += letter_size;
|
||||
pos_conv_wr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t char_change_to_pair(uint32_t letter)
|
||||
{
|
||||
|
||||
uint8_t i;
|
||||
for(i = 0; bracket_left[i] != '\0'; i++) {
|
||||
if(letter == bracket_left[i]) return bracket_right[i];
|
||||
}
|
||||
|
||||
for(i = 0; bracket_right[i] != '\0'; i++) {
|
||||
if(letter == bracket_right[i]) return bracket_left[i];
|
||||
}
|
||||
|
||||
return letter;
|
||||
}
|
||||
|
||||
static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32_t len, uint32_t letter, lv_bidi_dir_t base_dir)
|
||||
{
|
||||
lv_bidi_dir_t bracket_dir = LV_BIDI_DIR_NEUTRAL;
|
||||
|
||||
uint8_t i;
|
||||
/*Is the letter an opening bracket?*/
|
||||
for(i = 0; bracket_left[i] != '\0'; i++) {
|
||||
if(bracket_left[i] == letter) {
|
||||
/* If so find it's matching closing bracket.
|
||||
* If a char with base dir. direction is found then the brackets will have `base_dir` direction*/
|
||||
uint32_t txt_i = next_pos;
|
||||
while(txt_i < len) {
|
||||
uint32_t letter_next = lv_txt_encoded_next(txt, &txt_i);
|
||||
if(letter_next == bracket_right[i]) {
|
||||
/*Closing bracket found*/
|
||||
break;
|
||||
} else {
|
||||
/*Save the dir*/
|
||||
lv_bidi_dir_t letter_dir = lv_bidi_get_letter_dir(letter_next);
|
||||
if(letter_dir == base_dir) {
|
||||
bracket_dir = base_dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*There were no matching closing bracket*/
|
||||
if(txt_i > len) return LV_BIDI_DIR_NEUTRAL;
|
||||
|
||||
/*There where a strong char with base dir in the bracket so the dir is found.*/
|
||||
if(bracket_dir != LV_BIDI_DIR_NEUTRAL && bracket_dir != LV_BIDI_DIR_WEAK) break;
|
||||
|
||||
/*If there were no matching strong chars in the brackets then check the previous chars*/
|
||||
txt_i = next_pos;
|
||||
if(txt_i) lv_txt_encoded_prev(txt, &txt_i);
|
||||
while(txt_i > 0) {
|
||||
uint32_t letter_next = lv_txt_encoded_prev(txt, &txt_i);
|
||||
lv_bidi_dir_t letter_dir = lv_bidi_get_letter_dir(letter_next);
|
||||
if(letter_dir == LV_BIDI_DIR_LTR || letter_dir == LV_BIDI_DIR_RTL) {
|
||||
bracket_dir = letter_dir;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*There where a previous strong char which can be used*/
|
||||
if(bracket_dir != LV_BIDI_DIR_NEUTRAL) break;
|
||||
|
||||
/*There were no strong chars before the bracket, so use the base dir.*/
|
||||
if(txt_i == 0) bracket_dir = base_dir;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*The letter was an opening bracket*/
|
||||
if(bracket_left[i] != '\0') {
|
||||
|
||||
if(bracket_dir == LV_BIDI_DIR_NEUTRAL || br_stack_p == LV_BIDI_BRACKLET_DEPTH) return LV_BIDI_DIR_NEUTRAL;
|
||||
|
||||
br_stack[br_stack_p].bracklet_pos = i;
|
||||
br_stack[br_stack_p].dir = bracket_dir;
|
||||
|
||||
br_stack_p++;
|
||||
return bracket_dir;
|
||||
} else if(br_stack_p > 0) {
|
||||
/*Is the letter a closing bracket of the last opening?*/
|
||||
if(letter == bracket_right[br_stack[br_stack_p - 1].bracklet_pos]) {
|
||||
bracket_dir = br_stack[br_stack_p - 1].dir;
|
||||
br_stack_p--;
|
||||
return bracket_dir;
|
||||
}
|
||||
}
|
||||
|
||||
return LV_BIDI_DIR_NEUTRAL;
|
||||
}
|
||||
|
||||
|
||||
#endif /*LV_USE_BIDI*/
|
||||
76
src/lv_misc/lv_bidi.h
Normal file
76
src/lv_misc/lv_bidi.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @file lv_bifi.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_BIDI_H
|
||||
#define LV_BIDI_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
/* Special non printable strong characters.
|
||||
* They can be inserted to texts to affect the run's direction*/
|
||||
#define LV_BIDI_LRO "\xE2\x80\xAD" /*U+202D*/
|
||||
#define LV_BIDI_RLO "\xE2\x80\xAE" /*U+202E*/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
enum
|
||||
{
|
||||
/*The first 4 values are stored in `lv_obj_t` on 2 bits*/
|
||||
LV_BIDI_DIR_LTR = 0x00,
|
||||
LV_BIDI_DIR_RTL = 0x01,
|
||||
LV_BIDI_DIR_AUTO = 0x02,
|
||||
LV_BIDI_DIR_INHERIT = 0x03,
|
||||
|
||||
LV_BIDI_DIR_NEUTRAL = 0x20,
|
||||
LV_BIDI_DIR_WEAK = 0x21,
|
||||
};
|
||||
|
||||
typedef uint8_t lv_bidi_dir_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
#if LV_USE_BIDI
|
||||
|
||||
void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir);
|
||||
void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir, uint16_t *pos_conv_out, uint16_t pos_conv_len);
|
||||
uint32_t lv_bidi_get_next_paragraph(const char * txt);
|
||||
lv_bidi_dir_t lv_bidi_detect_base_dir(const char * txt);
|
||||
lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter);
|
||||
bool lv_bidi_letter_is_weak(uint32_t letter);
|
||||
bool lv_bidi_letter_is_rtl(uint32_t letter);
|
||||
bool lv_bidi_letter_is_neutral(uint32_t letter);
|
||||
uint16_t lv_bidi_get_logical_pos(const char * str_in, char **bidi_txt, uint32_t len, lv_bidi_dir_t base_dir, uint32_t visual_pos, bool *is_rtl);
|
||||
uint16_t lv_bidi_get_visual_pos(const char * str_in, char **bidi_txt, uint16_t len, lv_bidi_dir_t base_dir, uint32_t logical_pos, bool *is_rtl);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_BIDI*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_BIDI_H*/
|
||||
@@ -67,10 +67,10 @@ 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
|
||||
(*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
|
||||
(*tmp) += 2 * (c->y - c->x) + 1; /*Change for y -> y+1, x -> x-1*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_color.h"
|
||||
#include "lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -105,39 +106,66 @@ lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an RGB color to HSV
|
||||
* @param r red
|
||||
* @param g green
|
||||
* @param b blue
|
||||
* @return the given RGB color n HSV
|
||||
* Convert a 32-bit RGB color to HSV
|
||||
* @param r8 8-bit red
|
||||
* @param g8 8-bit green
|
||||
* @param b8 8-bit blue
|
||||
* @return the given RGB color in HSV
|
||||
*/
|
||||
lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b)
|
||||
lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r8, uint8_t g8, uint8_t b8)
|
||||
{
|
||||
uint16_t r = ((uint32_t)r8 << 10) / 255;
|
||||
uint16_t g = ((uint32_t)g8 << 10) / 255;
|
||||
uint16_t b = ((uint32_t)b8 << 10) / 255;
|
||||
|
||||
uint16_t rgbMin = r < g ? (r < b ? r : b) : (g < b ? g : b);
|
||||
uint16_t rgbMax = r > g ? (r > b ? r : b) : (g > b ? g : b);
|
||||
|
||||
lv_color_hsv_t hsv;
|
||||
uint8_t rgbMin, rgbMax;
|
||||
|
||||
rgbMin = r < g ? (r < b ? r : b) : (g < b ? g : b);
|
||||
rgbMax = r > g ? (r > b ? r : b) : (g > b ? g : b);
|
||||
// https://en.wikipedia.org/wiki/HSL_and_HSV#Lightness
|
||||
hsv.v = (100 * rgbMax) >> 10;
|
||||
|
||||
hsv.v = rgbMax;
|
||||
if(hsv.v == 0) {
|
||||
int32_t delta = rgbMax - rgbMin;
|
||||
if (LV_MATH_ABS(delta) < 3) {
|
||||
hsv.h = 0;
|
||||
hsv.s = 0;
|
||||
return hsv;
|
||||
}
|
||||
|
||||
hsv.s = 255 * (long)(rgbMax - rgbMin) / hsv.v;
|
||||
if(hsv.s == 0) {
|
||||
// https://en.wikipedia.org/wiki/HSL_and_HSV#Saturation
|
||||
hsv.s = 100 * delta / rgbMax;
|
||||
if(hsv.s < 3) {
|
||||
hsv.h = 0;
|
||||
return hsv;
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/HSL_and_HSV#Hue_and_chroma
|
||||
int32_t h;
|
||||
if(rgbMax == r)
|
||||
hsv.h = 0 + 43 * (g - b) / (rgbMax - rgbMin);
|
||||
h = (((g - b) << 10) / delta) + (g < b ? (6 << 10) : 0); // between yellow & magenta
|
||||
else if(rgbMax == g)
|
||||
hsv.h = 85 + 43 * (b - r) / (rgbMax - rgbMin);
|
||||
h = (((b - r) << 10) / delta) + (2 << 10); // between cyan & yellow
|
||||
else if(rgbMax == b)
|
||||
h = (((r - g) << 10) / delta) + (4 << 10); // between magenta & cyan
|
||||
else
|
||||
hsv.h = 171 + 43 * (r - g) / (rgbMax - rgbMin);
|
||||
h = 0;
|
||||
h *= 60;
|
||||
h >>= 10;
|
||||
if (h < 0) h += 360;
|
||||
|
||||
hsv.h = h;
|
||||
return hsv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a color to HSV
|
||||
* @param color color
|
||||
* @return the given color in HSV
|
||||
*/
|
||||
lv_color_hsv_t lv_color_to_hsv(lv_color_t color)
|
||||
{
|
||||
lv_color32_t color32;
|
||||
color32.full = lv_color_to32(color);
|
||||
return lv_color_rgb_to_hsv(color32.ch.red, color32.ch.green, color32.ch.blue);
|
||||
}
|
||||
|
||||
@@ -90,16 +90,123 @@ enum {
|
||||
#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!"
|
||||
#endif
|
||||
|
||||
/*---------------------------------------
|
||||
* Macros for all existing color depths
|
||||
* to set/get values of the color channels
|
||||
*------------------------------------------*/
|
||||
# define LV_COLOR_SET_R1(c, v) (c).ch.red = (uint8_t)((v) & 0x1);
|
||||
# define LV_COLOR_SET_G1(c, v) (c).ch.green = (uint8_t)((v) & 0x1);
|
||||
# define LV_COLOR_SET_B1(c, v) (c).ch.blue = (uint8_t)((v) & 0x1);
|
||||
# define LV_COLOR_SET_A1(c, v)
|
||||
|
||||
# define LV_COLOR_GET_R1(c) (c).ch.red
|
||||
# define LV_COLOR_GET_G1(c) (c).ch.green
|
||||
# define LV_COLOR_GET_B1(c) (c).ch.blue
|
||||
# define LV_COLOR_GET_A1(c) 1
|
||||
|
||||
# define LV_COLOR_SET_R8(c, v) (c).ch.red = (uint8_t)(v) & 0x7U;
|
||||
# define LV_COLOR_SET_G8(c, v) (c).ch.green = (uint8_t)(v) & 0x7U;
|
||||
# define LV_COLOR_SET_B8(c, v) (c).ch.blue = (uint8_t)(v) & 0x3U;
|
||||
# define LV_COLOR_SET_A8(c, v) do {} while(0)
|
||||
|
||||
# define LV_COLOR_GET_R8(c) (c).ch.red
|
||||
# define LV_COLOR_GET_G8(c) (c).ch.green
|
||||
# define LV_COLOR_GET_B8(c) (c).ch.blue
|
||||
# define LV_COLOR_GET_A8(c) 0xFF
|
||||
|
||||
# define LV_COLOR_SET_R16(c, v) (c).ch.red = (uint8_t)(v) & 0x1FU;
|
||||
# define LV_COLOR_SET_G16(c, v) (c).ch.green = (uint8_t)(v) & 0x3FU;
|
||||
# define LV_COLOR_SET_G16_SWAP(c, v) {(c).ch.green_h = (uint8_t)(((v) >> 3) & 0x7); (c).ch.green_l = (uint8_t)((v) & 0x7);}
|
||||
# define LV_COLOR_SET_B16(c, v) (c).ch.blue = (uint8_t)(v) & 0x1FU;
|
||||
# define LV_COLOR_SET_A16(c, v) do {} while(0)
|
||||
|
||||
# define LV_COLOR_GET_R16(c) (c).ch.red
|
||||
# define LV_COLOR_GET_G16(c) (c).ch.green
|
||||
# define LV_COLOR_GET_G16_SWAP(c) (((c).ch.green_h << 3) + (c).ch.green_l)
|
||||
# define LV_COLOR_GET_B16(c) (c).ch.blue
|
||||
# define LV_COLOR_GET_A16(c) 0xFF
|
||||
|
||||
# define LV_COLOR_SET_R32(c, v) (c).ch.red = (uint32_t)((v) & 0xFF);
|
||||
# define LV_COLOR_SET_G32(c, v) (c).ch.green = (uint32_t)((v) & 0xFF);
|
||||
# define LV_COLOR_SET_B32(c, v) (c).ch.blue = (uint32_t)((v) & 0xFF);
|
||||
# define LV_COLOR_SET_A32(c, v) (c).ch.alpha = (uint32_t)((v) & 0xFF);
|
||||
|
||||
# define LV_COLOR_GET_R32(c) (c).ch.red
|
||||
# define LV_COLOR_GET_G32(c) (c).ch.green
|
||||
# define LV_COLOR_GET_B32(c) (c).ch.blue
|
||||
# define LV_COLOR_GET_A32(c) (c).ch.alpha
|
||||
|
||||
|
||||
/*---------------------------------------
|
||||
* Macros for the current color depth
|
||||
* to set/get values of the color channels
|
||||
*------------------------------------------*/
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
# define LV_COLOR_SET_R(c, v) LV_COLOR_SET_R1(c,v)
|
||||
# define LV_COLOR_SET_G(c, v) LV_COLOR_SET_G1(c,v)
|
||||
# define LV_COLOR_SET_B(c, v) LV_COLOR_SET_B1(c,v)
|
||||
# define LV_COLOR_SET_A(c, v) LV_COLOR_SET_A1(c,v)
|
||||
|
||||
# define LV_COLOR_GET_R(c) LV_COLOR_GET_R1(c)
|
||||
# define LV_COLOR_GET_G(c) LV_COLOR_GET_G1(c)
|
||||
# define LV_COLOR_GET_B(c) LV_COLOR_GET_B1(c)
|
||||
# define LV_COLOR_GET_A(c) LV_COLOR_GET_A1(c)
|
||||
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
# define LV_COLOR_SET_R(c, v) LV_COLOR_SET_R8(c,v)
|
||||
# define LV_COLOR_SET_G(c, v) LV_COLOR_SET_G8(c,v)
|
||||
# define LV_COLOR_SET_B(c, v) LV_COLOR_SET_B8(c,v)
|
||||
# define LV_COLOR_SET_A(c, v) LV_COLOR_SET_A8(c,v)
|
||||
|
||||
# define LV_COLOR_GET_R(c) LV_COLOR_GET_R8(c)
|
||||
# define LV_COLOR_GET_G(c) LV_COLOR_GET_G8(c)
|
||||
# define LV_COLOR_GET_B(c) LV_COLOR_GET_B8(c)
|
||||
# define LV_COLOR_GET_A(c) LV_COLOR_GET_A8(c)
|
||||
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
# define LV_COLOR_SET_R(c, v) LV_COLOR_SET_R16(c,v)
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
# define LV_COLOR_SET_G(c, v) LV_COLOR_SET_G16(c,v)
|
||||
# else
|
||||
# define LV_COLOR_SET_G(c, v) LV_COLOR_SET_G16_SWAP(c,v)
|
||||
# endif
|
||||
# define LV_COLOR_SET_B(c, v) LV_COLOR_SET_B16(c,v)
|
||||
# define LV_COLOR_SET_A(c, v) LV_COLOR_SET_A16(c,v)
|
||||
|
||||
# define LV_COLOR_GET_R(c) LV_COLOR_GET_R16(c)
|
||||
# if LV_COLOR_16_SWAP == 0
|
||||
# define LV_COLOR_GET_G(c) LV_COLOR_GET_G16(c)
|
||||
# else
|
||||
# define LV_COLOR_GET_G(c) LV_COLOR_GET_G16_SWAP(c)
|
||||
# endif
|
||||
# define LV_COLOR_GET_B(c) LV_COLOR_GET_B16(c)
|
||||
# define LV_COLOR_GET_A(c) LV_COLOR_GET_A16(c)
|
||||
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
# define LV_COLOR_SET_R(c, v) LV_COLOR_SET_R32(c,v)
|
||||
# define LV_COLOR_SET_G(c, v) LV_COLOR_SET_G32(c,v)
|
||||
# define LV_COLOR_SET_B(c, v) LV_COLOR_SET_B32(c,v)
|
||||
# define LV_COLOR_SET_A(c, v) LV_COLOR_SET_A32(c,v)
|
||||
|
||||
# define LV_COLOR_GET_R(c) LV_COLOR_GET_R32(c)
|
||||
# define LV_COLOR_GET_G(c) LV_COLOR_GET_G32(c)
|
||||
# define LV_COLOR_GET_B(c) LV_COLOR_GET_B32(c)
|
||||
# define LV_COLOR_GET_A(c) LV_COLOR_GET_A32(c)
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef union
|
||||
{
|
||||
uint8_t blue : 1;
|
||||
uint8_t green : 1;
|
||||
uint8_t red : 1;
|
||||
uint8_t full : 1;
|
||||
struct
|
||||
{
|
||||
uint8_t blue : 1;
|
||||
uint8_t green : 1;
|
||||
uint8_t red : 1;
|
||||
} ch;
|
||||
uint8_t full;
|
||||
} lv_color1_t;
|
||||
|
||||
typedef union
|
||||
@@ -191,24 +298,19 @@ static inline uint8_t lv_color_to1(lv_color_t color)
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
return color.full;
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
if((color.ch.red & 0x4) || (color.ch.green & 0x4) || (color.ch.blue & 0x2)) {
|
||||
if((LV_COLOR_GET_R(color) & 0x4) || (LV_COLOR_GET_G(color) & 0x4) || (LV_COLOR_GET_B(color) & 0x2)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
#if LV_COLOR_16_SWAP == 0
|
||||
if((color.ch.red & 0x10) || (color.ch.green & 0x20) || (color.ch.blue & 0x10)) {
|
||||
if((LV_COLOR_GET_R(color) & 0x10) || (LV_COLOR_GET_G(color) & 0x20) || (LV_COLOR_GET_B(color) & 0x10)) {
|
||||
return 1;
|
||||
#else
|
||||
if((color.ch.red & 0x10) || (color.ch.green_h & 0x20) || (color.ch.blue & 0x10)) {
|
||||
return 1;
|
||||
#endif
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
if((color.ch.red & 0x80) || (color.ch.green & 0x80) || (color.ch.blue & 0x80)) {
|
||||
if((LV_COLOR_GET_R(color) & 0x80) || (LV_COLOR_GET_G(color) & 0x80) || (LV_COLOR_GET_B(color) & 0x80)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@@ -226,25 +328,16 @@ 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.ch.red = color.ch.red >> 2; /* 5 - 3 = 2*/
|
||||
ret.ch.green = color.ch.green >> 3; /* 6 - 3 = 3*/
|
||||
ret.ch.blue = color.ch.blue >> 3; /* 5 - 2 = 3*/
|
||||
LV_COLOR_SET_R8(ret, LV_COLOR_GET_R(color) >> 2); /* 5 - 3 = 2*/
|
||||
LV_COLOR_SET_G8(ret, LV_COLOR_GET_G(color) >> 3); /* 6 - 3 = 3*/
|
||||
LV_COLOR_SET_B8(ret, LV_COLOR_GET_B(color) >> 3); /* 5 - 2 = 3*/
|
||||
return ret.full;
|
||||
#else
|
||||
lv_color8_t ret;
|
||||
ret.ch.red = color.ch.red >> 2; /* 5 - 3 = 2*/
|
||||
ret.ch.green = color.ch.green_h; /* 6 - 3 = 3*/
|
||||
ret.ch.blue = color.ch.blue >> 3; /* 5 - 2 = 3*/
|
||||
return ret.full;
|
||||
#endif
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
lv_color8_t ret;
|
||||
ret.ch.red = color.ch.red >> 5; /* 8 - 3 = 5*/
|
||||
ret.ch.green = color.ch.green >> 5; /* 8 - 3 = 5*/
|
||||
ret.ch.blue = color.ch.blue >> 6; /* 8 - 2 = 6*/
|
||||
LV_COLOR_SET_R8(ret, LV_COLOR_GET_R(color) >> 5); /* 8 - 3 = 5*/
|
||||
LV_COLOR_SET_G8(ret, LV_COLOR_GET_G(color) >> 5); /* 8 - 3 = 5*/
|
||||
LV_COLOR_SET_B8(ret, LV_COLOR_GET_B(color) >> 6); /* 8 - 2 = 6*/
|
||||
return ret.full;
|
||||
#endif
|
||||
}
|
||||
@@ -258,34 +351,28 @@ static inline uint16_t lv_color_to16(lv_color_t color)
|
||||
return 0xFFFF;
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
lv_color16_t ret;
|
||||
LV_COLOR_SET_R16(ret, LV_COLOR_GET_R(color) * 4); /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/
|
||||
#if LV_COLOR_16_SWAP == 0
|
||||
ret.ch.red = color.ch.red * 4; /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/
|
||||
ret.ch.green = color.ch.green * 9; /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/
|
||||
ret.ch.blue = color.ch.blue * 10; /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/
|
||||
LV_COLOR_SET_G16(ret, LV_COLOR_GET_G(color) * 9); /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/
|
||||
#else
|
||||
ret.red = color.ch.red * 4;
|
||||
uint8_t g_tmp = color.ch.green * 9;
|
||||
ret.ch.green_h = (g_tmp & 0x1F) >> 3;
|
||||
ret.ch.green_l = g_tmp & 0x07;
|
||||
ret.ch.blue = color.ch.blue * 10;
|
||||
LV_COLOR_SET_G16_SWAP(ret, (LV_COLOR_GET_G(color) * 9)); /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/
|
||||
#endif
|
||||
LV_COLOR_SET_B16(ret, LV_COLOR_GET_B(color) * 10); /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/
|
||||
return ret.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
return color.full;
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
lv_color16_t ret;
|
||||
LV_COLOR_SET_R16(ret, LV_COLOR_GET_R(color) >> 3); /* 8 - 5 = 3*/
|
||||
|
||||
#if LV_COLOR_16_SWAP == 0
|
||||
ret.ch.red = color.ch.red >> 3; /* 8 - 5 = 3*/
|
||||
ret.ch.green = color.ch.green >> 2; /* 8 - 6 = 2*/
|
||||
ret.ch.blue = color.ch.blue >> 3; /* 8 - 5 = 3*/
|
||||
LV_COLOR_SET_G16(ret, LV_COLOR_GET_G(color) >> 2); /* 8 - 6 = 2*/
|
||||
#else
|
||||
ret.ch.red = color.ch.red >> 3;
|
||||
ret.ch.green_h = (color.ch.green & 0xE0) >> 5;
|
||||
ret.ch.green_l = (color.ch.green & 0x1C) >> 2;
|
||||
ret.ch.blue = color.ch.blue >> 3;
|
||||
LV_COLOR_SET_G16_SWAP(ret, ret.ch.green_h = (LV_COLOR_GET_G(color) >> 2); /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/
|
||||
#endif
|
||||
LV_COLOR_SET_B16(ret, LV_COLOR_GET_B(color) >> 3); /* 8 - 5 = 3*/
|
||||
return ret.full;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t lv_color_to32(lv_color_t color)
|
||||
@@ -297,27 +384,46 @@ static inline uint32_t lv_color_to32(lv_color_t color)
|
||||
return 0xFFFFFFFF;
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
lv_color32_t ret;
|
||||
ret.ch.red = color.ch.red * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/
|
||||
ret.ch.green = color.ch.green * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/
|
||||
ret.ch.blue = color.ch.blue * 85; /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/
|
||||
ret.ch.alpha = 0xFF;
|
||||
LV_COLOR_SET_R32(ret, LV_COLOR_GET_R(color) * 36); /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/
|
||||
LV_COLOR_SET_G32(ret, LV_COLOR_GET_G(color) * 36); /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/
|
||||
LV_COLOR_SET_B32(ret, LV_COLOR_GET_B(color) * 85); /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/
|
||||
LV_COLOR_SET_A32(ret, 0xFF);
|
||||
return ret.full;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
#if LV_COLOR_16_SWAP == 0
|
||||
/**
|
||||
* The floating point math for conversion is:
|
||||
* valueto = valuefrom * ( (2^bitsto - 1) / (float)(2^bitsfrom - 1) )
|
||||
* The faster integer math for conversion is:
|
||||
* valueto = ( valuefrom * multiplier + adder ) >> divisor
|
||||
* multiplier = FLOOR( ( (2^bitsto - 1) << divisor ) / (float)(2^bitsfrom - 1) )
|
||||
*
|
||||
* Find the first divisor where ( adder >> divisor ) <= 0
|
||||
*
|
||||
* 5-bit to 8-bit: ( 31 * multiplier + adder ) >> divisor = 255
|
||||
* divisor multiplier adder min (0) max (31)
|
||||
* 0 8 7 7 255
|
||||
* 1 16 14 7 255
|
||||
* 2 32 28 7 255
|
||||
* 3 65 25 3 255
|
||||
* 4 131 19 1 255
|
||||
* 5 263 7 0 255
|
||||
*
|
||||
* 6-bit to 8-bit: 255 = ( 63 * multiplier + adder ) >> divisor
|
||||
* divisor multiplier adder min (0) max (63)
|
||||
* 0 4 3 3 255
|
||||
* 1 8 6 3 255
|
||||
* 2 16 12 3 255
|
||||
* 3 32 24 3 255
|
||||
* 4 64 48 3 255
|
||||
* 5 129 33 1 255
|
||||
* 6 259 3 0 255
|
||||
*/
|
||||
lv_color32_t ret;
|
||||
ret.ch.red = color.ch.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
|
||||
ret.ch.green = color.ch.green * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/
|
||||
ret.ch.blue = color.ch.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
|
||||
ret.ch.alpha = 0xFF;
|
||||
LV_COLOR_SET_R32(ret, (LV_COLOR_GET_R(color) * 263 + 7 ) >> 5);
|
||||
LV_COLOR_SET_G32(ret, (LV_COLOR_GET_G(color) * 259 + 3 ) >> 6);
|
||||
LV_COLOR_SET_B32(ret, (LV_COLOR_GET_B(color) * 263 + 7 ) >> 5);
|
||||
LV_COLOR_SET_A32(ret, 0xFF);
|
||||
return ret.full;
|
||||
#else
|
||||
lv_color32_t ret;
|
||||
ret.ch.red = color.ch.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
|
||||
ret.ch.green = ((color.ch.green_h << 3) + color.ch.green_l) * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/
|
||||
ret.ch.blue = color.ch.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
|
||||
ret.ch.alpha = 0xFF;
|
||||
return ret.full;
|
||||
#endif
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
return color.full;
|
||||
#endif
|
||||
@@ -328,21 +434,10 @@ static inline lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix)
|
||||
lv_color_t ret;
|
||||
#if LV_COLOR_DEPTH != 1
|
||||
/*LV_COLOR_DEPTH == 8, 16 or 32*/
|
||||
ret.ch.red = (uint16_t)((uint16_t)c1.ch.red * mix + (c2.ch.red * (255 - mix))) >> 8;
|
||||
#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP
|
||||
/*If swapped Green is in 2 parts*/
|
||||
uint16_t g_1 = (c1.ch.green_h << 3) + c1.ch.green_l;
|
||||
uint16_t g_2 = (c2.ch.green_h << 3) + c2.ch.green_l;
|
||||
uint16_t g_out = (uint16_t)((uint16_t)g_1 * mix + (g_2 * (255 - mix))) >> 8;
|
||||
ret.ch.green_h = g_out >> 3;
|
||||
ret.ch.green_l = g_out & 0x7;
|
||||
#else
|
||||
ret.ch.green = (uint16_t)((uint16_t)c1.ch.green * mix + (c2.ch.green * (255 - mix))) >> 8;
|
||||
#endif
|
||||
ret.ch.blue = (uint16_t)((uint16_t)c1.ch.blue * mix + (c2.ch.blue * (255 - mix))) >> 8;
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
ret.ch.alpha = 0xFF;
|
||||
#endif
|
||||
LV_COLOR_SET_R(ret, (uint16_t)((uint16_t) LV_COLOR_GET_R(c1) * mix + LV_COLOR_GET_R(c2) * (255 - mix)) >> 8);
|
||||
LV_COLOR_SET_G(ret, (uint16_t)((uint16_t) LV_COLOR_GET_G(c1) * mix + LV_COLOR_GET_G(c2) * (255 - mix)) >> 8);
|
||||
LV_COLOR_SET_B(ret, (uint16_t)((uint16_t) LV_COLOR_GET_B(c1) * mix + LV_COLOR_GET_B(c2) * (255 - mix)) >> 8);
|
||||
LV_COLOR_SET_A(ret, 0xFF);
|
||||
#else
|
||||
/*LV_COLOR_DEPTH == 1*/
|
||||
ret.full = mix > LV_OPA_50 ? c1.full : c2.full;
|
||||
@@ -360,65 +455,30 @@ static inline uint8_t lv_color_brightness(lv_color_t color)
|
||||
{
|
||||
lv_color32_t c32;
|
||||
c32.full = lv_color_to32(color);
|
||||
uint16_t bright = 3 * c32.ch.red + c32.ch.blue + 4 * c32.ch.green;
|
||||
return (uint16_t)bright >> 3;
|
||||
uint16_t bright = (uint16_t)(3u * LV_COLOR_GET_R32(c32) + LV_COLOR_GET_B32(c32) + 4u * LV_COLOR_GET_G32(c32));
|
||||
return (uint8_t)(bright >> 3);
|
||||
}
|
||||
|
||||
/* The most simple macro to create a color from R,G and B values */
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(b8 >> 7 | g8 >> 7 | r8 >> 7)})
|
||||
static inline lv_color_t lv_color_make(int r8, int g8, int b8)
|
||||
{
|
||||
lv_color_t color;
|
||||
color.full = (b8 >> 7 | g8 >> 7 | r8 >> 7);
|
||||
return color;
|
||||
}
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){.full = (uint8_t)((b8 >> 7) | (g8 >> 7) | (r8 >> 7))})
|
||||
#elif LV_COLOR_DEPTH == 8
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 6, g8 >> 5, r8 >> 5}})
|
||||
static inline lv_color_t lv_color_make(uint8_t r8, int g8, int b8)
|
||||
{
|
||||
lv_color_t color;
|
||||
color.ch.blue = b8 >> 6;
|
||||
color.ch.green = g8 >> 5;
|
||||
color.ch.red = r8 >> 5;
|
||||
return color;
|
||||
}
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{(uint8_t)((b8 >> 6) & 0x3U), (uint8_t)((g8 >> 5) & 0x7U), (uint8_t)((r8 >> 5) & 0x7U)}})
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
#if LV_COLOR_16_SWAP == 0
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 3, g8 >> 2, r8 >> 3}})
|
||||
static inline lv_color_t lv_color_make(uint8_t r8, uint8_t g8, uint8_t b8)
|
||||
{
|
||||
lv_color_t color;
|
||||
color.ch.blue = (uint16_t)(b8 >> 3);
|
||||
color.ch.green = (uint16_t)(g8 >> 2);
|
||||
color.ch.red = (uint16_t)(r8 >> 3);
|
||||
return color;
|
||||
}
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{(uint16_t)((b8 >> 3) & 0x1FU), (uint16_t)((g8 >> 2) & 0x3FU), (uint16_t)((r8 >> 3) & 0x1FU)}})
|
||||
#else
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{g8 >> 5, r8 >> 3, b8 >> 3, (g8 >> 2) & 0x7}})
|
||||
static inline lv_color_t lv_color_make(uint8_t r8, uint8_t g8, uint8_t b8)
|
||||
{
|
||||
lv_color_t color;
|
||||
color.ch.green_h = (uint16_t)(g8 >> 5);
|
||||
color.ch.red = (uint16_t)(r8 >> 3);
|
||||
color.ch.blue = (uint16_t)(b8 >> 3);
|
||||
color.ch.green_l = (uint16_t)((g8 >> 2) & 0x7);
|
||||
return color;
|
||||
}
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{(uint16_t)((g8 >> 5) & 0x7U), (uint16_t)((r8 >> 3) & 0x1FU), (uint16_t)((b8 >> 3) & 0x1FU), (uint16_t)((g8 >> 2) & 0x7U)}})
|
||||
#endif
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8, g8, r8, 0xff}}) /*Fix 0xff alpha*/
|
||||
static inline lv_color_t lv_color_make(uint8_t r8, uint8_t g8, uint8_t b8)
|
||||
{
|
||||
lv_color_t color;
|
||||
color.ch.blue = b8;
|
||||
color.ch.green = g8;
|
||||
color.ch.red = r8;
|
||||
color.ch.alpha = 0xff;
|
||||
return color;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline lv_color_t lv_color_make(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return LV_COLOR_MAKE(r, g, b);
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_color_hex(uint32_t c)
|
||||
{
|
||||
return lv_color_make((uint8_t)((c >> 16) & 0xFF), (uint8_t)((c >> 8) & 0xFF), (uint8_t)(c & 0xFF));
|
||||
@@ -440,13 +500,20 @@ static inline lv_color_t lv_color_hex3(uint32_t c)
|
||||
lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v);
|
||||
|
||||
/**
|
||||
* Convert an RGB color to HSV
|
||||
* @param r red
|
||||
* @param g green
|
||||
* @param b blue
|
||||
* @return the given RGB color n HSV
|
||||
* Convert a 32-bit RGB color to HSV
|
||||
* @param r8 8-bit red
|
||||
* @param g8 8-bit green
|
||||
* @param b8 8-bit blue
|
||||
* @return the given RGB color in HSV
|
||||
*/
|
||||
lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b);
|
||||
lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r8, uint8_t g8, uint8_t b8);
|
||||
|
||||
/**
|
||||
* Convert a color to HSV
|
||||
* @param color color
|
||||
* @return the given color in HSV
|
||||
*/
|
||||
lv_color_hsv_t lv_color_to_hsv(lv_color_t color);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "lv_fs.h"
|
||||
#if LV_USE_FILESYSTEM
|
||||
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "lv_ll.h"
|
||||
#include <string.h>
|
||||
#include "lv_gc.h"
|
||||
@@ -37,7 +38,6 @@
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static const char * lv_fs_get_real_path(const char * path);
|
||||
static lv_fs_drv_t * lv_fs_get_drv(char letter);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -108,7 +108,7 @@ lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mo
|
||||
}
|
||||
|
||||
file_p->file_d = lv_mem_alloc(file_p->drv->file_size);
|
||||
lv_mem_assert(file_p->file_d);
|
||||
LV_ASSERT_MEM(file_p->file_d);
|
||||
if(file_p->file_d == NULL) {
|
||||
file_p->drv = NULL;
|
||||
return LV_FS_RES_OUT_OF_MEM; /* Out of memory */
|
||||
@@ -368,7 +368,7 @@ lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path)
|
||||
}
|
||||
|
||||
rddir_p->dir_d = lv_mem_alloc(rddir_p->drv->rddir_size);
|
||||
lv_mem_assert(rddir_p->dir_d);
|
||||
LV_ASSERT_MEM(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 */
|
||||
@@ -487,12 +487,30 @@ void lv_fs_drv_register(lv_fs_drv_t * drv_p)
|
||||
/*Save the new driver*/
|
||||
lv_fs_drv_t * new_drv;
|
||||
new_drv = lv_ll_ins_head(&LV_GC_ROOT(_lv_drv_ll));
|
||||
lv_mem_assert(new_drv);
|
||||
LV_ASSERT_MEM(new_drv);
|
||||
if(new_drv == NULL) return;
|
||||
|
||||
memcpy(new_drv, drv_p, sizeof(lv_fs_drv_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Give a pointer to a driver from its letter
|
||||
* @param letter the driver letter
|
||||
* @return pointer to a driver or NULL if not found
|
||||
*/
|
||||
lv_fs_drv_t * lv_fs_get_drv(char letter)
|
||||
{
|
||||
lv_fs_drv_t * drv;
|
||||
|
||||
LV_LL_READ(LV_GC_ROOT(_lv_drv_ll), drv)
|
||||
{
|
||||
if(drv->letter == letter) {
|
||||
return drv;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/**
|
||||
* Fill a buffer with the letters of existing drivers
|
||||
* @param buf buffer to store the letters ('\0' added after the last letter)
|
||||
@@ -521,7 +539,7 @@ char * lv_fs_get_letters(char * buf)
|
||||
*/
|
||||
const char * lv_fs_get_ext(const char * fn)
|
||||
{
|
||||
uint16_t i;
|
||||
size_t i;
|
||||
for(i = strlen(fn); i > 0; i--) {
|
||||
if(fn[i] == '.') {
|
||||
return &fn[i + 1];
|
||||
@@ -540,7 +558,7 @@ const char * lv_fs_get_ext(const char * fn)
|
||||
*/
|
||||
char * lv_fs_up(char * path)
|
||||
{
|
||||
uint16_t len = strlen(path);
|
||||
size_t len = strlen(path);
|
||||
if(len == 0) return path;
|
||||
|
||||
len--; /*Go before the trailing '\0'*/
|
||||
@@ -554,7 +572,7 @@ char * lv_fs_up(char * path)
|
||||
return path;
|
||||
}
|
||||
|
||||
uint16_t i;
|
||||
size_t i;
|
||||
for(i = len; i > 0; i--) {
|
||||
if(path[i] == '/' || path[i] == '\\') break;
|
||||
}
|
||||
@@ -571,7 +589,7 @@ char * lv_fs_up(char * path)
|
||||
*/
|
||||
const char * lv_fs_get_last(const char * path)
|
||||
{
|
||||
uint16_t len = strlen(path);
|
||||
size_t len = strlen(path);
|
||||
if(len == 0) return path;
|
||||
|
||||
len--; /*Go before the trailing '\0'*/
|
||||
@@ -584,7 +602,7 @@ const char * lv_fs_get_last(const char * path)
|
||||
return path;
|
||||
}
|
||||
|
||||
uint16_t i;
|
||||
size_t i;
|
||||
for(i = len; i > 0; i--) {
|
||||
if(path[i] == '/' || path[i] == '\\') break;
|
||||
}
|
||||
@@ -621,23 +639,4 @@ static const char * lv_fs_get_real_path(const char * path)
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give a pointer to a driver from its letter
|
||||
* @param letter the driver letter
|
||||
* @return pointer to a driver or NULL if not found
|
||||
*/
|
||||
static lv_fs_drv_t * lv_fs_get_drv(char letter)
|
||||
{
|
||||
lv_fs_drv_t * drv;
|
||||
|
||||
LV_LL_READ(LV_GC_ROOT(_lv_drv_ll), drv)
|
||||
{
|
||||
if(drv->letter == letter) {
|
||||
return drv;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_FILESYSTEM*/
|
||||
|
||||
@@ -29,6 +29,7 @@ extern "C" {
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_FS_MAX_FN_LENGTH 64
|
||||
#define LV_FS_MAX_PATH_LENGTH 256
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -126,6 +127,13 @@ void lv_fs_drv_init(lv_fs_drv_t * drv);
|
||||
*/
|
||||
void lv_fs_drv_register(lv_fs_drv_t * drv_p);
|
||||
|
||||
/**
|
||||
* Give a pointer to a driver from its letter
|
||||
* @param letter the driver letter
|
||||
* @return pointer to a driver or NULL if not found
|
||||
*/
|
||||
lv_fs_drv_t * lv_fs_get_drv(char letter);
|
||||
|
||||
/**
|
||||
* Test if a drive is rady or not. If the `ready` function was not initialized `true` will be
|
||||
* returned.
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
*********************/
|
||||
|
||||
#include "lv_gc.h"
|
||||
#include "string.h"
|
||||
|
||||
#if defined(LV_GC_INCLUDE)
|
||||
#include LV_GC_INCLUDE
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -35,6 +40,12 @@ LV_ROOTS
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_gc_clear_roots(void)
|
||||
{
|
||||
#define LV_CLEAR_ROOT(root_type, root_name) memset(&LV_GC_ROOT(root_name), 0, sizeof(LV_GC_ROOT(root_name)));
|
||||
LV_ITERATE_ROOTS(LV_CLEAR_ROOT)
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
@@ -30,20 +30,21 @@ extern "C" {
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define LV_GC_ROOTS(prefix) \
|
||||
prefix lv_ll_t _lv_task_ll; /*Linked list to store the lv_tasks*/ \
|
||||
prefix lv_ll_t _lv_disp_ll; /*Linked list of screens*/ \
|
||||
prefix lv_ll_t _lv_indev_ll; /*Linked list of screens*/ \
|
||||
prefix lv_ll_t _lv_drv_ll; \
|
||||
prefix lv_ll_t _lv_file_ll; \
|
||||
prefix lv_ll_t _lv_anim_ll; \
|
||||
prefix lv_ll_t _lv_group_ll; \
|
||||
prefix lv_ll_t _lv_img_defoder_ll; \
|
||||
prefix lv_img_cache_entry_t * _lv_img_cache_array; \
|
||||
prefix void * _lv_task_act;
|
||||
#define LV_ITERATE_ROOTS(f) \
|
||||
f(lv_ll_t, _lv_task_ll) /*Linked list to store the lv_tasks*/ \
|
||||
f(lv_ll_t, _lv_disp_ll) /*Linked list of screens*/ \
|
||||
f(lv_ll_t, _lv_indev_ll) /*Linked list of screens*/ \
|
||||
f(lv_ll_t, _lv_drv_ll) \
|
||||
f(lv_ll_t, _lv_file_ll) \
|
||||
f(lv_ll_t, _lv_anim_ll) \
|
||||
f(lv_ll_t, _lv_group_ll) \
|
||||
f(lv_ll_t, _lv_img_defoder_ll) \
|
||||
f(lv_img_cache_entry_t*, _lv_img_cache_array) \
|
||||
f(void*, _lv_task_act) \
|
||||
f(void*, _lv_draw_buf)
|
||||
|
||||
#define LV_NO_PREFIX
|
||||
#define LV_ROOTS LV_GC_ROOTS(LV_NO_PREFIX)
|
||||
#define LV_DEFINE_ROOT(root_type, root_name) root_type root_name;
|
||||
#define LV_ROOTS LV_ITERATE_ROOTS(LV_DEFINE_ROOT)
|
||||
|
||||
#if LV_ENABLE_GC == 1
|
||||
#if LV_MEM_CUSTOM != 1
|
||||
@@ -51,7 +52,8 @@ extern "C" {
|
||||
#endif /* LV_MEM_CUSTOM */
|
||||
#else /* LV_ENABLE_GC */
|
||||
#define LV_GC_ROOT(x) x
|
||||
LV_GC_ROOTS(extern)
|
||||
#define LV_EXTERN_ROOT(root_type, root_name) extern root_type root_name;
|
||||
LV_ITERATE_ROOTS(LV_EXTERN_ROOT)
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
/**********************
|
||||
@@ -62,6 +64,8 @@ LV_GC_ROOTS(extern)
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_gc_clear_roots(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -335,14 +335,6 @@ uint32_t lv_ll_get_len(const lv_ll_t * ll_p)
|
||||
return len;
|
||||
}
|
||||
|
||||
void lv_ll_swap(lv_ll_t * ll_p, void * n1_p, void * n2_p)
|
||||
{
|
||||
(void)(ll_p);
|
||||
(void)(n1_p);
|
||||
(void)(n2_p);
|
||||
/*TODO*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a nodw before an other node in the same linked list
|
||||
* @param ll_p pointer to a linked list
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#if LV_LOG_PRINTF
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
@@ -30,7 +30,14 @@ extern "C" {
|
||||
#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 /**< Number of log levels */
|
||||
#define LV_LOG_LEVEL_NONE 4 /**< Do not log anything*/
|
||||
#define _LV_LOG_LEVEL_NUM 5 /**< Number of log levels */
|
||||
|
||||
LV_EXPORT_CONST_INT(LV_LOG_LEVEL_TRACE);
|
||||
LV_EXPORT_CONST_INT(LV_LOG_LEVEL_INFO);
|
||||
LV_EXPORT_CONST_INT(LV_LOG_LEVEL_WARN);
|
||||
LV_EXPORT_CONST_INT(LV_LOG_LEVEL_ERROR);
|
||||
LV_EXPORT_CONST_INT(LV_LOG_LEVEL_NONE);
|
||||
|
||||
typedef int8_t lv_log_level_t;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static int16_t sin0_90_table[] = {
|
||||
static const 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,
|
||||
@@ -94,6 +94,110 @@ int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3)
|
||||
return v1 + v2 + v3 + v4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the atan2 of a vector.
|
||||
* @param x
|
||||
* @param y
|
||||
* @return the angle in degree calculated from the given parameters in range of [0..360]
|
||||
*/
|
||||
uint16_t lv_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the integer square root of a number.
|
||||
* @param num
|
||||
* @return square root of 'num'
|
||||
*/
|
||||
uint32_t lv_sqrt(uint32_t num)
|
||||
{
|
||||
// http://www.codecodex.com/wiki/Calculate_an_integer_square_root#C
|
||||
uint32_t root = 0;
|
||||
uint32_t place = 0x40000000;
|
||||
|
||||
while(place > num) place >>= 2;
|
||||
while(place) {
|
||||
if(num >= root + place) {
|
||||
num -= root + place;
|
||||
root += (place << 1);
|
||||
}
|
||||
root >>= 1;
|
||||
place >>= 2;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
@@ -22,6 +22,11 @@ extern "C" {
|
||||
#define LV_MATH_MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define LV_MATH_ABS(x) ((x) > 0 ? (x) : (-(x)))
|
||||
|
||||
#define LV_IS_SIGNED(t) (((t)(-1)) < ((t) 0))
|
||||
#define LV_UMAX_OF(t) (((0x1ULL << ((sizeof(t) * 8ULL) - 1ULL)) - 1ULL) | (0xFULL << ((sizeof(t) * 8ULL) - 4ULL)))
|
||||
#define LV_SMAX_OF(t) (((0x1ULL << ((sizeof(t) * 8ULL) - 1ULL)) - 1ULL) | (0x7ULL << ((sizeof(t) * 8ULL) - 4ULL)))
|
||||
#define LV_MAX_OF(t) ((unsigned long) (LV_IS_SIGNED(t) ? LV_SMAX_OF(t) : LV_UMAX_OF(t)))
|
||||
|
||||
#define LV_TRIGO_SIN_MAX 32767
|
||||
#define LV_TRIGO_SHIFT 15 /**< >> LV_TRIGO_SHIFT to normalize*/
|
||||
|
||||
@@ -54,6 +59,21 @@ int16_t lv_trigo_sin(int16_t angle);
|
||||
*/
|
||||
int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3);
|
||||
|
||||
/**
|
||||
* Calculate the atan2 of a vector.
|
||||
* @param x
|
||||
* @param y
|
||||
* @return the angle in degree calculated from the given parameters in range of [0..360]
|
||||
*/
|
||||
uint16_t lv_atan2(int x, int y);
|
||||
|
||||
/**
|
||||
* Calculate the integer square root of a number.
|
||||
* @param num
|
||||
* @return square root of 'num'
|
||||
*/
|
||||
uint32_t lv_sqrt(uint32_t num);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -19,9 +19,11 @@
|
||||
* DEFINES
|
||||
*********************/
|
||||
/*Add memory junk on alloc (0xaa) and free(0xbb) (just for testing purposes)*/
|
||||
#define LV_MEM_ADD_JUNK 1
|
||||
#ifndef LV_MEM_ADD_JUNK
|
||||
#define LV_MEM_ADD_JUNK 0
|
||||
#endif
|
||||
|
||||
#ifdef LV_MEM_ENV64
|
||||
#ifdef LV_ARCH_64
|
||||
#define MEM_UNIT uint64_t
|
||||
#else
|
||||
#define MEM_UNIT uint32_t
|
||||
@@ -38,10 +40,10 @@ typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
MEM_UNIT used : 1; // 1: if the entry is used
|
||||
MEM_UNIT d_size : 31; // Size off the data (1 means 4 bytes)
|
||||
MEM_UNIT used : 1; /* 1: if the entry is used*/
|
||||
MEM_UNIT d_size : 31; /* Size off the data (1 means 4 bytes)*/
|
||||
} s;
|
||||
MEM_UNIT header; // The header (used + d_size)
|
||||
MEM_UNIT header; /* The header (used + d_size)*/
|
||||
} lv_mem_header_t;
|
||||
|
||||
typedef struct
|
||||
@@ -57,8 +59,8 @@ typedef struct
|
||||
**********************/
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e);
|
||||
static void * ent_alloc(lv_mem_ent_t * e, uint32_t size);
|
||||
static void ent_trunc(lv_mem_ent_t * e, uint32_t size);
|
||||
static void * ent_alloc(lv_mem_ent_t * e, size_t size);
|
||||
static void ent_trunc(lv_mem_ent_t * e, size_t size);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
@@ -100,18 +102,33 @@ void lv_mem_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up the memory buffer which frees all the allocated memories.
|
||||
* @note It work only if `LV_MEM_CUSTOM == 0`
|
||||
*/
|
||||
void lv_mem_deinit(void)
|
||||
{
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
memset(work_mem, 0x00, (LV_MEM_SIZE / sizeof(MEM_UNIT)) * sizeof(MEM_UNIT));
|
||||
lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem;
|
||||
full->header.s.used = 0;
|
||||
/*The total mem size id reduced by the first header and the close patterns */
|
||||
full->header.s.d_size = LV_MEM_SIZE - sizeof(lv_mem_header_t);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a memory dynamically
|
||||
* @param size size of the memory to allocate in bytes
|
||||
* @return pointer to the allocated memory
|
||||
*/
|
||||
void * lv_mem_alloc(uint32_t size)
|
||||
void * lv_mem_alloc(size_t size)
|
||||
{
|
||||
if(size == 0) {
|
||||
return &zero_mem;
|
||||
}
|
||||
|
||||
#ifdef LV_MEM_ENV64
|
||||
#ifdef LV_ARCH_64
|
||||
/*Round the size up to 8*/
|
||||
if(size & 0x7) {
|
||||
size = size & (~0x7);
|
||||
@@ -130,16 +147,16 @@ void * lv_mem_alloc(uint32_t size)
|
||||
/*Use the built-in allocators*/
|
||||
lv_mem_ent_t * e = NULL;
|
||||
|
||||
// Search for a appropriate entry
|
||||
/* Search for a appropriate entry*/
|
||||
do {
|
||||
// Get the next entry
|
||||
/* Get the next entry*/
|
||||
e = ent_get_next(e);
|
||||
|
||||
/*If there is next entry then try to allocate there*/
|
||||
if(e != NULL) {
|
||||
alloc = ent_alloc(e, size);
|
||||
}
|
||||
// End if there is not next entry OR the alloc. is successful
|
||||
/* End if there is not next entry OR the alloc. is successful*/
|
||||
} while(e != NULL && alloc == NULL);
|
||||
|
||||
#else
|
||||
@@ -220,7 +237,7 @@ void lv_mem_free(const void * data)
|
||||
|
||||
#if LV_ENABLE_GC == 0
|
||||
|
||||
void * lv_mem_realloc(void * data_p, uint32_t new_size)
|
||||
void * lv_mem_realloc(void * data_p, size_t new_size)
|
||||
{
|
||||
/*data_p could be previously freed pointer (in this case it is invalid)*/
|
||||
if(data_p != NULL) {
|
||||
@@ -260,7 +277,7 @@ void * lv_mem_realloc(void * data_p, uint32_t new_size)
|
||||
|
||||
#else /* LV_ENABLE_GC */
|
||||
|
||||
void * lv_mem_realloc(void * data_p, uint32_t new_size)
|
||||
void * lv_mem_realloc(void * data_p, size_t new_size)
|
||||
{
|
||||
void * new_p = LV_MEM_CUSTOM_REALLOC(data_p, new_size);
|
||||
if(new_p == NULL) LV_LOG_WARN("Couldn't allocate memory");
|
||||
@@ -405,7 +422,7 @@ static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e)
|
||||
* @param size size of the new memory in bytes
|
||||
* @return pointer to the allocated memory or NULL if not enough memory in the entry
|
||||
*/
|
||||
static void * ent_alloc(lv_mem_ent_t * e, uint32_t size)
|
||||
static void * ent_alloc(lv_mem_ent_t * e, size_t size)
|
||||
{
|
||||
void * alloc = NULL;
|
||||
|
||||
@@ -428,9 +445,9 @@ static void * ent_alloc(lv_mem_ent_t * e, uint32_t size)
|
||||
* @param e Pointer to an entry
|
||||
* @param size new size in bytes
|
||||
*/
|
||||
static void ent_trunc(lv_mem_ent_t * e, uint32_t size)
|
||||
static void ent_trunc(lv_mem_ent_t * e, size_t size)
|
||||
{
|
||||
#ifdef LV_MEM_ENV64
|
||||
#ifdef LV_ARCH_64
|
||||
/*Round the size up to 8*/
|
||||
if(size & 0x7) {
|
||||
size = size & (~0x7);
|
||||
@@ -454,11 +471,11 @@ static void ent_trunc(lv_mem_ent_t * e, uint32_t size)
|
||||
uint8_t * e_data = &e->first_data;
|
||||
lv_mem_ent_t * after_new_e = (lv_mem_ent_t *)&e_data[size];
|
||||
after_new_e->header.s.used = 0;
|
||||
after_new_e->header.s.d_size = e->header.s.d_size - size - sizeof(lv_mem_header_t);
|
||||
after_new_e->header.s.d_size = (uint32_t)e->header.s.d_size - size - sizeof(lv_mem_header_t);
|
||||
}
|
||||
|
||||
/* Set the new size for the original entry */
|
||||
e->header.s.d_size = size;
|
||||
e->header.s.d_size = (uint32_t)size;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,21 +22,11 @@ extern "C" {
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "lv_log.h"
|
||||
#include "lv_types.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
// Check windows
|
||||
#ifdef __WIN64
|
||||
#define LV_MEM_ENV64
|
||||
#endif
|
||||
|
||||
// Check GCC
|
||||
#ifdef __GNUC__
|
||||
#if defined(__x86_64__) || defined(__ppc64__)
|
||||
#define LV_MEM_ENV64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -65,12 +55,18 @@ typedef struct
|
||||
*/
|
||||
void lv_mem_init(void);
|
||||
|
||||
/**
|
||||
* Clean up the memory buffer which frees all the allocated memories.
|
||||
* @note It work only if `LV_MEM_CUSTOM == 0`
|
||||
*/
|
||||
void lv_mem_deinit(void);
|
||||
|
||||
/**
|
||||
* Allocate a memory dynamically
|
||||
* @param size size of the memory to allocate in bytes
|
||||
* @return pointer to the allocated memory
|
||||
*/
|
||||
void * lv_mem_alloc(uint32_t size);
|
||||
void * lv_mem_alloc(size_t size);
|
||||
|
||||
/**
|
||||
* Free an allocated data
|
||||
@@ -85,7 +81,7 @@ void lv_mem_free(const void * data);
|
||||
* @param new_size the desired new size in byte
|
||||
* @return pointer to the new memory
|
||||
*/
|
||||
void * lv_mem_realloc(void * data_p, uint32_t new_size);
|
||||
void * lv_mem_realloc(void * data_p, size_t new_size);
|
||||
|
||||
/**
|
||||
* Join the adjacent free memory blocks
|
||||
@@ -110,27 +106,6 @@ uint32_t lv_mem_get_size(const void * data);
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Halt on NULL pointer
|
||||
* p pointer to a memory
|
||||
*/
|
||||
#if LV_USE_LOG == 0
|
||||
#define lv_mem_assert(p) \
|
||||
{ \
|
||||
if(p == NULL) \
|
||||
while(1) \
|
||||
; \
|
||||
}
|
||||
#else
|
||||
#define lv_mem_assert(p) \
|
||||
{ \
|
||||
if(p == NULL) { \
|
||||
LV_LOG_ERROR("Out of memory!"); \
|
||||
while(1) \
|
||||
; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -11,6 +11,10 @@ CSRCS += lv_math.c
|
||||
CSRCS += lv_log.c
|
||||
CSRCS += lv_gc.c
|
||||
CSRCS += lv_utils.c
|
||||
CSRCS += lv_async.c
|
||||
CSRCS += lv_printf.c
|
||||
CSRCS += lv_bidi.c
|
||||
|
||||
|
||||
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/src/lv_misc
|
||||
VPATH += :$(LVGL_DIR)/lvgl/src/lv_misc
|
||||
|
||||
852
src/lv_misc/lv_printf.c
Normal file
852
src/lv_misc/lv_printf.c
Normal file
@@ -0,0 +1,852 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources. These routines are thread
|
||||
// safe and reentrant!
|
||||
// Use this instead of the bloated standard/newlib printf cause these use
|
||||
// malloc for printf (and may not be thread safe).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "lv_printf.h"
|
||||
|
||||
#if LV_SPRINTF_CUSTOM == 0
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// 'ntoa' conversion buffer size, this must be big enough to hold one converted
|
||||
// numeric number including padded zeros (dynamically created on stack)
|
||||
// default: 32 byte
|
||||
#ifndef PRINTF_NTOA_BUFFER_SIZE
|
||||
#define PRINTF_NTOA_BUFFER_SIZE 32U
|
||||
#endif
|
||||
|
||||
// 'ftoa' conversion buffer size, this must be big enough to hold one converted
|
||||
// float number including padded zeros (dynamically created on stack)
|
||||
// default: 32 byte
|
||||
#ifndef PRINTF_FTOA_BUFFER_SIZE
|
||||
#define PRINTF_FTOA_BUFFER_SIZE 32U
|
||||
#endif
|
||||
|
||||
// support for the floating point type (%f)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_FLOAT
|
||||
#define PRINTF_SUPPORT_FLOAT
|
||||
#endif
|
||||
|
||||
// support for exponential floating point notation (%e/%g)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
|
||||
#define PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif
|
||||
|
||||
// define the default floating point precision
|
||||
// default: 6 digits
|
||||
#ifndef PRINTF_DEFAULT_FLOAT_PRECISION
|
||||
#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
|
||||
#endif
|
||||
|
||||
// define the largest float suitable to print with %f
|
||||
// default: 1e9
|
||||
#ifndef PRINTF_MAX_FLOAT
|
||||
#define PRINTF_MAX_FLOAT 1e9
|
||||
#endif
|
||||
|
||||
// support for the long long types (%llu or %p)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
|
||||
#define PRINTF_SUPPORT_LONG_LONG
|
||||
#endif
|
||||
|
||||
// support for the ptrdiff_t type (%t)
|
||||
// ptrdiff_t is normally defined in <stddef.h> as long or long long type
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
|
||||
#define PRINTF_SUPPORT_PTRDIFF_T
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// internal flag definitions
|
||||
#define FLAGS_ZEROPAD (1U << 0U)
|
||||
#define FLAGS_LEFT (1U << 1U)
|
||||
#define FLAGS_PLUS (1U << 2U)
|
||||
#define FLAGS_SPACE (1U << 3U)
|
||||
#define FLAGS_HASH (1U << 4U)
|
||||
#define FLAGS_UPPERCASE (1U << 5U)
|
||||
#define FLAGS_CHAR (1U << 6U)
|
||||
#define FLAGS_SHORT (1U << 7U)
|
||||
#define FLAGS_LONG (1U << 8U)
|
||||
#define FLAGS_LONG_LONG (1U << 9U)
|
||||
#define FLAGS_PRECISION (1U << 10U)
|
||||
#define FLAGS_ADAPT_EXP (1U << 11U)
|
||||
|
||||
|
||||
// import float.h for DBL_MAX
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
|
||||
// output function type
|
||||
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
|
||||
|
||||
|
||||
// wrapper (used as buffer) for output function type
|
||||
typedef struct {
|
||||
void (*fct)(char character, void* arg);
|
||||
void* arg;
|
||||
} out_fct_wrap_type;
|
||||
|
||||
|
||||
// internal buffer output
|
||||
static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
if (idx < maxlen) {
|
||||
((char*)buffer)[idx] = character;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// internal null output
|
||||
static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)character; (void)buffer; (void)idx; (void)maxlen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// internal secure strlen
|
||||
// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
|
||||
static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
|
||||
{
|
||||
const char* s;
|
||||
for (s = str; *s && maxsize--; ++s);
|
||||
return (unsigned int)(s - str);
|
||||
}
|
||||
|
||||
|
||||
// internal test if char is a digit (0-9)
|
||||
// \return true if char is a digit
|
||||
static inline bool _is_digit(char ch)
|
||||
{
|
||||
return (ch >= '0') && (ch <= '9');
|
||||
}
|
||||
|
||||
|
||||
// internal ASCII string to unsigned int conversion
|
||||
static unsigned int _atoi(const char** str)
|
||||
{
|
||||
unsigned int i = 0U;
|
||||
while (_is_digit(**str)) {
|
||||
i = i * 10U + (unsigned int)(*((*str)++) - '0');
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
// output the specified string in reverse, taking care of any zero-padding
|
||||
static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
|
||||
{
|
||||
const size_t start_idx = idx;
|
||||
|
||||
// pad spaces up to given width
|
||||
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||
size_t i;
|
||||
for (i = len; i < width; i++) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
// reverse string
|
||||
while (len) {
|
||||
out(buf[--len], buffer, idx++, maxlen);
|
||||
}
|
||||
|
||||
// append pad spaces up to given width
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
// internal itoa format
|
||||
static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
// handle hash
|
||||
if (flags & FLAGS_HASH) {
|
||||
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
|
||||
len--;
|
||||
if (len && (base == 16U)) {
|
||||
len--;
|
||||
}
|
||||
}
|
||||
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'x';
|
||||
}
|
||||
else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'X';
|
||||
}
|
||||
else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'b';
|
||||
}
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
}
|
||||
else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
}
|
||||
else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
|
||||
// internal itoa for 'long' type
|
||||
static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||
}
|
||||
|
||||
|
||||
// internal itoa for 'long long' type
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_LONG_LONG
|
||||
|
||||
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
|
||||
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags);
|
||||
#endif
|
||||
|
||||
|
||||
// internal ftoa for fixed decimal floating point
|
||||
static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
double diff = 0.0;
|
||||
|
||||
// powers of 10
|
||||
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
|
||||
// test for special values
|
||||
if (value != value)
|
||||
return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
|
||||
if (value < -DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
|
||||
if (value > DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
|
||||
|
||||
// test for very large values
|
||||
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
|
||||
if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
#else
|
||||
return 0U;
|
||||
#endif
|
||||
}
|
||||
|
||||
// test for negative
|
||||
bool negative = false;
|
||||
if (value < 0) {
|
||||
negative = true;
|
||||
value = 0 - value;
|
||||
}
|
||||
|
||||
// set default precision, if not set explicitly
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
|
||||
buf[len++] = '0';
|
||||
prec--;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
double tmp = (value - whole) * pow10[prec];
|
||||
unsigned long frac = (unsigned long)tmp;
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5) {
|
||||
++frac;
|
||||
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
|
||||
if (frac >= pow10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
else if (diff < 0.5) {
|
||||
}
|
||||
else if ((frac == 0U) || (frac & 1U)) {
|
||||
// if halfway, round up if odd OR if last digit is 0
|
||||
++frac;
|
||||
}
|
||||
|
||||
if (prec == 0U) {
|
||||
diff = value - (double)whole;
|
||||
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
|
||||
// exactly 0.5 and ODD, then round up
|
||||
// 1.5 -> 2, but 2.5 -> 2
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned int count = prec;
|
||||
// now do fractional part, as an unsigned number
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
--count;
|
||||
buf[len++] = (char)(48U + (frac % 10U));
|
||||
if (!(frac /= 10U)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add extra 0s
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
// add decimal
|
||||
buf[len++] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
// do whole part, number is reversed
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
buf[len++] = (char)(48 + (whole % 10));
|
||||
if (!(whole /= 10)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
|
||||
if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
}
|
||||
else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
}
|
||||
else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
|
||||
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
// check for NaN and special values
|
||||
if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
|
||||
return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
}
|
||||
|
||||
// determine the sign
|
||||
const bool negative = value < 0;
|
||||
if (negative) {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
// default precision
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
|
||||
// determine the decimal exponent
|
||||
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
|
||||
union {
|
||||
uint64_t U;
|
||||
double F;
|
||||
} conv;
|
||||
|
||||
conv.F = value;
|
||||
int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
|
||||
conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
|
||||
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5
|
||||
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
|
||||
// now we want to compute 10^expval but we want to be sure it won't overflow
|
||||
exp2 = (int)(expval * 3.321928094887362 + 0.5);
|
||||
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
|
||||
const double z2 = z * z;
|
||||
conv.U = (uint64_t)(exp2 + 1023) << 52U;
|
||||
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
|
||||
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
|
||||
// correct for rounding errors
|
||||
if (value < conv.F) {
|
||||
expval--;
|
||||
conv.F /= 10;
|
||||
}
|
||||
|
||||
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
|
||||
unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
|
||||
|
||||
// in "%g" mode, "prec" is the number of *significant figures* not decimals
|
||||
if (flags & FLAGS_ADAPT_EXP) {
|
||||
// do we want to fall-back to "%f" mode?
|
||||
if ((value >= 1e-4) && (value < 1e6)) {
|
||||
if ((int)prec > expval) {
|
||||
prec = (unsigned)((int)prec - expval - 1);
|
||||
}
|
||||
else {
|
||||
prec = 0;
|
||||
}
|
||||
flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
|
||||
// no characters in exponent
|
||||
minwidth = 0U;
|
||||
expval = 0;
|
||||
}
|
||||
else {
|
||||
// we use one sigfig for the whole part
|
||||
if ((prec > 0) && (flags & FLAGS_PRECISION)) {
|
||||
--prec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// will everything fit?
|
||||
unsigned int fwidth = width;
|
||||
if (width > minwidth) {
|
||||
// we didn't fall-back so subtract the characters required for the exponent
|
||||
fwidth -= minwidth;
|
||||
} else {
|
||||
// not enough characters, so go back to default sizing
|
||||
fwidth = 0U;
|
||||
}
|
||||
if ((flags & FLAGS_LEFT) && minwidth) {
|
||||
// if we're padding on the right, DON'T pad the floating part
|
||||
fwidth = 0U;
|
||||
}
|
||||
|
||||
// rescale the float value
|
||||
if (expval) {
|
||||
value /= conv.F;
|
||||
}
|
||||
|
||||
// output the floating part
|
||||
const size_t start_idx = idx;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
|
||||
|
||||
// output the exponent part
|
||||
if (minwidth) {
|
||||
// output the exponential symbol
|
||||
out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
|
||||
// output the exponent value
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS);
|
||||
// might need to right-pad spaces
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width) out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
|
||||
|
||||
// internal vsnprintf
|
||||
static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
|
||||
{
|
||||
unsigned int flags, width, precision, n;
|
||||
size_t idx = 0U;
|
||||
|
||||
if (!buffer) {
|
||||
// use null output function
|
||||
out = _out_null;
|
||||
}
|
||||
|
||||
while (*format)
|
||||
{
|
||||
// format specifier? %[flags][width][.precision][length]
|
||||
if (*format != '%') {
|
||||
// no
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// yes, evaluate it
|
||||
format++;
|
||||
}
|
||||
|
||||
// evaluate flags
|
||||
flags = 0U;
|
||||
do {
|
||||
switch (*format) {
|
||||
case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break;
|
||||
case '-': flags |= FLAGS_LEFT; format++; n = 1U; break;
|
||||
case '+': flags |= FLAGS_PLUS; format++; n = 1U; break;
|
||||
case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break;
|
||||
case '#': flags |= FLAGS_HASH; format++; n = 1U; break;
|
||||
default : n = 0U; break;
|
||||
}
|
||||
} while (n);
|
||||
|
||||
// evaluate width field
|
||||
width = 0U;
|
||||
if (_is_digit(*format)) {
|
||||
width = _atoi(&format);
|
||||
}
|
||||
else if (*format == '*') {
|
||||
const int w = va_arg(va, int);
|
||||
if (w < 0) {
|
||||
flags |= FLAGS_LEFT; // reverse padding
|
||||
width = (unsigned int)-w;
|
||||
}
|
||||
else {
|
||||
width = (unsigned int)w;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
|
||||
// evaluate precision field
|
||||
precision = 0U;
|
||||
if (*format == '.') {
|
||||
flags |= FLAGS_PRECISION;
|
||||
format++;
|
||||
if (_is_digit(*format)) {
|
||||
precision = _atoi(&format);
|
||||
}
|
||||
else if (*format == '*') {
|
||||
const int prec = (int)va_arg(va, int);
|
||||
precision = prec > 0 ? (unsigned int)prec : 0U;
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate length field
|
||||
switch (*format) {
|
||||
case 'l' :
|
||||
flags |= FLAGS_LONG;
|
||||
format++;
|
||||
if (*format == 'l') {
|
||||
flags |= FLAGS_LONG_LONG;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
case 'h' :
|
||||
flags |= FLAGS_SHORT;
|
||||
format++;
|
||||
if (*format == 'h') {
|
||||
flags |= FLAGS_CHAR;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
|
||||
case 't' :
|
||||
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
#endif
|
||||
case 'j' :
|
||||
flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
case 'z' :
|
||||
flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
// evaluate specifier
|
||||
switch (*format) {
|
||||
case 'd' :
|
||||
case 'i' :
|
||||
case 'u' :
|
||||
case 'x' :
|
||||
case 'X' :
|
||||
case 'o' :
|
||||
case 'b' : {
|
||||
// set the base
|
||||
unsigned int base;
|
||||
if (*format == 'x' || *format == 'X') {
|
||||
base = 16U;
|
||||
}
|
||||
else if (*format == 'o') {
|
||||
base = 8U;
|
||||
}
|
||||
else if (*format == 'b') {
|
||||
base = 2U;
|
||||
}
|
||||
else {
|
||||
base = 10U;
|
||||
flags &= ~FLAGS_HASH; // no hash for dec format
|
||||
}
|
||||
// uppercase
|
||||
if (*format == 'X') {
|
||||
flags |= FLAGS_UPPERCASE;
|
||||
}
|
||||
|
||||
// no plus or space flag for u, x, X, o, b
|
||||
if ((*format != 'i') && (*format != 'd')) {
|
||||
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||
}
|
||||
|
||||
// ignore '0' flag when precision is given
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
flags &= ~FLAGS_ZEROPAD;
|
||||
}
|
||||
|
||||
// convert the integer
|
||||
if ((*format == 'i') || (*format == 'd')) {
|
||||
// signed
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const long long value = va_arg(va, long long);
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
#endif
|
||||
}
|
||||
else if (flags & FLAGS_LONG) {
|
||||
const long value = va_arg(va, long);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
}
|
||||
else {
|
||||
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// unsigned
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
|
||||
#endif
|
||||
}
|
||||
else if (flags & FLAGS_LONG) {
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags);
|
||||
}
|
||||
else {
|
||||
const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
case 'f' :
|
||||
case 'F' :
|
||||
if (*format == 'F') flags |= FLAGS_UPPERCASE;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
|
||||
if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
|
||||
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
case 'c' : {
|
||||
unsigned int l = 1U;
|
||||
// pre padding
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// char output
|
||||
out((char)va_arg(va, int), buffer, idx++, maxlen);
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 's' : {
|
||||
const char* p = va_arg(va, char*);
|
||||
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
|
||||
// pre padding
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
l = (l < precision ? l : precision);
|
||||
}
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// string output
|
||||
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
|
||||
out(*(p++), buffer, idx++, maxlen);
|
||||
}
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p' : {
|
||||
width = sizeof(void*) * 2U;
|
||||
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||
if (is_ll) {
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
}
|
||||
#endif
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case '%' :
|
||||
out('%', buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
|
||||
default :
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// termination
|
||||
out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
|
||||
// return written chars without terminating \0
|
||||
return (int)idx;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int lv_snprintf(char* buffer, size_t count, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lv_vsnprintf(char* buffer, size_t count, const char* format, va_list va)
|
||||
{
|
||||
return _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
}
|
||||
|
||||
#endif /*LV_SPRINTF_CUSTOM*/
|
||||
|
||||
75
src/lv_misc/lv_printf.h
Normal file
75
src/lv_misc/lv_printf.h
Normal file
@@ -0,0 +1,75 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources.
|
||||
// Use this instead of bloated standard/newlib printf.
|
||||
// These routines are thread safe and reentrant.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _LV_PRINTF_H_
|
||||
#define _LV_PRINTF_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||
#include "lv_conf.h"
|
||||
#else
|
||||
#include "../../../lv_conf.h"
|
||||
#endif
|
||||
|
||||
#if LV_SPRINTF_CUSTOM == 0
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* Tiny snprintf/vsnprintf implementation
|
||||
* \param buffer A pointer to the buffer where to store the formatted string
|
||||
* \param count The maximum number of characters to store in the buffer, including a terminating null character
|
||||
* \param format A string that specifies the format of the output
|
||||
* \param va A value identifying a variable arguments list
|
||||
* \return The number of characters that COULD have been written into the buffer, not counting the terminating
|
||||
* null character. A value equal or larger than count indicates truncation. Only when the returned value
|
||||
* is non-negative and less than count, the string has been completely written.
|
||||
*/
|
||||
int lv_snprintf(char* buffer, size_t count, const char* format, ...);
|
||||
int lv_vsnprintf(char* buffer, size_t count, const char* format, va_list va);
|
||||
|
||||
#else
|
||||
#include LV_SPRINTF_INCLUDE
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // _PRINTF_H_
|
||||
@@ -9,6 +9,7 @@
|
||||
*********************/
|
||||
#include <stddef.h>
|
||||
#include "lv_task.h"
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_hal/lv_hal_tick.h"
|
||||
#include "lv_gc.h"
|
||||
|
||||
@@ -67,16 +68,16 @@ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void)
|
||||
LV_LOG_TRACE("lv_task_handler started");
|
||||
|
||||
/*Avoid concurrent running of the task handler*/
|
||||
static bool task_handler_mutex = false;
|
||||
if(task_handler_mutex) return;
|
||||
task_handler_mutex = true;
|
||||
static bool already_running = false;
|
||||
if(already_running) return;
|
||||
already_running = true;
|
||||
|
||||
static uint32_t idle_period_start = 0;
|
||||
static uint32_t handler_start = 0;
|
||||
static uint32_t busy_time = 0;
|
||||
|
||||
if(lv_task_run == false) {
|
||||
task_handler_mutex = false; /*Release mutex*/
|
||||
already_running = false; /*Release mutex*/
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -115,14 +116,16 @@ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void)
|
||||
if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_HIGHEST) {
|
||||
lv_task_exec(LV_GC_ROOT(_lv_task_act));
|
||||
}
|
||||
/*Tasks with higher priority then the interrupted shall be run in every case*/
|
||||
/*Tasks with higher priority than the interrupted shall be run in every case*/
|
||||
else if(task_interrupter) {
|
||||
if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio > task_interrupter->prio) {
|
||||
if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) {
|
||||
task_interrupter =
|
||||
LV_GC_ROOT(_lv_task_act); /*Check all tasks again from the highest priority */
|
||||
end_flag = false;
|
||||
break;
|
||||
if(!task_created && !task_deleted) {
|
||||
/*Check all tasks again from the highest priority */
|
||||
task_interrupter = LV_GC_ROOT(_lv_task_act);
|
||||
end_flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,14 +133,19 @@ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void)
|
||||
* Just run the remaining tasks*/
|
||||
else {
|
||||
if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) {
|
||||
task_interrupter = LV_GC_ROOT(_lv_task_act); /*Check all tasks again from the highest priority */
|
||||
end_flag = false;
|
||||
break;
|
||||
if(!task_created && !task_deleted) {
|
||||
task_interrupter = LV_GC_ROOT(_lv_task_act); /*Check all tasks again from the highest priority */
|
||||
end_flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(task_deleted) break; /*If a task was deleted then this or the next item might be corrupted*/
|
||||
if(task_created) break; /*If a task was created then this or the next item might be corrupted*/
|
||||
/*If a task was created or deleted then this or the next item might be corrupted*/
|
||||
if(task_created || task_deleted) {
|
||||
task_interrupter = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
LV_GC_ROOT(_lv_task_act) = next; /*Load the next task*/
|
||||
}
|
||||
@@ -153,7 +161,7 @@ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void)
|
||||
idle_period_start = lv_tick_get();
|
||||
}
|
||||
|
||||
task_handler_mutex = false; /*Release the mutex*/
|
||||
already_running = false; /*Release the mutex*/
|
||||
|
||||
LV_LOG_TRACE("lv_task_handler ready");
|
||||
}
|
||||
@@ -173,7 +181,7 @@ lv_task_t * lv_task_create_basic(void)
|
||||
/*It's the first task*/
|
||||
if(NULL == tmp) {
|
||||
new_task = lv_ll_ins_head(&LV_GC_ROOT(_lv_task_ll));
|
||||
lv_mem_assert(new_task);
|
||||
LV_ASSERT_MEM(new_task);
|
||||
if(new_task == NULL) return NULL;
|
||||
}
|
||||
/*Insert the new task to proper place according to its priority*/
|
||||
@@ -181,7 +189,7 @@ lv_task_t * lv_task_create_basic(void)
|
||||
do {
|
||||
if(tmp->prio <= DEF_PRIO) {
|
||||
new_task = lv_ll_ins_prev(&LV_GC_ROOT(_lv_task_ll), tmp);
|
||||
lv_mem_assert(new_task);
|
||||
LV_ASSERT_MEM(new_task);
|
||||
if(new_task == NULL) return NULL;
|
||||
break;
|
||||
}
|
||||
@@ -191,7 +199,7 @@ lv_task_t * lv_task_create_basic(void)
|
||||
/*Only too high priority tasks were found. Add the task to the end*/
|
||||
if(tmp == NULL) {
|
||||
new_task = lv_ll_ins_tail(&LV_GC_ROOT(_lv_task_ll));
|
||||
lv_mem_assert(new_task);
|
||||
LV_ASSERT_MEM(new_task);
|
||||
if(new_task == NULL) return NULL;
|
||||
}
|
||||
}
|
||||
@@ -223,7 +231,7 @@ lv_task_t * lv_task_create_basic(void)
|
||||
lv_task_t * lv_task_create(lv_task_cb_t task_cb, uint32_t period, lv_task_prio_t prio, void * user_data)
|
||||
{
|
||||
lv_task_t * new_task = lv_task_create_basic();
|
||||
lv_mem_assert(new_task);
|
||||
LV_ASSERT_MEM(new_task);
|
||||
if(new_task == NULL) return NULL;
|
||||
|
||||
lv_task_set_cb(new_task, task_cb);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*********************/
|
||||
#include "lv_txt.h"
|
||||
#include "lv_math.h"
|
||||
#include "lv_log.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -56,7 +57,7 @@ uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_utf8_con
|
||||
uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_utf8_next;
|
||||
uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_utf8_prev;
|
||||
uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_utf8_get_byte_id;
|
||||
uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) = lv_txt_utf8_get_char_id;
|
||||
uint32_t (*lv_txt_encoded_get_char_id)(const char *, uint32_t) = lv_txt_utf8_get_char_id;
|
||||
uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_utf8_get_length;
|
||||
#elif LV_TXT_ENC == LV_TXT_ENC_ASCII
|
||||
uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_iso8859_1_size;
|
||||
@@ -65,7 +66,7 @@ uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_iso8859_
|
||||
uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_iso8859_1_next;
|
||||
uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_iso8859_1_prev;
|
||||
uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_iso8859_1_get_byte_id;
|
||||
uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) = lv_txt_iso8859_1_get_char_id;
|
||||
uint32_t (*lv_txt_encoded_get_char_id)(const char *, uint32_t) = lv_txt_iso8859_1_get_char_id;
|
||||
uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_iso8859_1_get_length;
|
||||
|
||||
#endif
|
||||
@@ -108,8 +109,14 @@ void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t *
|
||||
/*Calc. the height and longest line*/
|
||||
while(text[line_start] != '\0') {
|
||||
new_line_start += lv_txt_get_next_line(&text[line_start], font, letter_space, max_width, flag);
|
||||
size_res->y += letter_height;
|
||||
size_res->y += line_space;
|
||||
|
||||
if ((unsigned long)size_res->y + (unsigned long)letter_height + (unsigned long)line_space > LV_MAX_OF(lv_coord_t)) {
|
||||
LV_LOG_WARN("lv_txt_get_size: integer overflow while calculating text height");
|
||||
return;
|
||||
} else {
|
||||
size_res->y += letter_height;
|
||||
size_res->y += line_space;
|
||||
}
|
||||
|
||||
/*Calculate the the longest line*/
|
||||
act_line_length = lv_txt_get_width(&text[line_start], new_line_start - line_start, font, letter_space, flag);
|
||||
@@ -118,7 +125,7 @@ void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t *
|
||||
line_start = new_line_start;
|
||||
}
|
||||
|
||||
/*Ma ke the text one line taller if the last character is '\n' or '\r'*/
|
||||
/*Make the text one line taller if the last character is '\n' or '\r'*/
|
||||
if((line_start != 0) && (text[line_start - 1] == '\n' || text[line_start - 1] == '\r')) {
|
||||
size_res->y += letter_height + line_space;
|
||||
}
|
||||
@@ -130,8 +137,151 @@ void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t *
|
||||
size_res->y -= line_space;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next word of text. A word is delimited by break characters.
|
||||
*
|
||||
* If the word cannot fit in the max_width space, obey LV_TXT_LINE_BREAK_LONG_* rules.
|
||||
*
|
||||
* If the next word cannot fit anything, return 0.
|
||||
*
|
||||
* If the first character is a break character, returns the next index.
|
||||
*
|
||||
* Example calls from lv_txt_get_next_line() assuming sufficent max_width and
|
||||
* txt = "Test text\n"
|
||||
* 0123456789
|
||||
*
|
||||
* Calls would be as follows:
|
||||
* 1. Return i=4, pointing at breakchar ' ', for the string "Test"
|
||||
* 2. Return i=5, since i=4 was a breakchar.
|
||||
* 3. Return i=9, pointing at breakchar '\n'
|
||||
* 4. Parenting lv_txt_get_next_line() would detect subsequent '\0'
|
||||
*
|
||||
* TODO: Returned word_w_ptr may overestimate the returned word's width when
|
||||
* max_width is reached. In current usage, this has no impact.
|
||||
*
|
||||
* @param txt a '\0' terminated string
|
||||
* @param font pointer to a font
|
||||
* @param letter_space letter space
|
||||
* @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks
|
||||
* @param flags settings for the text from 'txt_flag_type' enum
|
||||
* @param[out] word_w_ptr width (in pixels) of the parsed word. May be NULL.
|
||||
* @param force Force return the fraction of the word that can fit in the provided space.
|
||||
* @return the index of the first char of the next word (in byte index not letter index. With UTF-8 they are different)
|
||||
*/
|
||||
static uint16_t lv_txt_get_next_word(const char * txt, const lv_font_t * font,
|
||||
lv_coord_t letter_space, lv_coord_t max_width,
|
||||
lv_txt_flag_t flag, uint32_t *word_w_ptr, lv_txt_cmd_state_t * cmd_state, bool force)
|
||||
{
|
||||
if(txt == NULL || txt[0] == '\0') return 0;
|
||||
if(font == NULL) return 0;
|
||||
|
||||
if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX;
|
||||
|
||||
uint32_t i = 0, i_next = 0, i_next_next = 0; /* Iterating index into txt */
|
||||
uint32_t letter = 0; /* Letter at i */
|
||||
uint32_t letter_next = 0; /* Letter at i_next */
|
||||
lv_coord_t letter_w;
|
||||
lv_coord_t cur_w = 0; /* Pixel Width of transversed string */
|
||||
uint32_t word_len = 0; /* Number of characters in the transversed word */
|
||||
uint32_t break_index = NO_BREAK_FOUND; /* only used for "long" words */
|
||||
uint32_t break_letter_count = 0; /* Number of characters up to the long word break point */
|
||||
|
||||
letter = lv_txt_encoded_next(txt, &i_next);
|
||||
i_next_next = i_next;
|
||||
|
||||
/* Obtain the full word, regardless if it fits or not in max_width */
|
||||
while(txt[i] != '\0') {
|
||||
letter_next = lv_txt_encoded_next(txt, &i_next_next);
|
||||
word_len++;
|
||||
|
||||
/*Handle the recolor command*/
|
||||
if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
|
||||
if(lv_txt_is_cmd(cmd_state, letter) != false) {
|
||||
i = i_next;
|
||||
i_next = i_next_next;
|
||||
letter = letter_next;
|
||||
continue; /*Skip the letter is it is part of a command*/
|
||||
}
|
||||
}
|
||||
|
||||
letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
cur_w += letter_w;
|
||||
|
||||
if(letter_w > 0) {
|
||||
cur_w += letter_space;
|
||||
}
|
||||
|
||||
/* Test if this character fits within max_width */
|
||||
if(break_index == NO_BREAK_FOUND && (cur_w - letter_space) > max_width) {
|
||||
break_index = i;
|
||||
break_letter_count = word_len - 1;
|
||||
/* break_index is now pointing at the character that doesn't fit */
|
||||
}
|
||||
|
||||
/*Check for new line chars and breakchars*/
|
||||
if(letter == '\n' || letter == '\r' || is_break_char(letter)) {
|
||||
/* Update the output width on the first character if it fits.
|
||||
* Must do this here incase first letter is a break character. */
|
||||
if(i == 0 && break_index == NO_BREAK_FOUND && word_w_ptr != NULL) *word_w_ptr = cur_w;
|
||||
word_len--;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update the output width */
|
||||
if( word_w_ptr != NULL && break_index == NO_BREAK_FOUND ) *word_w_ptr = cur_w;
|
||||
|
||||
|
||||
i = i_next;
|
||||
i_next = i_next_next;
|
||||
letter = letter_next;
|
||||
}
|
||||
|
||||
/* Entire Word fits in the provided space */
|
||||
if( break_index == NO_BREAK_FOUND ) {
|
||||
if( word_len == 0 || (letter == '\r' && letter_next == '\n') ) i = i_next;
|
||||
return i;
|
||||
}
|
||||
|
||||
#if LV_TXT_LINE_BREAK_LONG_LEN > 0
|
||||
/* Word doesn't fit in provided space, but isn't "long" */
|
||||
if(word_len < LV_TXT_LINE_BREAK_LONG_LEN) {
|
||||
if( force ) return break_index;
|
||||
if(word_w_ptr != NULL) *word_w_ptr = 0; /* Return no word */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Word is "long," but insufficient amounts can fit in provided space */
|
||||
if(break_letter_count < LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN) {
|
||||
if( force ) return break_index;
|
||||
if(word_w_ptr != NULL) *word_w_ptr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Word is a "long", but letters may need to be better distributed */
|
||||
{
|
||||
i = break_index;
|
||||
int32_t n_move = LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN - (word_len - break_letter_count);
|
||||
/* Move pointer "i" backwards */
|
||||
for(;n_move>0; n_move--){
|
||||
lv_txt_encoded_prev(txt, &i);
|
||||
// TODO: it would be appropriate to update the returned word width here
|
||||
// However, in current usage, this doesn't impact anything.
|
||||
}
|
||||
}
|
||||
return i;
|
||||
#else
|
||||
if( force ) return break_index;
|
||||
if(word_w_ptr != NULL) *word_w_ptr = 0; /* Return no word */
|
||||
(void) break_letter_count;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next line of text. Check line length and break chars too.
|
||||
*
|
||||
* A line of txt includes the \n character.
|
||||
*
|
||||
* @param txt a '\0' terminated string
|
||||
* @param font pointer to a font
|
||||
* @param letter_space letter space
|
||||
@@ -139,75 +289,40 @@ void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t *
|
||||
* @param flags settings for the text from 'txt_flag_type' enum
|
||||
* @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different)
|
||||
*/
|
||||
uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, lv_coord_t letter_space, lv_coord_t max_width,
|
||||
lv_txt_flag_t flag)
|
||||
uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font,
|
||||
lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag)
|
||||
{
|
||||
if(txt == NULL) return 0;
|
||||
if(font == NULL) return 0;
|
||||
|
||||
if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX;
|
||||
|
||||
uint32_t i = 0;
|
||||
uint32_t i_next = 0;
|
||||
lv_coord_t cur_w = 0;
|
||||
uint32_t last_break = NO_BREAK_FOUND;
|
||||
lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT;
|
||||
uint32_t letter_w;
|
||||
uint32_t letter = 0;
|
||||
uint32_t letter_next = 0;
|
||||
uint32_t i = 0; /* Iterating index into txt */
|
||||
|
||||
letter_next = lv_txt_encoded_next(txt, &i_next);
|
||||
while(txt[i] != '\0' && max_width > 0) {
|
||||
uint32_t word_w = 0;
|
||||
uint32_t advance = lv_txt_get_next_word(&txt[i], font, letter_space, max_width, flag, &word_w, &cmd_state, i==0);
|
||||
max_width -= word_w;
|
||||
|
||||
while(txt[i] != '\0') {
|
||||
letter = letter_next;
|
||||
i = i_next;
|
||||
letter_next = lv_txt_encoded_next(txt, &i_next);
|
||||
|
||||
/*Handle the recolor command*/
|
||||
if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
|
||||
if(lv_txt_is_cmd(&cmd_state, letter) != false) {
|
||||
continue; /*Skip the letter is it is part of a command*/
|
||||
}
|
||||
if( advance == 0 ){
|
||||
if(i == 0) lv_txt_encoded_next(txt, &i); // prevent inf loops
|
||||
break;
|
||||
}
|
||||
|
||||
/*Check for new line chars*/
|
||||
if(letter == '\n' || letter == '\r') {
|
||||
/*Return with the first letter of the next line*/
|
||||
if(letter == '\r' && letter_next == '\n')
|
||||
return i_next;
|
||||
else
|
||||
return i;
|
||||
} else { /*Check the actual length*/
|
||||
letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
cur_w += letter_w;
|
||||
i += advance;
|
||||
|
||||
/*If the txt is too long then finish, this is the line end*/
|
||||
if(cur_w > max_width) {
|
||||
/*If a break character was already found break there*/
|
||||
if(last_break != NO_BREAK_FOUND) {
|
||||
i = last_break;
|
||||
} else {
|
||||
/* Now this character is out of the area so it will be first character of the next line*/
|
||||
/* But 'i' already points to the next character (because of lv_txt_utf8_next) step beck one*/
|
||||
lv_txt_encoded_prev(txt, &i);
|
||||
}
|
||||
if(txt[0] == '\n' || txt[0] == '\r') break;
|
||||
|
||||
/* Do not let to return without doing nothing.
|
||||
* Find at least one character (Avoid infinite loop )*/
|
||||
if(i == 0) lv_txt_encoded_next(txt, &i);
|
||||
|
||||
return i;
|
||||
}
|
||||
/*If this char still can fit to this line then check if
|
||||
* txt can be broken here later */
|
||||
else if(is_break_char(letter)) {
|
||||
last_break = i; /*Save the first char index after break*/
|
||||
}
|
||||
if(txt[i] == '\n' || txt[i] == '\r'){
|
||||
i++; /* Include the following newline in the current line */
|
||||
break;
|
||||
}
|
||||
|
||||
if(letter_w > 0) {
|
||||
cur_w += letter_space;
|
||||
}
|
||||
}
|
||||
|
||||
/* Always step at least one to avoid infinite loops */
|
||||
if(i == 0) {
|
||||
lv_txt_encoded_next(txt, &i);
|
||||
}
|
||||
|
||||
return i;
|
||||
@@ -309,13 +424,13 @@ bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c)
|
||||
*/
|
||||
void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt)
|
||||
{
|
||||
uint32_t old_len = strlen(txt_buf);
|
||||
uint32_t ins_len = strlen(ins_txt);
|
||||
uint32_t new_len = ins_len + old_len;
|
||||
size_t old_len = strlen(txt_buf);
|
||||
size_t ins_len = strlen(ins_txt);
|
||||
size_t new_len = ins_len + old_len;
|
||||
pos = lv_txt_encoded_get_byte_id(txt_buf, pos); /*Convert to byte index instead of letter index*/
|
||||
|
||||
/*Copy the second part into the end to make place to text to insert*/
|
||||
uint32_t i;
|
||||
size_t i;
|
||||
for(i = new_len; i >= pos + ins_len; i--) {
|
||||
txt_buf[i] = txt_buf[i - ins_len];
|
||||
}
|
||||
@@ -334,7 +449,7 @@ void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt)
|
||||
void lv_txt_cut(char * txt, uint32_t pos, uint32_t len)
|
||||
{
|
||||
|
||||
uint32_t old_len = strlen(txt);
|
||||
size_t old_len = strlen(txt);
|
||||
|
||||
pos = lv_txt_encoded_get_byte_id(txt, pos); /*Convert to byte index instead of letter index*/
|
||||
len = lv_txt_encoded_get_byte_id(&txt[pos], len);
|
||||
@@ -366,7 +481,7 @@ static uint8_t lv_txt_utf8_size(const char * str)
|
||||
return 3;
|
||||
else if((str[0] & 0xF8) == 0xF0)
|
||||
return 4;
|
||||
return 1; /*If the char was invalid step tell it's 1 byte long*/
|
||||
return 0; /*If the char was invalid tell it's 1 byte long*/
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -543,7 +658,8 @@ static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id)
|
||||
uint32_t i;
|
||||
uint32_t byte_cnt = 0;
|
||||
for(i = 0; i < utf8_id; i++) {
|
||||
byte_cnt += lv_txt_encoded_size(&txt[byte_cnt]);
|
||||
uint8_t c_size = lv_txt_encoded_size(&txt[byte_cnt]);
|
||||
byte_cnt += c_size > 0 ? c_size : 1;
|
||||
}
|
||||
|
||||
return byte_cnt;
|
||||
|
||||
@@ -27,7 +27,9 @@ extern "C" {
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#ifndef LV_TXT_COLOR_CMD
|
||||
#define LV_TXT_COLOR_CMD "#"
|
||||
#endif
|
||||
|
||||
#define LV_TXT_ENC_UTF8 1
|
||||
#define LV_TXT_ENC_ASCII 2
|
||||
@@ -188,7 +190,7 @@ extern uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t);
|
||||
* @param byte_id byte index
|
||||
* @return character index of the letter at 'byte_id'th position
|
||||
*/
|
||||
extern uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t);
|
||||
extern uint32_t (*lv_txt_encoded_get_char_id)(const char *, uint32_t);
|
||||
|
||||
/**
|
||||
* Get the number of characters (and NOT bytes) in a string.
|
||||
|
||||
@@ -17,6 +17,17 @@ extern "C" {
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
// Check windows
|
||||
#ifdef _WIN64
|
||||
#define LV_ARCH_64
|
||||
#endif
|
||||
|
||||
// Check GCC
|
||||
#ifdef __GNUC__
|
||||
#if defined(__x86_64__) || defined(__ppc64__)
|
||||
#define LV_ARCH_64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -32,6 +43,12 @@ enum {
|
||||
};
|
||||
typedef uint8_t lv_res_t;
|
||||
|
||||
#ifdef LV_ARCH_64
|
||||
typedef uint64_t lv_uintptr_t;
|
||||
#else
|
||||
typedef uint32_t lv_uintptr_t;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "lv_arc.h"
|
||||
#if LV_USE_ARC != 0
|
||||
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
#include "../lv_draw/lv_draw_arc.h"
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
@@ -16,6 +17,7 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_OBJX_NAME "lv_arc"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -54,12 +56,12 @@ lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
|
||||
/*Create the ancestor of arc*/
|
||||
lv_obj_t * new_arc = lv_obj_create(par, copy);
|
||||
lv_mem_assert(new_arc);
|
||||
LV_ASSERT_MEM(new_arc);
|
||||
if(new_arc == NULL) return NULL;
|
||||
|
||||
/*Allocate the arc type specific extended data*/
|
||||
lv_arc_ext_t * ext = lv_obj_allocate_ext_attr(new_arc, sizeof(lv_arc_ext_t));
|
||||
lv_mem_assert(ext);
|
||||
LV_ASSERT_MEM(ext);
|
||||
if(ext == NULL) return NULL;
|
||||
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_arc);
|
||||
@@ -119,6 +121,8 @@ lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
*/
|
||||
void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end)
|
||||
{
|
||||
LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
|
||||
|
||||
lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
|
||||
|
||||
if(start > 360) start = 360;
|
||||
@@ -138,6 +142,8 @@ void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end)
|
||||
* */
|
||||
void lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, const lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
|
||||
|
||||
switch(type) {
|
||||
case LV_ARC_STYLE_MAIN: lv_obj_set_style(arc, style); break;
|
||||
}
|
||||
@@ -154,6 +160,8 @@ void lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, const lv_style_t * st
|
||||
*/
|
||||
uint16_t lv_arc_get_angle_start(lv_obj_t * arc)
|
||||
{
|
||||
LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
|
||||
|
||||
lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
|
||||
|
||||
return ext->angle_start;
|
||||
@@ -166,6 +174,8 @@ uint16_t lv_arc_get_angle_start(lv_obj_t * arc)
|
||||
*/
|
||||
uint16_t lv_arc_get_angle_end(lv_obj_t * arc)
|
||||
{
|
||||
LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
|
||||
|
||||
lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
|
||||
|
||||
return ext->angle_end;
|
||||
@@ -179,6 +189,8 @@ uint16_t lv_arc_get_angle_end(lv_obj_t * arc)
|
||||
* */
|
||||
const lv_style_t * lv_arc_get_style(const lv_obj_t * arc, lv_arc_style_t type)
|
||||
{
|
||||
LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
|
||||
|
||||
const lv_style_t * style = NULL;
|
||||
|
||||
switch(type) {
|
||||
@@ -281,15 +293,10 @@ static lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param)
|
||||
res = ancestor_signal(arc, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
|
||||
if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
|
||||
|
||||
if(sign == LV_SIGNAL_CLEANUP) {
|
||||
/*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_arc";
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "lv_bar.h"
|
||||
#if LV_USE_BAR != 0
|
||||
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
#include "../lv_misc/lv_anim.h"
|
||||
@@ -19,6 +20,7 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_OBJX_NAME "lv_bar"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -61,7 +63,7 @@ lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
|
||||
/*Create the ancestor basic object*/
|
||||
lv_obj_t * new_bar = lv_obj_create(par, copy);
|
||||
lv_mem_assert(new_bar);
|
||||
LV_ASSERT_MEM(new_bar);
|
||||
if(new_bar == NULL) return NULL;
|
||||
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_bar);
|
||||
@@ -69,7 +71,7 @@ lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
|
||||
/*Allocate the object type specific extended data*/
|
||||
lv_bar_ext_t * ext = lv_obj_allocate_ext_attr(new_bar, sizeof(lv_bar_ext_t));
|
||||
lv_mem_assert(ext);
|
||||
LV_ASSERT_MEM(ext);
|
||||
if(ext == NULL) return NULL;
|
||||
|
||||
ext->min_value = 0;
|
||||
@@ -130,6 +132,8 @@ lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
*/
|
||||
void lv_bar_set_value(lv_obj_t * bar, int16_t value, lv_anim_enable_t anim)
|
||||
{
|
||||
LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
|
||||
|
||||
#if LV_USE_ANIMATION == 0
|
||||
anim = false;
|
||||
#endif
|
||||
@@ -185,6 +189,8 @@ void lv_bar_set_value(lv_obj_t * bar, int16_t value, lv_anim_enable_t anim)
|
||||
*/
|
||||
void lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max)
|
||||
{
|
||||
LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
|
||||
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
if(ext->min_value == min && ext->max_value == max) return;
|
||||
|
||||
@@ -209,6 +215,8 @@ void lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max)
|
||||
*/
|
||||
void lv_bar_set_sym(lv_obj_t * bar, bool en)
|
||||
{
|
||||
LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
|
||||
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
ext->sym = en ? 1 : 0;
|
||||
}
|
||||
@@ -220,6 +228,8 @@ void lv_bar_set_sym(lv_obj_t * bar, bool en)
|
||||
*/
|
||||
void lv_bar_set_anim_time(lv_obj_t * bar, uint16_t anim_time)
|
||||
{
|
||||
LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
ext->anim_time = anim_time;
|
||||
@@ -237,6 +247,8 @@ void lv_bar_set_anim_time(lv_obj_t * bar, uint16_t anim_time)
|
||||
*/
|
||||
void lv_bar_set_style(lv_obj_t * bar, lv_bar_style_t type, const lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
|
||||
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
|
||||
switch(type) {
|
||||
@@ -259,6 +271,8 @@ void lv_bar_set_style(lv_obj_t * bar, lv_bar_style_t type, const lv_style_t * st
|
||||
*/
|
||||
int16_t lv_bar_get_value(const lv_obj_t * bar)
|
||||
{
|
||||
LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
|
||||
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
/*If animated tell that it's already at the end value*/
|
||||
#if LV_USE_ANIMATION
|
||||
@@ -275,6 +289,8 @@ int16_t lv_bar_get_value(const lv_obj_t * bar)
|
||||
*/
|
||||
int16_t lv_bar_get_min_value(const lv_obj_t * bar)
|
||||
{
|
||||
LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
|
||||
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
return ext->min_value;
|
||||
}
|
||||
@@ -286,6 +302,8 @@ int16_t lv_bar_get_min_value(const lv_obj_t * bar)
|
||||
*/
|
||||
int16_t lv_bar_get_max_value(const lv_obj_t * bar)
|
||||
{
|
||||
LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
|
||||
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
return ext->max_value;
|
||||
}
|
||||
@@ -297,6 +315,8 @@ int16_t lv_bar_get_max_value(const lv_obj_t * bar)
|
||||
*/
|
||||
bool lv_bar_get_sym(lv_obj_t * bar)
|
||||
{
|
||||
LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
|
||||
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
return ext->sym ? true : false;
|
||||
}
|
||||
@@ -308,6 +328,8 @@ bool lv_bar_get_sym(lv_obj_t * bar)
|
||||
*/
|
||||
uint16_t lv_bar_get_anim_time(lv_obj_t * bar)
|
||||
{
|
||||
LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
return ext->anim_time;
|
||||
@@ -325,6 +347,8 @@ uint16_t lv_bar_get_anim_time(lv_obj_t * bar)
|
||||
*/
|
||||
const lv_style_t * lv_bar_get_style(const lv_obj_t * bar, lv_bar_style_t type)
|
||||
{
|
||||
LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
|
||||
|
||||
const lv_style_t * style = NULL;
|
||||
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
|
||||
|
||||
@@ -495,17 +519,11 @@ static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param)
|
||||
/* Include the ancient signal function */
|
||||
res = ancestor_signal(bar, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
|
||||
|
||||
if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) {
|
||||
const lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC);
|
||||
if(style_indic->body.shadow.width > bar->ext_draw_pad) bar->ext_draw_pad = style_indic->body.shadow.width;
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_bar";
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
@@ -43,6 +43,11 @@ extern "C" {
|
||||
/** log2(LV_BAR_ANIM_STATE_END) used to normalize data*/
|
||||
#define LV_BAR_ANIM_STATE_NORM 8
|
||||
|
||||
LV_EXPORT_CONST_INT(LV_BAR_ANIM_STATE_START);
|
||||
LV_EXPORT_CONST_INT(LV_BAR_ANIM_STATE_END);
|
||||
LV_EXPORT_CONST_INT(LV_BAR_ANIM_STATE_INV);
|
||||
LV_EXPORT_CONST_INT(LV_BAR_ANIM_STATE_NORM);
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include "../lv_core/lv_group.h"
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
#include "../lv_misc/lv_area.h"
|
||||
@@ -21,6 +22,7 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_OBJX_NAME "lv_btn"
|
||||
#define LV_BTN_INK_VALUE_MAX 256
|
||||
#define LV_BTN_INK_VALUE_MAX_SHIFT 8
|
||||
|
||||
@@ -64,7 +66,7 @@ static lv_point_t ink_point;
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a button objects
|
||||
* Create a button object
|
||||
* @param par pointer to an object, it will be the parent of the new button
|
||||
* @param copy pointer to a button object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created button
|
||||
@@ -76,7 +78,7 @@ lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
lv_obj_t * new_btn;
|
||||
|
||||
new_btn = lv_cont_create(par, copy);
|
||||
lv_mem_assert(new_btn);
|
||||
LV_ASSERT_MEM(new_btn);
|
||||
if(new_btn == NULL) return NULL;
|
||||
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_btn);
|
||||
@@ -84,7 +86,7 @@ lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
|
||||
/*Allocate the extended data*/
|
||||
lv_btn_ext_t * ext = lv_obj_allocate_ext_attr(new_btn, sizeof(lv_btn_ext_t));
|
||||
lv_mem_assert(ext);
|
||||
LV_ASSERT_MEM(ext);
|
||||
if(ext == NULL) return NULL;
|
||||
|
||||
ext->state = LV_BTN_STATE_REL;
|
||||
@@ -136,7 +138,7 @@ lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
ext->ink_wait_time = copy_ext->ink_wait_time;
|
||||
ext->ink_out_time = copy_ext->ink_out_time;
|
||||
#endif
|
||||
memcpy(ext->styles, copy_ext->styles, sizeof(ext->styles));
|
||||
memcpy((void*) ext->styles, copy_ext->styles, sizeof(ext->styles));
|
||||
|
||||
/*Refresh the style with new signal function*/
|
||||
lv_obj_refresh_style(new_btn);
|
||||
@@ -158,6 +160,8 @@ lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
*/
|
||||
void lv_btn_set_toggle(lv_obj_t * btn, bool tgl)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
|
||||
ext->toggle = tgl != false ? 1 : 0;
|
||||
@@ -170,6 +174,8 @@ void lv_btn_set_toggle(lv_obj_t * btn, bool tgl)
|
||||
*/
|
||||
void lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
if(ext->state != state) {
|
||||
ext->state = state;
|
||||
@@ -183,6 +189,8 @@ void lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state)
|
||||
*/
|
||||
void lv_btn_toggle(lv_obj_t * btn)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
switch(ext->state) {
|
||||
case LV_BTN_STATE_REL: lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); break;
|
||||
@@ -200,6 +208,8 @@ void lv_btn_toggle(lv_obj_t * btn)
|
||||
*/
|
||||
void lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
ext->ink_in_time = time;
|
||||
@@ -218,6 +228,8 @@ void lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time)
|
||||
*/
|
||||
void lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
@@ -237,6 +249,8 @@ void lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time)
|
||||
*/
|
||||
void lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
ext->ink_out_time = time;
|
||||
@@ -256,6 +270,8 @@ void lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time)
|
||||
*/
|
||||
void lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, const lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
|
||||
switch(type) {
|
||||
@@ -281,6 +297,8 @@ void lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, const lv_style_t * st
|
||||
*/
|
||||
lv_btn_state_t lv_btn_get_state(const lv_obj_t * btn)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
return ext->state;
|
||||
}
|
||||
@@ -288,10 +306,12 @@ lv_btn_state_t lv_btn_get_state(const lv_obj_t * btn)
|
||||
/**
|
||||
* Get the toggle enable attribute of the button
|
||||
* @param btn pointer to a button object
|
||||
* @return ture: toggle enabled, false: disabled
|
||||
* @return true: toggle enabled, false: disabled
|
||||
*/
|
||||
bool lv_btn_get_toggle(const lv_obj_t * btn)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
|
||||
return ext->toggle != 0 ? true : false;
|
||||
@@ -304,6 +324,8 @@ bool lv_btn_get_toggle(const lv_obj_t * btn)
|
||||
*/
|
||||
uint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
return ext->ink_in_time;
|
||||
@@ -320,6 +342,8 @@ uint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn)
|
||||
*/
|
||||
uint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
return ext->ink_wait_time;
|
||||
@@ -335,9 +359,11 @@ uint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn)
|
||||
*/
|
||||
uint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
return ext->ink_in_time;
|
||||
return ext->ink_out_time;
|
||||
#else
|
||||
(void)btn; /*Unused*/
|
||||
return 0;
|
||||
@@ -352,6 +378,8 @@ uint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn)
|
||||
*/
|
||||
const lv_style_t * lv_btn_get_style(const lv_obj_t * btn, lv_btn_style_t type)
|
||||
{
|
||||
LV_ASSERT_OBJ(btn, LV_OBJX_NAME);
|
||||
|
||||
const lv_style_t * style = NULL;
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
lv_btn_state_t state = lv_btn_get_state(btn);
|
||||
@@ -483,6 +511,7 @@ static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param)
|
||||
/* Include the ancient signal function */
|
||||
res = ancestor_signal(btn, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
|
||||
|
||||
lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
|
||||
bool tgl = lv_btn_get_toggle(btn);
|
||||
@@ -634,13 +663,6 @@ static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param)
|
||||
ink_obj = NULL;
|
||||
}
|
||||
#endif
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_btn";
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
@@ -112,7 +112,7 @@ typedef uint8_t lv_btn_style_t;
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a button objects
|
||||
* Create a button object
|
||||
* @param par pointer to an object, it will be the parent of the new button
|
||||
* @param copy pointer to a button object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created button
|
||||
@@ -155,11 +155,11 @@ static inline void lv_btn_set_layout(lv_obj_t * btn, lv_layout_t layout)
|
||||
|
||||
/**
|
||||
* Set the fit policy in all 4 directions separately.
|
||||
* It tell how to change the button size automatically.
|
||||
* It tells how to change the button size automatically.
|
||||
* @param btn pointer to a button object
|
||||
* @param left left fit policy from `lv_fit_t`
|
||||
* @param right right fit policy from `lv_fit_t`
|
||||
* @param top bottom fit policy from `lv_fit_t`
|
||||
* @param top top fit policy from `lv_fit_t`
|
||||
* @param bottom bottom fit policy from `lv_fit_t`
|
||||
*/
|
||||
static inline void lv_btn_set_fit4(lv_obj_t * btn, lv_fit_t left, lv_fit_t right, lv_fit_t top, lv_fit_t bottom)
|
||||
@@ -169,9 +169,9 @@ static inline void lv_btn_set_fit4(lv_obj_t * btn, lv_fit_t left, lv_fit_t right
|
||||
|
||||
/**
|
||||
* Set the fit policy horizontally and vertically separately.
|
||||
* It tell how to change the button size automatically.
|
||||
* It tells how to change the button size automatically.
|
||||
* @param btn pointer to a button object
|
||||
* @param hot horizontal fit policy from `lv_fit_t`
|
||||
* @param hor horizontal fit policy from `lv_fit_t`
|
||||
* @param ver vertical fit policy from `lv_fit_t`
|
||||
*/
|
||||
static inline void lv_btn_set_fit2(lv_obj_t * btn, lv_fit_t hor, lv_fit_t ver)
|
||||
@@ -181,13 +181,13 @@ static inline void lv_btn_set_fit2(lv_obj_t * btn, lv_fit_t hor, lv_fit_t ver)
|
||||
|
||||
/**
|
||||
* Set the fit policy in all 4 direction at once.
|
||||
* It tell how to change the button size automatically.
|
||||
* It tells how to change the button size automatically.
|
||||
* @param btn pointer to a button object
|
||||
* @param fit fit policy from `lv_fit_t`
|
||||
*/
|
||||
static inline void lv_btn_set_fit(lv_obj_t * cont, lv_fit_t fit)
|
||||
static inline void lv_btn_set_fit(lv_obj_t * btn, lv_fit_t fit)
|
||||
{
|
||||
lv_cont_set_fit(cont, fit);
|
||||
lv_cont_set_fit(btn, fit);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,7 +233,7 @@ lv_btn_state_t lv_btn_get_state(const lv_obj_t * btn);
|
||||
/**
|
||||
* Get the toggle enable attribute of the button
|
||||
* @param btn pointer to a button object
|
||||
* @return ture: toggle enabled, false: disabled
|
||||
* @return true: toggle enabled, false: disabled
|
||||
*/
|
||||
bool lv_btn_get_toggle(const lv_obj_t * btn);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "lv_btnm.h"
|
||||
#if LV_USE_BTNM != 0
|
||||
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_core/lv_group.h"
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_core/lv_refr.h"
|
||||
@@ -18,6 +19,7 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_OBJX_NAME "lv_btnm"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -70,14 +72,14 @@ lv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
|
||||
/*Create the ancestor object*/
|
||||
lv_obj_t * new_btnm = lv_obj_create(par, copy);
|
||||
lv_mem_assert(new_btnm);
|
||||
LV_ASSERT_MEM(new_btnm);
|
||||
if(new_btnm == NULL) return NULL;
|
||||
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_btnm);
|
||||
|
||||
/*Allocate the object type specific extended data*/
|
||||
lv_btnm_ext_t * ext = lv_obj_allocate_ext_attr(new_btnm, sizeof(lv_btnm_ext_t));
|
||||
lv_mem_assert(ext);
|
||||
LV_ASSERT_MEM(ext);
|
||||
if(ext == NULL) return NULL;
|
||||
|
||||
ext->btn_cnt = 0;
|
||||
@@ -101,8 +103,8 @@ lv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
|
||||
/*Init the new button matrix object*/
|
||||
if(copy == NULL) {
|
||||
lv_obj_set_size(new_btnm, LV_DPI * 3, LV_DPI * 2);
|
||||
lv_btnm_set_map(new_btnm, lv_btnm_def_map);
|
||||
lv_obj_set_size(new_btnm, LV_DPI * 3, LV_DPI * 2);
|
||||
|
||||
/*Set the default styles*/
|
||||
lv_theme_t * th = lv_theme_get_current();
|
||||
@@ -120,7 +122,7 @@ lv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
/*Copy an existing object*/
|
||||
else {
|
||||
lv_btnm_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
|
||||
memcpy(ext->styles_btn, copy_ext->styles_btn, sizeof(ext->styles_btn));
|
||||
memcpy((void*)ext->styles_btn, copy_ext->styles_btn, sizeof(ext->styles_btn));
|
||||
lv_btnm_set_map(new_btnm, lv_btnm_get_map_array(copy));
|
||||
}
|
||||
|
||||
@@ -142,7 +144,8 @@ lv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
*/
|
||||
void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[])
|
||||
{
|
||||
if(map == NULL) return;
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(map);
|
||||
|
||||
/*
|
||||
* lv_btnm_set_map is called on receipt of signals such as
|
||||
@@ -201,9 +204,11 @@ void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[])
|
||||
|
||||
/*Make sure the last row is at the bottom of 'btnm'*/
|
||||
if(map_p_tmp[btn_cnt][0] == '\0') { /*Last row?*/
|
||||
btn_h = max_h - act_y + style_bg->body.padding.bottom - 1;
|
||||
btn_h = lv_obj_get_height(btnm)- act_y - style_bg->body.padding.bottom - 1;
|
||||
}
|
||||
|
||||
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(btnm);
|
||||
|
||||
/*Only deal with the non empty lines*/
|
||||
if(btn_cnt != 0) {
|
||||
/*Calculate the width of all units*/
|
||||
@@ -211,7 +216,8 @@ void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[])
|
||||
|
||||
/*Set the button size and positions and set the texts*/
|
||||
uint16_t i;
|
||||
lv_coord_t act_x = style_bg->body.padding.left;
|
||||
lv_coord_t act_x;
|
||||
|
||||
lv_coord_t act_unit_w;
|
||||
unit_act_cnt = 0;
|
||||
for(i = 0; i < btn_cnt; i++) {
|
||||
@@ -222,9 +228,13 @@ void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[])
|
||||
act_unit_w--; /*-1 because e.g. width = 100 means 101 pixels (0..100)*/
|
||||
|
||||
/*Always recalculate act_x because of rounding errors */
|
||||
act_x = (unit_act_cnt * all_unit_w) / unit_cnt + i * style_bg->body.padding.inner +
|
||||
style_bg->body.padding.left;
|
||||
|
||||
if(base_dir == LV_BIDI_DIR_RTL) {
|
||||
act_x = (unit_act_cnt * all_unit_w) / unit_cnt + i * style_bg->body.padding.inner;
|
||||
act_x = lv_obj_get_width(btnm) - style_bg->body.padding.right - act_x - act_unit_w - 1;
|
||||
} else {
|
||||
act_x = (unit_act_cnt * all_unit_w) / unit_cnt + i * style_bg->body.padding.inner +
|
||||
style_bg->body.padding.left;
|
||||
}
|
||||
/* Set the button's area.
|
||||
* If inner padding is zero then use the prev. button x2 as x1 to avoid rounding
|
||||
* errors*/
|
||||
@@ -241,7 +251,7 @@ void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[])
|
||||
btn_i++;
|
||||
}
|
||||
}
|
||||
act_y += btn_h + style_bg->body.padding.inner;
|
||||
act_y += btn_h + style_bg->body.padding.inner + 1;
|
||||
|
||||
if(strlen(map_p_tmp[btn_cnt]) == 0) break; /*Break on end of map*/
|
||||
map_p_tmp = &map_p_tmp[btn_cnt + 1]; /*Set the map to the next line*/
|
||||
@@ -265,6 +275,8 @@ void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[])
|
||||
*/
|
||||
void lv_btnm_set_ctrl_map(const lv_obj_t * btnm, const lv_btnm_ctrl_t ctrl_map[])
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
memcpy(ext->ctrl_bits, ctrl_map, sizeof(lv_btnm_ctrl_t) * ext->btn_cnt);
|
||||
|
||||
@@ -279,6 +291,8 @@ void lv_btnm_set_ctrl_map(const lv_obj_t * btnm, const lv_btnm_ctrl_t ctrl_map[]
|
||||
*/
|
||||
void lv_btnm_set_pressed(const lv_obj_t * btnm, uint16_t id)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
|
||||
if(id >= ext->btn_cnt && id != LV_BTNM_BTN_NONE) return;
|
||||
@@ -297,6 +311,8 @@ void lv_btnm_set_pressed(const lv_obj_t * btnm, uint16_t id)
|
||||
*/
|
||||
void lv_btnm_set_style(lv_obj_t * btnm, lv_btnm_style_t type, const lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
|
||||
switch(type) {
|
||||
@@ -331,6 +347,8 @@ void lv_btnm_set_style(lv_obj_t * btnm, lv_btnm_style_t type, const lv_style_t *
|
||||
*/
|
||||
void lv_btnm_set_recolor(const lv_obj_t * btnm, bool en)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
|
||||
ext->recolor = en;
|
||||
@@ -344,6 +362,8 @@ void lv_btnm_set_recolor(const lv_obj_t * btnm, bool en)
|
||||
*/
|
||||
void lv_btnm_set_btn_ctrl(const lv_obj_t * btnm, uint16_t btn_id, lv_btnm_ctrl_t ctrl)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
|
||||
if(btn_id >= ext->btn_cnt) return;
|
||||
@@ -359,6 +379,8 @@ void lv_btnm_set_btn_ctrl(const lv_obj_t * btnm, uint16_t btn_id, lv_btnm_ctrl_t
|
||||
*/
|
||||
void lv_btnm_clear_btn_ctrl(const lv_obj_t * btnm, uint16_t btn_id, lv_btnm_ctrl_t ctrl)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
|
||||
if(btn_id >= ext->btn_cnt) return;
|
||||
@@ -374,6 +396,8 @@ void lv_btnm_clear_btn_ctrl(const lv_obj_t * btnm, uint16_t btn_id, lv_btnm_ctrl
|
||||
*/
|
||||
void lv_btnm_set_btn_ctrl_all(lv_obj_t * btnm, lv_btnm_ctrl_t ctrl)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
uint16_t i;
|
||||
for(i = 0; i < ext->btn_cnt; i++) {
|
||||
@@ -389,6 +413,8 @@ void lv_btnm_set_btn_ctrl_all(lv_obj_t * btnm, lv_btnm_ctrl_t ctrl)
|
||||
*/
|
||||
void lv_btnm_clear_btn_ctrl_all(lv_obj_t * btnm, lv_btnm_ctrl_t ctrl)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
uint16_t i;
|
||||
for(i = 0; i < ext->btn_cnt; i++) {
|
||||
@@ -407,6 +433,8 @@ void lv_btnm_clear_btn_ctrl_all(lv_obj_t * btnm, lv_btnm_ctrl_t ctrl)
|
||||
*/
|
||||
void lv_btnm_set_btn_width(const lv_obj_t * btnm, uint16_t btn_id, uint8_t width)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
if(btn_id >= ext->btn_cnt) return;
|
||||
@@ -427,6 +455,8 @@ void lv_btnm_set_btn_width(const lv_obj_t * btnm, uint16_t btn_id, uint8_t width
|
||||
*/
|
||||
void lv_btnm_set_one_toggle(lv_obj_t * btnm, bool one_toggle)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
ext->one_toggle = one_toggle;
|
||||
|
||||
@@ -445,6 +475,8 @@ void lv_btnm_set_one_toggle(lv_obj_t * btnm, bool one_toggle)
|
||||
*/
|
||||
const char ** lv_btnm_get_map_array(const lv_obj_t * btnm)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
return ext->map_p;
|
||||
}
|
||||
@@ -456,6 +488,8 @@ const char ** lv_btnm_get_map_array(const lv_obj_t * btnm)
|
||||
*/
|
||||
bool lv_btnm_get_recolor(const lv_obj_t * btnm)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
|
||||
return ext->recolor;
|
||||
@@ -469,6 +503,8 @@ bool lv_btnm_get_recolor(const lv_obj_t * btnm)
|
||||
*/
|
||||
uint16_t lv_btnm_get_active_btn(const lv_obj_t * btnm)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
return ext->btn_id_act;
|
||||
}
|
||||
@@ -481,6 +517,8 @@ uint16_t lv_btnm_get_active_btn(const lv_obj_t * btnm)
|
||||
*/
|
||||
const char * lv_btnm_get_active_btn_text(const lv_obj_t * btnm)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
if(ext->btn_id_act != LV_BTNM_BTN_NONE) {
|
||||
return lv_btnm_get_btn_text(btnm, ext->btn_id_act);
|
||||
@@ -497,6 +535,8 @@ const char * lv_btnm_get_active_btn_text(const lv_obj_t * btnm)
|
||||
*/
|
||||
uint16_t lv_btnm_get_pressed_btn(const lv_obj_t * btnm)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
return ext->btn_id_pr;
|
||||
}
|
||||
@@ -510,6 +550,8 @@ uint16_t lv_btnm_get_pressed_btn(const lv_obj_t * btnm)
|
||||
*/
|
||||
const char * lv_btnm_get_btn_text(const lv_obj_t * btnm, uint16_t btn_id)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
if(btn_id > ext->btn_cnt) return NULL;
|
||||
|
||||
@@ -539,6 +581,8 @@ const char * lv_btnm_get_btn_text(const lv_obj_t * btnm, uint16_t btn_id)
|
||||
*/
|
||||
bool lv_btnm_get_btn_ctrl(lv_obj_t * btnm, uint16_t btn_id, lv_btnm_ctrl_t ctrl)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
if(btn_id >= ext->btn_cnt) return false;
|
||||
|
||||
@@ -553,6 +597,8 @@ bool lv_btnm_get_btn_ctrl(lv_obj_t * btnm, uint16_t btn_id, lv_btnm_ctrl_t ctrl)
|
||||
*/
|
||||
const lv_style_t * lv_btnm_get_style(const lv_obj_t * btnm, lv_btnm_style_t type)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
const lv_style_t * style = NULL;
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
|
||||
@@ -576,6 +622,8 @@ const lv_style_t * lv_btnm_get_style(const lv_obj_t * btnm, lv_btnm_style_t type
|
||||
*/
|
||||
bool lv_btnm_get_one_toggle(const lv_obj_t * btnm)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
|
||||
return ext->one_toggle;
|
||||
@@ -603,7 +651,6 @@ static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mo
|
||||
}
|
||||
/*Draw the object*/
|
||||
else if(mode == LV_DESIGN_DRAW_MAIN) {
|
||||
|
||||
ancestor_design_f(btnm, mask, mode);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
@@ -624,7 +671,6 @@ static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mo
|
||||
lv_txt_flag_t txt_flag = LV_TXT_FLAG_NONE;
|
||||
|
||||
if(ext->recolor) txt_flag = LV_TXT_FLAG_RECOLOR;
|
||||
|
||||
for(btn_i = 0; btn_i < ext->btn_cnt; btn_i++, txt_i++) {
|
||||
/*Search the next valid text in the map*/
|
||||
while(strcmp(ext->map_p[txt_i], "\n") == 0) {
|
||||
@@ -693,9 +739,10 @@ static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mo
|
||||
area_tmp.x2 = area_tmp.x1 + txt_size.x;
|
||||
area_tmp.y2 = area_tmp.y1 + txt_size.y;
|
||||
|
||||
lv_draw_label(&area_tmp, mask, btn_style, opa_scale, ext->map_p[txt_i], txt_flag, NULL, -1, -1, NULL);
|
||||
lv_draw_label(&area_tmp, mask, btn_style, opa_scale, ext->map_p[txt_i], txt_flag, NULL, NULL, NULL, lv_obj_get_base_dir(btnm));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -713,6 +760,7 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param)
|
||||
/* Include the ancient signal function */
|
||||
res = ancestor_signal(btnm, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
|
||||
|
||||
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
|
||||
lv_point_t p;
|
||||
@@ -767,7 +815,8 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param)
|
||||
} else if(sign == LV_SIGNAL_RELEASED) {
|
||||
if(ext->btn_id_pr != LV_BTNM_BTN_NONE) {
|
||||
/*Toggle the button if enabled*/
|
||||
if(button_is_tgl_enabled(ext->ctrl_bits[ext->btn_id_pr])) {
|
||||
if(button_is_tgl_enabled(ext->ctrl_bits[ext->btn_id_pr]) &&
|
||||
!button_is_inactive(ext->ctrl_bits[ext->btn_id_pr])) {
|
||||
if(button_get_tgl_state(ext->ctrl_bits[ext->btn_id_pr])) {
|
||||
ext->ctrl_bits[ext->btn_id_pr] &= (~LV_BTNM_CTRL_TGL_STATE);
|
||||
} else {
|
||||
@@ -813,6 +862,13 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param)
|
||||
#if LV_USE_GROUP
|
||||
lv_indev_t * indev = lv_indev_get_act();
|
||||
lv_indev_type_t indev_type = lv_indev_get_type(indev);
|
||||
|
||||
/*If not focused by an input device assume the last input device*/
|
||||
if(indev == NULL) {
|
||||
indev = lv_indev_get_next(NULL);
|
||||
indev_type = lv_indev_get_type(indev);
|
||||
}
|
||||
|
||||
if(indev_type == LV_INDEV_TYPE_POINTER) {
|
||||
/*Select the clicked button*/
|
||||
lv_point_t p1;
|
||||
@@ -863,7 +919,7 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param)
|
||||
for(area_below = ext->btn_id_pr; area_below < ext->btn_cnt; area_below++) {
|
||||
if(ext->button_areas[area_below].y1 > ext->button_areas[ext->btn_id_pr].y1 &&
|
||||
pr_center >= ext->button_areas[area_below].x1 &&
|
||||
pr_center <= ext->button_areas[area_below].x2 + style->body.padding.left) {
|
||||
pr_center <= ext->button_areas[area_below].x2 + style->body.padding.inner) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -884,7 +940,7 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param)
|
||||
|
||||
for(area_above = ext->btn_id_pr; area_above >= 0; area_above--) {
|
||||
if(ext->button_areas[area_above].y1 < ext->button_areas[ext->btn_id_pr].y1 &&
|
||||
pr_center >= ext->button_areas[area_above].x1 - style->body.padding.left &&
|
||||
pr_center >= ext->button_areas[area_above].x1 - style->body.padding.inner &&
|
||||
pr_center <= ext->button_areas[area_above].x2) {
|
||||
break;
|
||||
}
|
||||
@@ -897,15 +953,7 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param)
|
||||
} else if(sign == LV_SIGNAL_GET_EDITABLE) {
|
||||
bool * editable = (bool *)param;
|
||||
*editable = true;
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_btnm";
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -938,9 +986,9 @@ static void allocate_btn_areas_and_controls(const lv_obj_t * btnm, const char **
|
||||
}
|
||||
|
||||
ext->button_areas = lv_mem_alloc(sizeof(lv_area_t) * btn_cnt);
|
||||
lv_mem_assert(ext->button_areas);
|
||||
LV_ASSERT_MEM(ext->button_areas);
|
||||
ext->ctrl_bits = lv_mem_alloc(sizeof(lv_btnm_ctrl_t) * btn_cnt);
|
||||
lv_mem_assert(ext->ctrl_bits);
|
||||
LV_ASSERT_MEM(ext->ctrl_bits);
|
||||
if(ext->button_areas == NULL || ext->ctrl_bits == NULL) btn_cnt = 0;
|
||||
|
||||
memset(ext->ctrl_bits, 0, sizeof(lv_btnm_ctrl_t) * btn_cnt);
|
||||
@@ -1036,7 +1084,7 @@ static void invalidate_button_area(const lv_obj_t * btnm, uint16_t btn_idx)
|
||||
btn_area.x2 += btnm_area.x1;
|
||||
btn_area.y2 += btnm_area.y1;
|
||||
|
||||
lv_inv_area(lv_obj_get_disp(btnm), &btn_area);
|
||||
lv_obj_invalidate_area(btnm, &btn_area);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,6 +31,8 @@ extern "C" {
|
||||
#define LV_BTNM_WIDTH_MASK 0x0007
|
||||
#define LV_BTNM_BTN_NONE 0xFFFF
|
||||
|
||||
LV_EXPORT_CONST_INT(LV_BTNM_BTN_NONE);
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "lv_calendar.h"
|
||||
#if LV_USE_CALENDAR != 0
|
||||
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_hal/lv_hal_indev.h"
|
||||
#include "../lv_misc/lv_utils.h"
|
||||
@@ -19,6 +20,7 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_OBJX_NAME "lv_calendar"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -77,12 +79,12 @@ lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
|
||||
/*Create the ancestor of calendar*/
|
||||
lv_obj_t * new_calendar = lv_obj_create(par, copy);
|
||||
lv_mem_assert(new_calendar);
|
||||
LV_ASSERT_MEM(new_calendar);
|
||||
if(new_calendar == NULL) return NULL;
|
||||
|
||||
/*Allocate the calendar type specific extended data*/
|
||||
lv_calendar_ext_t * ext = lv_obj_allocate_ext_attr(new_calendar, sizeof(lv_calendar_ext_t));
|
||||
lv_mem_assert(ext);
|
||||
LV_ASSERT_MEM(ext);
|
||||
if(ext == NULL) return NULL;
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_calendar);
|
||||
if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_cb(new_calendar);
|
||||
@@ -195,6 +197,9 @@ lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
*/
|
||||
void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(today);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
ext->today.year = today->year;
|
||||
ext->today.month = today->month;
|
||||
@@ -211,6 +216,9 @@ void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today)
|
||||
*/
|
||||
void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(showed);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
ext->showed_date.year = showed->year;
|
||||
ext->showed_date.month = showed->month;
|
||||
@@ -226,8 +234,11 @@ void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showe
|
||||
* WILL BE SAVED! CAN'T BE LOCAL ARRAY.
|
||||
* @param date_num number of dates in the array
|
||||
*/
|
||||
void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num)
|
||||
void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t highlighted[], uint16_t date_num)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(highlighted);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
ext->highlighted_dates = highlighted;
|
||||
ext->highlighted_dates_num = date_num;
|
||||
@@ -244,6 +255,9 @@ void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t *
|
||||
*/
|
||||
void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(day_names);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
ext->day_names = day_names;
|
||||
lv_obj_invalidate(calendar);
|
||||
@@ -252,14 +266,17 @@ void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names)
|
||||
/**
|
||||
* Set the name of the month
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param day_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb",
|
||||
* @param month_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb",
|
||||
* ...}` Only the pointer will be saved so this variable can't be local which will be destroyed
|
||||
* later.
|
||||
*/
|
||||
void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names)
|
||||
void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** month_names)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(month_names);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
ext->month_names = day_names;
|
||||
ext->month_names = month_names;
|
||||
lv_obj_invalidate(calendar);
|
||||
}
|
||||
|
||||
@@ -271,6 +288,8 @@ void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names)
|
||||
* */
|
||||
void lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, const lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
|
||||
switch(type) {
|
||||
@@ -298,6 +317,8 @@ void lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, const
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return &ext->today;
|
||||
}
|
||||
@@ -309,6 +330,8 @@ lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar)
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return &ext->showed_date;
|
||||
}
|
||||
@@ -317,11 +340,14 @@ lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar)
|
||||
* Get the the pressed date.
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return pointer to an `lv_calendar_date_t` variable containing the pressed date.
|
||||
* `NULL` if not date pressed (e.g. the header)
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return &ext->pressed_date;
|
||||
return ext->pressed_date.year != 0 ? &ext->pressed_date : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -331,6 +357,8 @@ lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar)
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return ext->highlighted_dates;
|
||||
}
|
||||
@@ -342,6 +370,8 @@ lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar
|
||||
*/
|
||||
uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return ext->highlighted_dates_num;
|
||||
}
|
||||
@@ -353,6 +383,8 @@ uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar)
|
||||
*/
|
||||
const char ** lv_calendar_get_day_names(const lv_obj_t * calendar)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return ext->day_names;
|
||||
}
|
||||
@@ -364,6 +396,8 @@ const char ** lv_calendar_get_day_names(const lv_obj_t * calendar)
|
||||
*/
|
||||
const char ** lv_calendar_get_month_names(const lv_obj_t * calendar)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
return ext->month_names;
|
||||
}
|
||||
@@ -376,6 +410,8 @@ const char ** lv_calendar_get_month_names(const lv_obj_t * calendar)
|
||||
* */
|
||||
const lv_style_t * lv_calendar_get_style(const lv_obj_t * calendar, lv_calendar_style_t type)
|
||||
{
|
||||
LV_ASSERT_OBJ(calendar, LV_OBJX_NAME);
|
||||
|
||||
const lv_style_t * style = NULL;
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
|
||||
@@ -453,6 +489,7 @@ static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void *
|
||||
/* Include the ancient signal function */
|
||||
res = ancestor_signal(calendar, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
|
||||
|
||||
if(sign == LV_SIGNAL_CLEANUP) {
|
||||
/*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/
|
||||
@@ -541,13 +578,6 @@ static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void *
|
||||
}
|
||||
lv_obj_invalidate(calendar);
|
||||
}
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set date*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_calendar";
|
||||
}
|
||||
|
||||
return res;
|
||||
@@ -640,6 +670,9 @@ static lv_coord_t get_day_names_height(lv_obj_t * calendar)
|
||||
static void draw_header(lv_obj_t * calendar, const lv_area_t * mask)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
|
||||
lv_bidi_dir_t bidi_dir = lv_obj_get_base_dir(calendar);
|
||||
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar);
|
||||
|
||||
lv_area_t header_area;
|
||||
@@ -657,19 +690,19 @@ static void draw_header(lv_obj_t * calendar, const lv_area_t * mask)
|
||||
txt_buf[5] = '\0';
|
||||
strcpy(&txt_buf[5], get_month_name(calendar, ext->showed_date.month));
|
||||
header_area.y1 += ext->style_header->body.padding.top;
|
||||
lv_draw_label(&header_area, mask, ext->style_header, opa_scale, txt_buf, LV_TXT_FLAG_CENTER, NULL, -1, -1, NULL);
|
||||
lv_draw_label(&header_area, mask, ext->style_header, opa_scale, txt_buf, LV_TXT_FLAG_CENTER, NULL, NULL, NULL, bidi_dir);
|
||||
|
||||
/*Add the left arrow*/
|
||||
const lv_style_t * arrow_style = ext->btn_pressing < 0 ? ext->style_header_pr : ext->style_header;
|
||||
header_area.x1 += ext->style_header->body.padding.left;
|
||||
lv_draw_label(&header_area, mask, arrow_style, opa_scale, LV_SYMBOL_LEFT, LV_TXT_FLAG_NONE, NULL, -1, -1, NULL);
|
||||
lv_draw_label(&header_area, mask, arrow_style, opa_scale, LV_SYMBOL_LEFT, LV_TXT_FLAG_NONE, NULL, NULL, NULL, bidi_dir);
|
||||
|
||||
/*Add the right arrow*/
|
||||
arrow_style = ext->btn_pressing > 0 ? ext->style_header_pr : ext->style_header;
|
||||
header_area.x1 = header_area.x2 - ext->style_header->body.padding.right -
|
||||
lv_txt_get_width(LV_SYMBOL_RIGHT, strlen(LV_SYMBOL_RIGHT), arrow_style->text.font,
|
||||
lv_txt_get_width(LV_SYMBOL_RIGHT, (uint16_t)strlen(LV_SYMBOL_RIGHT), arrow_style->text.font,
|
||||
arrow_style->text.line_space, LV_TXT_FLAG_NONE);
|
||||
lv_draw_label(&header_area, mask, arrow_style, opa_scale, LV_SYMBOL_RIGHT, LV_TXT_FLAG_NONE, NULL, -1, -1, NULL);
|
||||
lv_draw_label(&header_area, mask, arrow_style, opa_scale, LV_SYMBOL_RIGHT, LV_TXT_FLAG_NONE, NULL, NULL, NULL, bidi_dir);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -680,6 +713,7 @@ static void draw_header(lv_obj_t * calendar, const lv_area_t * mask)
|
||||
static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
lv_bidi_dir_t bidi_dir = lv_obj_get_base_dir(calendar);
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar);
|
||||
|
||||
lv_coord_t l_pad = ext->style_day_names->body.padding.left;
|
||||
@@ -694,7 +728,7 @@ static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask)
|
||||
label_area.x1 = calendar->coords.x1 + (w * i) / 7 + l_pad;
|
||||
label_area.x2 = label_area.x1 + box_w - 1;
|
||||
lv_draw_label(&label_area, mask, ext->style_day_names, opa_scale, get_day_name(calendar, i), LV_TXT_FLAG_CENTER,
|
||||
NULL, -1, -1, NULL);
|
||||
NULL, NULL, NULL, bidi_dir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -706,6 +740,7 @@ static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask)
|
||||
static void draw_days(lv_obj_t * calendar, const lv_area_t * mask)
|
||||
{
|
||||
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
|
||||
lv_bidi_dir_t bidi_dir = lv_obj_get_base_dir(calendar);
|
||||
const lv_style_t * style_bg = lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG);
|
||||
lv_area_t label_area;
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar);
|
||||
@@ -786,7 +821,7 @@ static void draw_days(lv_obj_t * calendar, const lv_area_t * mask)
|
||||
}
|
||||
|
||||
label_area.x1 =
|
||||
calendar->coords.x1 + (w * day) / 7 + style_bg->body.padding.left + style_bg->body.padding.right;
|
||||
calendar->coords.x1 + (w * day) / 7 + style_bg->body.padding.left;
|
||||
label_area.x2 = label_area.x1 + box_w - 1;
|
||||
|
||||
/*Draw the "today box"*/
|
||||
@@ -823,7 +858,7 @@ static void draw_days(lv_obj_t * calendar, const lv_area_t * mask)
|
||||
|
||||
/*Write the day's number*/
|
||||
lv_utils_num_to_str(day_cnt, buf);
|
||||
lv_draw_label(&label_area, mask, final_style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL, -1, -1, NULL);
|
||||
lv_draw_label(&label_area, mask, final_style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL, NULL, NULL, bidi_dir);
|
||||
|
||||
/*Go to the next day*/
|
||||
day_cnt++;
|
||||
|
||||
@@ -50,8 +50,8 @@ typedef struct
|
||||
lv_calendar_date_t showed_date; /*Currently visible month (day is ignored)*/
|
||||
lv_calendar_date_t * highlighted_dates; /*Apply different style on these days (pointer to an
|
||||
array defined by the user)*/
|
||||
uint8_t highlighted_dates_num; /*Number of elements in `highlighted_days`*/
|
||||
int8_t btn_pressing; /*-1: prev month pressing, +1 next month pressing on the header*/
|
||||
uint16_t highlighted_dates_num; /*Number of elements in `highlighted_days`*/
|
||||
lv_calendar_date_t pressed_date;
|
||||
const char ** day_names; /*Pointer to an array with the name of the days (NULL: use default names)*/
|
||||
const char ** month_names; /*Pointer to an array with the name of the month (NULL. use default names)*/
|
||||
@@ -122,7 +122,7 @@ void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showe
|
||||
* WILL BE SAVED! CAN'T BE LOCAL ARRAY.
|
||||
* @param date_num number of dates in the array
|
||||
*/
|
||||
void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num);
|
||||
void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t highlighted[], uint16_t date_num);
|
||||
|
||||
/**
|
||||
* Set the name of the days
|
||||
@@ -136,11 +136,11 @@ void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names);
|
||||
/**
|
||||
* Set the name of the month
|
||||
* @param calendar pointer to a calendar object
|
||||
* @param day_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb",
|
||||
* @param month_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb",
|
||||
* ...}` Only the pointer will be saved so this variable can't be local which will be destroyed
|
||||
* later.
|
||||
*/
|
||||
void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names);
|
||||
void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** month_names);
|
||||
|
||||
/**
|
||||
* Set a style of a calendar.
|
||||
@@ -172,6 +172,7 @@ lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar);
|
||||
* Get the the pressed date.
|
||||
* @param calendar pointer to a calendar object
|
||||
* @return pointer to an `lv_calendar_date_t` variable containing the pressed date.
|
||||
* `NULL` if not date pressed (e.g. the header)
|
||||
*/
|
||||
lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*********************/
|
||||
#include <stdlib.h>
|
||||
#include "lv_canvas.h"
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_core/lv_refr.h"
|
||||
@@ -17,6 +18,7 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_OBJX_NAME "lv_canvas"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -53,12 +55,12 @@ lv_obj_t * lv_canvas_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
|
||||
/*Create the ancestor of canvas*/
|
||||
lv_obj_t * new_canvas = lv_img_create(par, copy);
|
||||
lv_mem_assert(new_canvas);
|
||||
LV_ASSERT_MEM(new_canvas);
|
||||
if(new_canvas == NULL) return NULL;
|
||||
|
||||
/*Allocate the canvas type specific extended data*/
|
||||
lv_canvas_ext_t * ext = lv_obj_allocate_ext_attr(new_canvas, sizeof(lv_canvas_ext_t));
|
||||
lv_mem_assert(ext);
|
||||
LV_ASSERT_MEM(ext);
|
||||
if(ext == NULL) return NULL;
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_canvas);
|
||||
if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_cb(new_canvas);
|
||||
@@ -111,6 +113,9 @@ lv_obj_t * lv_canvas_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
*/
|
||||
void lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(buf);
|
||||
|
||||
lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
|
||||
|
||||
ext->dsc.header.cf = cf;
|
||||
@@ -131,6 +136,8 @@ void lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_
|
||||
*/
|
||||
void lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
|
||||
lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
|
||||
|
||||
lv_img_buf_set_px_color(&ext->dsc, x, y, c);
|
||||
@@ -149,6 +156,8 @@ void lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t
|
||||
*/
|
||||
void lv_canvas_set_palette(lv_obj_t * canvas, uint8_t id, lv_color_t c)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
|
||||
lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
|
||||
|
||||
lv_img_buf_set_palette(&ext->dsc, id, c);
|
||||
@@ -163,6 +172,8 @@ void lv_canvas_set_palette(lv_obj_t * canvas, uint8_t id, lv_color_t c)
|
||||
*/
|
||||
void lv_canvas_set_style(lv_obj_t * canvas, lv_canvas_style_t type, const lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
|
||||
switch(type) {
|
||||
case LV_CANVAS_STYLE_MAIN: lv_img_set_style(canvas, LV_IMG_STYLE_MAIN, style); break;
|
||||
}
|
||||
@@ -181,6 +192,8 @@ void lv_canvas_set_style(lv_obj_t * canvas, lv_canvas_style_t type, const lv_sty
|
||||
*/
|
||||
lv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
|
||||
lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
|
||||
const lv_style_t * style = lv_canvas_get_style(canvas, LV_CANVAS_STYLE_MAIN);
|
||||
|
||||
@@ -194,6 +207,8 @@ lv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y)
|
||||
*/
|
||||
lv_img_dsc_t * lv_canvas_get_img(lv_obj_t * canvas)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
|
||||
lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
|
||||
|
||||
return &ext->dsc;
|
||||
@@ -207,7 +222,8 @@ lv_img_dsc_t * lv_canvas_get_img(lv_obj_t * canvas)
|
||||
*/
|
||||
const lv_style_t * lv_canvas_get_style(const lv_obj_t * canvas, lv_canvas_style_t type)
|
||||
{
|
||||
// lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
|
||||
const lv_style_t * style = NULL;
|
||||
|
||||
switch(type) {
|
||||
@@ -234,8 +250,11 @@ const lv_style_t * lv_canvas_get_style(const lv_obj_t * canvas, lv_canvas_style_
|
||||
*/
|
||||
void lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(to_copy);
|
||||
|
||||
lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
|
||||
if(x + w >= ext->dsc.header.w || y + h >= ext->dsc.header.h) {
|
||||
if(x + w >= (lv_coord_t)ext->dsc.header.w || y + h >= (lv_coord_t)ext->dsc.header.h) {
|
||||
LV_LOG_WARN("lv_canvas_copy_buf: x or y out of the canvas");
|
||||
return;
|
||||
}
|
||||
@@ -267,6 +286,9 @@ void lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t x, l
|
||||
void lv_canvas_rotate(lv_obj_t * canvas, lv_img_dsc_t * img, int16_t angle, lv_coord_t offset_x, lv_coord_t offset_y,
|
||||
int32_t pivot_x, int32_t pivot_y)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(img);
|
||||
|
||||
lv_canvas_ext_t * ext_dst = lv_obj_get_ext_attr(canvas);
|
||||
const lv_style_t * style = lv_canvas_get_style(canvas, LV_CANVAS_STYLE_MAIN);
|
||||
int32_t sinma = lv_trigo_sin(-angle);
|
||||
@@ -431,6 +453,8 @@ void lv_canvas_rotate(lv_obj_t * canvas, lv_img_dsc_t * img, int16_t angle, lv_c
|
||||
*/
|
||||
void lv_canvas_fill_bg(lv_obj_t * canvas, lv_color_t color)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
|
||||
lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
|
||||
|
||||
uint32_t x = dsc->header.w * dsc->header.h;
|
||||
@@ -454,6 +478,9 @@ void lv_canvas_fill_bg(lv_obj_t * canvas, lv_color_t color)
|
||||
void lv_canvas_draw_rect(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h,
|
||||
const lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(style);
|
||||
|
||||
lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
|
||||
|
||||
/* Create a dummy display to fool the lv_draw function.
|
||||
@@ -483,6 +510,17 @@ void lv_canvas_draw_rect(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord
|
||||
disp.driver.hor_res = dsc->header.w;
|
||||
disp.driver.ver_res = dsc->header.h;
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
/*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/
|
||||
lv_color_t ctransp = LV_COLOR_TRANSP;
|
||||
if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED &&
|
||||
style->body.main_color.full == ctransp.full &&
|
||||
style->body.grad_color.full == ctransp.full)
|
||||
{
|
||||
disp.driver.antialiasing = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_disp_t * refr_ori = lv_refr_get_disp_refreshing();
|
||||
lv_refr_set_disp_refreshing(&disp);
|
||||
|
||||
@@ -504,6 +542,9 @@ void lv_canvas_draw_rect(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord
|
||||
void lv_canvas_draw_text(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_t max_w, const lv_style_t * style,
|
||||
const char * txt, lv_label_align_t align)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(style);
|
||||
|
||||
lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
|
||||
|
||||
/* Create a dummy display to fool the lv_draw function.
|
||||
@@ -544,8 +585,7 @@ void lv_canvas_draw_text(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord
|
||||
default: flag = LV_TXT_FLAG_NONE; break;
|
||||
}
|
||||
|
||||
lv_draw_label(&coords, &mask, style, LV_OPA_COVER, txt, flag, NULL, LV_LABEL_TEXT_SEL_OFF, LV_LABEL_TEXT_SEL_OFF,
|
||||
NULL);
|
||||
lv_draw_label(&coords, &mask, style, LV_OPA_COVER, txt, flag, NULL, NULL, NULL, lv_obj_get_base_dir(canvas));
|
||||
|
||||
lv_refr_set_disp_refreshing(refr_ori);
|
||||
}
|
||||
@@ -558,6 +598,9 @@ void lv_canvas_draw_text(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord
|
||||
*/
|
||||
void lv_canvas_draw_img(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, const void * src, const lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(style);
|
||||
|
||||
lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
|
||||
|
||||
/* Create a dummy display to fool the lv_draw function.
|
||||
@@ -611,6 +654,9 @@ void lv_canvas_draw_img(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, const voi
|
||||
*/
|
||||
void lv_canvas_draw_line(lv_obj_t * canvas, const lv_point_t * points, uint32_t point_cnt, const lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(style);
|
||||
|
||||
lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
|
||||
|
||||
/* Create a dummy display to fool the lv_draw function.
|
||||
@@ -634,14 +680,51 @@ void lv_canvas_draw_line(lv_obj_t * canvas, const lv_point_t * points, uint32_t
|
||||
disp.driver.hor_res = dsc->header.w;
|
||||
disp.driver.ver_res = dsc->header.h;
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
/*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/
|
||||
lv_color_t ctransp = LV_COLOR_TRANSP;
|
||||
if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED &&
|
||||
style->body.main_color.full == ctransp.full &&
|
||||
style->body.grad_color.full == ctransp.full)
|
||||
{
|
||||
disp.driver.antialiasing = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_disp_t * refr_ori = lv_refr_get_disp_refreshing();
|
||||
lv_refr_set_disp_refreshing(&disp);
|
||||
|
||||
lv_style_t circle_style_tmp; /*If rounded...*/
|
||||
if(style->line.rounded) {
|
||||
lv_style_copy(&circle_style_tmp, style);
|
||||
circle_style_tmp.body.radius = LV_RADIUS_CIRCLE;
|
||||
circle_style_tmp.body.main_color = style->line.color;
|
||||
circle_style_tmp.body.grad_color = style->line.color;
|
||||
circle_style_tmp.body.opa = style->line.opa;
|
||||
}
|
||||
lv_area_t circle_area;
|
||||
uint32_t i;
|
||||
for(i = 0; i < point_cnt - 1; i++) {
|
||||
lv_draw_line(&points[i], &points[i + 1], &mask, style, LV_OPA_COVER);
|
||||
|
||||
/*Draw circle on the joints if enabled*/
|
||||
if(style->line.rounded) {
|
||||
circle_area.x1 = points[i].x - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1);
|
||||
circle_area.y1 = points[i].y - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1);
|
||||
circle_area.x2 = points[i].x + ((style->line.width - 1) >> 1);
|
||||
circle_area.y2 = points[i].y + ((style->line.width - 1) >> 1);
|
||||
lv_draw_rect(&circle_area, &mask, &circle_style_tmp, LV_OPA_COVER);
|
||||
}
|
||||
}
|
||||
|
||||
/*Draw circle on the last point too if enabled*/
|
||||
if(style->line.rounded) {
|
||||
circle_area.x1 = points[i].x - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1);
|
||||
circle_area.y1 = points[i].y - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1);
|
||||
circle_area.x2 = points[i].x + ((style->line.width - 1) >> 1);
|
||||
circle_area.y2 = points[i].y + ((style->line.width - 1) >> 1);
|
||||
lv_draw_rect(&circle_area, &mask, &circle_style_tmp, LV_OPA_COVER);
|
||||
}
|
||||
|
||||
lv_refr_set_disp_refreshing(refr_ori);
|
||||
}
|
||||
|
||||
@@ -654,6 +737,9 @@ void lv_canvas_draw_line(lv_obj_t * canvas, const lv_point_t * points, uint32_t
|
||||
*/
|
||||
void lv_canvas_draw_polygon(lv_obj_t * canvas, const lv_point_t * points, uint32_t point_cnt, const lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(style);
|
||||
|
||||
lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
|
||||
|
||||
/* Create a dummy display to fool the lv_draw function.
|
||||
@@ -677,6 +763,17 @@ void lv_canvas_draw_polygon(lv_obj_t * canvas, const lv_point_t * points, uint32
|
||||
disp.driver.hor_res = dsc->header.w;
|
||||
disp.driver.ver_res = dsc->header.h;
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
/*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/
|
||||
lv_color_t ctransp = LV_COLOR_TRANSP;
|
||||
if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED &&
|
||||
style->body.main_color.full == ctransp.full &&
|
||||
style->body.grad_color.full == ctransp.full)
|
||||
{
|
||||
disp.driver.antialiasing = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_disp_t * refr_ori = lv_refr_get_disp_refreshing();
|
||||
lv_refr_set_disp_refreshing(&disp);
|
||||
|
||||
@@ -698,6 +795,9 @@ void lv_canvas_draw_polygon(lv_obj_t * canvas, const lv_point_t * points, uint32
|
||||
void lv_canvas_draw_arc(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_t r, int32_t start_angle,
|
||||
int32_t end_angle, const lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_OBJ(canvas, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(style);
|
||||
|
||||
lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
|
||||
|
||||
/* Create a dummy display to fool the lv_draw function.
|
||||
@@ -721,6 +821,17 @@ void lv_canvas_draw_arc(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_
|
||||
disp.driver.hor_res = dsc->header.w;
|
||||
disp.driver.ver_res = dsc->header.h;
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
/*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/
|
||||
lv_color_t ctransp = LV_COLOR_TRANSP;
|
||||
if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED &&
|
||||
style->body.main_color.full == ctransp.full &&
|
||||
style->body.grad_color.full == ctransp.full)
|
||||
{
|
||||
disp.driver.antialiasing = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_disp_t * refr_ori = lv_refr_get_disp_refreshing();
|
||||
lv_refr_set_disp_refreshing(&disp);
|
||||
|
||||
@@ -747,16 +858,10 @@ static lv_res_t lv_canvas_signal(lv_obj_t * canvas, lv_signal_t sign, void * par
|
||||
/* Include the ancient signal function */
|
||||
res = ancestor_signal(canvas, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
|
||||
|
||||
if(sign == LV_SIGNAL_CLEANUP) {
|
||||
/*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_canvas";
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
@@ -23,6 +23,7 @@ extern "C" {
|
||||
|
||||
#include "../lv_core/lv_obj.h"
|
||||
#include "../lv_objx/lv_img.h"
|
||||
#include "../lv_draw/lv_draw_img.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -239,21 +240,21 @@ void lv_canvas_draw_arc(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
#define LV_CANVAS_BUF_SIZE_TRUE_COLOR(w, h) ((LV_COLOR_SIZE / 8) * w * h)
|
||||
#define LV_CANVAS_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) ((LV_COLOR_SIZE / 8) * w * h)
|
||||
#define LV_CANVAS_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) (LV_IMG_PX_SIZE_ALPHA_BYTE * w * h)
|
||||
#define LV_CANVAS_BUF_SIZE_TRUE_COLOR(w, h) LV_IMG_BUF_SIZE_TRUE_COLOR(w, h)
|
||||
#define LV_CANVAS_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h)
|
||||
#define LV_CANVAS_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h)
|
||||
|
||||
/*+ 1: to be sure no fractional row*/
|
||||
#define LV_CANVAS_BUF_SIZE_ALPHA_1BIT(w, h) ((((w / 8) + 1) * h))
|
||||
#define LV_CANVAS_BUF_SIZE_ALPHA_2BIT(w, h) ((((w / 4) + 1) * h))
|
||||
#define LV_CANVAS_BUF_SIZE_ALPHA_4BIT(w, h) ((((w / 2) + 1) * h))
|
||||
#define LV_CANVAS_BUF_SIZE_ALPHA_8BIT(w, h) ((w * h))
|
||||
#define LV_CANVAS_BUF_SIZE_ALPHA_1BIT(w, h) LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h)
|
||||
#define LV_CANVAS_BUF_SIZE_ALPHA_2BIT(w, h) LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h)
|
||||
#define LV_CANVAS_BUF_SIZE_ALPHA_4BIT(w, h) LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h)
|
||||
#define LV_CANVAS_BUF_SIZE_ALPHA_8BIT(w, h) LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h)
|
||||
|
||||
/*4 * X: for palette*/
|
||||
#define LV_CANVAS_BUF_SIZE_INDEXED_1BIT(w, h) (LV_CANVAS_BUF_SIZE_ALPHA_1BIT(w, h) + 4 * 2)
|
||||
#define LV_CANVAS_BUF_SIZE_INDEXED_2BIT(w, h) (LV_CANVAS_BUF_SIZE_ALPHA_2BIT(w, h) + 4 * 4)
|
||||
#define LV_CANVAS_BUF_SIZE_INDEXED_4BIT(w, h) (LV_CANVAS_BUF_SIZE_ALPHA_4BIT(w, h) + 4 * 16)
|
||||
#define LV_CANVAS_BUF_SIZE_INDEXED_8BIT(w, h) (LV_CANVAS_BUF_SIZE_ALPHA_8BIT(w, h) + 4 * 256)
|
||||
#define LV_CANVAS_BUF_SIZE_INDEXED_1BIT(w, h) LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h)
|
||||
#define LV_CANVAS_BUF_SIZE_INDEXED_2BIT(w, h) LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h)
|
||||
#define LV_CANVAS_BUF_SIZE_INDEXED_4BIT(w, h) LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h)
|
||||
#define LV_CANVAS_BUF_SIZE_INDEXED_8BIT(w, h) LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h)
|
||||
|
||||
#endif /*LV_USE_CANVAS*/
|
||||
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
#include "lv_cb.h"
|
||||
#if LV_USE_CB != 0
|
||||
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_core/lv_group.h"
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_OBJX_NAME "lv_cb"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -55,14 +57,14 @@ lv_obj_t * lv_cb_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
|
||||
/*Create the ancestor basic object*/
|
||||
lv_obj_t * new_cb = lv_btn_create(par, copy);
|
||||
lv_mem_assert(new_cb);
|
||||
LV_ASSERT_MEM(new_cb);
|
||||
if(new_cb == NULL) return NULL;
|
||||
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_cb);
|
||||
if(ancestor_bg_design == NULL) ancestor_bg_design = lv_obj_get_design_cb(new_cb);
|
||||
|
||||
lv_cb_ext_t * ext = lv_obj_allocate_ext_attr(new_cb, sizeof(lv_cb_ext_t));
|
||||
lv_mem_assert(ext);
|
||||
LV_ASSERT_MEM(ext);
|
||||
if(ext == NULL) return NULL;
|
||||
|
||||
ext->bullet = NULL;
|
||||
@@ -126,6 +128,8 @@ lv_obj_t * lv_cb_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
*/
|
||||
void lv_cb_set_text(lv_obj_t * cb, const char * txt)
|
||||
{
|
||||
LV_ASSERT_OBJ(cb, LV_OBJX_NAME);
|
||||
|
||||
lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb);
|
||||
lv_label_set_text(ext->label, txt);
|
||||
}
|
||||
@@ -138,6 +142,8 @@ void lv_cb_set_text(lv_obj_t * cb, const char * txt)
|
||||
*/
|
||||
void lv_cb_set_static_text(lv_obj_t * cb, const char * txt)
|
||||
{
|
||||
LV_ASSERT_OBJ(cb, LV_OBJX_NAME);
|
||||
|
||||
lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb);
|
||||
lv_label_set_static_text(ext->label, txt);
|
||||
}
|
||||
@@ -150,6 +156,8 @@ void lv_cb_set_static_text(lv_obj_t * cb, const char * txt)
|
||||
* */
|
||||
void lv_cb_set_style(lv_obj_t * cb, lv_cb_style_t type, const lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_OBJ(cb, LV_OBJX_NAME);
|
||||
|
||||
lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb);
|
||||
|
||||
switch(type) {
|
||||
@@ -179,6 +187,8 @@ void lv_cb_set_style(lv_obj_t * cb, lv_cb_style_t type, const lv_style_t * style
|
||||
*/
|
||||
const char * lv_cb_get_text(const lv_obj_t * cb)
|
||||
{
|
||||
LV_ASSERT_OBJ(cb, LV_OBJX_NAME);
|
||||
|
||||
lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb);
|
||||
return lv_label_get_text(ext->label);
|
||||
}
|
||||
@@ -191,10 +201,13 @@ const char * lv_cb_get_text(const lv_obj_t * cb)
|
||||
* */
|
||||
const lv_style_t * lv_cb_get_style(const lv_obj_t * cb, lv_cb_style_t type)
|
||||
{
|
||||
LV_ASSERT_OBJ(cb, LV_OBJX_NAME);
|
||||
|
||||
const lv_style_t * style = NULL;
|
||||
lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb);
|
||||
|
||||
switch(type) {
|
||||
case LV_CB_STYLE_BG: style = lv_btn_get_style(cb, LV_BTN_STYLE_REL); break;
|
||||
case LV_CB_STYLE_BOX_REL: style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_REL); break;
|
||||
case LV_CB_STYLE_BOX_PR: style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_PR); break;
|
||||
case LV_CB_STYLE_BOX_TGL_REL: style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_TGL_REL); break;
|
||||
@@ -300,6 +313,7 @@ static lv_res_t lv_cb_signal(lv_obj_t * cb, lv_signal_t sign, void * param)
|
||||
/* Include the ancient signal function */
|
||||
res = ancestor_signal(cb, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
|
||||
|
||||
lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb);
|
||||
|
||||
@@ -316,13 +330,6 @@ static lv_res_t lv_cb_signal(lv_obj_t * cb, lv_signal_t sign, void * param)
|
||||
/*Follow the backgrounds state with the bullet*/
|
||||
lv_btn_set_state(ext->bullet, lv_btn_get_state(cb));
|
||||
}
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_cb";
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
@@ -149,7 +149,7 @@ static inline bool lv_cb_is_checked(const lv_obj_t * cb)
|
||||
*/
|
||||
static inline bool lv_cb_is_inactive(const lv_obj_t * cb)
|
||||
{
|
||||
return lv_btn_get_state(cb) == LV_BTN_STATE_INA ? false : true;
|
||||
return lv_btn_get_state(cb) == LV_BTN_STATE_INA ? true :false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "lv_chart.h"
|
||||
#if LV_USE_CHART != 0
|
||||
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_core/lv_refr.h"
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
@@ -16,6 +17,8 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_OBJX_NAME "lv_chart"
|
||||
|
||||
#define LV_CHART_YMIN_DEF 0
|
||||
#define LV_CHART_YMAX_DEF 100
|
||||
#define LV_CHART_HDIV_DEF 3
|
||||
@@ -24,11 +27,22 @@
|
||||
#define LV_CHART_AXIS_TO_LABEL_DISTANCE 4
|
||||
#define LV_CHART_AXIS_MAJOR_TICK_LEN_COE 1 / 15
|
||||
#define LV_CHART_AXIS_MINOR_TICK_LEN_COE 2 / 3
|
||||
#define LV_CHART_AXIS_PRIMARY_Y 1
|
||||
#define LV_CHART_AXIS_SECONDARY_Y 0
|
||||
#define LV_CHART_LABEL_ITERATOR_FORWARD 1
|
||||
#define LV_CHART_LABEL_ITERATOR_REVERSE 0
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
const char * list_start;
|
||||
const char * current_pos;
|
||||
uint8_t items_left;
|
||||
uint8_t is_reverse_iter;
|
||||
} lv_chart_label_iterator_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
@@ -44,6 +58,9 @@ static void lv_chart_draw_axes(lv_obj_t * chart, const lv_area_t * mask);
|
||||
static void lv_chart_inv_lines(lv_obj_t * chart, uint16_t i);
|
||||
static void lv_chart_inv_points(lv_obj_t * chart, uint16_t i);
|
||||
static void lv_chart_inv_cols(lv_obj_t * chart, uint16_t i);
|
||||
static void lv_chart_get_next_label(lv_chart_label_iterator_t * iterator, char * buf);
|
||||
static inline bool lv_chart_is_tick_with_label(uint8_t tick_num, lv_chart_axis_cfg_t * axis);
|
||||
static lv_chart_label_iterator_t lv_chart_create_label_iter(const char * list, uint8_t iterator_dir);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -72,12 +89,12 @@ lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
|
||||
/*Create the ancestor basic object*/
|
||||
lv_obj_t * new_chart = lv_obj_create(par, copy);
|
||||
lv_mem_assert(new_chart);
|
||||
LV_ASSERT_MEM(new_chart);
|
||||
if(new_chart == NULL) return NULL;
|
||||
|
||||
/*Allocate the object type specific extended data*/
|
||||
lv_chart_ext_t * ext = lv_obj_allocate_ext_attr(new_chart, sizeof(lv_chart_ext_t));
|
||||
lv_mem_assert(ext);
|
||||
LV_ASSERT_MEM(ext);
|
||||
if(ext == NULL) return NULL;
|
||||
|
||||
lv_ll_init(&ext->series_ll, sizeof(lv_chart_series_t));
|
||||
@@ -96,10 +113,13 @@ lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
ext->margin = 0;
|
||||
memset(&ext->x_axis, 0, sizeof(ext->x_axis));
|
||||
memset(&ext->y_axis, 0, sizeof(ext->y_axis));
|
||||
memset(&ext->secondary_y_axis, 0, sizeof(ext->secondary_y_axis));
|
||||
ext->x_axis.major_tick_len = LV_CHART_TICK_LENGTH_AUTO;
|
||||
ext->x_axis.minor_tick_len = LV_CHART_TICK_LENGTH_AUTO;
|
||||
ext->y_axis.major_tick_len = LV_CHART_TICK_LENGTH_AUTO;
|
||||
ext->y_axis.minor_tick_len = LV_CHART_TICK_LENGTH_AUTO;
|
||||
ext->secondary_y_axis.major_tick_len = LV_CHART_TICK_LENGTH_AUTO;
|
||||
ext->secondary_y_axis.minor_tick_len = LV_CHART_TICK_LENGTH_AUTO;
|
||||
|
||||
if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_cb(new_chart);
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_chart);
|
||||
@@ -132,6 +152,7 @@ lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
ext->margin = ext_copy->margin;
|
||||
memcpy(&ext->x_axis, &ext_copy->x_axis, sizeof(lv_chart_axis_cfg_t));
|
||||
memcpy(&ext->y_axis, &ext_copy->y_axis, sizeof(lv_chart_axis_cfg_t));
|
||||
memcpy(&ext->secondary_y_axis, &ext_copy->secondary_y_axis, sizeof(lv_chart_axis_cfg_t));
|
||||
|
||||
/*Refresh the style with new signal function*/
|
||||
lv_obj_refresh_style(new_chart);
|
||||
@@ -154,9 +175,11 @@ lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
*/
|
||||
lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
lv_chart_series_t * ser = lv_ll_ins_head(&ext->series_ll);
|
||||
lv_mem_assert(ser);
|
||||
LV_ASSERT_MEM(ser);
|
||||
if(ser == NULL) return NULL;
|
||||
|
||||
lv_coord_t def = LV_CHART_POINT_DEF;
|
||||
@@ -165,7 +188,7 @@ lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color)
|
||||
|
||||
ser->color = color;
|
||||
ser->points = lv_mem_alloc(sizeof(lv_coord_t) * ext->point_cnt);
|
||||
lv_mem_assert(ser->points);
|
||||
LV_ASSERT_MEM(ser->points);
|
||||
if(ser->points == NULL) {
|
||||
lv_ll_rem(&ext->series_ll, ser);
|
||||
lv_mem_free(ser);
|
||||
@@ -193,6 +216,9 @@ lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color)
|
||||
*/
|
||||
void lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(serie);
|
||||
|
||||
if(chart == NULL || serie == NULL) return;
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
if(ext == NULL) return;
|
||||
@@ -217,6 +243,8 @@ void lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie)
|
||||
*/
|
||||
void lv_chart_set_div_line_count(lv_obj_t * chart, uint8_t hdiv, uint8_t vdiv)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
if(ext->hdiv_cnt == hdiv && ext->vdiv_cnt == vdiv) return;
|
||||
|
||||
@@ -234,6 +262,8 @@ void lv_chart_set_div_line_count(lv_obj_t * chart, uint8_t hdiv, uint8_t vdiv)
|
||||
*/
|
||||
void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
if(ext->ymin == ymin && ext->ymax == ymax) return;
|
||||
|
||||
@@ -250,6 +280,8 @@ void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax)
|
||||
*/
|
||||
void lv_chart_set_type(lv_obj_t * chart, lv_chart_type_t type)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
if(ext->type == type) return;
|
||||
|
||||
@@ -265,6 +297,8 @@ void lv_chart_set_type(lv_obj_t * chart, lv_chart_type_t type)
|
||||
*/
|
||||
void lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
if(ext->point_cnt == point_cnt) return;
|
||||
|
||||
@@ -279,7 +313,7 @@ void lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt)
|
||||
{
|
||||
if(ser->start_point != 0) {
|
||||
lv_coord_t * new_points = lv_mem_alloc(sizeof(lv_coord_t) * point_cnt);
|
||||
lv_mem_assert(new_points);
|
||||
LV_ASSERT_MEM(new_points);
|
||||
if(new_points == NULL) return;
|
||||
|
||||
if(point_cnt >= point_cnt_old) {
|
||||
@@ -302,7 +336,7 @@ void lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt)
|
||||
ser->points = new_points;
|
||||
} else {
|
||||
ser->points = lv_mem_realloc(ser->points, sizeof(lv_coord_t) * point_cnt);
|
||||
lv_mem_assert(ser->points);
|
||||
LV_ASSERT_MEM(ser->points);
|
||||
if(ser->points == NULL) return;
|
||||
/*Initialize the new points*/
|
||||
if(point_cnt > point_cnt_old) {
|
||||
@@ -327,6 +361,8 @@ void lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt)
|
||||
*/
|
||||
void lv_chart_set_series_opa(lv_obj_t * chart, lv_opa_t opa)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
if(ext->series.opa == opa) return;
|
||||
|
||||
@@ -341,6 +377,8 @@ void lv_chart_set_series_opa(lv_obj_t * chart, lv_opa_t opa)
|
||||
*/
|
||||
void lv_chart_set_series_width(lv_obj_t * chart, lv_coord_t width)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
if(ext->series.width == width) return;
|
||||
|
||||
@@ -354,6 +392,8 @@ void lv_chart_set_series_width(lv_obj_t * chart, lv_coord_t width)
|
||||
*/
|
||||
void lv_chart_set_series_darking(lv_obj_t * chart, lv_opa_t dark_eff)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
if(ext->series.dark == dark_eff) return;
|
||||
|
||||
@@ -369,6 +409,9 @@ void lv_chart_set_series_darking(lv_obj_t * chart, lv_opa_t dark_eff)
|
||||
*/
|
||||
void lv_chart_init_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(ser);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
uint16_t i;
|
||||
for(i = 0; i < ext->point_cnt; i++) {
|
||||
@@ -386,6 +429,9 @@ void lv_chart_init_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t
|
||||
*/
|
||||
void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y_array[])
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(ser);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
memcpy(ser->points, y_array, ext->point_cnt * (sizeof(lv_coord_t)));
|
||||
ser->start_point = 0;
|
||||
@@ -400,6 +446,9 @@ void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y
|
||||
*/
|
||||
void lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(ser);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
if(ext->update_mode == LV_CHART_UPDATE_MODE_SHIFT) {
|
||||
ser->points[ser->start_point] =
|
||||
@@ -426,6 +475,8 @@ void lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y)
|
||||
*/
|
||||
void lv_chart_set_update_mode(lv_obj_t * chart, lv_chart_update_mode_t update_mode)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
if(ext->update_mode == update_mode) return;
|
||||
|
||||
@@ -443,6 +494,8 @@ void lv_chart_set_update_mode(lv_obj_t * chart, lv_chart_update_mode_t update_mo
|
||||
*/
|
||||
void lv_chart_set_x_tick_length(lv_obj_t * chart, uint8_t major_tick_len, uint8_t minor_tick_len)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
ext->x_axis.major_tick_len = major_tick_len;
|
||||
ext->x_axis.minor_tick_len = minor_tick_len;
|
||||
@@ -458,11 +511,30 @@ void lv_chart_set_x_tick_length(lv_obj_t * chart, uint8_t major_tick_len, uint8_
|
||||
*/
|
||||
void lv_chart_set_y_tick_length(lv_obj_t * chart, uint8_t major_tick_len, uint8_t minor_tick_len)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
ext->y_axis.major_tick_len = major_tick_len;
|
||||
ext->y_axis.minor_tick_len = minor_tick_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the length of the tick marks on the secondary y axis
|
||||
* @param chart pointer to the chart
|
||||
* @param major_tick_len the length of the major tick or `LV_CHART_TICK_LENGTH_AUTO` to set automatically
|
||||
* (where labels are added)
|
||||
* @param minor_tick_len the length of the minor tick, `LV_CHART_TICK_LENGTH_AUTO` to set automatically
|
||||
* (where no labels are added)
|
||||
*/
|
||||
void lv_chart_set_secondary_y_tick_length(lv_obj_t * chart, uint8_t major_tick_len, uint8_t minor_tick_len)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
ext->secondary_y_axis.major_tick_len = major_tick_len;
|
||||
ext->secondary_y_axis.minor_tick_len = minor_tick_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the x-axis tick count and labels of a chart
|
||||
* @param chart pointer to a chart object
|
||||
@@ -474,6 +546,9 @@ void lv_chart_set_y_tick_length(lv_obj_t * chart, uint8_t major_tick_len, uint8_
|
||||
void lv_chart_set_x_tick_texts(lv_obj_t * chart, const char * list_of_values, uint8_t num_tick_marks,
|
||||
lv_chart_axis_options_t options)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(list_of_values);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
ext->x_axis.num_tick_marks = num_tick_marks;
|
||||
ext->x_axis.list_of_values = list_of_values;
|
||||
@@ -491,12 +566,35 @@ void lv_chart_set_x_tick_texts(lv_obj_t * chart, const char * list_of_values, ui
|
||||
void lv_chart_set_y_tick_texts(lv_obj_t * chart, const char * list_of_values, uint8_t num_tick_marks,
|
||||
lv_chart_axis_options_t options)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(list_of_values);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
ext->y_axis.num_tick_marks = num_tick_marks;
|
||||
ext->y_axis.list_of_values = list_of_values;
|
||||
ext->y_axis.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the secondary y-axis tick count and labels of a chart
|
||||
* @param chart pointer to a chart object
|
||||
* @param list_of_values list of string values, terminated with \n, except the last
|
||||
* @param num_tick_marks if list_of_values is NULL: total number of ticks per axis
|
||||
* else number of ticks between two value labels
|
||||
* @param options extra options
|
||||
*/
|
||||
void lv_chart_set_secondary_y_tick_texts(lv_obj_t * chart, const char * list_of_values, uint8_t num_tick_marks,
|
||||
lv_chart_axis_options_t options)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(list_of_values);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
ext->secondary_y_axis.num_tick_marks = num_tick_marks;
|
||||
ext->secondary_y_axis.list_of_values = list_of_values;
|
||||
ext->secondary_y_axis.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the margin around the chart, used for axes value and ticks
|
||||
* @param chart pointer to an chart object
|
||||
@@ -504,6 +602,8 @@ void lv_chart_set_y_tick_texts(lv_obj_t * chart, const char * list_of_values, ui
|
||||
*/
|
||||
void lv_chart_set_margin(lv_obj_t * chart, uint16_t margin)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
ext->margin = margin;
|
||||
lv_obj_refresh_ext_draw_pad(chart);
|
||||
@@ -520,6 +620,8 @@ void lv_chart_set_margin(lv_obj_t * chart, uint16_t margin)
|
||||
*/
|
||||
lv_chart_type_t lv_chart_get_type(const lv_obj_t * chart)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
return ext->type;
|
||||
}
|
||||
@@ -531,6 +633,8 @@ lv_chart_type_t lv_chart_get_type(const lv_obj_t * chart)
|
||||
*/
|
||||
uint16_t lv_chart_get_point_cnt(const lv_obj_t * chart)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
return ext->point_cnt;
|
||||
}
|
||||
@@ -542,6 +646,8 @@ uint16_t lv_chart_get_point_cnt(const lv_obj_t * chart)
|
||||
*/
|
||||
lv_opa_t lv_chart_get_series_opa(const lv_obj_t * chart)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
return ext->series.opa;
|
||||
}
|
||||
@@ -553,6 +659,8 @@ lv_opa_t lv_chart_get_series_opa(const lv_obj_t * chart)
|
||||
*/
|
||||
lv_coord_t lv_chart_get_series_width(const lv_obj_t * chart)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
return ext->series.width;
|
||||
}
|
||||
@@ -564,6 +672,8 @@ lv_coord_t lv_chart_get_series_width(const lv_obj_t * chart)
|
||||
*/
|
||||
lv_opa_t lv_chart_get_series_darking(const lv_obj_t * chart)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
return ext->series.dark;
|
||||
}
|
||||
@@ -578,6 +688,8 @@ lv_opa_t lv_chart_get_series_darking(const lv_obj_t * chart)
|
||||
*/
|
||||
void lv_chart_refresh(lv_obj_t * chart)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_obj_invalidate(chart);
|
||||
}
|
||||
|
||||
@@ -588,6 +700,8 @@ void lv_chart_refresh(lv_obj_t * chart)
|
||||
*/
|
||||
uint16_t lv_chart_get_margin(lv_obj_t * chart)
|
||||
{
|
||||
LV_ASSERT_OBJ(chart, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
return ext->margin;
|
||||
}
|
||||
@@ -619,11 +733,20 @@ static bool lv_chart_design(lv_obj_t * chart, const lv_area_t * mask, lv_design_
|
||||
|
||||
lv_chart_draw_div(chart, mask);
|
||||
|
||||
if(ext->type & LV_CHART_TYPE_LINE) lv_chart_draw_lines(chart, mask);
|
||||
if(ext->type & LV_CHART_TYPE_COLUMN) lv_chart_draw_cols(chart, mask);
|
||||
if(ext->type & LV_CHART_TYPE_POINT) lv_chart_draw_points(chart, mask);
|
||||
if(ext->type & LV_CHART_TYPE_VERTICAL_LINE) lv_chart_draw_vertical_lines(chart, mask);
|
||||
if(ext->type & LV_CHART_TYPE_AREA) lv_chart_draw_areas(chart, mask);
|
||||
/* Adjust the mask to remove the margin (clips chart contents to be within background) */
|
||||
|
||||
lv_area_t mask_tmp, adjusted_mask;
|
||||
lv_obj_get_coords(chart, &mask_tmp);
|
||||
|
||||
bool union_ok = lv_area_intersect(&adjusted_mask, mask, &mask_tmp);
|
||||
|
||||
if(union_ok) {
|
||||
if(ext->type & LV_CHART_TYPE_LINE) lv_chart_draw_lines(chart, &adjusted_mask);
|
||||
if(ext->type & LV_CHART_TYPE_COLUMN) lv_chart_draw_cols(chart, &adjusted_mask);
|
||||
if(ext->type & LV_CHART_TYPE_POINT) lv_chart_draw_points(chart, &adjusted_mask);
|
||||
if(ext->type & LV_CHART_TYPE_VERTICAL_LINE) lv_chart_draw_vertical_lines(chart, &adjusted_mask);
|
||||
if(ext->type & LV_CHART_TYPE_AREA) lv_chart_draw_areas(chart, &adjusted_mask);
|
||||
}
|
||||
|
||||
lv_chart_draw_axes(chart, mask);
|
||||
}
|
||||
@@ -638,12 +761,13 @@ static bool lv_chart_design(lv_obj_t * chart, const lv_area_t * mask, lv_design_
|
||||
*/
|
||||
static lv_res_t lv_chart_signal(lv_obj_t * chart, lv_signal_t sign, void * param)
|
||||
{
|
||||
lv_res_t res;
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
|
||||
/* Include the ancient signal function */
|
||||
lv_res_t res;
|
||||
res = ancestor_signal(chart, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
|
||||
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
|
||||
if(sign == LV_SIGNAL_CLEANUP) {
|
||||
lv_coord_t ** datal;
|
||||
@@ -652,13 +776,6 @@ static lv_res_t lv_chart_signal(lv_obj_t * chart, lv_signal_t sign, void * param
|
||||
lv_mem_free(*datal);
|
||||
}
|
||||
lv_ll_clear(&ext->series_ll);
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_chart";
|
||||
} else if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) {
|
||||
/*Provide extra px draw area around the chart*/
|
||||
chart->ext_draw_pad = ext->margin;
|
||||
@@ -699,7 +816,7 @@ static void lv_chart_draw_div(lv_obj_t * chart, const lv_area_t * mask)
|
||||
}
|
||||
|
||||
p1.x = 0 + x_ofs;
|
||||
p2.x = w + x_ofs;
|
||||
p2.x = w - 1 + x_ofs;
|
||||
for(div_i = div_i_start; div_i <= div_i_end; div_i++) {
|
||||
p1.y = (int32_t)((int32_t)(h - style->line.width) * div_i) / (ext->hdiv_cnt + 1);
|
||||
p1.y += y_ofs;
|
||||
@@ -719,7 +836,7 @@ static void lv_chart_draw_div(lv_obj_t * chart, const lv_area_t * mask)
|
||||
}
|
||||
|
||||
p1.y = 0 + y_ofs;
|
||||
p2.y = h + y_ofs;
|
||||
p2.y = h + y_ofs - 1;
|
||||
for(div_i = div_i_start; div_i <= div_i_end; div_i++) {
|
||||
p1.x = (int32_t)((int32_t)(w - style->line.width) * div_i) / (ext->vdiv_cnt + 1);
|
||||
p1.x += x_ofs;
|
||||
@@ -834,7 +951,7 @@ static void lv_chart_draw_points(lv_obj_t * chart, const lv_area_t * mask)
|
||||
y_tmp = (int32_t)((int32_t)ser->points[p_act] - ext->ymin) * h;
|
||||
y_tmp = y_tmp / (ext->ymax - ext->ymin);
|
||||
|
||||
cir_a.y1 = h - y_tmp + y_ofs;
|
||||
cir_a.y1 = h - y_tmp + y_ofs - 1;
|
||||
cir_a.y2 = cir_a.y1 + style_point.body.radius;
|
||||
cir_a.y1 -= style_point.body.radius;
|
||||
|
||||
@@ -1037,65 +1154,187 @@ static void lv_chart_draw_areas(lv_obj_t * chart, const lv_area_t * mask)
|
||||
}
|
||||
}
|
||||
|
||||
static void lv_chart_draw_y_ticks(lv_obj_t * chart, const lv_area_t * mask)
|
||||
/**
|
||||
* Create iterator for newline-separated list
|
||||
* @param list pointer to newline-separated labels list
|
||||
* @param iterator_dir LV_CHART_ITERATOR_FORWARD or LV_CHART_LABEL_ITERATOR_REVERSE
|
||||
* @return lv_chart_label_iterator_t
|
||||
*/
|
||||
static lv_chart_label_iterator_t lv_chart_create_label_iter(const char * list, uint8_t iterator_dir)
|
||||
{
|
||||
lv_chart_label_iterator_t iterator = {0};
|
||||
uint8_t j;
|
||||
|
||||
iterator.list_start = list;
|
||||
|
||||
/* count number of list items */
|
||||
for(j = 0; list[j] != '\0'; j++) {
|
||||
if(list[j] == '\n')
|
||||
iterator.items_left++;
|
||||
}
|
||||
|
||||
if(iterator_dir == LV_CHART_LABEL_ITERATOR_FORWARD) {
|
||||
iterator.is_reverse_iter = 0;
|
||||
iterator.current_pos = list;
|
||||
} else {
|
||||
iterator.is_reverse_iter = 1;
|
||||
// -1 to skip '\0' at the end of the string
|
||||
iterator.current_pos = list + j - 1;
|
||||
}
|
||||
iterator.items_left++;
|
||||
return iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get next label from iterator created by lv_chart_create_label_iter()
|
||||
* @param iterator iterator to get label from
|
||||
* @param[out] buf buffer to point next label to
|
||||
*/
|
||||
static void lv_chart_get_next_label(lv_chart_label_iterator_t * iterator, char * buf)
|
||||
{
|
||||
uint8_t label_len = 0;
|
||||
if (iterator->is_reverse_iter) {
|
||||
const char * label_start;
|
||||
/* count the length of the current label*/
|
||||
while ((*iterator->current_pos != '\n') &&
|
||||
(iterator->current_pos != iterator->list_start)) {
|
||||
iterator->current_pos--;
|
||||
label_len++;
|
||||
}
|
||||
|
||||
label_start = iterator->current_pos;
|
||||
|
||||
if (*iterator->current_pos == '\n') {
|
||||
/* do not copy \n symbol, +1 to skip it*/
|
||||
label_start++;
|
||||
/* skip newline*/
|
||||
iterator->current_pos--;
|
||||
} else {
|
||||
/* it is last label in list (first one from the beginning )*/
|
||||
label_len++;
|
||||
}
|
||||
|
||||
/* do not allow output buffer overflow */
|
||||
if (label_len > LV_CHART_AXIS_TICK_LABEL_MAX_LEN) {
|
||||
label_len = LV_CHART_AXIS_TICK_LABEL_MAX_LEN;
|
||||
}
|
||||
|
||||
strncpy(buf, label_start, label_len);
|
||||
} else {
|
||||
/* search for tick string */
|
||||
while(iterator->current_pos[label_len] != '\n' &&
|
||||
iterator->current_pos[label_len] != '\0') {
|
||||
/* do not overflow the buffer, but move to the end of the current label */
|
||||
if(label_len < LV_CHART_AXIS_TICK_LABEL_MAX_LEN) {
|
||||
buf[label_len] = iterator->current_pos[label_len];
|
||||
label_len++;
|
||||
} else {
|
||||
label_len++;
|
||||
}
|
||||
}
|
||||
|
||||
iterator->current_pos += label_len;
|
||||
|
||||
/* do not allow output buffer overflow */
|
||||
if (label_len > LV_CHART_AXIS_TICK_LABEL_MAX_LEN) {
|
||||
label_len = LV_CHART_AXIS_TICK_LABEL_MAX_LEN;
|
||||
}
|
||||
|
||||
if(*iterator->current_pos == '\n') iterator->current_pos++;
|
||||
}
|
||||
|
||||
/* terminate the string */
|
||||
buf[label_len] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether there should be a label next to tick with given
|
||||
* number
|
||||
* @param tick_num number of the tick to check
|
||||
* @param axis pointer to struct containing info on the axis
|
||||
* @return true if label should be located next to current tick
|
||||
*/
|
||||
static inline bool lv_chart_is_tick_with_label(uint8_t tick_num, lv_chart_axis_cfg_t * axis)
|
||||
{
|
||||
return ((tick_num == 0) || ((tick_num % axis->num_tick_marks) == 0));
|
||||
}
|
||||
|
||||
static void lv_chart_draw_y_ticks(lv_obj_t * chart, const lv_area_t * mask, uint8_t which_axis)
|
||||
{
|
||||
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
|
||||
lv_chart_axis_cfg_t * y_axis = (which_axis == LV_CHART_AXIS_PRIMARY_Y) ?
|
||||
&ext->y_axis : &ext->secondary_y_axis;
|
||||
|
||||
if(ext->y_axis.list_of_values != NULL || ext->y_axis.num_tick_marks != 0) {
|
||||
if(y_axis->list_of_values != NULL || y_axis->num_tick_marks != 0) {
|
||||
|
||||
const lv_style_t * style = lv_obj_get_style(chart);
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(chart);
|
||||
|
||||
uint8_t i, j;
|
||||
uint8_t list_index;
|
||||
uint8_t i;
|
||||
uint8_t num_of_labels;
|
||||
uint8_t num_scale_ticks;
|
||||
uint8_t major_tick_len, minor_tick_len;
|
||||
int8_t major_tick_len, minor_tick_len;
|
||||
uint8_t iter_dir;
|
||||
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
lv_coord_t x_ofs = chart->coords.x1;
|
||||
lv_coord_t x_ofs;
|
||||
lv_chart_label_iterator_t iter;
|
||||
lv_coord_t y_ofs = chart->coords.y1;
|
||||
lv_coord_t h = lv_obj_get_height(chart);
|
||||
lv_coord_t w = lv_obj_get_width(chart);
|
||||
char buf[LV_CHART_AXIS_TICK_LABEL_MAX_LEN + 1]; /* up to N symbols per label + null terminator */
|
||||
|
||||
/* chose correct side of the chart */
|
||||
if(which_axis == LV_CHART_AXIS_PRIMARY_Y)
|
||||
x_ofs = chart->coords.x1;
|
||||
else
|
||||
x_ofs = chart->coords.x2;
|
||||
|
||||
/* calculate the size of tick marks */
|
||||
if(ext->y_axis.major_tick_len == LV_CHART_TICK_LENGTH_AUTO)
|
||||
if(y_axis->major_tick_len == LV_CHART_TICK_LENGTH_AUTO)
|
||||
major_tick_len = (int32_t)w * LV_CHART_AXIS_MAJOR_TICK_LEN_COE;
|
||||
else
|
||||
major_tick_len = ext->y_axis.major_tick_len;
|
||||
major_tick_len = y_axis->major_tick_len;
|
||||
|
||||
if(ext->y_axis.minor_tick_len == LV_CHART_TICK_LENGTH_AUTO)
|
||||
if(y_axis->minor_tick_len == LV_CHART_TICK_LENGTH_AUTO)
|
||||
minor_tick_len = major_tick_len * LV_CHART_AXIS_MINOR_TICK_LEN_COE;
|
||||
else
|
||||
minor_tick_len = ext->y_axis.minor_tick_len;
|
||||
minor_tick_len = y_axis->minor_tick_len;
|
||||
|
||||
/* count the '\n'-s to determine the number of options */
|
||||
list_index = 0;
|
||||
num_of_labels = 0;
|
||||
if(ext->y_axis.list_of_values != NULL) {
|
||||
for(j = 0; ext->y_axis.list_of_values[j] != '\0'; j++) {
|
||||
if(ext->y_axis.list_of_values[j] == '\n') num_of_labels++;
|
||||
}
|
||||
|
||||
num_of_labels++; /* last option in the at row*/
|
||||
/* tick lines on secondary y axis are drawn in other direction*/
|
||||
if(which_axis == LV_CHART_AXIS_SECONDARY_Y) {
|
||||
major_tick_len *= -1;
|
||||
minor_tick_len *= -1;
|
||||
}
|
||||
|
||||
iter_dir = (y_axis->options & LV_CHART_AXIS_INVERSE_LABELS_ORDER) ? LV_CHART_LABEL_ITERATOR_REVERSE : LV_CHART_LABEL_ITERATOR_FORWARD;
|
||||
iter = lv_chart_create_label_iter(y_axis->list_of_values, iter_dir);
|
||||
|
||||
/*determine the number of options */
|
||||
num_of_labels = iter.items_left;
|
||||
|
||||
/* we can't have string labels without ticks step, set to 1 if not specified */
|
||||
if(ext->y_axis.num_tick_marks == 0) ext->y_axis.num_tick_marks = 1;
|
||||
if(y_axis->num_tick_marks == 0) y_axis->num_tick_marks = 1;
|
||||
|
||||
/* calculate total number of ticks */
|
||||
if(num_of_labels < 2)
|
||||
num_scale_ticks = ext->y_axis.num_tick_marks;
|
||||
num_scale_ticks = y_axis->num_tick_marks;
|
||||
else
|
||||
num_scale_ticks = (ext->y_axis.num_tick_marks * (num_of_labels - 1));
|
||||
num_scale_ticks = (y_axis->num_tick_marks * (num_of_labels - 1));
|
||||
|
||||
for(i = 0; i < (num_scale_ticks + 1); i++) { /* one extra loop - it may not exist in the list, empty label */
|
||||
/* first point of the tick */
|
||||
p1.x = x_ofs - 1;
|
||||
p1.x = x_ofs;
|
||||
|
||||
/* move extra pixel out of chart boundary */
|
||||
if (which_axis == LV_CHART_AXIS_PRIMARY_Y)
|
||||
p1.x--;
|
||||
else
|
||||
p1.x++;
|
||||
|
||||
/* second point of the tick */
|
||||
if((num_of_labels != 0) && (i == 0 || i % ext->y_axis.num_tick_marks == 0))
|
||||
if((num_of_labels != 0) && (i == 0 || i % y_axis->num_tick_marks == 0))
|
||||
p2.x = p1.x - major_tick_len; /* major tick */
|
||||
else
|
||||
p2.x = p1.x - minor_tick_len; /* minor tick */
|
||||
@@ -1104,31 +1343,25 @@ static void lv_chart_draw_y_ticks(lv_obj_t * chart, const lv_area_t * mask)
|
||||
p2.y = p1.y =
|
||||
y_ofs + (int32_t)((int32_t)(h - style->line.width) * i) / num_scale_ticks;
|
||||
|
||||
if(i != num_scale_ticks)
|
||||
lv_draw_line(&p1, &p2, mask, style, opa_scale);
|
||||
else if((ext->y_axis.options & LV_CHART_AXIS_DRAW_LAST_TICK) != 0)
|
||||
lv_draw_line(&p1, &p2, mask, style, opa_scale);
|
||||
if(y_axis->options & LV_CHART_AXIS_INVERSE_LABELS_ORDER) {
|
||||
/*if label order is inversed last tick have number 0*/
|
||||
if(i != 0)
|
||||
lv_draw_line(&p1, &p2, mask, style, opa_scale);
|
||||
else if((y_axis->options & LV_CHART_AXIS_DRAW_LAST_TICK) != 0)
|
||||
lv_draw_line(&p1, &p2, mask, style, opa_scale);
|
||||
} else {
|
||||
if(i != num_scale_ticks)
|
||||
lv_draw_line(&p1, &p2, mask, style, opa_scale);
|
||||
else if((y_axis->options & LV_CHART_AXIS_DRAW_LAST_TICK) != 0)
|
||||
lv_draw_line(&p1, &p2, mask, style, opa_scale);
|
||||
}
|
||||
|
||||
/* draw values if available */
|
||||
if(num_of_labels != 0) {
|
||||
/* add text only to major tick */
|
||||
if(i == 0 || i % ext->y_axis.num_tick_marks == 0) {
|
||||
/* search for tick string */
|
||||
j = 0;
|
||||
while(ext->y_axis.list_of_values[list_index] != '\n' &&
|
||||
ext->y_axis.list_of_values[list_index] != '\0') {
|
||||
/* do not overflow the buffer, but move to the end of the current label */
|
||||
if(j < LV_CHART_AXIS_TICK_LABEL_MAX_LEN)
|
||||
buf[j++] = ext->y_axis.list_of_values[list_index++];
|
||||
else
|
||||
list_index++;
|
||||
}
|
||||
if(lv_chart_is_tick_with_label(i, y_axis)) {
|
||||
|
||||
/* this was a string, but not end of the list, so jump to the next string */
|
||||
if(ext->y_axis.list_of_values[list_index] == '\n') list_index++;
|
||||
|
||||
/* terminate the string */
|
||||
buf[j] = '\0';
|
||||
lv_chart_get_next_label(&iter, buf);
|
||||
|
||||
/* reserve appropriate area */
|
||||
lv_point_t size;
|
||||
@@ -1136,9 +1369,17 @@ static void lv_chart_draw_y_ticks(lv_obj_t * chart, const lv_area_t * mask)
|
||||
LV_COORD_MAX, LV_TXT_FLAG_CENTER);
|
||||
|
||||
/* set the area at some distance of the major tick len left of the tick */
|
||||
lv_area_t a = {(p2.x - size.x - LV_CHART_AXIS_TO_LABEL_DISTANCE), (p2.y - size.y / 2),
|
||||
(p2.x - LV_CHART_AXIS_TO_LABEL_DISTANCE), (p2.y + size.y / 2)};
|
||||
lv_draw_label(&a, mask, style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL, -1, -1, NULL);
|
||||
lv_area_t a = {.y1 = p2.y - size.y / 2, .y2 = p2.y + size.y / 2};
|
||||
|
||||
if(which_axis == LV_CHART_AXIS_PRIMARY_Y) {
|
||||
a.x1 = p2.x - size.x - LV_CHART_AXIS_TO_LABEL_DISTANCE;
|
||||
a.x2 = p2.x - LV_CHART_AXIS_TO_LABEL_DISTANCE;
|
||||
} else {
|
||||
a.x1 = p2.x + LV_CHART_AXIS_TO_LABEL_DISTANCE;
|
||||
a.x2 = p2.x + size.x + LV_CHART_AXIS_TO_LABEL_DISTANCE;
|
||||
}
|
||||
|
||||
lv_draw_label(&a, mask, style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL, NULL, NULL, lv_obj_get_base_dir(chart));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1155,11 +1396,11 @@ static void lv_chart_draw_x_ticks(lv_obj_t * chart, const lv_area_t * mask)
|
||||
const lv_style_t * style = lv_obj_get_style(chart);
|
||||
lv_opa_t opa_scale = lv_obj_get_opa_scale(chart);
|
||||
|
||||
uint8_t i, j;
|
||||
uint8_t list_index;
|
||||
uint8_t i;
|
||||
uint8_t num_of_labels;
|
||||
uint8_t num_scale_ticks;
|
||||
uint8_t major_tick_len, minor_tick_len;
|
||||
lv_chart_label_iterator_t iter;
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
lv_coord_t x_ofs = chart->coords.x1;
|
||||
@@ -1179,16 +1420,9 @@ static void lv_chart_draw_x_ticks(lv_obj_t * chart, const lv_area_t * mask)
|
||||
else
|
||||
minor_tick_len = ext->x_axis.minor_tick_len;
|
||||
|
||||
/* count the '\n'-s to determine the number of options */
|
||||
list_index = 0;
|
||||
num_of_labels = 0;
|
||||
if(ext->x_axis.list_of_values != NULL) {
|
||||
for(j = 0; ext->x_axis.list_of_values[j] != '\0'; j++) {
|
||||
if(ext->x_axis.list_of_values[j] == '\n') num_of_labels++;
|
||||
}
|
||||
|
||||
num_of_labels++; /* last option in the at row*/
|
||||
}
|
||||
/*determine the number of options */
|
||||
iter = lv_chart_create_label_iter(ext->x_axis.list_of_values, LV_CHART_LABEL_ITERATOR_FORWARD);
|
||||
num_of_labels = iter.items_left;
|
||||
|
||||
/* we can't have string labels without ticks step, set to 1 if not specified */
|
||||
if(ext->x_axis.num_tick_marks == 0) ext->x_axis.num_tick_marks = 1;
|
||||
@@ -1220,23 +1454,8 @@ static void lv_chart_draw_x_ticks(lv_obj_t * chart, const lv_area_t * mask)
|
||||
/* draw values if available */
|
||||
if(num_of_labels != 0) {
|
||||
/* add text only to major tick */
|
||||
if(i == 0 || i % ext->x_axis.num_tick_marks == 0) {
|
||||
/* search for tick string */
|
||||
j = 0;
|
||||
while(ext->x_axis.list_of_values[list_index] != '\n' &&
|
||||
ext->x_axis.list_of_values[list_index] != '\0') {
|
||||
/* do not overflow the buffer, but move to the end of the current label */
|
||||
if(j < LV_CHART_AXIS_TICK_LABEL_MAX_LEN)
|
||||
buf[j++] = ext->x_axis.list_of_values[list_index++];
|
||||
else
|
||||
list_index++;
|
||||
}
|
||||
|
||||
/* this was a string, but not end of the list, so jump to the next string */
|
||||
if(ext->x_axis.list_of_values[list_index] == '\n') list_index++;
|
||||
|
||||
/* terminate the string */
|
||||
buf[j] = '\0';
|
||||
if(lv_chart_is_tick_with_label(i, &(ext->x_axis))) {
|
||||
lv_chart_get_next_label(&iter, buf);
|
||||
|
||||
/* reserve appropriate area */
|
||||
lv_point_t size;
|
||||
@@ -1246,7 +1465,7 @@ static void lv_chart_draw_x_ticks(lv_obj_t * chart, const lv_area_t * mask)
|
||||
/* set the area at some distance of the major tick len under of the tick */
|
||||
lv_area_t a = {(p2.x - size.x / 2), (p2.y + LV_CHART_AXIS_TO_LABEL_DISTANCE), (p2.x + size.x / 2),
|
||||
(p2.y + size.y + LV_CHART_AXIS_TO_LABEL_DISTANCE)};
|
||||
lv_draw_label(&a, mask, style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL, -1, -1, NULL);
|
||||
lv_draw_label(&a, mask, style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL, NULL, NULL, lv_obj_get_base_dir(chart));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1255,7 +1474,8 @@ static void lv_chart_draw_x_ticks(lv_obj_t * chart, const lv_area_t * mask)
|
||||
|
||||
static void lv_chart_draw_axes(lv_obj_t * chart, const lv_area_t * mask)
|
||||
{
|
||||
lv_chart_draw_y_ticks(chart, mask);
|
||||
lv_chart_draw_y_ticks(chart, mask, LV_CHART_AXIS_PRIMARY_Y);
|
||||
lv_chart_draw_y_ticks(chart, mask, LV_CHART_AXIS_SECONDARY_Y);
|
||||
lv_chart_draw_x_ticks(chart, mask);
|
||||
}
|
||||
|
||||
@@ -1276,13 +1496,13 @@ static void lv_chart_inv_lines(lv_obj_t * chart, uint16_t i)
|
||||
if(i < ext->point_cnt - 1) {
|
||||
coords.x1 = ((w * i) / (ext->point_cnt - 1)) + x_ofs - ext->series.width;
|
||||
coords.x2 = ((w * (i + 1)) / (ext->point_cnt - 1)) + x_ofs + ext->series.width;
|
||||
lv_inv_area(lv_obj_get_disp(chart), &coords);
|
||||
lv_obj_invalidate_area(chart, &coords);
|
||||
}
|
||||
|
||||
if(i > 0) {
|
||||
coords.x1 = ((w * (i - 1)) / (ext->point_cnt - 1)) + x_ofs - ext->series.width;
|
||||
coords.x2 = ((w * i) / (ext->point_cnt - 1)) + x_ofs + ext->series.width;
|
||||
lv_inv_area(lv_obj_get_disp(chart), &coords);
|
||||
lv_obj_invalidate_area(chart, &coords);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ extern "C" {
|
||||
/**Automatically calculate the tick length*/
|
||||
#define LV_CHART_TICK_LENGTH_AUTO 255
|
||||
|
||||
LV_EXPORT_CONST_INT(LV_CHART_POINT_DEF);
|
||||
LV_EXPORT_CONST_INT(LV_CHART_TICK_LENGTH_AUTO);
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
@@ -65,8 +68,9 @@ typedef struct
|
||||
|
||||
/** Data of axis */
|
||||
enum {
|
||||
LV_CHART_AXIS_SKIP_LAST_TICK = 0x00, /**< don't draw the last tick */
|
||||
LV_CHART_AXIS_DRAW_LAST_TICK = 0x01 /**< draw the last tick */
|
||||
LV_CHART_AXIS_SKIP_LAST_TICK = 0x00, /**< don't draw the last tick */
|
||||
LV_CHART_AXIS_DRAW_LAST_TICK = 0x01, /**< draw the last tick */
|
||||
LV_CHART_AXIS_INVERSE_LABELS_ORDER = 0x02 /**< draw tick labels in an inversed order*/
|
||||
};
|
||||
typedef uint8_t lv_chart_axis_options_t;
|
||||
|
||||
@@ -93,6 +97,7 @@ typedef struct
|
||||
lv_chart_type_t type; /*Line, column or point chart (from 'lv_chart_type_t')*/
|
||||
lv_chart_axis_cfg_t y_axis;
|
||||
lv_chart_axis_cfg_t x_axis;
|
||||
lv_chart_axis_cfg_t secondary_y_axis;
|
||||
uint16_t margin;
|
||||
uint8_t update_mode : 1;
|
||||
struct
|
||||
@@ -259,6 +264,16 @@ void lv_chart_set_x_tick_length(lv_obj_t * chart, uint8_t major_tick_len, uint8_
|
||||
*/
|
||||
void lv_chart_set_y_tick_length(lv_obj_t * chart, uint8_t major_tick_len, uint8_t minor_tick_len);
|
||||
|
||||
/**
|
||||
* Set the length of the tick marks on the secondary y axis
|
||||
* @param chart pointer to the chart
|
||||
* @param major_tick_len the length of the major tick or `LV_CHART_TICK_LENGTH_AUTO` to set automatically
|
||||
* (where labels are added)
|
||||
* @param minor_tick_len the length of the minor tick, `LV_CHART_TICK_LENGTH_AUTO` to set automatically
|
||||
* (where no labels are added)
|
||||
*/
|
||||
void lv_chart_set_secondary_y_tick_length(lv_obj_t * chart, uint8_t major_tick_len, uint8_t minor_tick_len);
|
||||
|
||||
/**
|
||||
* Set the x-axis tick count and labels of a chart
|
||||
* @param chart pointer to a chart object
|
||||
@@ -270,6 +285,17 @@ void lv_chart_set_y_tick_length(lv_obj_t * chart, uint8_t major_tick_len, uint8_
|
||||
void lv_chart_set_x_tick_texts(lv_obj_t * chart, const char * list_of_values, uint8_t num_tick_marks,
|
||||
lv_chart_axis_options_t options);
|
||||
|
||||
/**
|
||||
* Set the secondary y-axis tick count and labels of a chart
|
||||
* @param chart pointer to a chart object
|
||||
* @param list_of_values list of string values, terminated with \n, except the last
|
||||
* @param num_tick_marks if list_of_values is NULL: total number of ticks per axis
|
||||
* else number of ticks between two value labels
|
||||
* @param options extra options
|
||||
*/
|
||||
void lv_chart_set_secondary_y_tick_texts(lv_obj_t * chart, const char * list_of_values, uint8_t num_tick_marks,
|
||||
lv_chart_axis_options_t options);
|
||||
|
||||
/**
|
||||
* Set the y-axis tick count and labels of a chart
|
||||
* @param chart pointer to a chart object
|
||||
|
||||
@@ -14,16 +14,19 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../lv_core/lv_debug.h"
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_draw/lv_draw_basic.h"
|
||||
#include "../lv_themes/lv_theme.h"
|
||||
#include "../lv_misc/lv_area.h"
|
||||
#include "../lv_misc/lv_color.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
#include "../lv_misc/lv_bidi.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_OBJX_NAME "lv_cont"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -67,7 +70,7 @@ lv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
|
||||
/*Create a basic object*/
|
||||
lv_obj_t * new_cont = lv_obj_create(par, copy);
|
||||
lv_mem_assert(new_cont);
|
||||
LV_ASSERT_MEM(new_cont);
|
||||
if(new_cont == NULL) return NULL;
|
||||
|
||||
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_cont);
|
||||
@@ -76,7 +79,7 @@ lv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
lv_cont_ext_t * ext = lv_obj_get_ext_attr(new_cont);
|
||||
if(ext == NULL) return NULL;
|
||||
|
||||
lv_mem_assert(ext);
|
||||
LV_ASSERT_MEM(ext);
|
||||
ext->fit_left = LV_FIT_NONE;
|
||||
ext->fit_right = LV_FIT_NONE;
|
||||
ext->fit_top = LV_FIT_NONE;
|
||||
@@ -126,6 +129,8 @@ lv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy)
|
||||
*/
|
||||
void lv_cont_set_layout(lv_obj_t * cont, lv_layout_t layout)
|
||||
{
|
||||
LV_ASSERT_OBJ(cont, LV_OBJX_NAME);
|
||||
|
||||
lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);
|
||||
if(ext->layout == layout) return;
|
||||
|
||||
@@ -146,6 +151,8 @@ void lv_cont_set_layout(lv_obj_t * cont, lv_layout_t layout)
|
||||
*/
|
||||
void lv_cont_set_fit4(lv_obj_t * cont, lv_fit_t left, lv_fit_t right, lv_fit_t top, lv_fit_t bottom)
|
||||
{
|
||||
LV_ASSERT_OBJ(cont, LV_OBJX_NAME);
|
||||
|
||||
lv_obj_invalidate(cont);
|
||||
lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);
|
||||
if(ext->fit_left == left && ext->fit_right == right && ext->fit_top == top && ext->fit_bottom == bottom) {
|
||||
@@ -172,6 +179,8 @@ void lv_cont_set_fit4(lv_obj_t * cont, lv_fit_t left, lv_fit_t right, lv_fit_t t
|
||||
*/
|
||||
lv_layout_t lv_cont_get_layout(const lv_obj_t * cont)
|
||||
{
|
||||
LV_ASSERT_OBJ(cont, LV_OBJX_NAME);
|
||||
|
||||
lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);
|
||||
return ext->layout;
|
||||
}
|
||||
@@ -183,6 +192,8 @@ lv_layout_t lv_cont_get_layout(const lv_obj_t * cont)
|
||||
*/
|
||||
lv_fit_t lv_cont_get_fit_left(const lv_obj_t * cont)
|
||||
{
|
||||
LV_ASSERT_OBJ(cont, LV_OBJX_NAME);
|
||||
|
||||
lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);
|
||||
return ext->fit_left;
|
||||
}
|
||||
@@ -194,6 +205,8 @@ lv_fit_t lv_cont_get_fit_left(const lv_obj_t * cont)
|
||||
*/
|
||||
lv_fit_t lv_cont_get_fit_right(const lv_obj_t * cont)
|
||||
{
|
||||
LV_ASSERT_OBJ(cont, LV_OBJX_NAME);
|
||||
|
||||
lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);
|
||||
return ext->fit_right;
|
||||
}
|
||||
@@ -205,6 +218,8 @@ lv_fit_t lv_cont_get_fit_right(const lv_obj_t * cont)
|
||||
*/
|
||||
lv_fit_t lv_cont_get_fit_top(const lv_obj_t * cont)
|
||||
{
|
||||
LV_ASSERT_OBJ(cont, LV_OBJX_NAME);
|
||||
|
||||
lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);
|
||||
return ext->fit_top;
|
||||
}
|
||||
@@ -216,6 +231,8 @@ lv_fit_t lv_cont_get_fit_top(const lv_obj_t * cont)
|
||||
*/
|
||||
lv_fit_t lv_cont_get_fit_bottom(const lv_obj_t * cont)
|
||||
{
|
||||
LV_ASSERT_OBJ(cont, LV_OBJX_NAME);
|
||||
|
||||
lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);
|
||||
return ext->fit_bottom;
|
||||
}
|
||||
@@ -238,6 +255,7 @@ static lv_res_t lv_cont_signal(lv_obj_t * cont, lv_signal_t sign, void * param)
|
||||
/* Include the ancient signal function */
|
||||
res = ancestor_signal(cont, sign, param);
|
||||
if(res != LV_RES_OK) return res;
|
||||
if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
|
||||
|
||||
if(sign == LV_SIGNAL_STYLE_CHG) { /*Recalculate the padding if the style changed*/
|
||||
lv_cont_refr_layout(cont);
|
||||
@@ -254,13 +272,6 @@ static lv_res_t lv_cont_signal(lv_obj_t * cont, lv_signal_t sign, void * param)
|
||||
/*FLOOD and FILL fit needs to be refreshed if the parent size has changed*/
|
||||
lv_cont_refr_autofit(cont);
|
||||
|
||||
} else if(sign == LV_SIGNAL_GET_TYPE) {
|
||||
lv_obj_type_t * buf = param;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
|
||||
if(buf->type[i] == NULL) break;
|
||||
}
|
||||
buf->type[i] = "lv_cont";
|
||||
}
|
||||
|
||||
return res;
|
||||
@@ -354,23 +365,23 @@ static void lv_cont_layout_row(lv_obj_t * cont)
|
||||
lv_align_t align;
|
||||
const lv_style_t * style = lv_obj_get_style(cont);
|
||||
lv_coord_t vpad_corr;
|
||||
|
||||
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(cont);
|
||||
switch(type) {
|
||||
case LV_LAYOUT_ROW_T:
|
||||
vpad_corr = style->body.padding.top;
|
||||
align = LV_ALIGN_IN_TOP_LEFT;
|
||||
align = base_dir == LV_BIDI_DIR_RTL ? LV_ALIGN_IN_TOP_RIGHT : LV_ALIGN_IN_TOP_LEFT;
|
||||
break;
|
||||
case LV_LAYOUT_ROW_M:
|
||||
vpad_corr = 0;
|
||||
align = LV_ALIGN_IN_LEFT_MID;
|
||||
align = base_dir == LV_BIDI_DIR_RTL ? LV_ALIGN_IN_RIGHT_MID: LV_ALIGN_IN_LEFT_MID;
|
||||
break;
|
||||
case LV_LAYOUT_ROW_B:
|
||||
vpad_corr = -style->body.padding.bottom;
|
||||
align = LV_ALIGN_IN_BOTTOM_LEFT;
|
||||
align = base_dir == LV_BIDI_DIR_RTL ? LV_ALIGN_IN_BOTTOM_RIGHT: LV_ALIGN_IN_BOTTOM_LEFT;
|
||||
break;
|
||||
default:
|
||||
vpad_corr = 0;
|
||||
align = LV_ALIGN_IN_TOP_LEFT;
|
||||
align = base_dir == LV_BIDI_DIR_RTL ? LV_ALIGN_IN_TOP_RIGHT : LV_ALIGN_IN_TOP_LEFT;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -379,12 +390,19 @@ static void lv_cont_layout_row(lv_obj_t * cont)
|
||||
lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG);
|
||||
|
||||
/* Align the children */
|
||||
lv_coord_t last_cord = style->body.padding.left;
|
||||
lv_coord_t last_cord;
|
||||
if(base_dir == LV_BIDI_DIR_RTL) last_cord = style->body.padding.right;
|
||||
else last_cord = style->body.padding.left;
|
||||
|
||||
LV_LL_READ_BACK(cont->child_ll, child)
|
||||
{
|
||||
if(lv_obj_get_hidden(child) != false || lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue;
|
||||
|
||||
lv_obj_align(child, cont, align, last_cord, vpad_corr);
|
||||
// last_cord -= lv_obj_get_width(child);
|
||||
|
||||
if(base_dir == LV_BIDI_DIR_RTL) lv_obj_align(child, cont, align, -last_cord, vpad_corr);
|
||||
else lv_obj_align(child, cont, align, last_cord, vpad_corr);
|
||||
|
||||
last_cord += lv_obj_get_width(child) + style->body.padding.inner;
|
||||
}
|
||||
|
||||
@@ -537,13 +555,12 @@ static void lv_cont_layout_grid(lv_obj_t * cont)
|
||||
const lv_style_t * style = lv_obj_get_style(cont);
|
||||
lv_coord_t w_tot = lv_obj_get_width(cont);
|
||||
lv_coord_t w_obj = lv_obj_get_width(lv_obj_get_child(cont, NULL));
|
||||
lv_coord_t w_fit = lv_obj_get_width_fit(cont);
|
||||
lv_coord_t h_obj = lv_obj_get_height(lv_obj_get_child(cont, NULL));
|
||||
uint16_t obj_row = (w_tot - style->body.padding.left - style->body.padding.right) /
|
||||
(w_obj + style->body.padding.inner); /*Obj. num. in a row*/
|
||||
uint16_t obj_row = (w_fit) / (w_obj + style->body.padding.inner); /*Obj. num. in a row*/
|
||||
lv_coord_t x_ofs;
|
||||
if(obj_row > 1) {
|
||||
x_ofs = (w_obj + (w_tot - style->body.padding.left - style->body.padding.right) - (obj_row * w_obj)) /
|
||||
(obj_row - 1);
|
||||
x_ofs = w_obj + (w_fit - (obj_row * w_obj)) / (obj_row - 1);
|
||||
} else {
|
||||
x_ofs = w_tot / 2 - w_obj / 2;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user