First commit with working display
4
managed_components/lvgl__lvgl/docs/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
build/
|
||||
doxygen/
|
||||
intermediate/
|
||||
src/_static/built_lv_examples
|
||||
76
managed_components/lvgl__lvgl/docs/CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our
|
||||
project and our community a harassment-free experience for everyone,
|
||||
regardless of age, body size, disability, ethnicity, gender identity and
|
||||
expression, level of experience, nationality, personal appearance, race,
|
||||
religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
- The use of sexualized language or imagery and unwelcome sexual
|
||||
attention or advances
|
||||
- Trolling, insulting/derogatory comments, and personal or political
|
||||
attacks
|
||||
- Public or private harassment
|
||||
- Publishing others\' private information, such as a physical or
|
||||
electronic address, without explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in
|
||||
a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of
|
||||
acceptable behavior and are expected to take appropriate and fair
|
||||
corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit,
|
||||
or reject comments, commits, code, wiki edits, issues, and other
|
||||
contributions that are not aligned to this Code of Conduct, or to ban
|
||||
temporarily or permanently any contributor for other behaviors that they
|
||||
deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public
|
||||
spaces when an individual is representing the project or its community.
|
||||
Examples of representing a project or community include using an
|
||||
official project e-mail address, posting via an official social media
|
||||
account, or acting as an appointed representative at an online or
|
||||
offline event. Representation of a project may be further defined and
|
||||
clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may
|
||||
be reported by contacting the project team using the [contact
|
||||
form](https://lvgl.io/about). All complaints will be reviewed and
|
||||
investigated and will result in a response that is deemed necessary and
|
||||
appropriate to the circumstances. The project team is obligated to
|
||||
maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted
|
||||
separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in
|
||||
good faith may face temporary or permanent repercussions as determined
|
||||
by other members of the project\'s leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor
|
||||
Covenant](http://contributor-covenant.org), version 1.4, available at
|
||||
[http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4/)
|
||||
2465
managed_components/lvgl__lvgl/docs/Doxyfile
Normal file
30
managed_components/lvgl__lvgl/docs/Makefile
Normal file
@@ -0,0 +1,30 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = intermediate
|
||||
BUILDDIR = build
|
||||
|
||||
# SOURCEDIR can be overridden by LVGL_DOC_BUILD_INTERMEDIATE_DIR
|
||||
LEN := $(shell printf '%s' '$(LVGL_DOC_BUILD_INTERMEDIATE_DIR)' | wc -c)
|
||||
|
||||
ifeq ($(shell test $(LEN) -gt 0; echo $$?),0)
|
||||
SOURCEDIR = $(LVGL_DOC_BUILD_INTERMEDIATE_DIR)
|
||||
else
|
||||
SOURCEDIR = intermediate
|
||||
endif
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
# It can be supplied from an environment variable 'O' or on make command line.
|
||||
%: Makefile
|
||||
$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
412
managed_components/lvgl__lvgl/docs/README.md
Normal file
@@ -0,0 +1,412 @@
|
||||
# Documentation
|
||||
|
||||
|
||||
## Building
|
||||
|
||||
Building the documentation is easy. Here are the requirements:
|
||||
|
||||
- Doxygen
|
||||
- Python >= 3.10
|
||||
- C compiler (gcc, msvc, clang, etc...)
|
||||
|
||||
Once Python is installed
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
will install all the prerequisite packages.
|
||||
|
||||
To build the documentation on Windows:
|
||||
|
||||
python build.py html
|
||||
|
||||
On Linux:
|
||||
|
||||
python3 build.py html
|
||||
|
||||
Intermediate files are normally prepared in `./docs/intermediate/` and the final documentation will normally appear in `./docs/build/html/`. Both of these directories can be overridden using environment variables. See documentation in `build.py` header comment for details.
|
||||
|
||||
If the list of document source files (including the `.h` files in the `./src/` directory) has changed (names or paths):
|
||||
|
||||
python build.py clean
|
||||
|
||||
Will remove the old intermediate and build files, eliminating the orphan files that would otherwise result.
|
||||
|
||||
To see a list of options available:
|
||||
|
||||
python build.py
|
||||
|
||||
Read the header comment in `build.py` for detailed documentation on each option.
|
||||
|
||||
|
||||
|
||||
## For Developers
|
||||
|
||||
One of our firm policies is ***EVERYTHING MUST BE DOCUMENTED***.
|
||||
|
||||
The below are some rules to follow when updating any of the `.rst` files located in the `./docs/src/` directory tree.
|
||||
|
||||
|
||||
|
||||
## reStructuredText Content
|
||||
|
||||
LVGL documentation uses **reStructuredText** (reST), rendered into HTML by Sphinx. You will find the following is a fairly-complete list of references about how to do things using reStructuredText:
|
||||
|
||||
| Docutils References (Fundamentals) | Sphinx References (What Sphinx Adds to Docutils) |
|
||||
| --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
|
||||
| [Introduction](https://docutils.sourceforge.io/docs/ref/rst/introduction.html) | [Configuration](https://www.sphinx-doc.org/en/master/usage/configuration.html) |
|
||||
| [Markup Specification](https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html) | [Directives](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html) |
|
||||
| [Markup Specification ∙ Tables](https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#tables) | [Directives ∙ Admonitions](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#admonitions-messages-and-warnings) |
|
||||
| [Markup Specification ∙ Substitution References](https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#substitution-references) | [Referencing](https://www.sphinx-doc.org/en/master/usage/referencing.html) |
|
||||
| [Directives](https://docutils.sourceforge.io/docs/ref/rst/directives.html) | [Interpreted Text Roles](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html) |
|
||||
| [Interpreted Text Roles](https://docutils.sourceforge.io/docs/ref/rst/roles.html) | [Glossary](https://www.sphinx-doc.org/en/master/glossary.html) |
|
||||
| [Quickstart](https://docutils.sourceforge.io/docs/user/rst/quickstart.html) | [Furo-theme Examples](https://sphinx-themes.org/sample-sites/furo/) |
|
||||
| [Examples](https://docutils.sourceforge.io/docs/user/rst/demo.html) | [Kitchen Sink Page](https://sphinx-themes.org/sample-sites/furo/kitchen-sink/) |
|
||||
| [Quick Reference](https://docutils.sourceforge.io/docs/user/rst/quickref.html) | [Sphinx Themes Gallery](https://sphinx-themes.org/) |
|
||||
|
||||
If you prefer to learn by examples, the [Furo-theme Examples](https://sphinx-themes.org/sample-sites/furo/) and especially the [Kitchen Sink Page](https://sphinx-themes.org/sample-sites/furo/kitchen-sink/) are excellent resources. View the `.rst` source file that generated that page by clicking the "eye" icon at the top of the page.
|
||||
|
||||
Note: the section headings in these pages use a different convention than the one presented below. For LVGL documentation, use the [section-heading convention presented below](https://github.com/lvgl/lvgl/tree/master/docs#section-headings).
|
||||
|
||||
|
||||
|
||||
### Text Format
|
||||
|
||||
Please wrap the text around column 86 or narrower. Wrapping at *exactly* column 86 is not important, but readability and ease of editing is.
|
||||
|
||||
Indent using 4 spaces (not tab characters). This applies to code blocks as well.
|
||||
|
||||
|
||||
|
||||
### index.rst Files
|
||||
|
||||
If you create a new directory you will need an `index.rst` file in that directory and that index file needs to be pointed to in the `index.rst` file that is located in the parent directory.
|
||||
|
||||
Let's take a look at the `index.rst` file that is located in the `docs/src/common-widget-features/layouts` directory.
|
||||
|
||||
```rst
|
||||
.. _layouts:
|
||||
|
||||
=======
|
||||
Layouts
|
||||
=======
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
overview
|
||||
flex
|
||||
grid
|
||||
```
|
||||
|
||||
|
||||
Explanation:
|
||||
|
||||
```rst
|
||||
.. _layouts: <=== Creates an explicit link target
|
||||
<=== Empty line -- important!
|
||||
=======
|
||||
Layouts <=== Document title, seen in documentation
|
||||
=======
|
||||
|
||||
<=== any text introducing this topic and the TOC below
|
||||
|
||||
.. toctree:: <=== Table of contents directive
|
||||
:maxdepth: 2 <=== Internal use and needs to always be set this way
|
||||
|
||||
overview <=== relative path to .rst files located in the same directory
|
||||
flex
|
||||
grid
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Section Headings
|
||||
|
||||
Section headings are created by underlining the section title with a punctuation character, at least as long as the text. Example:
|
||||
|
||||
```
|
||||
This Is a Heading
|
||||
*****************
|
||||
```
|
||||
|
||||
Use these conventions for section headings in LVGL documentation:
|
||||
|
||||
```
|
||||
==============
|
||||
Document Title
|
||||
==============
|
||||
|
||||
Section
|
||||
*******
|
||||
|
||||
Sub Section
|
||||
-----------
|
||||
|
||||
Sub Sub Section
|
||||
~~~~~~~~~~~~~~~
|
||||
```
|
||||
|
||||
1. ``====``, ``****``, ``----`` are encouraged.
|
||||
2. ``~~~~`` only if really needed.
|
||||
|
||||
Being consistent about this helps the reST parser to format the tables of contents correctly.
|
||||
|
||||
For improved readability in text editors:
|
||||
|
||||
- place 3 blank lines above the 2nd and subsequent "Section" titles (see above),
|
||||
- 2 blank lines above "Sub Section" headings, and
|
||||
- 1 at least blank line above all lower-level section headings.
|
||||
|
||||
|
||||
|
||||
### Italics, Boldface and Underlining
|
||||
|
||||
Emphasis using `*italics*`. Emphasis using `**boldface**`.
|
||||
|
||||
Normally underlining and combining these text styles is not possible in reStructuredText. However, LVGL documentation provides a work-around for this using reST <u>Interpreted Text Roles</u>. Just remember that the Interpreted Text Role names combine the letters `i`, `b` and `u` to provide the desired combination. All possible permutations of these letters are supported so you do not have to remember what sequence works. Examples: ``:u:`underline` ``, ``:ub:`underline and bold` ``, `` :bi:`bold italic` ``.
|
||||
|
||||
|
||||
|
||||
### Code Blocks
|
||||
|
||||
* Indent using 4 spaces (not tab characters).
|
||||
* Include at least 1 empty line after a code block.
|
||||
* There must be one empty line between the code block directive and the code.
|
||||
* `.. code-block::` is the only directive that should be used. Do not use lone `::`, `:code:` or `.. code::`.
|
||||
* Specify the language after the directive for appropriate syntax highlighting. Examples:
|
||||
|
||||
- `.. code-block:: c`,
|
||||
- `.. code-block:: cpp`,
|
||||
- `.. code-block:: python`,
|
||||
- `.. code-block:: shell`,
|
||||
- `.. code-block:: bash`,
|
||||
- `.. code-block:: kconfig`,
|
||||
- `.. code-block:: json`,
|
||||
- `.. code-block:: yaml`,
|
||||
- `.. code-block:: dot` (graphviz),
|
||||
- `.. code-block:: html`,
|
||||
- `.. code-block:: css`,
|
||||
- `.. code-block:: xml`,
|
||||
- `.. code-block:: make`.
|
||||
|
||||
See [the full set of supported code lexers](https://pygments.org/docs/lexers/) for more details.
|
||||
|
||||
|
||||
|
||||
### Bulleted Lists
|
||||
|
||||
```rst
|
||||
- First item description
|
||||
- If you want to span multiple lines, indent subsequent
|
||||
lines to align with item text like this.
|
||||
- If you want to include multiple paragraphs and/or code blocks under a
|
||||
list item, it must be intended to align with the list item like this:
|
||||
|
||||
Second paragraph.
|
||||
|
||||
.. code-block: python
|
||||
<=== blank line here is important
|
||||
# Python code here
|
||||
<=== blank line here is important
|
||||
- If you want to have nested bulleted lists, indent each
|
||||
new level to align with its parent list item like this:
|
||||
<=== blank line here is important
|
||||
- level 2 item 1: text
|
||||
- level 2 item 2: text
|
||||
<=== blank line here is important
|
||||
- Last list item. Note that the nested list above is preceded
|
||||
and followed by 1 blank line.
|
||||
```
|
||||
|
||||
All lists (including nested lists) **must** be preceded and followed with at least 1 blank line for the reST parser to process it correctly.
|
||||
|
||||
|
||||
|
||||
### External Links
|
||||
|
||||
URLs are converted to links automatically. E.g. `Visit https://lvgl.io`.
|
||||
|
||||
To add links with custom link text use
|
||||
|
||||
```rst
|
||||
Visit `My Website <https://pro.lvgl.io>`__.
|
||||
```
|
||||
|
||||
If an external link will be used on many pages:
|
||||
|
||||
- Add it to `./docs/src/include/external_links.txt` if not already there. Example:
|
||||
|
||||
```rst
|
||||
.. _LVGL Pro: https://pro.lvgl.io
|
||||
```
|
||||
|
||||
- `.. include: /include/external_links.txt` once at the top of each `.rst` file that uses it.
|
||||
|
||||
- Use it by name in text:
|
||||
|
||||
```rst
|
||||
For further details see `LVGL Pro`_.
|
||||
```
|
||||
|
||||
Note: back-quotes are not needed if there are no spaces in the name.
|
||||
|
||||
|
||||
|
||||
### Internal Links
|
||||
|
||||
Add a link target (anchor) before heading or paragraph that will be linked to:
|
||||
|
||||
```rst
|
||||
.. _unique_anchor_name:
|
||||
|
||||
My Heading
|
||||
**********
|
||||
```
|
||||
|
||||
`unique_anchor_name` must be unique throughout all `.rst` files under `./docs/src/`.
|
||||
|
||||
Reference the link (anchor) by:
|
||||
|
||||
```rst
|
||||
Click :ref:`here <unique_anchor_name>` for more details.
|
||||
```
|
||||
|
||||
Result: "Click **_here_** for more details."
|
||||
|
||||
Or use the heading's text as the link's text:
|
||||
|
||||
```rst
|
||||
Click :ref:`unique_anchor_name` for more details.
|
||||
```
|
||||
|
||||
Result: "Click **_My Heading_** for more details."
|
||||
|
||||
`unique_anchor_name` may appear in places other than before a heading, but if so, custom link text (like "here" the first example above) must be provided.
|
||||
|
||||
|
||||
|
||||
### Tightening Tables
|
||||
|
||||
reStructuredText syntax for creating tables can be found in the [reST examples](https://sphinx-themes.org/sample-sites/furo/kitchen-sink/tables/) referred to above. (Click on the "eye" icon to see the source file.)
|
||||
|
||||
Very long or very wide tables can be difficult to read and use. To squeeze them down to make them more readable and usable, move your existing table under a `.. container:: tighter-table-N` directive (`N` = digit 1-7 with 7 being the tightest), and indent your table to make it the "content" of the directive. Example:
|
||||
|
||||
```rst
|
||||
.. container:: tighter-table-3
|
||||
|
||||
+-----------+--------------+--------------+--------+
|
||||
| Heading 1 | Heading 2 | Heading 3 | Hdg 4 |
|
||||
+===========+==============+==============+========+
|
||||
| row 1 c 1 | row 1 col 3 | row 1 col 3 | r1 c4 |
|
||||
+-----------+--------------+--------------+--------+
|
||||
| row 2 c 1 | row 2 col 3 | row 2 col 3 | r2 c4 |
|
||||
+-----------+--------------+--------------+--------+
|
||||
| row 3 c 1 | row 3 col 3 | row 3 col 3 | r3 c4 |
|
||||
+-----------+--------------+--------------+--------+
|
||||
```
|
||||
|
||||
This works for all types of tables.
|
||||
|
||||
|
||||
|
||||
### Special Symbols
|
||||
|
||||
Because not everyone has editors that deal with Unicode characters well, please reST substitutions to insert special characters into documentation. A list of the most commonly-used special symbols can be found in `./docs/src/include/substitutions.txt`. To use one of these, add this line at the top of the `.rst` file if it is not already there:
|
||||
|
||||
```rst
|
||||
.. include:: /include/substitutions.txt
|
||||
```
|
||||
|
||||
Then, any of those substitutions can be used in that `.rst` file. Example:
|
||||
|
||||
```rst
|
||||
The temperature outside is 20\ |deg|\ C.
|
||||
```
|
||||
|
||||
Result: "The temperature outside is 20°C."
|
||||
|
||||
The spaces surrounding substitutions *are required for parsing*, but when you need to remove them in the output (as in the example above), do so by escaping them with the `\` character. Exception: the `substitutions.txt` file contains 3 substitution definitions which are marked with the `:trim:` option since their use *always* removes these spaces in the output. These do not need this escaping:
|
||||
|
||||
- `|nbsp|` (non-breaking space),
|
||||
- `|shy|` (soft hyphen), and
|
||||
- `|nbhyph|` (non-breaking hyphen used in titles and official names)
|
||||
|
||||
If you need a substitution that is not already in `substitutions.txt`, please add it.
|
||||
|
||||
|
||||
|
||||
### Referencing API Documentation
|
||||
|
||||
Using the following generates links to API documentation that the reader can click directly in the text.
|
||||
|
||||
#### In-Line Code Expressions
|
||||
|
||||
Use the following Interpreted Text Roles in text to include in-line C code that links to documentation on that symbol when available:
|
||||
|
||||
:cpp:func:`lv_init` (note there are no parentheses after the function name)
|
||||
:c:macro:`LV_USE_FLEX`
|
||||
:cpp:type:`lv_event_t`
|
||||
:cpp:enum:`lv_state_t`
|
||||
:cpp:enumerator:`LV_STATE_CHECKED`
|
||||
:cpp:struct:`lv_image_dsc_t`
|
||||
:cpp:union:`lv_style_value_t`
|
||||
|
||||
**Note:** Doxygen documentation for macros with parameters works perfectly, but Sphinx does not yet know how to parse the parameter(s) on a macro that might look like this:
|
||||
```rst
|
||||
:c:macro:`LV_FREETYPE_FONT_STYLE_WEIGHT(x)`
|
||||
```
|
||||
|
||||
Here is how to make that work, look right in the document, and also produce a link to Doxygen documentation if there is any:
|
||||
```rst
|
||||
:c:macro:`LV_FREETYPE_FONT_STYLE_WEIGHT`\ (x)
|
||||
```
|
||||
|
||||
#### More Complex Expressions
|
||||
|
||||
Use the `:cpp:expr:` Interpreted Text Role for more complex expressions, for example when showing the arguments passed to a function.
|
||||
|
||||
:cpp:expr:`lv_obj_set_layout(widget, LV_LAYOUT_FLEX)`
|
||||
:cpp:expr:`lv_slider_set_mode(slider, LV_SLIDER_MODE_...)`
|
||||
|
||||
Arguments that contain more than one word or non-alphanumeric characters will cause the `:cpp:expr:` interpreted-text to fail. Examples:
|
||||
|
||||
| Expression | Cause of Failure |
|
||||
| ------------------------------------------------------------ | ---------------------- |
|
||||
| :cpp:expr:\`lv_obj_set_layout(widget, LV_LAYOUT_FLEX/GRID)\` | argument with > 1 word |
|
||||
| :cpp:expr:\`lv_obj_set_layout(widget, LV_LAYOUT_*)\` | asterisk |
|
||||
| :cpp:expr:\`lv_obj_set_layout(*widget, LV_LAYOUT_FLEX)\` | asterisk |
|
||||
| :cpp:expr:\`lv_obj_set_layout((lv_obj_t *)widget, LV_LAYOUT_FLEX)\` | cast |
|
||||
| :cpp:expr:\`lv_obj_set_layout(&widget, LV_LAYOUT_FLEX);\` | semicolon |
|
||||
| :cpp:expr:\`lv_obj_set_layout(widget, ...)\` | lone ellipsis |
|
||||
|
||||
For such examples, simply use reStructuredText literal markup like this:
|
||||
|
||||
```rst
|
||||
``lv_obj_set_layout(widget, LV_LAYOUT_FLEX/GRID)``
|
||||
``lv_obj_set_layout(widget, LV_LAYOUT_*)``
|
||||
``lv_obj_set_layout(*widget, LV_LAYOUT_FLEX)``
|
||||
``lv_obj_set_layout((lv_obj_t *)widget, LV_LAYOUT_FLEX)``
|
||||
``lv_obj_set_layout(&widget, LV_LAYOUT_FLEX);``
|
||||
``lv_obj_set_layout(widget, ...)``
|
||||
```
|
||||
|
||||
#### Providing Links to API Pages
|
||||
|
||||
To create a link to 1 or more API pages, set up a section at the end of your `.rst` file that looks like this, and use one or both types of the ``.. API `` pseudo-directives below:
|
||||
|
||||
```rst
|
||||
API
|
||||
***
|
||||
|
||||
.. API equals: lv_scale_t, lv_scale_create
|
||||
|
||||
.. API startswith:
|
||||
|
||||
lv_scale
|
||||
lv_obj_set_style
|
||||
```
|
||||
|
||||
The list of symbols (or prefixes) can be separated by commas or spaces, and they can wrap onto subsequent lines of text so long as they are indented. Each list is terminated by the next ``.. API `` pseudo-directive or end-of-file, whichever comes first.
|
||||
|
||||
The API-page generation logic will add at most 1 link to each API documentation page containing matched symbols. The links are to the whole API page, not to the symbols. The purpose is to provide the reader with links to applicable API pages. Links directly to code (e.g. function documentation) are accomplished by using the In-Line Code Expressions documented above.
|
||||
362
managed_components/lvgl__lvgl/docs/README_he.md
Normal file
@@ -0,0 +1,362 @@
|
||||
<a href="https://github.com/sponsors/lvgl" target="_blank"><img align="left" src="https://lvgl.io/github-assets/sponsor.png" height="32px"></a>
|
||||
|
||||
<p align="right">
|
||||
<b>עברית</b> | <a href="./docs/README_zh.md">中文</a> | <a href="./docs/README_pt_BR.md">Português do Brasil</a> | <a href="./docs/README_jp.md">日本語</a> | <a href="./README.md">English</a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://lvgl.io/github-assets/logo-colored.png" width=300px>
|
||||
</p>
|
||||
|
||||
<h1 align="center">ספריית גרפיקה קלה ורב-שימושית</h1>
|
||||
<br>
|
||||
<div align="center">
|
||||
<img src="https://lvgl.io/github-assets/smartwatch-demo.gif">
|
||||
|
||||
<img border="1px" src="https://lvgl.io/github-assets/widgets-demo.gif">
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://lvgl.io" title="עמוד הבית של LVGL">אתר</a> |
|
||||
<a href="https://pro.lvgl.io" title="עורך UI מבוסס XML של LVGL Pro">עורך LVGL Pro</a> |
|
||||
<a href="https://docs.lvgl.io/" title="תיעוד מפורט עם יותר מ־100 דוגמאות">תיעוד</a> |
|
||||
<a href="https://forum.lvgl.io" title="קבל עזרה ועזור לאחרים">פורום</a> |
|
||||
<a href="https://lvgl.io/demos" title="הדגמות שרצות בדפדפן">דוגמאות</a> |
|
||||
<a href="https://lvgl.io/services" title="עיצוב גרפי, יישום UI וייעוץ">שירותים</a>
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
||||
## 📒 סקירה
|
||||
|
||||
**LVGL** היא ספריית UI חינמית וקוד פתוח שמאפשרת ליצור ממשקי משתמש גרפיים לכל MCU או MPU מכל ספק ועל כל פלטפורמה.
|
||||
|
||||
**דרישות**: ל־LVGL אין תלות חיצונית, מה שמקל על הידור לכל יעד מודרני, החל מ־MCU קטנים ועד MPU מבוססי Linux מרובי ליבות עם תמיכת 3D. עבור UI פשוט דרושים רק ~100kB RAM, כ~200–300kB Flash ומאגר רינדור בגודל 1/10 מגודל המסך.
|
||||
|
||||
**להתחלה מהירה**: בחרו פרויקט מוכן ל־VSCode, Eclipse או כל סביבת פיתוח אחרת ונסו את LVGL על המחשב. קוד ה־UI של LVGL בלתי תלוי בפלטפורמה, ולכן ניתן להשתמש באותו קוד גם ביעדים משובצים.
|
||||
|
||||
**LVGL Pro** הוא מארז כלים מלא לבנייה, בדיקה, שיתוף והפצה מהירה יותר של UI. הוא כולל עורך XML ליצירה ולבדיקה מהירה של רכיבים לשימוש חוזר, ייצוא קוד C או טעינת קובצי XML בזמן ריצה. מידע נוסף באתר.
|
||||
|
||||
## 💡 יכולות
|
||||
|
||||
**חינמית וניידת**
|
||||
- ספריית C מלאה (תואמת ++C) ללא תלות חיצונית.
|
||||
- ניתנת לקימפול לכל MCU או MPU, עם כל (RT)OS. תומכת ב־Make, CMake וב־globbing פשוט.
|
||||
- תמיכה במסכי מונוכרום, ePaper, OLED או TFT, ואף במסכים של מחשבים. ראו [תצוגות](https://docs.lvgl.io/master/main-modules/display/index.html)
|
||||
- רישיון MIT המקל על שימוש מסחרי.
|
||||
- נדרשים רק 32kB RAM ו־128kB Flash, מאגר מסגרת, ולפחות מאגר רינדור בגודל 1/10 מגודל המסך.
|
||||
- מערכת הפעלה, זיכרון חיצוני ו־GPU נתמכים אך אינם נדרשים.
|
||||
|
||||
**וידג'טים, סגנונות, פריסות ועוד**
|
||||
- יותר מ־30 [וידג'טים](https://docs.lvgl.io/master/widgets/index.html) מובנים: Button, Label, Slider, Chart, Keyboard, Meter, Arc, Table ועוד רבים.
|
||||
- [מערכת סגנונות](https://docs.lvgl.io/master/common-widget-features/styles/index.html) גמישה עם כ~100 מאפייני עיצוב להתאמה של כל חלקי הווידג'טים בכל מצב.
|
||||
- מנועי פריסה בסגנון [Flexbox](https://docs.lvgl.io/master/common-widget-features/layouts/flex.html) ו־[Grid](https://docs.lvgl.io/master/common-widget-features/layouts/grid.html) למיקום וגודל רספונסיביים.
|
||||
- טקסט מעובד בקידוד UTF-8 עם תמיכה במערכות כתיבה סינית/יפנית/קוריאנית, תאית, הינדי, ערבית ופרסית.
|
||||
- [קישורי נתונים](https://docs.lvgl.io/master/main-modules/observer/index.html) לחיבור קל בין ה־UI ליישום.
|
||||
- מנוע רינדור עם תמיכה באנימציות, החלקת קצוות, שקיפות, גלילה חלקה, צללים, טרנספורמציות תמונה ועוד.
|
||||
- [מנוע רינדור 3D חזק](https://docs.lvgl.io/master/libs/gltf.html) להצגת [מודלי glTF](https://sketchfab.com/) עם OpenGL.
|
||||
- תמיכה בעכבר, משטח מגע, לוח מקשים, מקלדת, כפתורים חיצוניים ואנקודר [התקני קלט](https://docs.lvgl.io/master/main-modules/indev.html).
|
||||
- תמיכה ב[מסכים מרובים](https://docs.lvgl.io/master/main-modules/display/overview.html#how-many-displays-can-lvgl-use).
|
||||
|
||||
## 📦️ תמיכת פלטפורמות
|
||||
|
||||
ל־LVGL אין תלות חיצונית, ולכן ניתן לקמפל אותה בקלות לכל התקן. היא זמינה גם במנהלי חבילות רבים ובמערכות RTOS:
|
||||
|
||||
- [ספריית Arduino](https://docs.lvgl.io/master/integration/framework/arduino.html)
|
||||
- [חבילת PlatformIO](https://registry.platformio.org/libraries/lvgl/lvgl)
|
||||
- [ספריית Zephyr](https://docs.lvgl.io/master/integration/os/zephyr.html)
|
||||
- [רכיב ESP-IDF (ESP32)](https://components.espressif.com/components/lvgl/lvgl)
|
||||
- [רכיב NXP MCUXpresso](https://www.nxp.com/design/software/embedded-software/lvgl-open-source-graphics-library:LITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY)
|
||||
- [ספריית NuttX](https://docs.lvgl.io/master/integration/os/nuttx.html)
|
||||
- [RT-Thread RTOS](https://docs.lvgl.io/master/integration/os/rt-thread.html)
|
||||
- CMSIS-Pack
|
||||
- [חבילת RIOT OS](https://doc.riot-os.org/group__pkg__lvgl.html#details)
|
||||
|
||||
## 🚀 עורך LVGL Pro
|
||||
|
||||
LVGL Pro הוא מארז כלים מלא לבנייה, בדיקה, שיתוף והפצה יעילים של UI משובץ.
|
||||
|
||||
הוא מורכב מארבעה כלים המשולבים זה בזה:
|
||||
|
||||
1. **עורך XML**: הלב של LVGL Pro. יישום שולחני לבניית רכיבים ומסכים ב־XML, ניהול קישורי נתונים, תרגומים, אנימציות, בדיקות ועוד. קראו עוד על [פורמט ה־XML](https://docs.lvgl.io/master/xml/xml/index.html) ועל [העורך](https://docs.lvgl.io/master/xml/editor/index.html).
|
||||
2. **מציג מקוון**: הריצו את העורך בדפדפן, פתחו פרויקטים מ־GitHub ושיתפו בקלות בלי להקים סביבת פיתוח. בקרו ב־[https://viewer.lvgl.io](https://viewer.lvgl.io).
|
||||
3. **כלי CLI**: הפקת קוד C והרצת בדיקות ב־CI/CD. פרטים [כאן](https://docs.lvgl.io/master/xml/tools/cli.html).
|
||||
4. **תוסף Figma**: סנכרון וחילוץ סגנונות ישירות מ־Figma. מידע נוסף [כאן](https://docs.lvgl.io/master/xml/tools/figma.html).
|
||||
|
||||
ביחד, הכלים מאפשרים לבנות UI ביעילות, לבדוק באמינות ולשתף פעולה עם צוותים ולקוחות.
|
||||
|
||||
מידע נוסף: https://pro.lvgl.io
|
||||
|
||||
## 🤝 שירותים מסחריים
|
||||
|
||||
חברת LVGL LLC מספקת מגוון שירותים מסחריים לסיוע בפיתוח UI. עם יותר מ־15 שנות ניסיון בתחום הממשקים והגרפיקה, נוכל לקדם את ה־UI של המוצר שלכם לרמה הבאה.
|
||||
|
||||
- **עיצוב גרפי**: המעצבים הפנימיים שלנו מומחים בעיצוב מודרני ויפה שמתאים למוצר וליכולות החומרה.
|
||||
- **מימוש UI**: ניישם את ה־UI על בסיס העיצוב שלכם או שלנו, ונמצה את יכולות החומרה ו־LVGL. אם חסר רכיב או יכולת ב־LVGL, נפתח זאת עבורכם.
|
||||
- **ייעוץ ותמיכה**: ייעוץ מקצועי למניעת טעויות יקרות וגוזלות זמן במהלך פיתוח ה־UI.
|
||||
- **אישור לוחות**: לחברות שמציעות לוחות פיתוח או ערכות מוכנות לייצור אנו מספקים הסמכה שמדגימה כיצד הלוח מריץ LVGL.
|
||||
|
||||
עיינו ב[דוגמאות](https://lvgl.io/demos) שלנו לע参考. למידע נוסף ראו את [עמוד השירותים](https://lvgl.io/services).
|
||||
|
||||
[צרו קשר](https://lvgl.io/#contact) וספרו לנו כיצד נוכל לעזור.
|
||||
|
||||
## 🧑💻 שילוב LVGL
|
||||
|
||||
שילוב LVGL פשוט מאוד. הוסיפו אותו לפרויקט וקומפלו כמו קבצים אחרים.
|
||||
כדי להגדיר, העתיקו את `lv_conf_template.h` ל־`lv_conf.h`, הפעילו את ה־`#if 0` הראשון והתאימו את ההגדרות לפי הצורך.
|
||||
(בדרך כלל ברירת המחדל מספקת.) ניתן גם להשתמש ב־LVGL עם Kconfig כשזמין.
|
||||
|
||||
לאחר מכן אפשר לאתחל את LVGL וליצור התקני תצוגה וקלט כך:
|
||||
|
||||
```c
|
||||
#include "lvgl/lvgl.h" /*הגדירו LV_LVGL_H_INCLUDE_SIMPLE כדי לכלול כ-"lvgl.h"*/
|
||||
|
||||
#define TFT_HOR_RES 320
|
||||
#define TFT_VER_RES 240
|
||||
|
||||
static uint32_t my_tick_cb(void)
|
||||
{
|
||||
return my_get_millisec();
|
||||
}
|
||||
|
||||
static void my_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
|
||||
{
|
||||
/*כתבו את px_map לאזור המתאים במאגר המסגרת או בבקר התצוגה החיצוני*/
|
||||
}
|
||||
|
||||
static void my_touch_read_cb(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
{
|
||||
if(my_touch_is_pressed()) {
|
||||
data->point.x = touchpad_x;
|
||||
data->point.y = touchpad_y;
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
} else {
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
my_hardware_init();
|
||||
|
||||
/*אתחול LVGL*/
|
||||
lv_init();
|
||||
|
||||
/*הגדרת מקור טיק במילישניות כדי של־LVGL תהיה ספירת זמן*/
|
||||
lv_tick_set_cb(my_tick_cb);
|
||||
|
||||
/*יצירת תצוגה להוספת מסכים ווידג'טים*/
|
||||
lv_display_t * display = lv_display_create(TFT_HOR_RES, TFT_VER_RES);
|
||||
|
||||
/*הוספת מאגרי רינדור
|
||||
*כאן מוסיפים מאגר חלקי קטן בהנחה של 16 סיביות (RGB565)*/
|
||||
static uint8_t buf[TFT_HOR_RES * TFT_VER_RES / 10 * 2]; /* x2 בגלל עומק צבע 16 ביט */
|
||||
lv_display_set_buffers(display, buf, NULL, sizeof(buf), LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
/*קולבק לרענון התוכן מן המאגר אל התצוגה*/
|
||||
lv_display_set_flush_cb(display, my_flush_cb);
|
||||
|
||||
/*יצירת התקן קלט למגע*/
|
||||
lv_indev_t * indev = lv_indev_create();
|
||||
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(indev, my_touch_read_cb);
|
||||
|
||||
/*הדרייברים מוכנים, יוצרים UI*/
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(label, "Hello world");
|
||||
lv_obj_center(label);
|
||||
|
||||
/*לולאת משימות של LVGL*/
|
||||
while(1) {
|
||||
lv_timer_handler();
|
||||
my_sleep_ms(5); /*השהיה קצרה להורדת עומס המערכת*/
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤖 דוגמאות
|
||||
|
||||
מעל 100 דוגמאות זמינות ב־https://docs.lvgl.io/master/examples.html
|
||||
|
||||
המציג המקוון כולל גם מדריכים ללימוד XML: https://viewer.lvgl.io/
|
||||
|
||||
|
||||
### כפתור Hello World עם אירוע
|
||||
|
||||
<img width="311" height="232" alt="image" src="https://github.com/user-attachments/assets/5948b485-e3f7-4a63-bb21-984381417c4a" />
|
||||
|
||||
<details>
|
||||
<summary>קוד C</summary>
|
||||
|
||||
```c
|
||||
static void button_clicked_cb(lv_event_t * e)
|
||||
{
|
||||
printf("Clicked\n");
|
||||
}
|
||||
|
||||
[...]
|
||||
|
||||
lv_obj_t * button = lv_button_create(lv_screen_active());
|
||||
lv_obj_center(button);
|
||||
lv_obj_add_event_cb(button, button_clicked_cb, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
lv_obj_t * label = lv_label_create(button);
|
||||
lv_label_set_text(label, "Hello from LVGL!");
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>ב־XML עם LVGL Pro</summary>
|
||||
|
||||
```xml
|
||||
<screen>
|
||||
<view>
|
||||
<lv_button align="center">
|
||||
<event_cb callback="button_clicked_cb" />
|
||||
<lv_label text="Hello from LVGL!" />
|
||||
</lv_button>
|
||||
</view>
|
||||
</screen>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### מחוון מעוצב עם קישור נתונים
|
||||
|
||||
<img width="314" height="233" alt="image" src="https://github.com/user-attachments/assets/268db1a0-946c-42e2-aee4-9550bdf5f4f9" />
|
||||
|
||||
<details>
|
||||
<summary>קוד C</summary>
|
||||
|
||||
```c
|
||||
static void my_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
|
||||
{
|
||||
printf("Slider value: %d\n", lv_subject_get_int(subject));
|
||||
}
|
||||
|
||||
[...]
|
||||
|
||||
static lv_subject_t subject_value;
|
||||
lv_subject_init_int(&subject_value, 35);
|
||||
lv_subject_add_observer(&subject_value, my_observer_cb, NULL);
|
||||
|
||||
lv_style_t style_base;
|
||||
lv_style_init(&style_base);
|
||||
lv_style_set_bg_color(&style_base, lv_color_hex(0xff8800));
|
||||
lv_style_set_bg_opa(&style_base, 255);
|
||||
lv_style_set_radius(&style_base, 4);
|
||||
|
||||
lv_obj_t * slider = lv_slider_create(lv_screen_active());
|
||||
lv_obj_center(slider);
|
||||
lv_obj_set_size(slider, lv_pct(80), 16);
|
||||
lv_obj_add_style(slider, &style_base, LV_PART_INDICATOR);
|
||||
lv_obj_add_style(slider, &style_base, LV_PART_KNOB);
|
||||
lv_obj_add_style(slider, &style_base, 0);
|
||||
lv_obj_set_style_bg_opa(slider, LV_OPA_50, 0);
|
||||
lv_obj_set_style_border_width(slider, 3, LV_PART_KNOB);
|
||||
lv_obj_set_style_border_color(slider, lv_color_hex3(0xfff), LV_PART_KNOB);
|
||||
lv_slider_bind_value(slider, &subject_value);
|
||||
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, -30);
|
||||
lv_label_bind_text(label, &subject_value, "Temperature: %d °C");
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>ב־XML עם LVGL Pro</summary>
|
||||
|
||||
```xml
|
||||
<screen>
|
||||
<styles>
|
||||
<style name="style_base" bg_opa="100%" bg_color="0xff8800" radius="4" />
|
||||
<style name="style_border" border_color="0xfff" border_width="3" />
|
||||
</styles>
|
||||
|
||||
<view>
|
||||
<lv_label bind_text="value" bind_text-fmt="Temperature: %d °C" align="center" y="-30" />
|
||||
<lv_slider align="center" bind_value="value" style_bg_opa="30%">
|
||||
<style name="style_base" />
|
||||
<style name="style_base" selector="knob" />
|
||||
<style name="style_base" selector="indicator" />
|
||||
<style name="style_border" selector="knob" />
|
||||
</lv_slider>
|
||||
</view>
|
||||
</screen>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### תיבות סימון בפריסה
|
||||
|
||||
<img width="311" height="231" alt="image" src="https://github.com/user-attachments/assets/ba9af647-2ea1-4bc8-b53d-c7b43ce24b6e" />
|
||||
|
||||
<details>
|
||||
<summary>קוד C</summary>
|
||||
|
||||
```c
|
||||
/* יצירת מסך חדש וטעינתו */
|
||||
lv_obj_t * scr = lv_obj_create(NULL);
|
||||
lv_screen_load(scr);
|
||||
|
||||
/* הגדרת פריסת עמודה */
|
||||
lv_obj_set_flex_flow(scr, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(scr, LV_FLEX_ALIGN_SPACE_EVENLY, /*יישור אנכי*/
|
||||
LV_FLEX_ALIGN_START, /*יישור אופקי במסילה*/
|
||||
LV_FLEX_ALIGN_CENTER); /*יישור המסילה*/
|
||||
|
||||
/* יצירת 5 תיבות סימון */
|
||||
const char * texts[5] = {"Input 1", "Input 2", "Input 3", "Output 1", "Output 2"};
|
||||
for(int i = 0; i < 5; i++) {
|
||||
lv_obj_t * cb = lv_checkbox_create(scr);
|
||||
lv_checkbox_set_text(cb, texts[i]);
|
||||
}
|
||||
|
||||
/* שינוי מצבים */
|
||||
lv_obj_add_state(lv_obj_get_child(scr, 1), LV_STATE_CHECKED);
|
||||
lv_obj_add_state(lv_obj_get_child(scr, 3), LV_STATE_DISABLED);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>ב־XML עם LVGL Pro</summary>
|
||||
|
||||
```xml
|
||||
<screen>
|
||||
<view
|
||||
flex_flow="column"
|
||||
style_flex_main_place="space_evenly"
|
||||
style_flex_cross_place="start"
|
||||
style_flex_track_place="center"
|
||||
>
|
||||
<lv_checkbox text="Input 1"/>
|
||||
<lv_checkbox text="Input 2"/>
|
||||
<lv_checkbox text="Input 3" checked="true"/>
|
||||
<lv_checkbox text="Output 1"/>
|
||||
<lv_checkbox text="Output 2" disabled="true"/>
|
||||
</view>
|
||||
</screen>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
## 🌟 תרומה
|
||||
|
||||
LVGL הוא פרויקט פתוח ותרומות מתקבלות בברכה. אפשר לתרום בדרכים רבות: לשתף על הפרויקט שלכם, לכתוב דוגמאות, לשפר את התיעוד, לתקן תקלות ואפילו לארח פרויקט משלכם תחת ארגון LVGL.
|
||||
|
||||
לתיאור מפורט של אפשרויות התרומה, בקרו בפרק [Contributing](https://docs.lvgl.io/master/contributing/index.html) בתיעוד.
|
||||
|
||||
יותר מ־600 אנשים כבר הותירו חותם על LVGL. הצטרפו אלינו. נתראה שם 🙂
|
||||
|
||||
<a href="https://github.com/lvgl/lvgl/graphs/contributors"> <img src="https://contrib.rocks/image?repo=lvgl/lvgl&max=48" /> </a>
|
||||
|
||||
...ועוד רבים.
|
||||
|
||||
332
managed_components/lvgl__lvgl/docs/README_jp.md
Normal file
@@ -0,0 +1,332 @@
|
||||
<a href="https://github.com/sponsors/lvgl" target="_blank"><img align="left" src="https://lvgl.io/github-assets/sponsor.png" height="32px"></a>
|
||||
|
||||
|
||||
|
||||
<p align="right"><a href="../README.md">English</a> | <a href="./README_zh.md">中文</a> | <a href="./README_pt_BR.md">Português do Brasil</a> | <b>日本語</b> | <a href="./README_he.md">עברית</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://lvgl.io/github-assets/logo-colored.png" width=300px>
|
||||
</p>
|
||||
|
||||
|
||||
<h1 align="center">Light and Versatile Graphics Library</h1>
|
||||
<br>
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/kisvegabor/test/master/smartwatch_demo.gif">
|
||||
|
||||
<img border="1px" src="https://lvgl.io/github-assets/widgets-demo.gif">
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://lvgl.io" title="LVGL ホームページ">ウェブサイト</a> |
|
||||
<a href="https://pro.lvgl.io" title="LVGL Pro XML ベースの UI エディター">LVGL Pro エディター</a> |
|
||||
<a href="https://docs.lvgl.io/" title="100 以上のサンプル付き詳細ドキュメント">ドキュメント</a> |
|
||||
<a href="https://forum.lvgl.io" title="質問・回答コミュニティ">フォーラム</a> |
|
||||
<a href="https://lvgl.io/demos" title="ブラウザで実行できるデモ">デモ</a> |
|
||||
<a href="https://lvgl.io/services" title="グラフィックデザイン、UI 実装、コンサルティング">サービス</a>
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
||||
## 📒 概要
|
||||
|
||||
**LVGL** は、あらゆるメーカーやプラットフォームの MCU および MPU に対応した、無料でオープンソースの UI ライブラリです。
|
||||
|
||||
**要件**:LVGL は外部依存がないため、最新のあらゆるターゲットに簡単にコンパイルできます。小型 MCU から 3D 対応のマルチコア Linux MPU まで対応。シンプルな UI の場合、約 100kB の RAM、200~300kB のフラッシュ、および画面の 1/10 サイズのバッファで十分です。
|
||||
|
||||
**はじめに**:VSCode、Eclipse などのプロジェクトを選び、PC 上で LVGL を試してみましょう。LVGL の UI コードは完全にプラットフォーム非依存なので、そのまま組込みターゲットでも使用できます。
|
||||
|
||||
**LVGL Pro** は、UI をより迅速に構築・テスト・共有・出荷できる完全なツールキットです。XML エディターを備え、再利用可能なコンポーネントの作成・テスト、C コードのエクスポート、XML の実行時読み込みが可能です。詳細は公式サイトをご覧ください。
|
||||
|
||||
## 💡 機能
|
||||
|
||||
**無料でポータブル**
|
||||
- 外部依存のない完全な C(C++ 互換)ライブラリ。
|
||||
- あらゆる MCU / MPU、任意の (RT)OS に対応。Make、CMake、glob 構文をサポート。
|
||||
- モノクロ、電子ペーパー、OLED、TFT、さらにはモニターにも対応。[ディスプレイ](https://docs.lvgl.io/master/main-modules/display/index.html)
|
||||
- MIT ライセンスで商用利用も簡単。
|
||||
- 必要リソースはわずか 32kB RAM、128kB フラッシュ、フレームバッファ、および画面の 1/10 の描画バッファ。
|
||||
- OS、外部メモリ、GPU の使用は任意。
|
||||
|
||||
**ウィジェット・スタイル・レイアウトなど**
|
||||
- 30 以上の [ウィジェット](https://docs.lvgl.io/master/widgets/index.html):ボタン、ラベル、スライダー、チャート、キーボード、メーター、アーク、テーブルなど。
|
||||
- 約 100 のプロパティを持つ柔軟な [スタイルシステム](https://docs.lvgl.io/master/common-widget-features/styles/index.html)。
|
||||
- [Flexbox](https://docs.lvgl.io/master/common-widget-features/layouts/flex.html)、[Grid](https://docs.lvgl.io/master/common-widget-features/layouts/grid.html) レイアウトエンジンによる自動配置。
|
||||
- UTF-8 文字レンダリング。CJK、タイ語、ヒンディー語、アラビア語、ペルシャ語などをサポート。
|
||||
- [データバインディング](https://docs.lvgl.io/master/main-modules/observer/index.html) により、UI とアプリケーションを簡単に接続。
|
||||
- レンダリングエンジンはアニメーション、アンチエイリアス、不透明度、スムーズスクロール、影、画像変換をサポート。
|
||||
- [3D レンダリングエンジン](https://docs.lvgl.io/master/libs/gltf.html) により [glTF モデル](https://sketchfab.com/) を OpenGL で表示可能。
|
||||
- マウス、タッチパッド、キー入力、外部ボタン、エンコーダなどに対応。[入力デバイス](https://docs.lvgl.io/master/main-modules/indev.html)
|
||||
- [マルチディスプレイ](https://docs.lvgl.io/master/main-modules/display/overview.html#how-many-displays-can-lvgl-use) をサポート。
|
||||
|
||||
## 📦️ 対応プラットフォーム
|
||||
|
||||
LVGL は外部依存がなく、さまざまなデバイスで簡単にビルドでき、主要なパッケージマネージャや RTOS にも統合されています:
|
||||
|
||||
- [Arduino ライブラリ](https://docs.lvgl.io/master/integration/framework/arduino.html)
|
||||
- [PlatformIO パッケージ](https://registry.platformio.org/libraries/lvgl/lvgl)
|
||||
- [Zephyr ライブラリ](https://docs.lvgl.io/master/integration/os/zephyr.html)
|
||||
- [ESP-IDF (ESP32) コンポーネント](https://components.espressif.com/components/lvgl/lvgl)
|
||||
- [NXP MCUXpresso コンポーネント](https://www.nxp.com/design/software/embedded-software/lvgl-open-source-graphics-library:LITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY)
|
||||
- [NuttX ライブラリ](https://docs.lvgl.io/master/integration/os/nuttx.html)
|
||||
- [RT-Thread RTOS](https://docs.lvgl.io/master/integration/os/rt-thread.html)
|
||||
- CMSIS-Pack
|
||||
- [RIOT OS パッケージ](https://doc.riot-os.org/group__pkg__lvgl.html#details)
|
||||
|
||||
## 🚀 LVGL Pro エディター
|
||||
|
||||
LVGL Pro は、組込み UI を効率的に構築・テスト・共有・出荷するための完全なツール群です。
|
||||
|
||||
以下の 4 つのツールで構成されています:
|
||||
|
||||
1. **XML エディター**:LVGL Pro の中心。XML でコンポーネントや画面を作成し、データバインディング、翻訳、アニメーション、テストなどを管理。詳細は [XML フォーマット](https://docs.lvgl.io/master/xml/xml/index.html) および [エディター](https://docs.lvgl.io/master/xml/editor/index.html)。
|
||||
2. **オンラインビューア**:ブラウザでエディターを実行し、GitHub プロジェクトを開いて簡単に共有。環境構築は不要。アクセス:[https://viewer.lvgl.io](https://viewer.lvgl.io)
|
||||
3. **CLI ツール**:C コードの生成や CI/CD テストを自動化。詳細は [こちら](https://docs.lvgl.io/master/xml/tools/cli.html)。
|
||||
4. **Figma プラグイン**:Figma から直接スタイルを同期・抽出。[詳細はこちら](https://docs.lvgl.io/master/xml/tools/figma.html)。
|
||||
|
||||
これらのツールを組み合わせることで、開発者は効率的に UI を構築し、信頼性の高いテストとチームコラボレーションを実現できます。
|
||||
|
||||
詳細は https://pro.lvgl.io へ。
|
||||
|
||||
## 🤝 商用サービス
|
||||
|
||||
LVGL LLC は、UI 開発を支援するさまざまな商用サービスを提供しています。ユーザーインターフェースとグラフィック分野で 15 年以上の経験を活かし、あなたの製品 UI を次のレベルへ導きます。
|
||||
|
||||
- **グラフィックデザイン**:社内デザイナーが、製品とハードウェア性能に最適化された美しくモダンなデザインを提供。
|
||||
- **UI 実装**:お客様または当社が作成したデザインに基づき、最適な UI を実装。必要なウィジェットがない場合も新たに開発します。
|
||||
- **コンサルティング・サポート**:UI 開発での時間やコストの無駄を避けるための専門支援。
|
||||
- **ボード認証**:開発ボードや製品キットを提供する企業向けに、LVGL の動作実績を示す認証を提供。
|
||||
|
||||
参考として [デモ](https://lvgl.io/demos) をご覧ください。詳細は [サービスページ](https://lvgl.io/services) を参照ください。
|
||||
|
||||
[お問い合わせ](https://lvgl.io/#contact) からご連絡ください。
|
||||
|
||||
## 🧑💻 LVGL の統合
|
||||
|
||||
LVGL の統合は非常に簡単です。プロジェクトに追加して他のファイルと同様にコンパイルするだけです。
|
||||
設定するには、`lv_conf_template.h` を `lv_conf.h` としてコピーし、最初の `#if 0` を有効化して必要に応じて設定を調整します。
|
||||
(通常はデフォルト設定で十分です。)Kconfig にも対応しています。
|
||||
|
||||
プロジェクト内で LVGL を初期化し、ディスプレイと入力デバイスを作成する例:
|
||||
|
||||
```c
|
||||
#include "lvgl/lvgl.h" /*LV_LVGL_H_INCLUDE_SIMPLE を定義すると "lvgl.h" としてインクルード可能*/
|
||||
|
||||
#define TFT_HOR_RES 320
|
||||
#define TFT_VER_RES 240
|
||||
|
||||
static uint32_t my_tick_cb(void)
|
||||
{
|
||||
return my_get_millisec();
|
||||
}
|
||||
|
||||
static void my_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
|
||||
{
|
||||
/*px_map をフレームバッファまたは外部ディスプレイコントローラに書き込む*/
|
||||
}
|
||||
|
||||
static void my_touch_read_cb(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
{
|
||||
if(my_touch_is_pressed()) {
|
||||
data->point.x = touchpad_x;
|
||||
data->point.y = touchpad_y;
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
} else {
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
my_hardware_init();
|
||||
|
||||
/*LVGL を初期化*/
|
||||
lv_init();
|
||||
|
||||
/*ミリ秒単位のタイマーコールバックを設定*/
|
||||
lv_tick_set_cb(my_tick_cb);
|
||||
|
||||
/*ディスプレイを作成*/
|
||||
lv_display_t * display = lv_display_create(TFT_HOR_RES, TFT_VER_RES);
|
||||
|
||||
/*描画バッファを追加(16bit RGB565 の場合)*/
|
||||
static uint8_t buf[TFT_HOR_RES * TFT_VER_RES / 10 * 2];
|
||||
lv_display_set_buffers(display, buf, NULL, sizeof(buf), LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
/*描画内容をフラッシュするコールバックを設定*/
|
||||
lv_display_set_flush_cb(display, my_flush_cb);
|
||||
|
||||
/*入力デバイスを作成(タッチ用)*/
|
||||
lv_indev_t * indev = lv_indev_create();
|
||||
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(indev, my_touch_read_cb);
|
||||
|
||||
/*UI を作成*/
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(label, "Hello world");
|
||||
lv_obj_center(label);
|
||||
|
||||
/*メインループで LVGL を実行*/
|
||||
while(1) {
|
||||
lv_timer_handler();
|
||||
my_sleep_ms(5);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤖 サンプル
|
||||
|
||||
100 以上のサンプルが https://docs.lvgl.io/master/examples.html にあります。
|
||||
|
||||
オンラインビューア https://viewer.lvgl.io/ でも XML のチュートリアルを学べます。
|
||||
|
||||
|
||||
### Hello World ボタンイベント
|
||||
|
||||
<img width="311" height="232" alt="image" src="https://github.com/user-attachments/assets/5948b485-e3f7-4a63-bb21-984381417c4a" />
|
||||
|
||||
<details>
|
||||
<summary>C コード</summary>
|
||||
|
||||
```c
|
||||
static void button_clicked_cb(lv_event_t * e)
|
||||
{
|
||||
printf("Clicked\n");
|
||||
}
|
||||
|
||||
[...]
|
||||
|
||||
lv_obj_t * button = lv_button_create(lv_screen_active());
|
||||
lv_obj_center(button);
|
||||
lv_obj_add_event_cb(button, button_clicked_cb, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
lv_obj_t * label = lv_label_create(button);
|
||||
lv_label_set_text(label, "Hello from LVGL!");
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>LVGL Pro の XML</summary>
|
||||
|
||||
```xml
|
||||
<screen>
|
||||
<view>
|
||||
<lv_button align="center">
|
||||
<event_cb callback="button_clicked_cb" />
|
||||
<lv_label text="Hello from LVGL!" />
|
||||
</lv_button>
|
||||
</view>
|
||||
</screen>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### データバインド付きスライダー
|
||||
|
||||
<img width="314" height="233" alt="image" src="https://github.com/user-attachments/assets/268db1a0-946c-42e2-aee4-9550bdf5f4f9" />
|
||||
|
||||
<details>
|
||||
<summary>C コード</summary>
|
||||
|
||||
```c
|
||||
static void my_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
|
||||
{
|
||||
printf("Slider value: %d\n", lv_subject_get_int(subject));
|
||||
}
|
||||
|
||||
[...]
|
||||
|
||||
static lv_subject_t subject_value;
|
||||
lv_subject_init_int(&subject_value, 35);
|
||||
lv_subject_add_observer(&subject_value, my_observer_cb, NULL);
|
||||
|
||||
lv_style_t style_base;
|
||||
lv_style_init(&style_base);
|
||||
lv_style_set_bg_color(&style_base, lv_color_hex(0xff8800));
|
||||
lv_style_set_bg_opa(&style_base, 255);
|
||||
lv_style_set_radius(&style_base, 4);
|
||||
|
||||
lv_obj_t * slider = lv_slider_create(lv_screen_active());
|
||||
lv_obj_center(slider);
|
||||
lv_obj_set_size(slider, lv_pct(80), 16);
|
||||
lv_obj_add_style(slider, &style_base, LV_PART_INDICATOR);
|
||||
lv_obj_add_style(slider, &style_base, LV_PART_KNOB);
|
||||
lv_obj_add_style(slider, &style_base, 0);
|
||||
lv_obj_set_style_bg_opa(slider, LV_OPA_50, 0);
|
||||
lv_obj_set_style_border_width(slider, 3, LV_PART_KNOB);
|
||||
lv_obj_set_style_border_color(slider, lv_color_hex3(0xfff), LV_PART_KNOB);
|
||||
lv_slider_bind_value(slider, &subject_value);
|
||||
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, -30);
|
||||
lv_label_bind_text(label, &subject_value, "Temperature: %d °C");
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>LVGL Pro の XML</summary>
|
||||
|
||||
```xml
|
||||
<screen>
|
||||
<styles>
|
||||
<style name="style_base" bg_opa="100%" bg_color="0xff8800" radius="4" />
|
||||
<style name="style_border" border_color="0xfff" border_width="3" />
|
||||
</styles>
|
||||
|
||||
<view>
|
||||
<lv_label bind_text="value" bind_text-fmt="Temperature: %d °C" align="center" y="-30" />
|
||||
<lv_slider align="center" bind_value="value" style_bg_opa="30%">
|
||||
<style name="style_base" />
|
||||
<style name="style_base" selector="knob" />
|
||||
<style name="style_base" selector="indicator" />
|
||||
<style name="style_border" selector="knob" />
|
||||
</lv_slider>
|
||||
</view>
|
||||
</screen>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### レイアウト内のチェックボックス
|
||||
|
||||
<img width="311" height="231" alt="image" src="https://github.com/user-attachments/assets/ba9af647-2ea1-4bc8-b53d-c7b43ce24b6e" />
|
||||
|
||||
<details>
|
||||
<summary>C コード</summary>
|
||||
|
||||
```c
|
||||
/* 新しい画面を作成してロード */
|
||||
lv_obj_t * scr = lv_obj_create(NULL);
|
||||
lv_screen_load(scr);
|
||||
|
||||
/* 縦方向のレイアウトを設定 */
|
||||
lv_obj_set_flex_flow(scr, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(scr, LV_FLEX_ALIGN_SPACE_EVENLY,
|
||||
LV_FLEX_ALIGN_START,
|
||||
LV_FLEX_ALIGN_CENTER);
|
||||
|
||||
/* チェックボックスを 5 個作成 */
|
||||
const char * texts[5] = {"Input 1", "Input 2", "Input 3", "Output 1", "Output 2"};
|
||||
for(int i = 0; i < 5; i++) {
|
||||
lv_obj_t * cb = lv_checkbox_create(scr);
|
||||
lv_checkbox_set_text(cb, texts[i]);
|
||||
}
|
||||
|
||||
/* 状態変更 */
|
||||
lv_obj_add_state(lv_obj_get_child(scr, 1), LV_STATE_CHECKED);
|
||||
lv_obj_add_state(lv_obj_get_child(scr, 3), LV_STATE_DISABLED);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>LVGL Pro の XML</summary>
|
||||
|
||||
```xml
|
||||
<screen
|
||||
|
||||
376
managed_components/lvgl__lvgl/docs/README_pt_BR.md
Normal file
@@ -0,0 +1,376 @@
|
||||
|
||||
<a href="https://github.com/sponsors/lvgl" target="_blank"><img align="left" src="https://lvgl.io/github-assets/sponsor.png" height="32px"></a>
|
||||
|
||||
<p align="right">
|
||||
<a href="../README.md">English</a> |
|
||||
<a href="./README_zh.md">中文</a> |
|
||||
<b>Português do Brasil</b> |
|
||||
<a href="./README_jp.md">日本語</a> |
|
||||
<a href="./README_he.md">עברית</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<img src="https://lvgl.io/github-assets/logo-colored.png" width=300px>
|
||||
</p>
|
||||
|
||||
<h1 align="center">LVGL - Light and Versatile Graphics Library</h1>
|
||||
<br/>
|
||||
<h1 align="center">LVGL - Biblioteca gráfica leve e versátil</h1>
|
||||
|
||||
<br/>
|
||||
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/kisvegabor/test/master/smartwatch_demo.gif">
|
||||
|
||||
<img border="1px" src="https://lvgl.io/github-assets/widgets-demo.gif">
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://lvgl.io" title="Homepage of LVGL">Site</a> |
|
||||
<a href="https://pro.lvgl.io" title="LVGL Pro XML based UI Editor">Editor LVGL Pro</a> |
|
||||
<a href="https://docs.lvgl.io/" title="Detailed documentation with 100+ examples">Documentação</a> |
|
||||
<a href="https://forum.lvgl.io" title="Get help and help others">Fórum</a> |
|
||||
<a href="https://lvgl.io/demos" title="Demos running in your browser">Demos</a> |
|
||||
<a href="https://lvgl.io/services" title="Graphics design, UI implementation and consulting">Serviços</a>
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
||||
## 📒 Visão geral
|
||||
|
||||
**LVGL** é uma biblioteca de UI gratuita e de código aberto que permite criar interfaces gráficas
|
||||
para qualquer MCU e MPU, de qualquer fabricante, em qualquer plataforma.
|
||||
|
||||
**Requisitos**: o LVGL não possui dependências externas, o que facilita compilar para qualquer alvo moderno,
|
||||
desde pequenos MCUs até MPUs Linux multicore com suporte a 3D. Para uma UI simples, você precisa de ~100 kB de RAM,
|
||||
~200–300 kB de flash e um buffer de renderização com 1/10 do tamanho da tela.
|
||||
|
||||
**Para começar**, escolha um projeto pronto para uso no VSCode, Eclipse ou outro, e experimente o LVGL
|
||||
no seu PC. O código de UI do LVGL é totalmente independente de plataforma, então você pode reutilizá-lo
|
||||
nos seus alvos embarcados.
|
||||
|
||||
**LVGL Pro** é um kit completo para ajudar você a criar, testar, compartilhar e entregar UIs com mais rapidez.
|
||||
Ele inclui um Editor XML onde você pode criar e testar componentes reutilizáveis,
|
||||
exportar código C ou carregar os XMLs em tempo de execução. Saiba mais aqui.
|
||||
|
||||
## 💡 Recursos
|
||||
|
||||
**Gratuito e portátil**
|
||||
- Biblioteca totalmente em C (compatível com C++) sem dependências externas.
|
||||
- Pode ser compilada para qualquer MCU ou MPU, com qualquer (RT)OS. Make, CMake e globbing simples são suportados.
|
||||
- Suporta displays monocromáticos, ePaper, OLED, TFT e até monitores. [Displays](https://docs.lvgl.io/master/main-modules/display/index.html)
|
||||
- Licença MIT, o que facilita o uso em projetos comerciais.
|
||||
- Precisa de apenas 32 kB de RAM, 128 kB de Flash, um frame buffer e pelo menos um buffer de 1/10 da tela para renderização.
|
||||
- Sistema operacional, memória externa e GPU são suportados, mas não obrigatórios.
|
||||
|
||||
**Widgets, estilos, layouts e mais**
|
||||
- 30+ [Widgets](https://docs.lvgl.io/master/widgets/index.html) embutidos: Button, Label, Slider, Chart, Keyboard, Meter, Arc, Table e muitos outros.
|
||||
- [Sistema de estilos](https://docs.lvgl.io/master/common-widget-features/styles/index.html) flexível com ~100 propriedades para personalizar qualquer parte dos widgets em qualquer estado.
|
||||
- Motores de layout tipo [Flexbox](https://docs.lvgl.io/master/common-widget-features/layouts/flex.html) e [Grid](https://docs.lvgl.io/master/common-widget-features/layouts/grid.html) para dimensionar e posicionar widgets de forma responsiva.
|
||||
- Texto renderizado com codificação UTF-8, com suporte a CJK, tailandês, híndi, árabe e persa.
|
||||
- [Data bindings](https://docs.lvgl.io/master/main-modules/observer/index.html) para conectar facilmente a UI ao aplicativo.
|
||||
- Motor de renderização com suporte a animações, antialiasing, opacidade, rolagem suave, sombras, transformação de imagens e mais.
|
||||
- [Poderoso motor de renderização 3D](https://docs.lvgl.io/master/libs/gltf.html) para exibir [modelos glTF](https://sketchfab.com/) com OpenGL.
|
||||
- Suporte a mouse, touchpad, keypad, teclado, botões externos e encoder. [Dispositivos de entrada](https://docs.lvgl.io/master/main-modules/indev.html)
|
||||
- Suporte a [múltiplos displays](https://docs.lvgl.io/master/main-modules/display/overview.html#how-many-displays-can-lvgl-use).
|
||||
|
||||
## 📦️ Plataformas compatíveis
|
||||
|
||||
O LVGL não possui dependências externas, por isso é fácil de compilar para qualquer dispositivo e também está disponível em vários gerenciadores de pacotes e RTOS:
|
||||
|
||||
- [Biblioteca Arduino](https://docs.lvgl.io/master/integration/framework/arduino.html)
|
||||
- [Pacote PlatformIO](https://registry.platformio.org/libraries/lvgl/lvgl)
|
||||
- [Biblioteca Zephyr](https://docs.lvgl.io/master/integration/os/zephyr.html)
|
||||
- [Componente ESP-IDF (ESP32)](https://components.espressif.com/components/lvgl/lvgl)
|
||||
- [Componente NXP MCUXpresso](https://www.nxp.com/design/software/embedded-software/lvgl-open-source-graphics-library:LITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY)
|
||||
- [Biblioteca NuttX](https://docs.lvgl.io/master/integration/os/nuttx.html)
|
||||
- [RT-Thread RTOS](https://docs.lvgl.io/master/integration/os/rt-thread.html)
|
||||
- CMSIS-Pack
|
||||
- [Pacote RIOT OS](https://doc.riot-os.org/group__pkg__lvgl.html#details)
|
||||
|
||||
## 🚀 Editor LVGL Pro
|
||||
|
||||
O LVGL Pro é um conjunto completo para criar, testar, compartilhar e entregar UIs embarcadas com eficiência.
|
||||
|
||||
Ele é composto por quatro ferramentas integradas:
|
||||
|
||||
1. **Editor XML**: o coração do LVGL Pro. Um app de desktop para criar componentes e telas em XML, gerenciar data bindings, traduções, animações, testes e mais. Saiba mais sobre o [formato XML](https://docs.lvgl.io/master/xml/xml/index.html) e o [Editor](https://docs.lvgl.io/master/xml/editor/index.html).
|
||||
2. **Visualizador online**: execute o Editor no navegador, abra projetos do GitHub e compartilhe facilmente sem configurar um ambiente de desenvolvimento. Visite [https://viewer.lvgl.io](https://viewer.lvgl.io).
|
||||
3. **Ferramenta CLI**: gere código C e rode testes no CI/CD. Veja os detalhes [aqui](https://docs.lvgl.io/master/xml/tools/cli.html).
|
||||
4. **Plugin Figma**: sincronize e extraia estilos diretamente do Figma. Veja como funciona [aqui](https://docs.lvgl.io/master/xml/tools/figma.html).
|
||||
|
||||
Juntas, essas ferramentas permitem criar UIs com eficiência, testá-las com confiabilidade e colaborar com colegas e clientes.
|
||||
|
||||
Saiba mais em https://pro.lvgl.io
|
||||
|
||||
## 🤝 Serviços comerciais
|
||||
|
||||
A LVGL LLC oferece vários tipos de serviços comerciais para apoiar o seu desenvolvimento de UI. Com mais de 15 anos de experiência em interfaces de usuário e gráficos, ajudamos você a levar sua UI para o próximo nível.
|
||||
|
||||
- **Design gráfico**: nossos designers internos são especialistas em criar visuais modernos e bonitos que combinam com seu produto e com as capacidades do hardware.
|
||||
- **Implementação de UI**: implementamos sua UI com base no design criado por você ou por nós. Vamos tirar o máximo do seu hardware e do LVGL. Se faltar algum recurso ou widget no LVGL, nós implementamos para você.
|
||||
- **Consultoria e suporte**: oferecemos consultoria para evitar erros caros e demorados durante o desenvolvimento da UI.
|
||||
- **Certificação de placas**: para empresas que oferecem placas de desenvolvimento ou kits prontos para produção, fornecemos certificação demonstrando como a placa roda o LVGL.
|
||||
|
||||
Veja nossos [Demos](https://lvgl.io/demos) como referência. Para mais informações, acesse a [página de Serviços](https://lvgl.io/services).
|
||||
|
||||
[Entre em contato](https://lvgl.io/#contact) e conte como podemos ajudar.
|
||||
|
||||
## 🧑💻 Integração do LVGL
|
||||
|
||||
Integrar o LVGL é simples. Basta adicioná-lo ao projeto e compilar como você compila outros arquivos.
|
||||
Para configurar, copie `lv_conf_template.h` para `lv_conf.h`, habilite o primeiro `#if 0` e ajuste as configs conforme necessário.
|
||||
(A configuração padrão geralmente é suficiente.) Quando disponível, o LVGL também pode ser usado com Kconfig.
|
||||
|
||||
Depois de incluído no projeto, você pode inicializar o LVGL e criar dispositivos de display e de entrada assim:
|
||||
|
||||
```c
|
||||
#include "lvgl/lvgl.h" /*Defina LV_LVGL_H_INCLUDE_SIMPLE para incluir como "lvgl.h"*/
|
||||
|
||||
#define TFT_HOR_RES 320
|
||||
#define TFT_VER_RES 240
|
||||
|
||||
static uint32_t my_tick_cb(void)
|
||||
{
|
||||
return my_get_millisec();
|
||||
}
|
||||
|
||||
static void my_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
|
||||
{
|
||||
/*Escreva px_map na área (x1..x2, y1..y2) do frame buffer ou do controlador externo*/
|
||||
}
|
||||
|
||||
static void my_touch_read_cb(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
{
|
||||
if(my_touch_is_pressed()) {
|
||||
data->point.x = touchpad_x;
|
||||
data->point.y = touchpad_y;
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
} else {
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
my_hardware_init();
|
||||
|
||||
/*Inicialize o LVGL*/
|
||||
lv_init();
|
||||
|
||||
/*Defina a fonte de tick em milissegundos para o LVGL controlar o tempo*/
|
||||
lv_tick_set_cb(my_tick_cb);
|
||||
|
||||
/*Crie um display onde telas e widgets serão adicionados*/
|
||||
lv_display_t * display = lv_display_create(TFT_HOR_RES, TFT_VER_RES);
|
||||
|
||||
/*Adicione buffers de renderização
|
||||
*Aqui adicionamos um buffer parcial menor assumindo 16 bits (formato RGB565)*/
|
||||
static uint8_t buf[TFT_HOR_RES * TFT_VER_RES / 10 * 2]; /* x2 por causa de 16 bits por pixel */
|
||||
lv_display_set_buffers(display, buf, NULL, sizeof(buf), LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
/*Adicione o callback que faz o flush do conteúdo de `buf` quando renderizado*/
|
||||
lv_display_set_flush_cb(display, my_flush_cb);
|
||||
|
||||
/*Crie um dispositivo de entrada para toque*/
|
||||
lv_indev_t * indev = lv_indev_create();
|
||||
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(indev, my_touch_read_cb);
|
||||
|
||||
/*Drivers prontos, agora crie a UI*/
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(label, "Hello world");
|
||||
lv_obj_center(label);
|
||||
|
||||
/*Execute as tarefas do LVGL em loop*/
|
||||
while(1) {
|
||||
lv_timer_handler();
|
||||
my_sleep_ms(5); /*Espere um pouco para o sistema respirar*/
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤖 Exemplos
|
||||
|
||||
Você pode conferir mais de 100 exemplos em https://docs.lvgl.io/master/examples.html
|
||||
|
||||
O Visualizador Online também contém tutoriais para aprender XML com facilidade: https://viewer.lvgl.io/
|
||||
|
||||
|
||||
### Botão Hello World com evento
|
||||
|
||||
<img width="311" height="232" alt="image" src="https://github.com/user-attachments/assets/5948b485-e3f7-4a63-bb21-984381417c4a" />
|
||||
|
||||
<details>
|
||||
<summary>C code</summary>
|
||||
|
||||
```c
|
||||
static void button_clicked_cb(lv_event_t * e)
|
||||
{
|
||||
printf("Clicked\n");
|
||||
}
|
||||
|
||||
[...]
|
||||
|
||||
lv_obj_t * button = lv_button_create(lv_screen_active());
|
||||
lv_obj_center(button);
|
||||
lv_obj_add_event_cb(button, button_clicked_cb, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
lv_obj_t * label = lv_label_create(button);
|
||||
lv_label_set_text(label, "Hello from LVGL!");
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Em XML com o LVGL Pro</summary>
|
||||
|
||||
```xml
|
||||
<screen>
|
||||
<view>
|
||||
<lv_button align="center">
|
||||
<event_cb callback="button_clicked_cb" />
|
||||
<lv_label text="Hello from LVGL!" />
|
||||
</lv_button>
|
||||
</view>
|
||||
</screen>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Slider estilizado com data binding
|
||||
|
||||
<img width="314" height="233" alt="image" src="https://github.com/user-attachments/assets/268db1a0-946c-42e2-aee4-9550bdf5f4f9" />
|
||||
|
||||
<details>
|
||||
<summary>C code</summary>
|
||||
|
||||
```c
|
||||
static void my_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
|
||||
{
|
||||
printf("Slider value: %d\n", lv_subject_get_int(subject));
|
||||
}
|
||||
|
||||
[...]
|
||||
|
||||
static lv_subject_t subject_value;
|
||||
lv_subject_init_int(&subject_value, 35);
|
||||
lv_subject_add_observer(&subject_value, my_observer_cb, NULL);
|
||||
|
||||
lv_style_t style_base;
|
||||
lv_style_init(&style_base);
|
||||
lv_style_set_bg_color(&style_base, lv_color_hex(0xff8800));
|
||||
lv_style_set_bg_opa(&style_base, 255);
|
||||
lv_style_set_radius(&style_base, 4);
|
||||
|
||||
lv_obj_t * slider = lv_slider_create(lv_screen_active());
|
||||
lv_obj_center(slider);
|
||||
lv_obj_set_size(slider, lv_pct(80), 16);
|
||||
lv_obj_add_style(slider, &style_base, LV_PART_INDICATOR);
|
||||
lv_obj_add_style(slider, &style_base, LV_PART_KNOB);
|
||||
lv_obj_add_style(slider, &style_base, 0);
|
||||
lv_obj_set_style_bg_opa(slider, LV_OPA_50, 0);
|
||||
lv_obj_set_style_border_width(slider, 3, LV_PART_KNOB);
|
||||
lv_obj_set_style_border_color(slider, lv_color_hex3(0xfff), LV_PART_KNOB);
|
||||
lv_slider_bind_value(slider, &subject_value);
|
||||
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, -30);
|
||||
lv_label_bind_text(label, &subject_value, "Temperature: %d °C");
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Em XML com o LVGL Pro</summary>
|
||||
|
||||
```xml
|
||||
<screen>
|
||||
<styles>
|
||||
<style name="style_base" bg_opa="100%" bg_color="0xff8800" radius="4" />
|
||||
<style name="style_border" border_color="0xfff" border_width="3" />
|
||||
</styles>
|
||||
|
||||
<view>
|
||||
<lv_label bind_text="value" bind_text-fmt="Temperature: %d °C" align="center" y="-30" />
|
||||
<lv_slider align="center" bind_value="value" style_bg_opa="30%">
|
||||
<style name="style_base" />
|
||||
<style name="style_base" selector="knob" />
|
||||
<style name="style_base" selector="indicator" />
|
||||
<style name="style_border" selector="knob" />
|
||||
</lv_slider>
|
||||
</view>
|
||||
</screen>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Checkboxes em um layout
|
||||
|
||||
<img width="311" height="231" alt="image" src="https://github.com/user-attachments/assets/ba9af647-2ea1-4bc8-b53d-c7b43ce24b6e" />
|
||||
|
||||
<details>
|
||||
<summary>C code</summary>
|
||||
|
||||
```c
|
||||
/*Crie uma nova tela e carregue-a*/
|
||||
lv_obj_t * scr = lv_obj_create(NULL);
|
||||
lv_screen_load(scr);
|
||||
|
||||
/*Defina um layout em coluna*/
|
||||
lv_obj_set_flex_flow(scr, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(scr, LV_FLEX_ALIGN_SPACE_EVENLY, /*Alinhamento vertical*/
|
||||
LV_FLEX_ALIGN_START, /*Alinhamento horizontal na trilha*/
|
||||
LV_FLEX_ALIGN_CENTER); /*Alinhamento da trilha*/
|
||||
|
||||
/*Crie 5 checkboxes*/
|
||||
const char * texts[5] = {"Input 1", "Input 2", "Input 3", "Output 1", "Output 2"};
|
||||
for(int i = 0; i < 5; i++) {
|
||||
lv_obj_t * cb = lv_checkbox_create(scr);
|
||||
lv_checkbox_set_text(cb, texts[i]);
|
||||
}
|
||||
|
||||
/*Altere alguns estados*/
|
||||
lv_obj_add_state(lv_obj_get_child(scr, 1), LV_STATE_CHECKED);
|
||||
lv_obj_add_state(lv_obj_get_child(scr, 3), LV_STATE_DISABLED);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Em XML com o LVGL Pro</summary>
|
||||
|
||||
```xml
|
||||
<screen>
|
||||
<view
|
||||
flex_flow="column"
|
||||
style_flex_main_place="space_evenly"
|
||||
style_flex_cross_place="start"
|
||||
style_flex_track_place="center"
|
||||
>
|
||||
<lv_checkbox text="Input 1"/>
|
||||
<lv_checkbox text="Input 2"/>
|
||||
<lv_checkbox text="Input 3" checked="true"/>
|
||||
<lv_checkbox text="Output 1"/>
|
||||
<lv_checkbox text="Output 2" disabled="true"/>
|
||||
</view>
|
||||
</screen>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
## 🌟 Como contribuir
|
||||
|
||||
O LVGL é um projeto aberto, e contribuições são muito bem-vindas. Há muitas formas de contribuir, desde falar sobre o seu projeto, escrever exemplos, melhorar a documentação, corrigir bugs, até hospedar seu próprio projeto na organização LVGL.
|
||||
|
||||
Para uma descrição detalhada das oportunidades de contribuição, visite a seção [Contributing](https://docs.lvgl.io/master/contributing/index.html)
|
||||
da documentação.
|
||||
|
||||
Mais de 600 pessoas já deixaram sua marca no LVGL. Junte-se a nós. Até breve 🙂
|
||||
|
||||
<a href="https://github.com/lvgl/lvgl/graphs/contributors"> <img src="https://contrib.rocks/image?repo=lvgl/lvgl&max=48" /> </a>
|
||||
|
||||
... e muitas outras.
|
||||
|
||||
366
managed_components/lvgl__lvgl/docs/README_zh.md
Normal file
@@ -0,0 +1,366 @@
|
||||
<a href="https://github.com/sponsors/lvgl" target="_blank"><img align="left" src="https://lvgl.io/github-assets/sponsor.png" height="32px"></a>
|
||||
|
||||
<p align="right">
|
||||
<a href="../README.md">English</a> | <b>中文</b> | <a href="./README_pt_BR.md">Português do Brasil</a> | <a href="./README_jp.md">日本語</a> | <a href="./README_he.md">עברית</a>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://lvgl.io/github-assets/logo-colored.png" width=300px>
|
||||
</p>
|
||||
|
||||
|
||||
<h1 align="center">
|
||||
Light and Versatile Graphics Library
|
||||
</h1>
|
||||
|
||||
<h1 align="center">
|
||||
轻量级通用型图形库
|
||||
</h1>
|
||||
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/kisvegabor/test/master/smartwatch_demo.gif">
|
||||
|
||||
<img border="1px" src="https://lvgl.io/github-assets/widgets-demo.gif">
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://lvgl.io" title="LVGL 官方网站">网站</a> |
|
||||
<a href="https://pro.lvgl.io" title="LVGL Pro 基于 XML 的 UI 编辑器">LVGL Pro 编辑器</a> |
|
||||
<a href="https://docs.lvgl.io/" title="包含 100+ 示例的详细文档">文档</a> |
|
||||
<a href="https://forum.lvgl.io" title="寻求帮助或帮助他人">论坛</a> |
|
||||
<a href="https://lvgl.io/demos" title="在浏览器中运行的演示">演示</a> |
|
||||
<a href="https://lvgl.io/services" title="图形设计、UI 实现和咨询服务">服务</a>
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
||||
## 📒 概述
|
||||
|
||||
**LVGL** 是一个免费、开源的 UI 库,可用于为来自任何厂商、任何平台的 MCU 或 MPU 创建图形用户界面。
|
||||
|
||||
**要求**:LVGL 无需外部依赖,因此可以轻松编译到任何现代平台上,从小型 MCU 到支持 3D 的多核 Linux MPU。简单 UI 仅需约 100kB RAM、200–300kB Flash,以及 1/10 屏幕大小的渲染缓冲区。
|
||||
|
||||
**开始使用**:选择一个可直接使用的 VSCode、Eclipse 或其他项目,在 PC 上尝试 LVGL。LVGL 的 UI 代码完全平台无关,因此也可直接用于嵌入式设备。
|
||||
|
||||
**LVGL Pro** 是一套完整的工具包,可让你更快地构建、测试、共享和发布 UI。它附带一个 XML 编辑器,你可以在其中快速创建和测试可重用组件,导出 C 代码,或在运行时加载 XML。了解更多信息请点击这里。
|
||||
|
||||
## 💡 特性
|
||||
|
||||
**免费与可移植性**
|
||||
- 纯 C(兼容 C++)库,无外部依赖。
|
||||
- 可为任意 MCU 或 MPU 编译,支持任何 (RT)OS。支持 Make、CMake 和简单文件匹配。
|
||||
- 支持单色、电子墨水、OLED、TFT 显示器,甚至是 PC 显示器。详见 [显示模块](https://docs.lvgl.io/master/main-modules/display/index.html)
|
||||
- 采用 MIT 许可证,可自由用于商业项目。
|
||||
- 仅需 32kB RAM、128kB Flash、一个帧缓冲区,以及至少 1/10 屏幕大小的渲染缓冲。
|
||||
- 支持但不强制要求使用操作系统、外部存储或 GPU。
|
||||
|
||||
**控件、样式、布局等**
|
||||
- 超过 30 个内置 [控件](https://docs.lvgl.io/master/widgets/index.html):按钮、标签、滑块、图表、键盘、仪表、弧形、表格等。
|
||||
- 灵活的 [样式系统](https://docs.lvgl.io/master/common-widget-features/styles/index.html),提供约 100 种属性,可自定义控件任意部分与状态。
|
||||
- [Flexbox](https://docs.lvgl.io/master/common-widget-features/layouts/flex.html) 和 [Grid](https://docs.lvgl.io/master/common-widget-features/layouts/grid.html) 布局引擎可实现自适应布局。
|
||||
- 文本支持 UTF-8 编码,兼容中日韩、泰语、印地语、阿拉伯语、波斯语等。
|
||||
- [数据绑定](https://docs.lvgl.io/master/main-modules/observer/index.html) 模块轻松连接 UI 与应用逻辑。
|
||||
- 渲染引擎支持动画、抗锯齿、不透明度、平滑滚动、阴影、图像变换等。
|
||||
- [强大的 3D 渲染引擎](https://docs.lvgl.io/master/libs/gltf.html),可使用 OpenGL 显示 [glTF 模型](https://sketchfab.com/)。
|
||||
- 支持鼠标、触摸板、按键、键盘、外部按钮、编码器等 [输入设备](https://docs.lvgl.io/master/main-modules/indev.html)。
|
||||
- 支持 [多显示屏](https://docs.lvgl.io/master/main-modules/display/overview.html#how-many-displays-can-lvgl-use)。
|
||||
|
||||
## 📦️ 平台支持
|
||||
|
||||
LVGL 无外部依赖,因此可轻松编译到任何设备,并已被多个包管理器与 RTOS 集成:
|
||||
|
||||
- [Arduino 库](https://docs.lvgl.io/master/integration/framework/arduino.html)
|
||||
- [PlatformIO 包](https://registry.platformio.org/libraries/lvgl/lvgl)
|
||||
- [Zephyr 库](https://docs.lvgl.io/master/integration/os/zephyr.html)
|
||||
- [ESP-IDF (ESP32) 组件](https://components.espressif.com/components/lvgl/lvgl)
|
||||
- [NXP MCUXpresso 组件](https://www.nxp.com/design/software/embedded-software/lvgl-open-source-graphics-library:LITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY)
|
||||
- [NuttX 库](https://docs.lvgl.io/master/integration/os/nuttx.html)
|
||||
- [RT-Thread RTOS](https://docs.lvgl.io/master/integration/os/rt-thread.html)
|
||||
- CMSIS-Pack
|
||||
- [RIOT OS 包](https://doc.riot-os.org/group__pkg__lvgl.html#details)
|
||||
|
||||
## 🚀 LVGL Pro 编辑器
|
||||
|
||||
LVGL Pro 是一套完整的工具,用于高效构建、测试、共享和交付嵌入式 UI。
|
||||
|
||||
它包含四个紧密集成的工具:
|
||||
|
||||
1. **XML 编辑器**:LVGL Pro 的核心。桌面应用,用于通过 XML 构建组件与界面,管理数据绑定、翻译、动画、测试等。了解更多 [XML 格式](https://docs.lvgl.io/master/xml/xml/index.html) 和 [编辑器](https://docs.lvgl.io/master/xml/editor/index.html)。
|
||||
2. **在线预览器**:在浏览器中运行编辑器,打开 GitHub 项目,无需搭建开发环境即可共享。访问 [https://viewer.lvgl.io](https://viewer.lvgl.io)。
|
||||
3. **CLI 工具**:在 CI/CD 中生成 C 代码并运行测试。详见 [此处](https://docs.lvgl.io/master/xml/tools/cli.html)。
|
||||
4. **Figma 插件**:直接从 Figma 同步和提取样式。了解更多 [这里](https://docs.lvgl.io/master/xml/tools/figma.html)。
|
||||
|
||||
这些工具结合在一起,帮助开发者高效构建 UI、可靠测试,并便于团队协作。
|
||||
|
||||
了解更多:https://pro.lvgl.io
|
||||
|
||||
## 🤝 商业服务
|
||||
|
||||
LVGL LLC 提供多种商业服务,助力 UI 开发。凭借超过 15 年的用户界面与图形经验,我们能将你的产品 UI 提升到更高水平。
|
||||
|
||||
- **图形设计**:我们的内部设计师擅长打造美观现代的设计,兼顾产品特性与硬件能力。
|
||||
- **UI 实现**:我们可以基于你提供或我们设计的 UI 进行实现,充分发挥硬件与 LVGL 的潜力。如缺少特定功能或控件,我们也可为你开发。
|
||||
- **咨询与支持**:提供 UI 开发咨询,帮助你避免代价高昂、耗时的错误。
|
||||
- **开发板认证**:为提供开发板或量产套件的企业提供认证服务,展示该板卡的 LVGL 运行能力。
|
||||
|
||||
查看我们的 [演示](https://lvgl.io/demos) 以了解示例。更多信息请访问 [服务页面](https://lvgl.io/services)。
|
||||
|
||||
[联系我们](https://lvgl.io/#contact),告诉我们如何帮助你。
|
||||
|
||||
## 🧑💻 集成 LVGL
|
||||
|
||||
集成 LVGL 非常简单。将其添加到项目中并像其他源文件一样编译即可。
|
||||
配置时复制 `lv_conf_template.h` 为 `lv_conf.h`,启用第一个 `#if 0` 并按需修改配置。
|
||||
(默认配置通常已足够。)LVGL 也支持通过 Kconfig 配置。
|
||||
|
||||
项目中可按以下方式初始化 LVGL 并创建显示和输入设备:
|
||||
|
||||
```c
|
||||
#include "lvgl/lvgl.h" /*定义 LV_LVGL_H_INCLUDE_SIMPLE 可直接使用 "lvgl.h"*/
|
||||
|
||||
#define TFT_HOR_RES 320
|
||||
#define TFT_VER_RES 240
|
||||
|
||||
static uint32_t my_tick_cb(void)
|
||||
{
|
||||
return my_get_millisec();
|
||||
}
|
||||
|
||||
static void my_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
|
||||
{
|
||||
/*将 px_map 写入帧缓冲或显示控制器对应区域*/
|
||||
}
|
||||
|
||||
static void my_touch_read_cb(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
{
|
||||
if(my_touch_is_pressed()) {
|
||||
data->point.x = touchpad_x;
|
||||
data->point.y = touchpad_y;
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
} else {
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
my_hardware_init();
|
||||
|
||||
/*初始化 LVGL*/
|
||||
lv_init();
|
||||
|
||||
/*设置毫秒级时钟回调,用于 LVGL 计时*/
|
||||
lv_tick_set_cb(my_tick_cb);
|
||||
|
||||
/*创建显示对象,用于添加屏幕和控件*/
|
||||
lv_display_t * display = lv_display_create(TFT_HOR_RES, TFT_VER_RES);
|
||||
|
||||
/*添加渲染缓冲,这里假设使用 16 位 RGB565 格式*/
|
||||
static uint8_t buf[TFT_HOR_RES * TFT_VER_RES / 10 * 2];
|
||||
lv_display_set_buffers(display, buf, NULL, sizeof(buf), LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
/*设置刷新回调,将缓冲内容写入显示设备*/
|
||||
lv_display_set_flush_cb(display, my_flush_cb);
|
||||
|
||||
/*创建输入设备用于触摸处理*/
|
||||
lv_indev_t * indev = lv_indev_create();
|
||||
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(indev, my_touch_read_cb);
|
||||
|
||||
/*驱动已就绪,创建 UI*/
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(label, "Hello world");
|
||||
lv_obj_center(label);
|
||||
|
||||
/*循环执行 LVGL 任务*/
|
||||
while(1) {
|
||||
lv_timer_handler();
|
||||
my_sleep_ms(5);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤖 示例
|
||||
|
||||
可在 https://docs.lvgl.io/master/examples.html 查看 100+ 示例。
|
||||
|
||||
在线预览器 https://viewer.lvgl.io/ 也提供了易学的 XML 教程。
|
||||
|
||||
|
||||
### Hello World 按钮事件示例
|
||||
|
||||
<img width="311" height="232" alt="image" src="https://github.com/user-attachments/assets/5948b485-e3f7-4a63-bb21-984381417c4a" />
|
||||
|
||||
<details>
|
||||
<summary>C 代码</summary>
|
||||
|
||||
```c
|
||||
static void button_clicked_cb(lv_event_t * e)
|
||||
{
|
||||
printf("Clicked\n");
|
||||
}
|
||||
|
||||
[...]
|
||||
|
||||
lv_obj_t * button = lv_button_create(lv_screen_active());
|
||||
lv_obj_center(button);
|
||||
lv_obj_add_event_cb(button, button_clicked_cb, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
lv_obj_t * label = lv_label_create(button);
|
||||
lv_label_set_text(label, "Hello from LVGL!");
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>使用 LVGL Pro 的 XML</summary>
|
||||
|
||||
```xml
|
||||
<screen>
|
||||
<view>
|
||||
<lv_button align="center">
|
||||
<event_cb callback="button_clicked_cb" />
|
||||
<lv_label text="Hello from LVGL!" />
|
||||
</lv_button>
|
||||
</view>
|
||||
</screen>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### 带数据绑定的滑块
|
||||
|
||||
<img width="314" height="233" alt="image" src="https://github.com/user-attachments/assets/268db1a0-946c-42e2-aee4-9550bdf5f4f9" />
|
||||
|
||||
<details>
|
||||
<summary>C 代码</summary>
|
||||
|
||||
```c
|
||||
static void my_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
|
||||
{
|
||||
printf("Slider value: %d\n", lv_subject_get_int(subject));
|
||||
}
|
||||
|
||||
[...]
|
||||
|
||||
static lv_subject_t subject_value;
|
||||
lv_subject_init_int(&subject_value, 35);
|
||||
lv_subject_add_observer(&subject_value, my_observer_cb, NULL);
|
||||
|
||||
lv_style_t style_base;
|
||||
lv_style_init(&style_base);
|
||||
lv_style_set_bg_color(&style_base, lv_color_hex(0xff8800));
|
||||
lv_style_set_bg_opa(&style_base, 255);
|
||||
lv_style_set_radius(&style_base, 4);
|
||||
|
||||
lv_obj_t * slider = lv_slider_create(lv_screen_active());
|
||||
lv_obj_center(slider);
|
||||
lv_obj_set_size(slider, lv_pct(80), 16);
|
||||
lv_obj_add_style(slider, &style_base, LV_PART_INDICATOR);
|
||||
lv_obj_add_style(slider, &style_base, LV_PART_KNOB);
|
||||
lv_obj_add_style(slider, &style_base, 0);
|
||||
lv_obj_set_style_bg_opa(slider, LV_OPA_50, 0);
|
||||
lv_obj_set_style_border_width(slider, 3, LV_PART_KNOB);
|
||||
lv_obj_set_style_border_color(slider, lv_color_hex3(0xfff), LV_PART_KNOB);
|
||||
lv_slider_bind_value(slider, &subject_value);
|
||||
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, -30);
|
||||
lv_label_bind_text(label, &subject_value, "Temperature: %d °C");
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>使用 LVGL Pro 的 XML</summary>
|
||||
|
||||
```xml
|
||||
<screen>
|
||||
<styles>
|
||||
<style name="style_base" bg_opa="100%" bg_color="0xff8800" radius="4" />
|
||||
<style name="style_border" border_color="0xfff" border_width="3" />
|
||||
</styles>
|
||||
|
||||
<view>
|
||||
<lv_label bind_text="value" bind_text-fmt="Temperature: %d °C" align="center" y="-30" />
|
||||
<lv_slider align="center" bind_value="value" style_bg_opa="30%">
|
||||
<style name="style_base" />
|
||||
<style name="style_base" selector="knob" />
|
||||
<style name="style_base" selector="indicator" />
|
||||
<style name="style_border" selector="knob" />
|
||||
</lv_slider>
|
||||
</view>
|
||||
</screen>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### 布局中的复选框
|
||||
|
||||
<img width="311" height="231" alt="image" src="https://github.com/user-attachments/assets/ba9af647-2ea1-4bc8-b53d-c7b43ce24b6e" />
|
||||
|
||||
<details>
|
||||
<summary>C 代码</summary>
|
||||
|
||||
```c
|
||||
/*创建新屏幕并加载*/
|
||||
lv_obj_t * scr = lv_obj_create(NULL);
|
||||
lv_screen_load(scr);
|
||||
|
||||
/*设置列布局*/
|
||||
lv_obj_set_flex_flow(scr, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(scr, LV_FLEX_ALIGN_SPACE_EVENLY, /*垂直对齐*/
|
||||
LV_FLEX_ALIGN_START, /*主轴方向对齐*/
|
||||
LV_FLEX_ALIGN_CENTER); /*交叉轴方向对齐*/
|
||||
|
||||
/*创建 5 个复选框*/
|
||||
const char * texts[5] = {"Input 1", "Input 2", "Input 3", "Output 1", "Output 2"};
|
||||
for(int i = 0; i < 5; i++) {
|
||||
lv_obj_t * cb = lv_checkbox_create(scr);
|
||||
lv_checkbox_set_text(cb, texts[i]);
|
||||
}
|
||||
|
||||
/*更改状态*/
|
||||
lv_obj_add_state(lv_obj_get_child(scr, 1), LV_STATE_CHECKED);
|
||||
lv_obj_add_state(lv_obj_get_child(scr, 3), LV_STATE_DISABLED);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>使用 LVGL Pro 的 XML</summary>
|
||||
|
||||
```xml
|
||||
<screen>
|
||||
<view
|
||||
flex_flow="column"
|
||||
style_flex_main_place="space_evenly"
|
||||
style_flex_cross_place="start"
|
||||
style_flex_track_place="center"
|
||||
>
|
||||
<lv_checkbox text="Input 1"/>
|
||||
<lv_checkbox text="Input 2"/>
|
||||
<lv_checkbox text="Input 3" checked="true"/>
|
||||
<lv_checkbox text="Output 1"/>
|
||||
<lv_checkbox text="Output 2" disabled="true"/>
|
||||
</view>
|
||||
</screen>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
## 🌟 贡献
|
||||
|
||||
LVGL 是一个开放项目,欢迎任何形式的贡献。无论是分享你的项目、编写示例、改进文档、修复错误,还是将项目托管到 LVGL 组织下,都非常欢迎。
|
||||
|
||||
更多贡献方式详见 [贡献文档](https://docs.lvgl.io/master/contributing/index.html)。
|
||||
|
||||
已有超过 600 位开发者为 LVGL 留下足迹。加入我们吧!🙂
|
||||
|
||||
<a href="https://github.com/lvgl/lvgl/graphs/contributors"> <img src="https://contrib.rocks/image?repo=lvgl/lvgl&max=48" /> </a>
|
||||
|
||||
……还有更多人。
|
||||
|
||||
BIN
managed_components/lvgl__lvgl/docs/_obsolete/btn_example.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
BIN
managed_components/lvgl__lvgl/docs/_obsolete/codeblocks.jpg
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
managed_components/lvgl__lvgl/docs/_obsolete/eclipse.jpg
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
managed_components/lvgl__lvgl/docs/_obsolete/home_banner.jpg
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
managed_components/lvgl__lvgl/docs/_obsolete/js_calculator.gif
Normal file
|
After Width: | Height: | Size: 519 KiB |
BIN
managed_components/lvgl__lvgl/docs/_obsolete/js_code.png
Normal file
|
After Width: | Height: | Size: 312 KiB |
BIN
managed_components/lvgl__lvgl/docs/_obsolete/js_on_device.jpg
Normal file
|
After Width: | Height: | Size: 189 KiB |
BIN
managed_components/lvgl__lvgl/docs/_obsolete/js_widgets_demo.gif
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
managed_components/lvgl__lvgl/docs/_obsolete/platformio.jpg
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
managed_components/lvgl__lvgl/docs/_obsolete/qtcreator.jpg
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
BIN
managed_components/lvgl__lvgl/docs/_obsolete/sys.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
managed_components/lvgl__lvgl/docs/_obsolete/visualstudio.jpg
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
50
managed_components/lvgl__lvgl/docs/add_translation.py
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
|
||||
"""
|
||||
Please add the translation language you want to add here, while also modifying the variable URL_BASE in _ext/link_roles.py
|
||||
For example:
|
||||
|
||||
LANGUAGE = ':link_to_translation:`zh_CN:[中文]`\t' + \
|
||||
':link_to_translation:`en:[English]`\t' + \
|
||||
'\n\n'
|
||||
|
||||
|
||||
URL_BASE = {
|
||||
"zh_CN": "https://lvgl.100ask.net/",
|
||||
"en": "https://docs.lvgl.io/"
|
||||
}
|
||||
"""
|
||||
|
||||
LANGUAGE = ':link_to_translation:`zh_CN:[中文]`\t' + \
|
||||
'\n\n'
|
||||
|
||||
|
||||
|
||||
def find_files(dir_path, suffix):
|
||||
files = []
|
||||
|
||||
for root, _, filenames in os.walk(dir_path):
|
||||
for filename in filenames:
|
||||
if filename.endswith(suffix):
|
||||
files.append(os.path.join(root, filename))
|
||||
return files
|
||||
|
||||
|
||||
|
||||
def exec(temp_directory):
|
||||
"""
|
||||
files = find_files(temp_directory, '.rst')
|
||||
|
||||
for rst_file in files:
|
||||
with open(rst_file, 'r+', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
f.seek(0, 0)
|
||||
f.write(LANGUAGE + content)
|
||||
"""
|
||||
|
||||
rst_file = os.path.join(temp_directory, 'index.rst')
|
||||
with open(rst_file, 'r+', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
f.seek(0, 0)
|
||||
f.write(LANGUAGE + content)
|
||||
123
managed_components/lvgl__lvgl/docs/announce.py
Normal file
@@ -0,0 +1,123 @@
|
||||
"""announce.py
|
||||
Manage logging announcements to `stdout`
|
||||
|
||||
It is the designer's intention that:
|
||||
|
||||
1. The variable `__file__` be passed as the first argument in
|
||||
`announce()` and `announce_start()`.
|
||||
(Unfortunately, there is no way this author knows of yet to
|
||||
have this module know what Python module is importing it. So
|
||||
this is a hold-over requirement until that need is fulfilled.)
|
||||
|
||||
2. `announce_start()` and `announce_finish()` should be used
|
||||
in pairs like this:
|
||||
|
||||
announce_start(__file__, 'something is running...')
|
||||
# do something that takes a while here
|
||||
announce_finish()
|
||||
|
||||
3. If this is used in a module that sometimes has a need to
|
||||
not have anything output to STDOUT, when that is known,
|
||||
call `announce_set_silent_mode()`. To turn "silent mode"
|
||||
off, call `announce_set_silent_mode(False)`.
|
||||
|
||||
"""
|
||||
import os
|
||||
import datetime
|
||||
|
||||
__all__ = ('announce', 'announce_colored', 'announce_start', 'announce_finish', 'announce_set_silent_mode', 'is_silent_mode')
|
||||
_announce_start_time: datetime.datetime
|
||||
_announce_silent_mode: bool = False
|
||||
_console_color_commands = {
|
||||
'default' : '\x1b[0m',
|
||||
'black' : '\x1b[30m',
|
||||
'red' : '\x1b[31m',
|
||||
'green' : '\x1b[32m',
|
||||
'yellow' : '\x1b[33m',
|
||||
'blue' : '\x1b[34m',
|
||||
'majenta' : '\x1b[35m',
|
||||
'cyan' : '\x1b[36m',
|
||||
'white' : '\x1b[37m',
|
||||
'bright_black' : '\x1b[90m',
|
||||
'bright_red' : '\x1b[91m',
|
||||
'bright_green' : '\x1b[92m',
|
||||
'bright_yellow' : '\x1b[93m',
|
||||
'bright_blue' : '\x1b[94m',
|
||||
'bright_majenta': '\x1b[95m',
|
||||
'bright_cyan' : '\x1b[96m',
|
||||
'bright_white' : '\x1b[97m'
|
||||
}
|
||||
|
||||
|
||||
def _announce(file: str, args: tuple, start: bool, box: bool, box_char: str):
|
||||
if _announce_silent_mode:
|
||||
return
|
||||
|
||||
_args = []
|
||||
|
||||
for arg in args:
|
||||
# Avoid the single quotes `repr()` puts around strings.
|
||||
if type(arg) is str:
|
||||
_args.append(arg)
|
||||
else:
|
||||
_args.append(repr(arg))
|
||||
|
||||
msg = f'{os.path.basename(file)}: ' + ' '.join(_args)
|
||||
msg_len = len(msg)
|
||||
|
||||
# `start` takes precedence over `box` argument.
|
||||
if start:
|
||||
print(msg, end='', flush=True)
|
||||
else:
|
||||
if box:
|
||||
line = box_char * msg_len
|
||||
print(line)
|
||||
print(msg)
|
||||
print(line, flush=True)
|
||||
else:
|
||||
print(msg, flush=True)
|
||||
|
||||
|
||||
def announce(file: str, *args, box: bool = False, box_char: str = '*'):
|
||||
global _announce_start_time
|
||||
_announce_start_time = None
|
||||
_announce(file, args, False, box, box_char)
|
||||
|
||||
|
||||
def announce_colored(file: str, clr: str, *args, box: bool = False, box_char: str = '*'):
|
||||
global _announce_start_time
|
||||
_announce_start_time = None
|
||||
if len(args) > 0 and clr in _console_color_commands:
|
||||
# Tuples are non-mutable so we have to build a new one -- can't insert new elements.
|
||||
new_args_tuple = (_console_color_commands[clr],) + args + (_console_color_commands['default'],)
|
||||
_announce(file, new_args_tuple, False, box, box_char)
|
||||
else:
|
||||
_announce(file, args, False, box, box_char)
|
||||
|
||||
|
||||
def announce_start(file: str, *args, box: bool = False, box_char: str = '*'):
|
||||
global _announce_start_time
|
||||
_announce_start_time = datetime.datetime.now()
|
||||
_announce(file, args, True, box, box_char)
|
||||
|
||||
|
||||
def announce_finish():
|
||||
# Just output line ending to terminate output for `announce_start()`.
|
||||
global _announce_start_time
|
||||
if _announce_start_time is not None:
|
||||
if not _announce_silent_mode:
|
||||
print(' Elapsed: ', datetime.datetime.now() - _announce_start_time, flush=True)
|
||||
_announce_start_time = None
|
||||
else:
|
||||
if not _announce_silent_mode:
|
||||
print(flush=True)
|
||||
|
||||
|
||||
def announce_set_silent_mode(mode=True):
|
||||
global _announce_silent_mode
|
||||
_announce_silent_mode = mode
|
||||
|
||||
|
||||
def is_silent_mode(mode=True):
|
||||
global _announce_silent_mode
|
||||
return _announce_silent_mode
|
||||
896
managed_components/lvgl__lvgl/docs/api_doc_builder.py
Normal file
@@ -0,0 +1,896 @@
|
||||
"""api_doc_builder.py
|
||||
|
||||
Create and provide links to API pages in LVGL doc build.
|
||||
|
||||
Uses doxygen_xml.py module to:
|
||||
|
||||
- Prep and run Doxygen,
|
||||
- make Doxygen XML output available, and
|
||||
- make Doxygen-documented symbols from the C code available.
|
||||
|
||||
Because these 5 files are acceptable in a C project:
|
||||
|
||||
1. ./path/to/one/aaa.c
|
||||
2. ./path/to/one/aaa.h
|
||||
3. ./path/to/one/aaa.cpp
|
||||
4. ./path/to/one/aaa.hpp
|
||||
5. ./path/to/another/aaa.h
|
||||
|
||||
we see that:
|
||||
|
||||
- duplicate filename stems ('aaa' above) are acceptable, and
|
||||
- they must not only be differentiated by their extensions, but also by their path.
|
||||
|
||||
On the other hand, Sphinx link target names for :ref:`link_ref_name` link
|
||||
target names must be unique throughout a document project. Since API pages are
|
||||
generated from C source files, to make this effective, they must include:
|
||||
|
||||
A. at least part of the path,
|
||||
B. filename stem, and
|
||||
C. extension
|
||||
|
||||
in the link target names. Prior to 11-Aug-2025, link target names were formed
|
||||
using ONLY the filename stem. This created a conflict when an example of #4 above
|
||||
appeared in the LVGL code, and caused a doc-build failure because the API-page link
|
||||
target names to #2 and #4 were identical, and Sphinx (correctly) does not allow
|
||||
that. So after 11-Aug-2025, these link target names are now differentiated via all 3
|
||||
of A, B and C above.
|
||||
|
||||
.. note::
|
||||
|
||||
Since they are generated and dealt with programmatically, using the full path
|
||||
[below the docs source directory] will not be a problem. Even though it makes
|
||||
the names long, they never have to be hand-typed.
|
||||
|
||||
Likewise, API-page ``.rst`` filename stems also need to be unique within the directory
|
||||
they are in, so the stems must contain the C source file's filename stem plus the
|
||||
extension in them, in order to be unique in that directory, since they *must* end in
|
||||
``.rst``.
|
||||
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import doxygen_xml
|
||||
from announce import *
|
||||
|
||||
old_html_files = {}
|
||||
EMIT_WARNINGS = True
|
||||
rst_section_line_char = '='
|
||||
on_windows = (( os.name == 'nt' ))
|
||||
# `doxy_src_file_ext_list` must
|
||||
# - match the extensions in the Doxyfile FILE_PATTERNS list, and
|
||||
# - be in lower case.
|
||||
doxy_src_file_ext_list = [
|
||||
'.h',
|
||||
'.hh',
|
||||
'.hxx',
|
||||
'.hpp',
|
||||
'.h++'
|
||||
]
|
||||
|
||||
# Excluded from doxygen via EXCLUDE config item. (This config
|
||||
# item is set in `doxygen_xml.py`.)
|
||||
_cfg_exclude_list = ['lv_conf_internal.h']
|
||||
|
||||
# Multi-line match ``API + newline + \*\*\* + whitespace``.
|
||||
# NB: the ``\s*`` at the end forces the regex to match the whitespace
|
||||
# at the end including all \r\n's. This will match UP TO:
|
||||
# - the next non-blank character (could be many blank lines), or
|
||||
# - to the end of the file, whichever comes first.
|
||||
_re_api_section_sep = re.compile(r'(?mi)^API *\r?\n^\*\*\*\s*')
|
||||
|
||||
# Regex to identify '.. API equals: lv_obj_t, lv_array_t' directives.
|
||||
_re_api_equals = re.compile(r'(?mi)^\s*\.\.\s+API\s+equals:\s*([\w,\s]+)')
|
||||
|
||||
# Regex to identify '.. API startswith: lv_obj, lv_array' directives.
|
||||
_re_api_startswith = re.compile(r'(?mi)^\s*\.\.\s+API\s+startswith:\s*([\w,\s]+)')
|
||||
|
||||
# Regex to match comma and whitespace list-item separators on multiple lines.
|
||||
_re_multi_line_comma_sep = re.compile(r'(?m)[,\s]+')
|
||||
|
||||
# Regex to identify editor-added hyperlinks: :ref:`lv_obj_h`
|
||||
_re_editor_added_hyperlink = re.compile(r'^\s*:ref:`([\w/\.]+)`')
|
||||
|
||||
# Separator to mark place where this script added hyperlinks.
|
||||
_auto_gen_sep = '.. Autogenerated'
|
||||
|
||||
# List of symbol dictionaries
|
||||
_defines = {}
|
||||
_enums = {}
|
||||
_variables = {}
|
||||
_namespaces = {}
|
||||
_structs = {}
|
||||
_unions = {}
|
||||
_typedefs = {}
|
||||
_functions = {}
|
||||
|
||||
_symbol_dict_list = [
|
||||
_defines,
|
||||
_enums,
|
||||
_variables,
|
||||
_namespaces,
|
||||
_structs,
|
||||
_unions,
|
||||
_typedefs,
|
||||
_functions
|
||||
]
|
||||
|
||||
|
||||
def old_clean_name(nme):
|
||||
"""Strip beginning "_lv" and ending "_t"."""
|
||||
# Handle error:
|
||||
# AttributeError: 'NoneType' object has no attribute 'startswith'
|
||||
if nme is None:
|
||||
return nme
|
||||
|
||||
if nme.startswith('_lv_'):
|
||||
nme = nme[4:]
|
||||
elif nme.startswith('lv_'):
|
||||
nme = nme[3:]
|
||||
|
||||
if nme.endswith('_t'):
|
||||
nme = nme[:-2]
|
||||
|
||||
return nme
|
||||
|
||||
|
||||
# Definitions:
|
||||
# - "section" => The name "abc_def" has 2 sections.
|
||||
# - N = number of sections in `item_name`.
|
||||
# After removing leading '_lv_', 'lv_' and trailing '_t' from `obj_name`,
|
||||
# do the remaining first N "sections" of `obj_name` match `item_name`
|
||||
# (case sensitive)?
|
||||
def old_is_name_match(item_name, obj_name):
|
||||
# Handle error:
|
||||
# AttributeError: 'NoneType' object has no attribute 'split'
|
||||
if obj_name is None:
|
||||
return False
|
||||
|
||||
sect_count = item_name.count('_') + 1
|
||||
|
||||
obj_name = obj_name.split('_')
|
||||
|
||||
# Reject (False) if `obj_name` doesn't have as many sections as `item_name`.
|
||||
if len(obj_name) < sect_count:
|
||||
return False
|
||||
|
||||
obj_name = '_'.join(obj_name[:sect_count])
|
||||
|
||||
return item_name == obj_name
|
||||
|
||||
|
||||
def old_get_includes(name1, name2, obj, includes):
|
||||
name2 = old_clean_name(name2)
|
||||
|
||||
if not old_is_name_match(name1, name2):
|
||||
return
|
||||
|
||||
if obj.parent is not None and hasattr(obj.parent, 'header_file'):
|
||||
header_file = obj.parent.header_file
|
||||
elif hasattr(obj, 'header_file'):
|
||||
header_file = obj.header_file
|
||||
else:
|
||||
return
|
||||
|
||||
if not header_file:
|
||||
return
|
||||
|
||||
if header_file not in old_html_files:
|
||||
return
|
||||
|
||||
includes.add((header_file, old_html_files[header_file]))
|
||||
|
||||
|
||||
def _conditionally_add_hyperlink(obj, genned_link_set: set, exclude_set: set):
|
||||
"""
|
||||
Add hyperlink names to `link_set` if:
|
||||
- not in `exclude_set`, and
|
||||
- not already in `link_set`.
|
||||
:param obj: "thing" from dictionary with matching symbol.
|
||||
These are objects instantiated from classes
|
||||
in `doxygen_xml` module such as
|
||||
STRUCT, FUNCTION, DEFINE, ENUMVALUE, etc.
|
||||
:param genned_link_set: Set in which to accumulate link names
|
||||
:param exclude_set: Set with link names not to add to `link_set`
|
||||
:return:
|
||||
"""
|
||||
if obj.file_name is not None:
|
||||
# The link name should look like this: draw/sw/blend/lv_draw_sw_blend.h
|
||||
# including when running under Windows.
|
||||
# `obj.file_name` contains a path that looks like this:
|
||||
# '/path/to/lvgl/src/draw/sw/blend/lv_draw_sw_blend.h'
|
||||
# Note: we can't use 'lvgl/src' because there is no guarantee
|
||||
# that the user's LVGL repo directory will be called that.
|
||||
src_root = '/src/'
|
||||
i = obj.file_name.index(src_root) + len(src_root)
|
||||
link_name = obj.file_name[i:]
|
||||
if link_name not in genned_link_set:
|
||||
if link_name not in exclude_set:
|
||||
genned_link_set.add(link_name)
|
||||
|
||||
|
||||
def _add_startswith_matches(strings: [str], genned_link_set, editor_link_set):
|
||||
"""
|
||||
Add set of hyperlinks to `genned_link_set` that are not already in
|
||||
`editor_link_set`, for C symbols that start with strings in `strings`.
|
||||
|
||||
:param strings: List of strings to match against
|
||||
:param genned_link_set: Generated link set
|
||||
:param editor_link_set: Hyperlinks added by editor
|
||||
:return: n/a
|
||||
"""
|
||||
for partial_symbol in strings:
|
||||
for symbol_dict in _symbol_dict_list:
|
||||
for key in symbol_dict:
|
||||
if key is None:
|
||||
# Dictionary `enums` has a key `None` which contains
|
||||
# all enum values from all unnamed enums, and each
|
||||
# enum value has a `file_name` field.
|
||||
enum_values_list = symbol_dict[None].members
|
||||
for enum_val in enum_values_list:
|
||||
if enum_val.name.startswith(partial_symbol):
|
||||
_conditionally_add_hyperlink(enum_val, genned_link_set, editor_link_set)
|
||||
else:
|
||||
if key.startswith(partial_symbol):
|
||||
obj = symbol_dict[key]
|
||||
_conditionally_add_hyperlink(obj, genned_link_set, editor_link_set)
|
||||
|
||||
|
||||
def _add_exact_matches(symbols: [str], genned_link_set, editor_link_set):
|
||||
"""
|
||||
Add set of hyperlinks to `genned_link_set` that are not already in
|
||||
`editor_link_set`, for exact C symbol matches.
|
||||
|
||||
:param symbols: List of C symbols to match against
|
||||
:param genned_link_set: Generated link set
|
||||
:param editor_link_set: Hyperlinks added by editor
|
||||
:return: n/a
|
||||
"""
|
||||
for symbol in symbols:
|
||||
for symbol_dict in _symbol_dict_list:
|
||||
if symbol in symbol_dict:
|
||||
obj = symbol_dict[symbol]
|
||||
_conditionally_add_hyperlink(obj, genned_link_set, editor_link_set)
|
||||
|
||||
|
||||
def _hyperlink_sort_value(init_value: str):
|
||||
if init_value.endswith('.h'):
|
||||
result = init_value[:-2]
|
||||
else:
|
||||
result = init_value
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _process_end_of_eligible_doc(b: str, rst_file: str) -> (str, str, int):
|
||||
"""
|
||||
Edit end section after API section heading.
|
||||
|
||||
3. Initialize:
|
||||
- links_added_count = 0
|
||||
- editor_link_set = set()
|
||||
- genned_link_set = set()
|
||||
- C = '' # string for generated hyperlinks
|
||||
4. Remove `_auto_gen_sep` and everything after it:
|
||||
- new_B = B.split(_auto_gen_sep, 1)[0]
|
||||
5. With `new_B, add any editor-added hyperlinks to set:
|
||||
`editor_link_set`.
|
||||
6. If `_re_api_equals` match present:
|
||||
- build list of symbols
|
||||
- compute list of hyperlinks from symbols
|
||||
- add hyperlinks to `genned_link_set` if not in `editor_link_set`.
|
||||
7. If `_re_api_startswith` match present:
|
||||
- build list of symbols
|
||||
- compute list of hyperlinks from symbols
|
||||
- add hyperlinks to `genned_link_set` if not in `editor_link_set`.
|
||||
8. Lacking either of the above custom directives, use the lower-case
|
||||
stem of the filename and prefix it with "lv_" and try an
|
||||
"API startswith" search with it.
|
||||
9. If len(genned_link_set) > 0:
|
||||
- `C` = _auto_gen_sep + '\n\n' + `genned_link_set`
|
||||
(with a blank line between each).
|
||||
10. Return tuple: (new_B, C, links_added_count).
|
||||
|
||||
:param b: End of document after API section heading + whitespace.
|
||||
:return: Tuple: (new_B, C, links_added_count)
|
||||
"""
|
||||
# 3. Initialize:
|
||||
editor_link_set = set()
|
||||
genned_link_set = set()
|
||||
c = ''
|
||||
api_directives_found_count = 0
|
||||
|
||||
# 4. Remove `_auto_gen_sep` and everything after it:
|
||||
new_b = b.split(_auto_gen_sep, 1)[0]
|
||||
|
||||
# 5. With `new_b`, add any editor-added hyperlinks to set:
|
||||
# `editor_link_set`.
|
||||
for line in new_b.splitlines():
|
||||
match = _re_editor_added_hyperlink.match(line)
|
||||
if match is not None:
|
||||
editor_link_set.add(match[1])
|
||||
|
||||
# 6. If `_re_api_equals` present:
|
||||
# - build list of symbols
|
||||
# - compute list of hyperlinks from symbols
|
||||
# - add hyperlinks to `genned_link_set` if not in `editor_link_set`.
|
||||
match = _re_api_equals.search(new_b)
|
||||
if match is not None:
|
||||
api_directives_found_count += 1
|
||||
comma_sep_list = match[1].strip()
|
||||
symbols = _re_multi_line_comma_sep.split(comma_sep_list)
|
||||
_add_exact_matches(symbols, genned_link_set, editor_link_set)
|
||||
|
||||
# 7. If `_re_api_startswith` present:
|
||||
# - build list of symbols
|
||||
# - compute list of hyperlinks from symbols
|
||||
# - add hyperlinks to `genned_link_set` if not in `editor_link_set`.
|
||||
match = _re_api_startswith.search(new_b)
|
||||
if match is not None:
|
||||
api_directives_found_count += 1
|
||||
comma_sep_list = match[1].strip()
|
||||
symbols = _re_multi_line_comma_sep.split(comma_sep_list)
|
||||
_add_startswith_matches(symbols, genned_link_set, editor_link_set)
|
||||
|
||||
# 8. Lacking either of the above custom directives, use the lower-case
|
||||
# stem of the filename and prefix it with "lv_" and try an
|
||||
# "API startswith" with it.
|
||||
if api_directives_found_count == 0:
|
||||
base = os.path.basename(rst_file)
|
||||
stem = os.path.splitext(base)[0]
|
||||
_add_startswith_matches(['lv_' + stem], genned_link_set, editor_link_set)
|
||||
|
||||
# 9. If len(genned_link_set) > 0:
|
||||
# - `C` = _auto_gen_sep + '\n\n' + `genned_link_set`
|
||||
# (with a blank line between each).
|
||||
links_added_count = len(genned_link_set)
|
||||
|
||||
if links_added_count > 0:
|
||||
c = '\n' + _auto_gen_sep + '\n\n'
|
||||
for link_name in sorted(genned_link_set, key=_hyperlink_sort_value):
|
||||
c += ':ref:`' + link_name + '`\n\n'
|
||||
|
||||
# 10. Return tuple: (new_B, C, links_added_count).
|
||||
return new_b, c, links_added_count
|
||||
|
||||
|
||||
def _process_one_file(rst_file: str):
|
||||
"""
|
||||
Add applicable API hyperlinks to one file.
|
||||
|
||||
Eligible
|
||||
An `.rst` file is eligible if it contains an API section at
|
||||
its end. This can happen also in `index.rst` files when
|
||||
they head a single subject for which an API section is
|
||||
appropriate there and not in the sub-docs. So `index.rst`
|
||||
files are included, whereas they were not included previously.
|
||||
|
||||
Algorithm:
|
||||
----------
|
||||
A. Doc editors may have already added a set of hyperlinks of their
|
||||
own. This routine takes note of and does not duplicate what is
|
||||
already there.
|
||||
|
||||
B. Doc editors may also have added specifications for this routine
|
||||
that look like this:
|
||||
|
||||
.. API equals: lv_obj_t, lv_arc_t, lv_barcode_t,
|
||||
lv_win_t, lv_list_t,
|
||||
lv_button_t
|
||||
|
||||
.. API startswith: lv_obj, lv_arc, lv_barcode,
|
||||
lv_win, lv_list,
|
||||
lv_button
|
||||
|
||||
as directives for this routine to build a set of applicable
|
||||
hyperlinks.
|
||||
|
||||
C. Lacking any of the above custom directives, use the lower-case
|
||||
stem of the filename and prefix it with "lv_" and try an
|
||||
"API startswith" search with it.
|
||||
|
||||
Any hyperlinks added by this routine are prefixed with the
|
||||
reStructuredText comment defined by the `_auto_gen_sep`
|
||||
variable, normally:
|
||||
|
||||
.. Autogenerated
|
||||
|
||||
If `rst_file` is eligible, edit after API section heading such that:
|
||||
- any editor-added hyperlinks are retained at the top of the list;
|
||||
- `_auto_gen_sep` (looked for in case a source file ends up having it;
|
||||
anything after it is replaced);
|
||||
- applicable hyperlinks added such that they do not repeat those
|
||||
added by editors of `.rst` file.
|
||||
|
||||
Steps to Implement:
|
||||
-------------------
|
||||
0. links_added_count = 0
|
||||
1. Determine if eligible.
|
||||
- If not, skip to step 12.
|
||||
- If so, continue.
|
||||
2. Split doc into 2 parts:
|
||||
A. beginning through API section heading and subsequent
|
||||
whitespace including subsequent blank lines;
|
||||
B. anything after that which may include editor-added hyperlinks.
|
||||
3-10. new_B, C, links_added_count = _process_end_of_eligible_doc()
|
||||
11. Write `A` + `new_B` + `C` back to `rst_file`.
|
||||
12. Return links_added_count.
|
||||
|
||||
:param rst_file: Full path to `.rst` file in question.
|
||||
It may or may not be eligible.
|
||||
:return: Number of links added.
|
||||
"""
|
||||
links_added_count = 0
|
||||
|
||||
with open(rst_file, 'rb') as f:
|
||||
try:
|
||||
rst_contents = f.read().decode('utf-8')
|
||||
except UnicodeDecodeError:
|
||||
announce(__file__, f'Error: UnicodeDecodeError in [{rst_file}].')
|
||||
raise
|
||||
|
||||
eligible_match = _re_api_section_sep.search(rst_contents)
|
||||
|
||||
if eligible_match is not None:
|
||||
# Eligible (API section found).
|
||||
i = eligible_match.end()
|
||||
# Split just after the API section heading + whitespace.
|
||||
a = rst_contents[:i]
|
||||
b = rst_contents[i:]
|
||||
new_b, c, links_added_count = _process_end_of_eligible_doc(b, rst_file)
|
||||
|
||||
if links_added_count > 0:
|
||||
rst_contents = a + new_b + c
|
||||
|
||||
with open(rst_file, 'wb') as f:
|
||||
f.write(rst_contents.encode('utf-8'))
|
||||
|
||||
return links_added_count
|
||||
|
||||
|
||||
def _build_one_local_dictionary(local_dict, remote_dict):
|
||||
"""
|
||||
Remove '_' prefix in symbols beginning with '_lv' to make
|
||||
symbols like `lv_obj_t` actually connect with the struct
|
||||
in `lv_obj_private.h`, and not the typedef in `lv_types.h`.
|
||||
|
||||
:param local_dict: Local (adjusted) symbol dictionary
|
||||
:param remote_dict: Dictionary from `doxygen_xml` module
|
||||
:return: n/a
|
||||
"""
|
||||
for symbol in remote_dict:
|
||||
# Note: symbol `None` is actually a valid symbol in the
|
||||
# `enums` dictionary, containing all enum-value symbols
|
||||
# for enums without names.
|
||||
if symbol is None or not symbol.startswith('_lv'):
|
||||
loc_symbol = symbol
|
||||
else:
|
||||
# Remove '_' prefix.
|
||||
loc_symbol = symbol[1:]
|
||||
|
||||
local_dict[loc_symbol] = remote_dict[symbol]
|
||||
|
||||
|
||||
def _build_local_symbol_dictionaries():
|
||||
"""
|
||||
Build "work-around" dictionaries so that a symbol like `lv_obj_t`
|
||||
actually connects with the struct in `lv_obj_private.h`, and not
|
||||
the typedef in `lv_types.h`.
|
||||
|
||||
:return: n/a
|
||||
"""
|
||||
_build_one_local_dictionary(_defines, doxygen_xml.defines)
|
||||
_build_one_local_dictionary(_enums, doxygen_xml.enums)
|
||||
_build_one_local_dictionary(_variables, doxygen_xml.variables)
|
||||
_build_one_local_dictionary(_namespaces, doxygen_xml.namespaces)
|
||||
_build_one_local_dictionary(_structs, doxygen_xml.structures)
|
||||
_build_one_local_dictionary(_unions, doxygen_xml.unions)
|
||||
_build_one_local_dictionary(_typedefs, doxygen_xml.typedefs)
|
||||
_build_one_local_dictionary(_functions, doxygen_xml.functions)
|
||||
|
||||
|
||||
def _add_hyperlinks_to_eligible_files(intermediate_dir: str,
|
||||
new_algorithm: bool,
|
||||
*doc_rel_paths: [str]):
|
||||
"""
|
||||
Add applicable hyperlinks to eligible docs found joining
|
||||
`intermediate_dir` with each relative path in `doc_rel_paths`.
|
||||
|
||||
See API-link algorithm documented under `_process_one_file()`.
|
||||
|
||||
:param intermediate_dir: Top directory where hyperlinks are to be added.
|
||||
:param doc_rel_paths: Tuple of relative paths from `intermediate_dir` to
|
||||
walk to find docs eligible for API hyperlinks.
|
||||
:return:
|
||||
"""
|
||||
if new_algorithm:
|
||||
# Populate local symbol dictionary set with
|
||||
# symbols WITHOUT any '_' prefixes.
|
||||
_build_local_symbol_dictionaries()
|
||||
|
||||
# Build `.rst` file list.
|
||||
file_list = []
|
||||
|
||||
for rel_path in doc_rel_paths:
|
||||
top_dir = os.path.join(intermediate_dir, rel_path)
|
||||
for dir_bep, sub_dirs, files in os.walk(top_dir, topdown=False):
|
||||
for file in files:
|
||||
if file.lower().endswith('.rst'):
|
||||
file_list.append(os.path.join(dir_bep, file))
|
||||
|
||||
total_eligible_doc_count = 0
|
||||
total_links_added_count = 0
|
||||
|
||||
# For each `.rst` file, add appropriate API hyperlinks.
|
||||
for rst_file in file_list:
|
||||
links_added_count = _process_one_file(rst_file)
|
||||
|
||||
if links_added_count > 0:
|
||||
total_links_added_count += links_added_count
|
||||
total_eligible_doc_count += 1
|
||||
# announce(__file__, f'Eligible doc: [{rst_file}].')
|
||||
|
||||
announce(__file__, f'Docs eligible for API hyperlinks: {total_eligible_doc_count:>4}')
|
||||
announce(__file__, f'API hyperlinks added : {total_links_added_count:>4}')
|
||||
else:
|
||||
for folder in doc_rel_paths:
|
||||
# Fetch a list of '.rst' files excluding 'index.rst'.
|
||||
rst_files = list(
|
||||
(os.path.splitext(item)[0], os.path.join(folder, item))
|
||||
for item in os.listdir(folder)
|
||||
if item.endswith('.rst') and 'index.rst' not in item
|
||||
)
|
||||
|
||||
# For each .RST file in that directory...
|
||||
for stem, path in rst_files:
|
||||
# Start with an empty set.
|
||||
html_includes = set()
|
||||
|
||||
# Build `html_includes` set as a list of tuples containing
|
||||
# (name, html_file). Example: "draw.rst" has `stem` == 'draw',
|
||||
# and generates a list of tuples from .H files where matching
|
||||
# C-code-element names were found. Example:
|
||||
# {('lv_draw_line', 'draw\\lv_draw_line.html'),
|
||||
# ('lv_draw_sdl', 'draw\\sdl\\lv_draw_sdl.html'),
|
||||
# ('lv_draw_sw_blend_to_i1', 'draw\\sw\\blend\\lv_draw_sw_blend_to_i1.html'),
|
||||
# etc.}
|
||||
for symbol_dict in (
|
||||
doxygen_xml.defines,
|
||||
doxygen_xml.enums,
|
||||
doxygen_xml.variables,
|
||||
doxygen_xml.namespaces,
|
||||
doxygen_xml.structures,
|
||||
doxygen_xml.unions,
|
||||
doxygen_xml.typedefs,
|
||||
doxygen_xml.functions
|
||||
):
|
||||
for key, obj in symbol_dict.items():
|
||||
old_get_includes(stem, key, obj, html_includes)
|
||||
|
||||
if html_includes:
|
||||
# Convert `html_includes` set to a list of strings containing the
|
||||
# Sphinx hyperlink syntax "link target names". Example from above:
|
||||
# [':ref:`lv_draw_line_h`\n',
|
||||
# ':ref:`lv_draw_sdl_h`\n',
|
||||
# ':ref:`lv_draw_sw_blend_to_i1_h`\n',
|
||||
# etc.]
|
||||
html_includes = list(
|
||||
':ref:`{0}_h`\n'.format(inc)
|
||||
for inc, _ in html_includes
|
||||
)
|
||||
|
||||
# Convert that list to a single string of Sphinx hyperlink
|
||||
# target names with blank lines between them.
|
||||
# :ref:`lv_draw_line_h`
|
||||
#
|
||||
# :ref:`lv_draw_sdl_h`
|
||||
#
|
||||
# :ref:`lv_draw_sw_blend_to_i1_h`
|
||||
#
|
||||
# etc.
|
||||
output = ('\n'.join(html_includes)) + '\n'
|
||||
|
||||
# Append that string to the source .RST file being processed.
|
||||
with open(path, 'rb') as f:
|
||||
try:
|
||||
data = f.read().decode('utf-8')
|
||||
except UnicodeDecodeError:
|
||||
print(path)
|
||||
raise
|
||||
|
||||
data = data.split(_auto_gen_sep, 1)[0]
|
||||
|
||||
data += f'{_auto_gen_sep}\n\n'
|
||||
data += output
|
||||
|
||||
with open(path, 'wb') as f:
|
||||
f.write(data.encode('utf-8'))
|
||||
|
||||
|
||||
def _extended_stem_from_path(path: str) -> str:
|
||||
filename = os.path.basename(path)
|
||||
stem, ext = os.path.splitext(filename)
|
||||
return stem + '_' + ext[1:] # Remove leading '.' from ext.
|
||||
|
||||
|
||||
def _create_rst_files_for_dir(src_root_dir_len: int,
|
||||
src_dir_bep: str,
|
||||
elig_h_files: [str],
|
||||
elig_sub_dirs: [str],
|
||||
out_root_dir: str):
|
||||
"""
|
||||
- Create `index.rst` file and add its top section.
|
||||
- For each file in `elig_h_files`:
|
||||
- Create one `.rst` file.
|
||||
- Add reference to it in `index.rst`.
|
||||
- For each subdir in `elig_sub_dirs`:
|
||||
- add reference "sub_dir_name/index" in `index.rst`.
|
||||
|
||||
:param src_root_dir_len: Length of source-root path string, used with `out_root_dir` to build paths
|
||||
Example: 17
|
||||
:param src_dir_bep: Directory currently *being processed*
|
||||
Example: '/path/to/lvgl/src/draw/sw/blend'
|
||||
:param elig_h_files: Eligible `.h*` files directly contained in `src_dir_bep`
|
||||
Example: [] or
|
||||
[
|
||||
'/path/to/lvgl/src/draw/sw/blend/lv_draw_sw_blend.h',
|
||||
'/path/to/lvgl/src/draw/sw/blend/lv_draw_sw_blend_private.h',
|
||||
'/path/to/lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_al88.h',
|
||||
'/path/to/lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_argb8888.h',
|
||||
'/path/to/lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_argb8888_premultiplied.h',
|
||||
'/path/to/lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_i1.h',
|
||||
'/path/to/lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_l8.h',
|
||||
'/path/to/lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_rgb565.h',
|
||||
'/path/to/lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_rgb565_swapped.h',
|
||||
'/path/to/lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_rgb888.h'
|
||||
]
|
||||
:param elig_sub_dirs: List of sub-dirs that contained eligible `.h*` files
|
||||
Example: [] or
|
||||
[
|
||||
'/path/to/lvgl/src/draw/sw/blend/arm2d',
|
||||
'/path/to/lvgl/src/draw/sw/blend/helium',
|
||||
'/path/to/lvgl/src/draw/sw/blend/neon'
|
||||
]
|
||||
:param out_root_dir: Root of output directory, used with to build paths.
|
||||
Example: '/path/to/lvgl/src/docs/intermediate/API'
|
||||
:return: n/a
|
||||
"""
|
||||
indent = ' '
|
||||
# Keep only sub-path under 'lvgl/src/'.
|
||||
# Example: 'draw/sw/blend'
|
||||
sub_path = src_dir_bep[src_root_dir_len:]
|
||||
# Build full path to output directory for 'index.rst' file.
|
||||
# Example: '/path/to/lvgl/src/docs/intermediate/API/draw/sw/blend'
|
||||
out_dir = str(os.path.join(out_root_dir, sub_path))
|
||||
|
||||
# Ensure dir exists. Multiple dirs MAY have to be created
|
||||
# since `.rst` files are created in bottom-up sequence.
|
||||
if not os.path.isdir(out_dir):
|
||||
os.makedirs(out_dir)
|
||||
|
||||
# For top-level directory only... (the last index.rst created,
|
||||
# since they are created in bottom-up sequence)
|
||||
if len(sub_path) == 0 and out_dir.endswith(os.sep):
|
||||
# Trim trailing slash from `out_dir`.
|
||||
out_dir = out_dir[:-1]
|
||||
|
||||
# index.rst
|
||||
with open(os.path.join(out_dir, 'index.rst'), 'w') as f:
|
||||
subdir_stem = os.path.split(out_dir)[-1]
|
||||
section_line = (rst_section_line_char * len(subdir_stem)) + '\n'
|
||||
f.write(section_line)
|
||||
f.write(subdir_stem + '\n')
|
||||
f.write(section_line)
|
||||
f.write('\n')
|
||||
f.write('.. toctree::\n :maxdepth: 1\n :class: toctree-1-deep\n\n')
|
||||
|
||||
# One entry per `.rst` file
|
||||
for h_file in elig_h_files:
|
||||
extended_stem = _extended_stem_from_path(h_file)
|
||||
f.write(indent + extended_stem + '\n')
|
||||
|
||||
# One entry per eligible subdirectory.
|
||||
for sub_dir in elig_sub_dirs:
|
||||
stem = os.path.split(sub_dir)[-1]
|
||||
f.write(indent + stem + '/index\n')
|
||||
|
||||
# One .rst file per h_file
|
||||
for h_file in elig_h_files:
|
||||
filename = os.path.basename(h_file)
|
||||
extended_stem = _extended_stem_from_path(h_file)
|
||||
rst_file = os.path.join(out_dir, extended_stem + '.rst')
|
||||
html_file = os.path.join(sub_path, extended_stem + '.html')
|
||||
old_html_files[extended_stem] = html_file
|
||||
|
||||
with open(rst_file, 'w') as f:
|
||||
# Sphinx link target.
|
||||
# The link name should look like this: draw/sw/blend/lv_draw_sw_blend.h
|
||||
# including when running under Windows.
|
||||
if on_windows:
|
||||
link_name_path = sub_path.replace(os.sep, '/')
|
||||
else:
|
||||
link_name_path = sub_path
|
||||
|
||||
if len(link_name_path) > 0:
|
||||
link_name = link_name_path + '/' + filename
|
||||
else:
|
||||
link_name = filename
|
||||
|
||||
line = f'.. _{link_name}:\n\n'
|
||||
|
||||
f.write(line)
|
||||
# Doc title.
|
||||
section_line = (rst_section_line_char * len(filename)) + '\n'
|
||||
f.write(section_line)
|
||||
f.write(filename + '\n')
|
||||
f.write(section_line)
|
||||
f.write('\n')
|
||||
# Content for `breathe`.
|
||||
f.write(f'.. doxygenfile:: {filename}\n')
|
||||
f.write(' :project: lvgl\n\n')
|
||||
|
||||
|
||||
def _recursively_create_api_rst_files(depth: int,
|
||||
src_root_len: int,
|
||||
src_dir_bep: str,
|
||||
out_root_dir: str) -> int:
|
||||
"""
|
||||
Create `.rst` files for the eligible C source files found in `src_dir_bep` and
|
||||
recursively for subdirectories below it. ("bep" = being processed.)
|
||||
|
||||
Eligible
|
||||
An input file (e.g. `.h*`) file is eligible if Doxygen generated
|
||||
documentation for it. The combination of these configuration items in
|
||||
the Doxyfile:
|
||||
|
||||
- INPUT
|
||||
- FILE_PATTERNS
|
||||
- EXCLUDE
|
||||
- EXCLUDE_PATTERNS
|
||||
|
||||
controls the files Doxygen processes. Files not processed are not eligible.
|
||||
|
||||
Whether a subdirectory is eligible to be included in an `index.rst`
|
||||
file depends upon whether any eligible files were recursively
|
||||
found within it. And that isn't known until this function finishes
|
||||
(recursively) processing a directory and returns the number of
|
||||
eligible `.h*` files found in its subdirectory tree. Thus, the steps
|
||||
taken within are:
|
||||
|
||||
- Discover all eligible `.h*` files directly contained in `src_dir_bep`.
|
||||
- Recursively do the same for each subdirectory, adding the returned
|
||||
count of eligible `.h*` files to the sum (`elig_h_file_count`).
|
||||
- If `elig_h_file_count > 0`:
|
||||
- call _create_rst_files_for_dir() to generate appropriate
|
||||
`.rst` files for this directory.
|
||||
- Return `elig_h_file_count`.
|
||||
|
||||
Once we have accumulated this information, then we can generate
|
||||
all the `.rst` files for the current directory without any further
|
||||
directory-tree walking.
|
||||
|
||||
:param depth: Only used for testing/debugging
|
||||
:param src_root_len: Length of source-root path
|
||||
:param src_dir_bep: Source directory *being processed*
|
||||
:param out_root_dir: Output root directory (used to build output paths)
|
||||
:return: Number of `.h*` files encountered (so caller knows
|
||||
whether that directory recursively held any
|
||||
eligible `.h*` files, to know whether to include
|
||||
"subdir/index" in caller's local `index.rst` file).
|
||||
"""
|
||||
elig_h_files = []
|
||||
sub_dirs = []
|
||||
elig_sub_dirs = []
|
||||
elig_h_file_count = 0
|
||||
|
||||
# For each "thing" found in `src_dir_bep`, build lists:
|
||||
# `elig_sub_dirs` and `elig_h_files`.
|
||||
# By design change, we are including files with 'private'
|
||||
# in their names. Reason: advanced users who need to use
|
||||
# the structs defined within will need the documentation
|
||||
# in those API pages!
|
||||
for dir_item in os.listdir(src_dir_bep):
|
||||
path_bep = os.path.join(src_dir_bep, dir_item)
|
||||
if os.path.isdir(path_bep):
|
||||
sub_dirs.append(path_bep) # Add to sub-dir list.
|
||||
else:
|
||||
_, ext = os.path.splitext(dir_item)
|
||||
# `ext` is converted to lower case so that any incidental case change
|
||||
# in the extension on Windows will not break this algorithm.
|
||||
if ext.lower() in doxy_src_file_ext_list:
|
||||
eligible = (dir_item in doxygen_xml.files
|
||||
and dir_item not in _cfg_exclude_list)
|
||||
|
||||
if eligible:
|
||||
elig_h_files.append(path_bep) # Add file to list.
|
||||
elig_h_file_count += 1
|
||||
|
||||
# For each subdir...
|
||||
for sub_dir in sub_dirs:
|
||||
subdir_eligible_h_file_count = \
|
||||
_recursively_create_api_rst_files(depth + 1,
|
||||
src_root_len,
|
||||
sub_dir,
|
||||
out_root_dir)
|
||||
|
||||
if subdir_eligible_h_file_count > 0:
|
||||
elig_sub_dirs.append(sub_dir)
|
||||
elig_h_file_count += subdir_eligible_h_file_count
|
||||
|
||||
if elig_h_file_count > 0:
|
||||
# Sort both lists.
|
||||
# Evidently the Linux-Python's implementation of `listdir()` does not
|
||||
# automatically produce a sorted list.
|
||||
elig_sub_dirs.sort()
|
||||
elig_h_files.sort()
|
||||
|
||||
# Create index.rst plus .RST files for any .H* file directly in dir.
|
||||
_create_rst_files_for_dir(src_root_len,
|
||||
src_dir_bep,
|
||||
elig_h_files,
|
||||
elig_sub_dirs,
|
||||
out_root_dir)
|
||||
|
||||
return elig_h_file_count
|
||||
|
||||
|
||||
def create_api_rst_files(src_root_dir: str, out_root_dir: str):
|
||||
"""
|
||||
Create `.rst` files for API pages based on the `.h*` files found
|
||||
in a tree-walk of `a_src_root` and the current contents of the
|
||||
`doxygen_xml.files` dictionary (used to filter out `.h*` files that
|
||||
Doxygen generated no documentation for). Output the `.rst` files
|
||||
into `out_root_dir` mirroring the `a_src_root` directory structure.
|
||||
|
||||
:param src_root_dir: root source directory to walk
|
||||
:param out_root_dir: output directory
|
||||
:return: n/a
|
||||
"""
|
||||
src_root_len = len(src_root_dir) + 1
|
||||
_recursively_create_api_rst_files(0, src_root_len, src_root_dir, out_root_dir)
|
||||
|
||||
|
||||
def build_api_docs(lvgl_src_dir, intermediate_dir, doxyfile_src_file, *doc_rel_paths):
|
||||
"""
|
||||
- Prep and run Doxygen, outputting XML.
|
||||
- Load that XML in a form that can quickly tie C symbols to the
|
||||
source files they came from.
|
||||
- Generate API page `.rst` files for source files Doxygen generated
|
||||
documentation for.
|
||||
- Add hyperlinks to these API pages for `.rst` files in `*doc_rel_paths`
|
||||
that are eligible.
|
||||
|
||||
:param lvgl_src_dir: Path to LVGL src directory
|
||||
:param intermediate_dir: Path to intermediate dir being built
|
||||
:param doxyfile_src_file: Full path to src doxygen configuration file
|
||||
:param doc_rel_paths: List of relative paths from `intermediate_dir` to
|
||||
walk to find docs eligible for API hyperlinks.
|
||||
"""
|
||||
# ---------------------------------------------------------------------
|
||||
# - Generate Doxyfile replacing tokens,
|
||||
# - run Doxygen generating XML, and
|
||||
# - load the generated XML from Doxygen output.
|
||||
# ---------------------------------------------------------------------
|
||||
doxygen_xml.EMIT_WARNINGS = EMIT_WARNINGS
|
||||
|
||||
xml_parser = doxygen_xml.DoxygenXml(lvgl_src_dir,
|
||||
intermediate_dir,
|
||||
doxyfile_src_file,
|
||||
silent_mode=False
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Generate .RST files for API pages.
|
||||
# ---------------------------------------------------------------------
|
||||
announce(__file__, "Generating API documentation .RST files...")
|
||||
api_out_root_dir = os.path.join(intermediate_dir, 'API')
|
||||
create_api_rst_files(lvgl_src_dir, api_out_root_dir)
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# For each directory entry in `doc_rel_paths` array...
|
||||
# - add API hyperlinks to .RST files in the directories in passed array.
|
||||
# ---------------------------------------------------------------------
|
||||
announce(__file__, "Adding API-page hyperlinks to source docs...")
|
||||
_add_hyperlinks_to_eligible_files(intermediate_dir,
|
||||
True,
|
||||
*doc_rel_paths)
|
||||
788
managed_components/lvgl__lvgl/docs/build.py
Normal file
@@ -0,0 +1,788 @@
|
||||
#!/usr/bin/env python3
|
||||
""" build.py -- Generate LVGL documentation using Doxygen and Sphinx + Breathe.
|
||||
|
||||
Data Flow
|
||||
---------
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Inputs Generated Source Files Output
|
||||
----------- ---------------------- ----------------------
|
||||
./docs/src/ \
|
||||
./src/ >===> ./docs/intermediate/ ===> ./docs/build/<format>/
|
||||
./examples/ /
|
||||
|
||||
Once ./docs/intermediate/ is built, you can use all the Sphinx output
|
||||
formats, e.g.
|
||||
|
||||
- make html
|
||||
- make latex
|
||||
- make man
|
||||
- make htmlhelp
|
||||
- etc.
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
Copy source files to an intermediate directory and modify them there before
|
||||
doc generation occurs. If a full rebuild is being done (e.g. after a `clean`)
|
||||
run Doxygen on LVGL's source files to generate intermediate API information
|
||||
in XML format. Generate API documents for Breathe's consumption. Add API
|
||||
links to end of some documents. Generate example documents. From there,
|
||||
Sphinx with Breathe extension uses the resulting set of intermediate files
|
||||
to generate the desired output.
|
||||
|
||||
It is only during this first build that the `--skip-api` option has meaning.
|
||||
After the first build, no further actions is taken regarding API pages since
|
||||
they are not regenerated after the first build.
|
||||
|
||||
The intermediate directory has a fixed location (overridable by
|
||||
`LVGL_DOC_BUILD_INTERMEDIATE_DIR` environment variable) and by default this
|
||||
script attempts to rebuild only those documents whose path, name or
|
||||
modification date has changed since the last build.
|
||||
|
||||
The output directory also has a fixed location (overridable by
|
||||
`LVGL_DOC_BUILD_OUTPUT_DIR` environment variable).
|
||||
|
||||
Caution:
|
||||
|
||||
The document build meant for end-user consumption should ONLY be done after a
|
||||
`--clean` unless you know that no API documentation and no code examples have changed.
|
||||
|
||||
A `sphinx-build` will do a full doc rebuild any time:
|
||||
|
||||
- the intermediate directory doesn't exist or is empty (since the new files in
|
||||
the intermediate directory will have modification times after the generated
|
||||
HTML or Latex files, even if nothing changed),
|
||||
- the targeted output directory doesn't exist or is empty, or
|
||||
- Sphinx determines that a full rebuild is necessary. This happens when:
|
||||
- intermediate directory path (Sphinx's source-file path) has changed,
|
||||
- any options on the `sphinx-build` command line have changed,
|
||||
- `conf.py` modification date has changed, or
|
||||
- `--fresh-env` argument is included (runs `sphinx-build` with -E option).
|
||||
|
||||
Typical run time:
|
||||
|
||||
Full build: 22.5 min
|
||||
--skip-api: 1.9 min (applies to first build only)
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
usage: build.py [-h] [-s] [-E]
|
||||
{html,latex,intermediate,clean,clean-intermediate,clean-html,clean-latex}
|
||||
[{html,latex,intermediate,clean,clean-intermediate,clean-html,clean-latex} ...]
|
||||
|
||||
Build LVGL documents
|
||||
|
||||
positional arguments:
|
||||
{html,latex,intermediate,clean,clean-intermediate,clean-html,clean-latex}
|
||||
output targets to generate; one or more of these;
|
||||
`clean...` targets are completed first
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-s, --skip-api skip API-page generation
|
||||
-E, --fresh-env rebuild Sphinx environment
|
||||
|
||||
|
||||
Options
|
||||
-------
|
||||
--help
|
||||
Print usage note and exit with status 0.
|
||||
|
||||
Targets:
|
||||
|
||||
html [ --skip-api ] [ --fresh-env ]
|
||||
Build HTML output.
|
||||
`--skip-api` only has effect on first build after a `clean` or `clean_intermediate`.
|
||||
|
||||
latex [ --skip-api ] [ --fresh-env ]
|
||||
Build Latex/PDF output (on hold pending removal of non-ASCII characters from input files).
|
||||
`--skip-api` only has effect on first build after a `clean` or `clean_intermediate`.
|
||||
|
||||
intermediate [ --skip-api ]
|
||||
Generate intermediate directory contents (ready to build output formats).
|
||||
If they already exist, they are removed and re-generated.
|
||||
Note: "intermediate" can be abbreviated down to "int".
|
||||
|
||||
clean
|
||||
Remove all generated files.
|
||||
|
||||
clean-intermediate
|
||||
Remove intermediate directory.
|
||||
Note: "clean_intermediate" can be abbreviated down to "clean_int".
|
||||
|
||||
clean-html
|
||||
Remove HTML output directory.
|
||||
|
||||
clean-latex
|
||||
Remove Latex output directory.
|
||||
|
||||
Options with Output Targets:
|
||||
|
||||
--skip-api (-s) (with `html` and/or `latex` and/or `intermediate` options)
|
||||
Skip API pages and links when intermediate directory contents are being generated
|
||||
(saving about 91% of build time). Note: they are not thereafter regenerated unless
|
||||
requested by `intermediate` argument or the intermediate directory does not
|
||||
exist. This is intended to be used only during doc development to speed up
|
||||
turn-around time between doc modifications and seeing final results.
|
||||
|
||||
--fresh-env (-E) (with `html` and/or `latex` options)
|
||||
Run `sphinx-build` with -E command-line argument, which makes it regenerate its
|
||||
"environment" (memory of what was built previously, forcing a full rebuild).
|
||||
|
||||
Unrecognized arguments print error message, usage note, and exit with status 1.
|
||||
|
||||
|
||||
Python Package Requirements
|
||||
---------------------------
|
||||
The list of Python package requirements are in `requirements.txt`.
|
||||
|
||||
Install them by:
|
||||
|
||||
$ pip install -r requirements.txt
|
||||
|
||||
|
||||
History
|
||||
-------
|
||||
The first version of this file (Apr 2021) discovered the name of
|
||||
the current branch (e.g. 'master', 'release/v8.4', etc.) to support
|
||||
different versions of the documentation by establishing the base URL
|
||||
(used in `conf.py` and in [Edit on GitHub] links), and then ran:
|
||||
|
||||
- Doxygen (to generate LVGL API XML), then
|
||||
- Sphinx
|
||||
|
||||
to generate the LVGL document tree. Internally, Sphinx uses `breathe`
|
||||
(a Sphinx extension) to provide a bridge between Doxygen XML output and
|
||||
Sphinx documentation. It also supported a command-line option `--clean`
|
||||
to remove generated files before starting (eliminates orphan files,
|
||||
for docs that have moved or changed).
|
||||
|
||||
Since then its duties have grown to include:
|
||||
|
||||
- Using environment variables to convey branch names to several more
|
||||
places where they are used in the docs-generating process (instead
|
||||
of re-writing `conf.py` and a `header.rst` each time docs were
|
||||
generated). These are documented where they generated below.
|
||||
|
||||
- Supporting additional command-line options.
|
||||
|
||||
- Generating a `./docs/lv_conf.h` for Doxygen to use (config_builder.py).
|
||||
|
||||
- Supporting multiple execution platforms (which then required tokenizing
|
||||
Doxygen's INPUT path in `Doxyfile` and re-writing portions that used
|
||||
`sed` to generate input or modify files).
|
||||
|
||||
- Adding translation and API links (requiring generating docs in an
|
||||
intermediate directory so that the links could be programmatically
|
||||
added to each document before Sphinx was run). Note: translation links
|
||||
are now done manually since they are only on the main landing page.
|
||||
|
||||
- Generating EXAMPLES page. Specific example groups are added to individual
|
||||
documents by each document having an ``.. include:: /examples/.../index.rst``
|
||||
directive where the example(s) should go.
|
||||
|
||||
- Building PDF via latex.
|
||||
|
||||
- Shifting doc-generation paradigm to behave more like `make`.
|
||||
|
||||
"""
|
||||
|
||||
# ****************************************************************************
|
||||
# IMPORTANT: If you are getting a PDF-lexer error for an example, check
|
||||
# for extra lines at the end of the file. Only a single empty line
|
||||
# is allowed!!! Ask me how long it took me to figure this out.
|
||||
# -- @kdschlosser
|
||||
# ****************************************************************************
|
||||
|
||||
# Python Library
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import shutil
|
||||
import dirsync
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
|
||||
# LVGL Custom
|
||||
import example_list
|
||||
import api_doc_builder
|
||||
import config_builder
|
||||
from src.lvgl_version import lvgl_version
|
||||
from announce import *
|
||||
|
||||
# Not Currently Used
|
||||
# (Code is kept in case we want to re-implement it later.)
|
||||
# import add_translation
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Configuration
|
||||
# -------------------------------------------------------------------------
|
||||
# These are relative paths from the ./docs/ directory.
|
||||
cfg_project_dir = '..'
|
||||
cfg_lvgl_src_dir = 'src'
|
||||
cfg_doc_src_dir = 'src'
|
||||
cfg_examples_dir = 'examples'
|
||||
cfg_default_intermediate_dir = 'intermediate'
|
||||
cfg_default_output_dir = 'build'
|
||||
cfg_static_dir = '_static'
|
||||
cfg_downloads_dir = 'downloads'
|
||||
cfg_lv_conf_filename = 'lv_conf.h'
|
||||
cfg_lv_version_filename = 'lv_version.h'
|
||||
cfg_doxyfile_filename = 'Doxyfile'
|
||||
cfg_top_index_filename = 'index.rst'
|
||||
cfg_default_branch = 'master'
|
||||
cfg_target_html = 'html'
|
||||
cfg_target_latex = 'latex'
|
||||
cfg_target_intermediate = 'intermediate'
|
||||
cfg_target_clean_all = 'clean'
|
||||
cfg_target_clean_intermediate = 'clean-intermediate'
|
||||
cfg_target_clean_html = 'clean-html'
|
||||
cfg_target_clean_latex = 'clean-latex'
|
||||
|
||||
# Filename generated in `latex_output_dir` and copied to `pdf_output_dir`.
|
||||
cfg_pdf_filename = 'LVGL.pdf'
|
||||
|
||||
|
||||
def remove_dir(tgt_dir):
|
||||
"""Remove directory `tgt_dir`."""
|
||||
if os.path.isdir(tgt_dir):
|
||||
announce(__file__, f'Removing {tgt_dir}...')
|
||||
shutil.rmtree(tgt_dir)
|
||||
else:
|
||||
announce(__file__, f'{tgt_dir} already removed...')
|
||||
|
||||
|
||||
def cmd(cmd_str, start_dir=None, exit_on_error=True):
|
||||
"""Run external command and abort build on error."""
|
||||
saved_dir = None
|
||||
|
||||
if start_dir is not None:
|
||||
saved_dir = os.getcwd()
|
||||
os.chdir(start_dir)
|
||||
|
||||
announce(__file__, f'Running [{cmd_str}] in [{os.getcwd()}]...')
|
||||
return_code = os.system(cmd_str)
|
||||
|
||||
if saved_dir is not None:
|
||||
os.chdir(saved_dir)
|
||||
|
||||
if return_code != 0 and exit_on_error:
|
||||
announce(__file__, "Exiting build due to previous error.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def intermediate_dir_contents_exists(intermediate_dir):
|
||||
"""Provide answer to question: Can we have reasonable confidence that
|
||||
the contents of `intermediate_directory` already exists?
|
||||
"""
|
||||
result = False
|
||||
c1 = os.path.isdir(intermediate_dir)
|
||||
|
||||
if c1:
|
||||
temp_path = os.path.join(intermediate_dir, 'CHANGELOG.rst')
|
||||
c2 = os.path.exists(temp_path)
|
||||
temp_path = os.path.join(intermediate_dir, '_ext')
|
||||
c3 = os.path.isdir(temp_path)
|
||||
temp_path = os.path.join(intermediate_dir, '_static')
|
||||
c4 = os.path.isdir(temp_path)
|
||||
temp_path = os.path.join(intermediate_dir, 'debugging')
|
||||
c5 = os.path.isdir(temp_path)
|
||||
temp_path = os.path.join(intermediate_dir, 'introduction')
|
||||
c6 = os.path.isdir(temp_path)
|
||||
temp_path = os.path.join(intermediate_dir, 'contributing')
|
||||
c7 = os.path.isdir(temp_path)
|
||||
temp_path = os.path.join(intermediate_dir, cfg_examples_dir)
|
||||
c8 = os.path.isdir(temp_path)
|
||||
result = c2 and c3 and c4 and c5 and c6 and c7 and c8
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def run():
|
||||
"""Perform doc-build function(s) requested."""
|
||||
|
||||
def print_setting(setting_name, val):
|
||||
"""Print one setting; used for debugging."""
|
||||
announce(__file__, f'{setting_name:18} = [{val}]')
|
||||
|
||||
def print_settings(args, and_exit: bool):
|
||||
"""Print all settings and optionally exit; used for debugging.
|
||||
|
||||
This routine has proven useful for verification and validation,
|
||||
and is being kept for future debugging purposes.
|
||||
"""
|
||||
# Targets
|
||||
print_setting("build_html", cfg_target_html in args.targets)
|
||||
print_setting("build_latex", cfg_target_latex in args.targets)
|
||||
print_setting("build_intermediate", cfg_target_intermediate in args.targets)
|
||||
print_setting("clean_all", cfg_target_clean_all in args.targets)
|
||||
print_setting("clean_intermediate", cfg_target_clean_intermediate in args.targets)
|
||||
print_setting("clean_html", cfg_target_clean_html in args.targets)
|
||||
print_setting("clean_latex", cfg_target_clean_latex in args.targets)
|
||||
# Options
|
||||
print_setting("skip_api", args.skip_api)
|
||||
print_setting("fresh_sphinx_env", args.fresh_sphinx_env)
|
||||
|
||||
if and_exit:
|
||||
exit(0)
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Process command-line args.
|
||||
# ---------------------------------------------------------------------
|
||||
ap = argparse.ArgumentParser(description='Build LVGL documents')
|
||||
ap.add_argument('targets', nargs='+', choices=[
|
||||
cfg_target_html,
|
||||
cfg_target_latex,
|
||||
cfg_target_intermediate,
|
||||
cfg_target_clean_all,
|
||||
cfg_target_clean_intermediate,
|
||||
cfg_target_clean_html,
|
||||
cfg_target_clean_latex,
|
||||
],
|
||||
help='output targets to generate; one or more of these;\n`clean...` targets are completed first')
|
||||
|
||||
ap.add_argument('-s', '--skip-api' , action='store_true', dest='skip_api',
|
||||
help='skip API-page generation' )
|
||||
ap.add_argument('-E', '--fresh-env', action='store_true', dest='fresh_sphinx_env',
|
||||
help='rebuild Sphinx environment' )
|
||||
args = ap.parse_args()
|
||||
|
||||
if cfg_target_clean_all in args.targets:
|
||||
if cfg_target_clean_intermediate not in args.targets:
|
||||
args.targets.append(cfg_target_clean_intermediate)
|
||||
if cfg_target_clean_html not in args.targets:
|
||||
args.targets.append(cfg_target_clean_html)
|
||||
if cfg_target_clean_latex not in args.targets:
|
||||
args.targets.append(cfg_target_clean_latex)
|
||||
|
||||
# '-E' option forces Sphinx to rebuild its environment so all docs are
|
||||
# fully regenerated, even if not changed.
|
||||
# Note: Sphinx runs in ./docs/, but uses `intermediate_dir` for input.
|
||||
if args.fresh_sphinx_env:
|
||||
announce(__file__, "Force-regenerating all files...")
|
||||
env_opt = '-E'
|
||||
else:
|
||||
env_opt = ''
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Start.
|
||||
# ---------------------------------------------------------------------
|
||||
t0 = datetime.now()
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Set up paths.
|
||||
#
|
||||
# Variable Suffixes:
|
||||
# _filename = filename without path
|
||||
# _path = path leading to a file or directory (absolute or relative)
|
||||
# _file = path leading to a file (absolute or relative)
|
||||
# _dir = path leading to a directory (absolute or relative)
|
||||
# ---------------------------------------------------------------------
|
||||
base_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
project_dir = os.path.abspath(os.path.join(base_dir, cfg_project_dir))
|
||||
examples_dir = os.path.join(project_dir, cfg_examples_dir)
|
||||
lvgl_src_dir = os.path.join(project_dir, cfg_lvgl_src_dir)
|
||||
|
||||
# Establish intermediate directory. The presence of environment variable
|
||||
# `LVGL_DOC_BUILD_INTERMEDIATE_DIR` overrides default in `cfg_default_intermediate_dir`.
|
||||
if 'LVGL_DOC_BUILD_INTERMEDIATE_DIR' in os.environ:
|
||||
intermediate_dir = os.environ['LVGL_DOC_BUILD_INTERMEDIATE_DIR']
|
||||
else:
|
||||
intermediate_dir = os.path.join(base_dir, cfg_default_intermediate_dir)
|
||||
|
||||
lv_conf_file = os.path.join(intermediate_dir, cfg_lv_conf_filename)
|
||||
lv_temp_conf_file_for_doxygen = os.path.join(lvgl_src_dir, cfg_lv_conf_filename)
|
||||
version_dst_file = os.path.join(intermediate_dir, cfg_lv_version_filename)
|
||||
top_index_file = os.path.join(intermediate_dir, cfg_top_index_filename)
|
||||
doxyfile_src_file = os.path.join(base_dir, cfg_doxyfile_filename)
|
||||
doxyfile_dst_file = os.path.join(intermediate_dir, cfg_doxyfile_filename)
|
||||
pdf_intermediate_dst_dir = os.path.join(intermediate_dir, cfg_static_dir, cfg_downloads_dir)
|
||||
pdf_intermediate_dst_file = os.path.join(pdf_intermediate_dst_dir, cfg_pdf_filename)
|
||||
sphinx_path_sep = '/'
|
||||
pdf_relative_file = cfg_static_dir + sphinx_path_sep + cfg_downloads_dir + sphinx_path_sep + cfg_pdf_filename
|
||||
pdf_link_ref_str = f'PDF Version: :download:`{cfg_pdf_filename} <{pdf_relative_file}>`'
|
||||
|
||||
# Establish build directory. The presence of environment variable
|
||||
# `LVGL_DOC_BUILD_OUTPUT_DIR` overrides default in `cfg_default_output_dir`.
|
||||
if 'LVGL_DOC_BUILD_OUTPUT_DIR' in os.environ:
|
||||
output_dir = os.environ['LVGL_DOC_BUILD_OUTPUT_DIR']
|
||||
else:
|
||||
output_dir = os.path.join(base_dir, cfg_default_output_dir)
|
||||
|
||||
html_output_dir = os.path.join(output_dir, 'html')
|
||||
latex_output_dir = os.path.join(output_dir, 'latex')
|
||||
pdf_output_dir = os.path.join(output_dir, 'pdf')
|
||||
pdf_src_file = os.path.join(latex_output_dir, cfg_pdf_filename)
|
||||
pdf_dst_file = os.path.join(pdf_output_dir, cfg_pdf_filename)
|
||||
version_src_file = os.path.join(project_dir, cfg_lv_version_filename)
|
||||
|
||||
# Special stuff for right-aligning PDF download link.
|
||||
# Note: this needs to be embedded in a <div> tag because the
|
||||
# Sphinx `:download:` role causes the link to appear in a <p> tag
|
||||
# and in HTML5, <p> tags cannot be nested!
|
||||
cfg_right_just_para_text = """.. raw:: html
|
||||
|
||||
<div style="text-align: right;">"""
|
||||
cfg_end_right_just_para_text = """.. raw:: html
|
||||
|
||||
</div>"""
|
||||
# Blank lines are required due to the directives.
|
||||
cfg_pdf_link_ref_block_str = \
|
||||
cfg_right_just_para_text + os.linesep \
|
||||
+ os.linesep \
|
||||
+ pdf_link_ref_str + os.linesep + \
|
||||
os.linesep \
|
||||
+ cfg_end_right_just_para_text + os.linesep \
|
||||
+ os.linesep
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Change to script directory for consistent run-time environment.
|
||||
# ---------------------------------------------------------------------
|
||||
os.chdir(base_dir)
|
||||
announce(__file__, f'Intermediate dir: [{intermediate_dir}]')
|
||||
announce(__file__, f'Output dir : [{output_dir}]')
|
||||
announce(__file__, f'Running from : [{base_dir}]')
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Clean? If so, clean (like `make clean`), but do not exit.
|
||||
# ---------------------------------------------------------------------
|
||||
some_cleaning_to_be_done = cfg_target_clean_intermediate in args.targets \
|
||||
or cfg_target_clean_html in args.targets \
|
||||
or cfg_target_clean_latex in args.targets \
|
||||
or cfg_target_clean_all in args.targets \
|
||||
or ( \
|
||||
os.path.isdir(intermediate_dir) \
|
||||
and cfg_target_intermediate in args.targets \
|
||||
)
|
||||
|
||||
if some_cleaning_to_be_done:
|
||||
announce(__file__, "Cleaning...", box=True)
|
||||
|
||||
if cfg_target_clean_intermediate in args.targets:
|
||||
remove_dir(intermediate_dir)
|
||||
|
||||
if cfg_target_clean_html in args.targets:
|
||||
remove_dir(html_output_dir)
|
||||
|
||||
if cfg_target_clean_latex in args.targets:
|
||||
remove_dir(latex_output_dir)
|
||||
|
||||
if cfg_target_clean_all in args.targets:
|
||||
remove_dir(output_dir)
|
||||
|
||||
if os.path.isdir(intermediate_dir) and cfg_target_intermediate in args.targets:
|
||||
remove_dir(intermediate_dir)
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Populate LVGL_URLPATH and LVGL_GITCOMMIT environment variables:
|
||||
# - LVGL_URLPATH <= 'master' or '8.4' '9.2' etc.
|
||||
# - LVGL_GITCOMMIT <= same (see 03-Oct-2024 note below).
|
||||
#
|
||||
# These supply input later in the doc-generation process as follows:
|
||||
#
|
||||
# LVGL_URLPATH is used by:
|
||||
# - `conf.py` to build `html_baseurl` for Sphinx for
|
||||
# - generated index
|
||||
# - generated search window
|
||||
# - establishing canonical page for search engines
|
||||
# - `link_roles.py` to generate translation links
|
||||
# - `doxygen_xml.py` to generate links to API pages
|
||||
#
|
||||
# LVGL_GITCOMMIT is used by:
|
||||
# - `conf.py` => html_context['github_version'] for
|
||||
# Sphinx Read-the-Docs theme to add to [Edit on GitHub] links
|
||||
# - `conf.py` => repo_commit_hash for generated EXAMPLES pages for:
|
||||
# - [View on GitHub] buttons (view C code examples)
|
||||
# - [View on GitHub] buttons (view Python code examples)
|
||||
# ---------------------------------------------------------------------
|
||||
# 03-Oct-2024: Gabor requested LVGL_GITCOMMIT be changed to a branch
|
||||
# name since that will always be current, and it will fix a large
|
||||
# number of broken links on the docs website, since commits that
|
||||
# generated docs can sometimes go away. This gets used in:
|
||||
# - [Edit on GitHub] links in doc pages (via Sphinx theme), and
|
||||
# - [View on GitHub] links in example pages (via `example_list.py`
|
||||
# and `lv_example.py`).
|
||||
# Original code:
|
||||
# status, br = subprocess.getstatusoutput("git branch --show-current")
|
||||
# _, gitcommit = subprocess.getstatusoutput("git rev-parse HEAD")
|
||||
# br = re.sub(r'\* ', '', br)
|
||||
# 're' was previously used to remove leading '* ' from current branch
|
||||
# string when we were parsing output from bare `git branch` output.
|
||||
# This is no longer needed with `--show-current` option now used.
|
||||
# ---------------------------------------------------------------------
|
||||
status, branch = subprocess.getstatusoutput("git branch --show-current")
|
||||
|
||||
# If above failed (i.e. `branch` not valid), default to 'master'.
|
||||
if status != 0:
|
||||
branch = cfg_default_branch
|
||||
elif branch == cfg_default_branch:
|
||||
# Expected in most cases. Nothing to change.
|
||||
pass
|
||||
else:
|
||||
# `branch` is valid. Capture release version if in a 'release/' branch.
|
||||
if branch.startswith('release/'):
|
||||
branch = branch[8:]
|
||||
else:
|
||||
# Default to 'master'.
|
||||
branch = cfg_default_branch
|
||||
|
||||
os.environ['LVGL_URLPATH'] = branch
|
||||
os.environ['LVGL_GITCOMMIT'] = branch
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Prep `intermediate_dir` to become the `sphinx-build` source dir.
|
||||
# ---------------------------------------------------------------------
|
||||
# dirsync `exclude_list` = list of regex patterns to exclude.
|
||||
intermediate_re = r'^' + cfg_default_intermediate_dir + r'.*'
|
||||
output_re = r'^' + cfg_default_output_dir + r'.*'
|
||||
exclude_list = [r'lv_conf\.h', r'^__pycache__.*', intermediate_re, output_re]
|
||||
|
||||
if intermediate_dir_contents_exists(intermediate_dir):
|
||||
# We are just doing an update of the intermediate_dir contents.
|
||||
announce(__file__, "Updating intermediate directory...", box=True)
|
||||
|
||||
exclude_list.append(r'examples.*')
|
||||
options = {
|
||||
'verbose': True, # Report files copied.
|
||||
'create': True, # Create directories if they don't exist.
|
||||
'twoway': False, # False means data flow only src => tgt.
|
||||
'purge': False, # False means DO NOT remove orphan files/dirs in tgt dir (preserving examples/ dir).
|
||||
'exclude': exclude_list
|
||||
}
|
||||
# action == 'sync' means copy files even when they do not already exist in tgt dir.
|
||||
# action == 'update' means DO NOT copy files when they do not already exist in tgt dir.
|
||||
dirsync.sync(cfg_doc_src_dir, intermediate_dir, 'sync', **options)
|
||||
dirsync.sync(examples_dir, os.path.join(intermediate_dir, cfg_examples_dir), 'sync', **options)
|
||||
elif cfg_target_intermediate in args.targets or cfg_target_html in args.targets or cfg_target_latex in args.targets:
|
||||
# We are having to create the intermediate_dir contents by copying.
|
||||
announce(__file__, "Building intermediate directory...", box=True)
|
||||
|
||||
t1 = datetime.now()
|
||||
copy_method = 1
|
||||
|
||||
# Both of these methods work.
|
||||
if copy_method == 0:
|
||||
# --------- Method 0:
|
||||
ignore_func = shutil.ignore_patterns('tmp*', 'output*')
|
||||
announce(__file__, 'Copying docs...')
|
||||
shutil.copytree(cfg_doc_src_dir, intermediate_dir, ignore=ignore_func, dirs_exist_ok=True)
|
||||
announce(__file__, 'Copying examples...')
|
||||
shutil.copytree(examples_dir, os.path.join(intermediate_dir, cfg_examples_dir), dirs_exist_ok=True)
|
||||
else:
|
||||
# --------- Method 1:
|
||||
options = {
|
||||
'create': True, # Create directories if they don't exist.
|
||||
'exclude': exclude_list
|
||||
}
|
||||
# action == 'sync' means copy files even when they do not already exist in tgt dir.
|
||||
# action == 'update' means DO NOT copy files when they do not already exist in tgt dir.
|
||||
announce(__file__, 'Copying docs...')
|
||||
dirsync.sync(cfg_doc_src_dir, intermediate_dir, 'sync', **options)
|
||||
announce(__file__, 'Copying examples...')
|
||||
dirsync.sync(examples_dir, os.path.join(intermediate_dir, cfg_examples_dir), 'sync', **options)
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Build <intermediate_dir>/lv_conf.h from lv_conf_template.h.
|
||||
# -----------------------------------------------------------------
|
||||
config_builder.run(lv_conf_file)
|
||||
# Build a temporary version of this file in ../src/ so Doxygen can see it.
|
||||
# Reason: Doxygen's input is the master `lvgl/src/` directory,
|
||||
# not the intermediate directory. This file gets deleted later.
|
||||
config_builder.run(lv_temp_conf_file_for_doxygen)
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Copy `lv_version.h` into intermediate directory.
|
||||
# -----------------------------------------------------------------
|
||||
shutil.copyfile(version_src_file, version_dst_file)
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Generate examples pages. Include sub-pages pages that get included
|
||||
# in individual documents where applicable.
|
||||
# -----------------------------------------------------------------
|
||||
announce(__file__, "Generating examples...")
|
||||
example_list.make_warnings_into_errors()
|
||||
example_list.exec(intermediate_dir)
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Add translation links.
|
||||
# This is being skipped in favor of a manually-placed
|
||||
# translation link at the top of `./docs/index.rst`.
|
||||
# -----------------------------------------------------------------
|
||||
# Original code:
|
||||
# if True:
|
||||
# announce(__file__, "Skipping adding translation links.")
|
||||
# else:
|
||||
# announce(__file__, "Adding translation links...")
|
||||
# add_translation.exec(intermediate_dir)
|
||||
|
||||
if args.skip_api:
|
||||
announce(__file__, "Skipping API generation as requested.")
|
||||
else:
|
||||
# -------------------------------------------------------------
|
||||
# Generate API pages and links thereto.
|
||||
# -------------------------------------------------------------
|
||||
announce(__file__, "API page and link processing...")
|
||||
api_doc_builder.EMIT_WARNINGS = False
|
||||
|
||||
# api_doc_builder.run() => doxy_xml_parser.DoxygenXml() now:
|
||||
# - preps and runs Doxygen generating XML,
|
||||
# - loads generated XML.
|
||||
# Then api_doc_builder.run():
|
||||
# - creates .RST files for API pages, and
|
||||
# - adds API hyperlinks to .RST files in the directories in passed array.
|
||||
api_doc_builder.build_api_docs(lvgl_src_dir,
|
||||
intermediate_dir,
|
||||
doxyfile_src_file,
|
||||
'auxiliary-modules',
|
||||
'common-widget-features',
|
||||
'contributing',
|
||||
'debugging',
|
||||
'getting_started',
|
||||
'guides',
|
||||
'integration',
|
||||
'introduction',
|
||||
'libs',
|
||||
'main-modules',
|
||||
'widgets',
|
||||
'xml',
|
||||
)
|
||||
|
||||
# Now that Doxygen has run, this file is no longer needed.
|
||||
# Clean up now rather than later to keep logic clean.
|
||||
os.remove(lv_temp_conf_file_for_doxygen)
|
||||
|
||||
# Note time when this stage completed.
|
||||
t2 = datetime.now()
|
||||
announce(__file__, 'Example/API run time: ' + str(t2 - t1))
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Build PDF
|
||||
# ---------------------------------------------------------------------
|
||||
if cfg_target_latex not in args.targets:
|
||||
announce(__file__, "Skipping Latex build.")
|
||||
else:
|
||||
t1 = datetime.now()
|
||||
announce(__file__, "Building Latex output...", box=True)
|
||||
|
||||
# If PDF link is present in top index.rst, remove it so PDF
|
||||
# does not have a link to itself.
|
||||
with open(top_index_file, 'rb') as f:
|
||||
index_data = f.read().decode('utf-8')
|
||||
|
||||
if pdf_link_ref_str in index_data:
|
||||
index_data = index_data.replace(pdf_link_ref_str, '')
|
||||
|
||||
with open(top_index_file, 'wb') as f:
|
||||
f.write(index_data.encode('utf-8'))
|
||||
|
||||
src = intermediate_dir
|
||||
dst = output_dir
|
||||
cpu = os.cpu_count()
|
||||
|
||||
# The -D option correctly replaces (overrides) configuration attribute
|
||||
# values in the `conf.py` module. Since `conf.py` now correctly
|
||||
# computes its own `version` value, we don't have to override it here
|
||||
# with a -D options. If it should need to be used in the future,
|
||||
# the value after the '=' MUST NOT have quotation marks around it
|
||||
# or it won't work. Correct usage: f'-D version={ver}' .
|
||||
cmd_line = f'sphinx-build -M latex "{src}" "{dst}" -j {cpu} --fail-on-warning --keep-going'
|
||||
cmd(cmd_line)
|
||||
|
||||
# Generate PDF.
|
||||
announce(__file__, "Building PDF...", box=True)
|
||||
cmd_line = 'latexmk -pdf "LVGL.tex"'
|
||||
cmd(cmd_line, latex_output_dir, False)
|
||||
|
||||
# Move resulting PDF to its output directory.
|
||||
if not os.path.exists(pdf_output_dir):
|
||||
os.makedirs(pdf_output_dir)
|
||||
|
||||
shutil.move(pdf_src_file, pdf_dst_file)
|
||||
t2 = datetime.now()
|
||||
announce(__file__, 'PDF : ' + pdf_dst_file)
|
||||
announce(__file__, 'Latex gen time: ' + str(t2 - t1))
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Build HTML
|
||||
# ---------------------------------------------------------------------
|
||||
if cfg_target_html not in args.targets:
|
||||
announce(__file__, "Skipping HTML build.")
|
||||
else:
|
||||
t1 = datetime.now()
|
||||
announce(__file__, "Building HTML output...", box=True)
|
||||
|
||||
# If PDF is present in build directory, copy it to
|
||||
# intermediate directory for use by HTML build.
|
||||
# (Sphinx copies it to its HTML output, so it ends
|
||||
# up on the webserver where it can be downloaded).
|
||||
if os.path.isfile(pdf_dst_file):
|
||||
# Create _static/download/ directory if needed.
|
||||
if not os.path.exists(pdf_intermediate_dst_dir):
|
||||
os.makedirs(pdf_intermediate_dst_dir)
|
||||
|
||||
shutil.copyfile(pdf_dst_file, pdf_intermediate_dst_file)
|
||||
|
||||
# If PDF is present, ensure there is a link to it in the top
|
||||
# index.rst so HTML build will have it.
|
||||
# Support both Windows and Linux platforms with `os.linesep`.
|
||||
if os.path.isfile(pdf_intermediate_dst_file):
|
||||
with open(top_index_file, 'rb') as f:
|
||||
index_data = f.read().decode('utf-8')
|
||||
|
||||
if pdf_link_ref_str not in index_data:
|
||||
index_data = cfg_pdf_link_ref_block_str + index_data
|
||||
|
||||
with open(top_index_file, 'wb') as f:
|
||||
f.write(index_data.encode('utf-8'))
|
||||
|
||||
# Note: While it can be done (e.g. if one needs to set a stop point
|
||||
# in Sphinx code for development purposes), it is NOT a good idea to
|
||||
# run Sphinx from script as
|
||||
# from sphinx.cmd.build import main as sphinx_build
|
||||
# sphinx_args = [...]
|
||||
# sphinx_build(sphinx_args)
|
||||
# because it takes ~10X longer to run than `sphinx_build` executable,
|
||||
# literally > 3 hours.
|
||||
|
||||
ver = lvgl_version(version_src_file)
|
||||
src = intermediate_dir
|
||||
dst = output_dir
|
||||
cpu = os.cpu_count()
|
||||
|
||||
debugging_breathe = 0
|
||||
if debugging_breathe:
|
||||
from sphinx.cmd.build import main as sphinx_build
|
||||
# Don't allow parallel processing while debugging (the '-j' arg is removed).
|
||||
sphinx_args = ['-M', 'html', f'{src}', f'{dst}']
|
||||
|
||||
if len(env_opt) > 0:
|
||||
sphinx_args.append(f'{env_opt}')
|
||||
|
||||
sphinx_build(sphinx_args)
|
||||
else:
|
||||
# The -D option correctly replaces (overrides) configuration attribute
|
||||
# values in the `conf.py` module. Since `conf.py` now correctly
|
||||
# computes its own `version` value, we don't have to override it here
|
||||
# with a -D options. If it should need to be used in the future,
|
||||
# the value after the '=' MUST NOT have quotation marks around it
|
||||
# or it won't work. Correct usage: f'-D version={ver}' .
|
||||
cmd_line = f'sphinx-build -M html "{src}" "{dst}" -j {cpu} {env_opt} --fail-on-warning --keep-going'
|
||||
cmd(cmd_line)
|
||||
|
||||
t2 = datetime.now()
|
||||
announce(__file__, 'HTML gen time : ' + str(t2 - t1))
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Indicate results.
|
||||
# ---------------------------------------------------------------------
|
||||
t_end = datetime.now()
|
||||
announce(__file__, 'Total run time: ' + str(t_end - t0))
|
||||
announce(__file__, 'Done.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
"""Make module importable as well as run-able."""
|
||||
run()
|
||||
76
managed_components/lvgl__lvgl/docs/config_builder.py
Normal file
@@ -0,0 +1,76 @@
|
||||
"""
|
||||
Create lv_conf.h in same directory as this file
|
||||
from ../lv_conf_template.h that has:
|
||||
|
||||
1. all its #define LV_USE... 0-or-1 options set to 1
|
||||
(except for LV_USER_PROFILER),
|
||||
2. all its #define LV_FONT... 0-or-1 options set to 1,
|
||||
3. its #if 0 directive set to #if 1.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
base_path = os.path.dirname(__file__)
|
||||
dest_config = os.path.join(base_path, 'lv_conf.h')
|
||||
src_config = os.path.abspath(os.path.join(
|
||||
base_path,
|
||||
'..',
|
||||
'lv_conf_template.h'
|
||||
))
|
||||
disabled_option_re = re.compile(r'^\s*#define\s+(LV_(?:USE|FONT)_\w+)\s+(\b0\b)')
|
||||
|
||||
leave_disabled_list = [
|
||||
'LV_USE_PROFILER',
|
||||
'LV_USE_DRAW_ARM2D_SYNC',
|
||||
'LV_USE_NATIVE_HELIUM_ASM',
|
||||
]
|
||||
|
||||
|
||||
def run(output_cfg_path=None):
|
||||
global dest_config
|
||||
enable_content_macro_processed = False
|
||||
os.chdir(base_path)
|
||||
|
||||
if output_cfg_path is not None:
|
||||
dest_config = output_cfg_path
|
||||
|
||||
with open(src_config, 'r') as f:
|
||||
data = f.read()
|
||||
|
||||
lines = data.split('\n')
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
if not enable_content_macro_processed:
|
||||
if line.startswith('#if 0'):
|
||||
line = line.replace('#if 0', '#if 1')
|
||||
lines[i] = line
|
||||
enable_content_macro_processed = True
|
||||
else:
|
||||
match = disabled_option_re.search(line)
|
||||
if match:
|
||||
# Except for these...
|
||||
if match[1] in leave_disabled_list:
|
||||
continue
|
||||
else:
|
||||
# ...replace '0' with '1' without altering any other part of line.
|
||||
# Set `j` to index where '0' was found.
|
||||
j = match.regs[2][0]
|
||||
# Surgically insert '1' in place of '0'. Strings are immutable.
|
||||
line = line[:j] + '1' + line[j + 1:]
|
||||
lines[i] = line
|
||||
|
||||
data = '\n'.join(lines)
|
||||
|
||||
with open(dest_config, 'w') as f:
|
||||
f.write(data)
|
||||
|
||||
|
||||
def cleanup():
|
||||
if os.path.exists(dest_config):
|
||||
os.remove(dest_config)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
"""Make module importable as well as run-able."""
|
||||
run()
|
||||
429
managed_components/lvgl__lvgl/docs/doxygen_config.py
Normal file
@@ -0,0 +1,429 @@
|
||||
"""doxygen_config.py
|
||||
Python Interface to Doxygen Config Files (Doxyfiles)
|
||||
|
||||
Author : "Victor Wheeler"
|
||||
Copyright: "Copyright (C) 2025 WGA Crystal Research, Inc."
|
||||
License : "MIT"
|
||||
Version : "1.0"
|
||||
|
||||
This work was inspired by the `doxygen-python-interface` project at
|
||||
https://github.com/TraceSoftwareInternational/doxygen-python-interface.
|
||||
On 27-Feb-2025 I was engaged in a production project wherein I wanted
|
||||
to find a Python module that I could re-use to reliably work with
|
||||
Doxygen configuration files (Doxyfiles). The best one I found was
|
||||
`doxygen-python-interface`. Unfortunately, the ``configParser`` from
|
||||
that project could not be used because it both had important bugs and
|
||||
design flaws in it (conflicts with legal Doxygen config syntax), and
|
||||
it appears to have been abandoned after 26-Apr-2018, preventing these
|
||||
things from being remedied.
|
||||
|
||||
So a brand-new module has been created herewith based on sound O-O design
|
||||
principles and a design that actually works in alignment with Doxygen
|
||||
configuration syntax.
|
||||
|
||||
Usage:
|
||||
|
||||
import doxygen_config
|
||||
...
|
||||
# 1. Load configuration from Doxyfile.
|
||||
cfg = doxygen_config.DoxygenConfig()
|
||||
cfg.load(doxyfile_src_file)
|
||||
|
||||
# 2. Get a list of Doxygen option names.
|
||||
opt_list = cfg.options()
|
||||
ok_to_proceed = cfg.is_valid_option('PREDEFINED') \
|
||||
and cfg.is_valid_option('INPUT')
|
||||
|
||||
# 3. Update it.
|
||||
if ok_to_proceed:
|
||||
temp = cfg.value('PREDEFINED')
|
||||
temp = temp.replace('<<CONFIG_PATH>>', config_file)
|
||||
cfg.set('PREDEFINED', temp)
|
||||
|
||||
temp = cfg.value('INPUT')
|
||||
temp = temp.replace('<<SRC>>', f'"{pjt_src_dir}"')
|
||||
cfg.set('INPUT', temp)
|
||||
|
||||
# 4. Save it.
|
||||
# The original comments and order of config options are preserved.
|
||||
# The ``bare`` argument discards comments from the output.
|
||||
cfg.save(cfg_dict, doxyfile_dst_file, bare=True)
|
||||
|
||||
Design Differences from `doxygen-python-interface`:
|
||||
|
||||
- The DoxygenConfig class represents the actual Doxygen configuration,
|
||||
in alignment with O-O theory --- it is not just a place to store a
|
||||
set of functions that never needed to be a class.
|
||||
|
||||
- If the user does a default ``save()`` (not requesting a "bare"
|
||||
version of the Doxygen configuration), the saved Doxyfile
|
||||
should be a binary match to the original Doxyfile loaded.
|
||||
|
||||
Exceptions:
|
||||
|
||||
1. Any trailing whitespace in original Doxyfile after the ``=``
|
||||
on empty options is not preserved.
|
||||
|
||||
2. Multi-line lists that had unaligned backslashes after them like this:
|
||||
|
||||
EXCLUDE_PATTERNS = */libs/barcode/code* \
|
||||
*/libs/freetype/ft* \
|
||||
*/libs/gif/gif* \
|
||||
*/libs/lodepng/lode* \
|
||||
*/libs/qrcode/qr* \
|
||||
*/libs/thorvg/* \
|
||||
*/libs/tiny_ttf/stb* \
|
||||
*/libs/tjpgd/tjp* \
|
||||
*/others/vg_lite_tvg/vg*
|
||||
|
||||
will be saved like this:
|
||||
|
||||
EXCLUDE_PATTERNS = */libs/barcode/code* \
|
||||
*/libs/freetype/ft* \
|
||||
*/libs/gif/gif* \
|
||||
*/libs/lodepng/lode* \
|
||||
*/libs/qrcode/qr* \
|
||||
*/libs/thorvg/* \
|
||||
*/libs/tiny_ttf/stb* \
|
||||
*/libs/tjpgd/tjp* \
|
||||
*/others/vg_lite_tvg/vg*
|
||||
|
||||
``doxygen-python-interface`` did not save the comments so an
|
||||
"edit in place" of a Doxyfile could be catastrophic if the
|
||||
comments were needed in the source Doxyfile as they often are
|
||||
in production scenarios.
|
||||
|
||||
- The ``save()`` method has an optional ``bare`` argument (default False)
|
||||
that can be used to save a "bare" version of the Doxyfile options,
|
||||
discarding the comments from the currently-loaded Doxyfile.
|
||||
|
||||
- Input values are preserved exactly as they were found. The
|
||||
`doxygen-python-interface`'s ``configParser`` class removed
|
||||
quotation marks from incoming values and added quotation marks
|
||||
to values containing spaces before storing them again. While
|
||||
this "sounds nice", it was incompatible with Doxygen for every
|
||||
type of item that could have a "list" as a value, such as the
|
||||
PREDEFINED and ABBREVIATE_BRIEF options.
|
||||
|
||||
Examples:
|
||||
|
||||
PREDEFINED = USE_LIST USE_TABLE USE_CHART
|
||||
|
||||
PREDEFINED = DOXYGEN CONFIG_PATH="/path with spaces/to/config.h"
|
||||
|
||||
PREDEFINED = DOXYGEN \
|
||||
CONFIG_PATH="/path with spaces/to/config.h"
|
||||
|
||||
These are all valid values for the PREDEFINED option and
|
||||
MUST NOT have quotes around any of them! Can you imagine the havoc
|
||||
that would result if a Python module meant to handle Doxygen Doxyfiles
|
||||
altered Doxygen configuration items like this?
|
||||
|
||||
PREDEFINED = "USE_LIST USE_TABLE USE_CHART"
|
||||
|
||||
Thus, it is up to the user to know when values he is changing
|
||||
have space(s) AND ALSO need quotes and take appropriate measures
|
||||
by adding quotes when needed and not otherwise.
|
||||
|
||||
- The storage of the list of Doxygen options is encapsulated
|
||||
in the instance of the DoxygenConfig class instead of being
|
||||
returned as a dictionary from the ``load...()`` function.
|
||||
Its values are readable and writeable via methods. The
|
||||
end user is not able to add options that were not part
|
||||
of the original input Doxyfile, nor remove options that were
|
||||
part of the original input Doxyfile. This gives some level of
|
||||
control on retaining valid Doxygen options.
|
||||
|
||||
It is an error to attempt to set a value with an option name
|
||||
that does not exist in the configuration. A NameError exception
|
||||
is raised if it is attempted. Attempting to read the value of
|
||||
an option name that does not exist returns the value ``None``.
|
||||
|
||||
While Doxygen options change from time to time, it is up to the
|
||||
end user to use ``doxygen -u Doxyfile`` to keep his input
|
||||
Doxyfile(s) up to date.
|
||||
|
||||
Storage:
|
||||
|
||||
The actual configuration values are represented in an internal
|
||||
dictionary not intended to be accessed directly by the typical end
|
||||
user. The keys are the Doxygen option names and the values are:
|
||||
|
||||
- str : single values with possibly embedded spaces
|
||||
- list: multi-line values with possibly embedded spaces
|
||||
|
||||
Quotation marks are neither removed nor added, so it is up to the
|
||||
user to set values compatible with Doxygen configuration syntax.
|
||||
This also makes it okay for multi-line values to have more than one
|
||||
value per line: if it is okay by Doxygen, then it is okay by
|
||||
the DoxygenConfig class.
|
||||
|
||||
If the user sets an option value passing a list, those values
|
||||
will be represented as a multi-line value in the saved Doxyfile.
|
||||
|
||||
The Philosophy of Removing Quotation Marks Is Not Workable for Doxygen:
|
||||
|
||||
When one asks, "Is it appropriate to remove the quotation marks?"
|
||||
What if a value looked like this (2 quoted items in one line),
|
||||
removing quotation marks would be an error:
|
||||
|
||||
"abc def" "ghi jkl"
|
||||
|
||||
The ABBREVIATE_BRIEF list could indeed appear like this.
|
||||
|
||||
If it were argued that all multi-value items should be formatted as
|
||||
multi-line lists, then quotation marks theory works, as the
|
||||
ABBREVIATE_BRIEF option does not require quotation marks around
|
||||
every value.
|
||||
|
||||
However, since Doxygen does not require this, there is still a
|
||||
strong argument for not tampering with quotation marks at all
|
||||
when importing values. The strongest reasons are:
|
||||
|
||||
- Doxygen can and does accept values like this where the value of
|
||||
an option can be a list. Doxygen sees this as 2 separate values:
|
||||
|
||||
"abc def" "ghi jkl"
|
||||
|
||||
- If the end user is going to set values with spaces in them,
|
||||
it could be made the user's responsibility to know when
|
||||
there are spaces and thus include quotes when needed.
|
||||
|
||||
In the end, the "do not tamper with quotation marks" argument wins
|
||||
for sake of reliability. So the policy is: quotation marks are
|
||||
neither removed nor added. It is up to the user to know when they
|
||||
are needed and add them himself.
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
__author__ = "Victor Wheeler"
|
||||
__copyright__ = "Copyright (C) 2025 WGA Crystal Research, Inc."
|
||||
__license__ = "MIT"
|
||||
__version__ = "1.0"
|
||||
|
||||
|
||||
class ParseException(Exception):
|
||||
"""Exception thrown upon unexpected parsing errors."""
|
||||
pass
|
||||
|
||||
|
||||
class DoxygenConfig:
|
||||
"""Doxygen Configurations (from/to Doxyfiles)"""
|
||||
|
||||
def __init__(self):
|
||||
"""Prepare instantiated DoxygenConfig for use."""
|
||||
# Regexes used during Doxyfile parsing
|
||||
self._re_single_line_option = re.compile(r'^\s*(\w+)\s*=\s*([^\\]*)\s*$')
|
||||
self._re_top_of_multiline_option = re.compile(r'^\s*(\w+)\s*=\s*(|.*\S)\s*\\$')
|
||||
# Doxygen cfg items by option name
|
||||
self._cfg_items_dict = {}
|
||||
# Comments by name of option below it.
|
||||
# Comments at end of file have key 'self._end_key'.
|
||||
self._cfg_comments_dict = {}
|
||||
# Key used for comments found after last option in Doxyfile
|
||||
self._end_key = 'END'
|
||||
# Configuration to match Doxygen -g output (template Doxyfile)
|
||||
self._char_count_before_equals = 23
|
||||
|
||||
def load(self, doxyfile: str):
|
||||
"""Load options and comments from `doxyfile`
|
||||
|
||||
:param doxyfile: Path to doxyfile
|
||||
|
||||
:raise FileNotFoundError: When doxyfile not found
|
||||
:raise ParseException: When there is a parsing error
|
||||
"""
|
||||
|
||||
if not os.path.exists(doxyfile):
|
||||
logging.error(f'Doxyfile not found {doxyfile}.')
|
||||
raise FileNotFoundError(doxyfile)
|
||||
|
||||
self._cfg_items_dict.clear()
|
||||
self._cfg_comments_dict.clear()
|
||||
|
||||
# Default encoding: UTF-8.
|
||||
with open(doxyfile, 'r') as file:
|
||||
in_multiline_opt = False
|
||||
multiline_opt_name_bep = None # "bep" = "being processed"
|
||||
accumulated_other_lines = []
|
||||
|
||||
for line in file.readlines():
|
||||
line = line.strip()
|
||||
|
||||
if in_multiline_opt:
|
||||
# There are 2 ways this list can end:
|
||||
# 1. the normal way when last item has no trailing `\`, or
|
||||
# 2. the last item has a trailing `\` and there is a blank-
|
||||
# or comment-line after it, which should NOT be added
|
||||
# to the list, but instead signal end-of-list.
|
||||
if not line.endswith('\\'):
|
||||
in_multiline_opt = False
|
||||
|
||||
val = line.rstrip('\\').strip()
|
||||
|
||||
if self._bool_comment_or_blank_line(val):
|
||||
accumulated_other_lines.append(line)
|
||||
in_multiline_opt = False
|
||||
else:
|
||||
self._cfg_items_dict[multiline_opt_name_bep].append(val)
|
||||
|
||||
elif self._bool_comment_or_blank_line(line):
|
||||
accumulated_other_lines.append(line)
|
||||
|
||||
elif self._bool_top_of_multiline_option(line):
|
||||
multiline_opt_name_bep, val = self._parse_multiline_option(line)
|
||||
self._cfg_items_dict[multiline_opt_name_bep] = [val]
|
||||
self._cfg_comments_dict[multiline_opt_name_bep] = accumulated_other_lines
|
||||
accumulated_other_lines = []
|
||||
in_multiline_opt = True
|
||||
|
||||
elif self._bool_single_line_option(line):
|
||||
option_name, val = self._parse_single_line_option(line)
|
||||
self._cfg_items_dict[option_name] = val
|
||||
self._cfg_comments_dict[option_name] = accumulated_other_lines
|
||||
accumulated_other_lines = []
|
||||
|
||||
# Any comments or blank lines found after last Doxygen option
|
||||
# are represented in _cfg_comments_dict with key `self._end_key`.
|
||||
if accumulated_other_lines:
|
||||
self._cfg_comments_dict[self._end_key] = accumulated_other_lines
|
||||
accumulated_other_lines.clear()
|
||||
|
||||
def save(self, doxyfile: str, bare=False):
|
||||
"""Save configuration to `doxyfile`.
|
||||
|
||||
:param doxyfile: Output path where Doxygen configuration will be
|
||||
written. Overwrites file if it exists.
|
||||
:param bare: Do not preserve comments from loaded file.
|
||||
"""
|
||||
|
||||
lines = []
|
||||
|
||||
for option_name, val in self._cfg_items_dict.items():
|
||||
if not bare:
|
||||
lines.extend(self._cfg_comments_dict[option_name])
|
||||
|
||||
if type(val) is list:
|
||||
# We will be aligning the backslashes after the
|
||||
# items in the list, so we need to know the longest.
|
||||
# First value in list:
|
||||
multi_line_indent = ' ' * (self._char_count_before_equals + 2)
|
||||
longest_len = len(max(val, key=len))
|
||||
val_w_len = val[0].ljust(longest_len)
|
||||
lines.append(f'{option_name:<23}= {val_w_len} \\')
|
||||
|
||||
# Next n-2 values in list:
|
||||
if len(val) > 2:
|
||||
for temp in val[1:-1]:
|
||||
val_w_len = temp.ljust(longest_len)
|
||||
lines.append(f'{multi_line_indent}{val_w_len} \\')
|
||||
|
||||
# Last value in list:
|
||||
lines.append(f'{multi_line_indent}{val[-1]}')
|
||||
elif type(val) is str:
|
||||
val_w_len = option_name.ljust(self._char_count_before_equals)
|
||||
if len(val) == 0:
|
||||
lines.append(f'{val_w_len}=')
|
||||
else:
|
||||
lines.append(f'{val_w_len}= {val}')
|
||||
|
||||
if self._end_key in self._cfg_comments_dict:
|
||||
if not bare:
|
||||
lines.extend(self._cfg_comments_dict[self._end_key])
|
||||
|
||||
# Ensure there is exactly 1 newline at end of file.
|
||||
lines.append('')
|
||||
|
||||
with open(doxyfile, 'w') as file:
|
||||
file.write('\n'.join(lines))
|
||||
|
||||
logging.debug(f'Saved configuration to [{doxyfile}].')
|
||||
|
||||
def option_names(self):
|
||||
"""List of contained Doxygen option names"""
|
||||
return self._cfg_items_dict.keys()
|
||||
|
||||
def is_valid_option(self, option_name: str) -> bool:
|
||||
"""Is `option_name` a valid option name?"""
|
||||
return option_name in self._cfg_items_dict
|
||||
|
||||
def set(self, option_name: str, val: str or list):
|
||||
"""Set value of specified option
|
||||
|
||||
:param option_name: Name of Doxygen option whose value to fetch
|
||||
:param val: Value to set
|
||||
- str = single-line value;
|
||||
- list = multi-line value.
|
||||
|
||||
:raises NameError: When ``name`` is not found.
|
||||
"""
|
||||
if option_name in self._cfg_items_dict:
|
||||
self._cfg_items_dict[option_name] = val
|
||||
if type(val) is list:
|
||||
logging.debug(f'Item [{option_name}] set to list.')
|
||||
else:
|
||||
logging.debug(f'Item [{option_name}] set to [{val}].')
|
||||
else:
|
||||
logging.error(f'Doxyfile option {option_name} not found.')
|
||||
raise NameError(f'Doxygen option {option_name} not found.')
|
||||
|
||||
def value(self, option_name: str) -> str or list:
|
||||
"""Value of specified option
|
||||
|
||||
:param option_name: Name of Doxygen option whose value to fetch
|
||||
|
||||
:returns string: single-line value
|
||||
:returns list: multi-line value
|
||||
:returns None: When ``option_name`` is not found.
|
||||
"""
|
||||
if option_name in self._cfg_items_dict:
|
||||
result = self._cfg_items_dict[option_name]
|
||||
logging.debug(f'Item [{option_name}] fetched.')
|
||||
else:
|
||||
result = None
|
||||
logging.debug(f'Item [{option_name}] not found.')
|
||||
|
||||
return result
|
||||
|
||||
def _parse_multiline_option(self, line) -> (str, str):
|
||||
"""Extract option name and first line of value of multi-line option.
|
||||
|
||||
:param line: line to parse
|
||||
:return: name and first line of multi-line option
|
||||
:raise ParseException: When process fail to extract data
|
||||
"""
|
||||
|
||||
matches = self._re_top_of_multiline_option.search(line)
|
||||
if matches is None or len(matches.groups()) != 2:
|
||||
logging.error(f'Error extracting first value in multi-line option from [{line}].')
|
||||
raise ParseException(f'Error extracting first value in multi-line option from [{line}].')
|
||||
|
||||
return matches.group(1), matches.group(2)
|
||||
|
||||
def _parse_single_line_option(self, line) -> (str, str):
|
||||
"""Extract option name and value of single line option.
|
||||
|
||||
:param line: line to parse
|
||||
:return: option name and value
|
||||
:raise ParseException: When process fail to extract data
|
||||
"""
|
||||
|
||||
matches = self._re_single_line_option.search(line)
|
||||
|
||||
if matches is None or len(matches.groups()) != 2:
|
||||
logging.error(f'Error extracting option name and value from [{line}].')
|
||||
raise ParseException(f'Error extracting option name and value from [{line}].')
|
||||
|
||||
return matches.group(1), matches.group(2)
|
||||
|
||||
def _bool_single_line_option(self, line: str) -> bool:
|
||||
return self._re_single_line_option.match(line) is not None
|
||||
|
||||
def _bool_comment_or_blank_line(self, line: str) -> bool: # NoQA
|
||||
return line.startswith("#") or (len(line) == 0)
|
||||
|
||||
def _bool_top_of_multiline_option(self, line) -> bool:
|
||||
return self._re_top_of_multiline_option.match(line) is not None
|
||||
1756
managed_components/lvgl__lvgl/docs/doxygen_xml.py
Normal file
561
managed_components/lvgl__lvgl/docs/example_list.py
Normal file
@@ -0,0 +1,561 @@
|
||||
#!/usr/bin/env python3
|
||||
""" example_list.py -- Build `examples.rst`
|
||||
|
||||
`examples.rst` is built by gathering all examples recursively under
|
||||
`lvgl/examples/`. The recognized directives in that file are then
|
||||
processed by Sphinx using `lvgl/docs/src/_ext/lv_example.py`.
|
||||
|
||||
Subsection names within `examples.rst` are made up of the capitalized
|
||||
directory names ('_' and '-' characters are converted to spaces) or
|
||||
are spelled out in `index.rst` files if the subsection names should be
|
||||
spelled differently. See "index.rst Format" section below for details.
|
||||
|
||||
An "example" is defined as:
|
||||
|
||||
- being anywhere under the `lvgl/examples/` directory,
|
||||
- the presence of an `index.rst` in a directory with examples, and
|
||||
- example C code in file names typically starting with "lv_example_".
|
||||
|
||||
That C code and a live, interactive running example, is pulled into each
|
||||
example in the EXAMPLES HTML page, as well as every doc where such
|
||||
examples are included, by a directive like this:
|
||||
|
||||
.. code::
|
||||
|
||||
.. include:: /examples/layouts/flex/index.rst
|
||||
|
||||
Note that in the intermediate dir (from which LVGL user docs are generated),
|
||||
``./examples/`` is a top-level subdirectory, so no relative "../../.." etc.
|
||||
is required in the path. Using a path starting at "root" tells Sphinx to
|
||||
start at the top-level directory where the docs are being generated,
|
||||
typically ``lvgl/docs/intermediate/``.
|
||||
|
||||
See `build.py` for more information about the intermediate directory.
|
||||
|
||||
If a subdirectory is included in the `avoid_dirs` list herein, it will
|
||||
not generate any output in the resulting `examples.rst` file.
|
||||
Example: `lvgl/examples/assets/`.
|
||||
|
||||
|
||||
Usage
|
||||
*****
|
||||
|
||||
.. code::
|
||||
|
||||
import example_list
|
||||
example_list.make_warnings_into_errors() # Optional
|
||||
example_list.DEBUG_MODE = True # Optional
|
||||
example_list.exec(intermediate_dir)
|
||||
|
||||
or run it directly:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
python3 example_list.py "/home/lvgl/docs/intermediate"
|
||||
|
||||
In both cases, the `intermediate_dir` passed is expected to have
|
||||
an `./examples/` directory in it (copy of `lvgl/examples/`) as a
|
||||
top-level subdirectory.
|
||||
|
||||
|
||||
Examples Directory Requirements
|
||||
*******************************
|
||||
|
||||
.. code:: text
|
||||
|
||||
lvgl/examples/
|
||||
index.rst (.. dir_order: pseudo-directive since sub-dirs
|
||||
are not presented in alphabetical order)
|
||||
anim/
|
||||
index.rst (see below for expected contents)
|
||||
lv_example_anim_1.c
|
||||
lv_example_anim_2.c
|
||||
lv_example_anim_3.c
|
||||
lv_example_anim_4.c
|
||||
lv_example_anim_timeline_1.c
|
||||
...
|
||||
layouts/
|
||||
flex/
|
||||
index.rst (see below for expected contents)
|
||||
lv_example_flex_1.c
|
||||
lv_example_flex_2.c
|
||||
lv_example_flex_3.c
|
||||
etc.
|
||||
grid/
|
||||
etc.
|
||||
libs/
|
||||
index.rst (section-heading name: "3rd-Party Libraries"
|
||||
[since it is different than parent directory name])
|
||||
barcode/
|
||||
index.rst (see below for expected contents)
|
||||
lv_example_barcode_1.c
|
||||
lv_example_barcode_1.h
|
||||
bmp/
|
||||
etc.
|
||||
etc.
|
||||
etc.
|
||||
|
||||
.. note:: The above shows only 2 levels of directories but deeper
|
||||
levels are supported (up to 5 below document title).
|
||||
|
||||
|
||||
index.rst Format
|
||||
****************
|
||||
|
||||
Examples
|
||||
--------
|
||||
Examples are included in `index.rst` files when they are sibling files with
|
||||
the example C code.
|
||||
|
||||
.. code::
|
||||
|
||||
Example 1 Title <-- required for each example
|
||||
--------------- <-- required for each example
|
||||
<-- blank lines are ignored
|
||||
.. lv_example:: anim/lv_example_anim_1 <-- path relative to the `lvgl/examples/` dir
|
||||
:language: c
|
||||
|
||||
Repeat the above pattern for each example in the current directory. That number
|
||||
may be zero (0) for directories like `libs/` in which all examples are in directories
|
||||
below that level. See directory structure above.
|
||||
|
||||
For paths outside the current directory, simply provide the path to the code example
|
||||
relative to the `lvgl/examples/` directory. Example from
|
||||
`lvgl/examples/widgets/scale/index.rst`:
|
||||
|
||||
.. code::
|
||||
|
||||
...
|
||||
|
||||
A round scale style simulating a compass
|
||||
----------------------------------------
|
||||
|
||||
.. lv_example:: widgets/scale/lv_example_scale_12
|
||||
:language: c
|
||||
|
||||
Axis ticks and labels with scrolling on a chart
|
||||
-----------------------------------------------
|
||||
|
||||
.. lv_example:: widgets/chart/lv_example_chart_2 <-- path is outside scale/ dir
|
||||
:language: c
|
||||
|
||||
.. note::
|
||||
|
||||
Starting the example code filename with `lv_example_` is not a requirement of the
|
||||
this script, but does make it clear that it is an example, so this pattern should
|
||||
be preserved for new and changed examples.
|
||||
|
||||
|
||||
Custom Section Headings
|
||||
-----------------------
|
||||
If a section heading needs to be spelled differently than the capitalized name of the
|
||||
parent directory, then an `index.rst` file in that directory may contain the desired
|
||||
section-heading name in an ``.. example_heading`` pseudo-directive. Example from
|
||||
`lvgl/examples/libs/index.rst`:
|
||||
|
||||
.. code::
|
||||
|
||||
.. example_heading: 3rd-Party Libraries
|
||||
|
||||
|
||||
Directory Reordering
|
||||
--------------------
|
||||
There are cases where it is not appropriate to present the contents of a
|
||||
set of subdirectories in alphabetical order. When this is the case, a
|
||||
pseudo-directive in the `index.rst` file in the parent directory can be specified
|
||||
to govern the sequence its subdirectories are processed. The example below
|
||||
is from `lvgl/examples/widgets/index.rst`. It is provided in order to
|
||||
cause the "Base Widget" (obj) directory to be processed first (and thus
|
||||
included in the output first).
|
||||
|
||||
.. code::
|
||||
|
||||
.. dir_order:
|
||||
|
||||
obj
|
||||
animimg
|
||||
arc
|
||||
arclabel
|
||||
bar
|
||||
button
|
||||
buttonmatrix
|
||||
etc.
|
||||
|
||||
.. note::
|
||||
|
||||
A warning is issued if either:
|
||||
|
||||
- a subdirectory is named that does not exist, or
|
||||
- a subdirectory exists that is not in the list and not in the `avoid_dirs` list.
|
||||
|
||||
|
||||
Making Warnings into Errors
|
||||
***************************
|
||||
|
||||
If `make_warnings_into_errors()` was called, if there were any warnings
|
||||
issued, after the output is completely generated, this script will exit
|
||||
with a non-zero exit code. This can be done by client modules like this:
|
||||
|
||||
.. code::
|
||||
|
||||
import example_list
|
||||
example_list.make_warnings_into_errors()
|
||||
example_list.exec(intermediate_dir)
|
||||
|
||||
To turn it off:
|
||||
|
||||
.. code::
|
||||
|
||||
example_list.make_warnings_into_errors(False)
|
||||
|
||||
|
||||
Debug Output
|
||||
************
|
||||
|
||||
Enable debug output like this:
|
||||
|
||||
.. code::
|
||||
|
||||
example_list.DEBUG_MODE = True
|
||||
|
||||
Suppressing DEBUG_MODE is the default.
|
||||
|
||||
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
from io import TextIOWrapper
|
||||
from announce import *
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# This is the order that LVGL documentation uses for the section heading
|
||||
# levels. header_defs[0] is the highest and header_defs[5] is the lowest.
|
||||
# If this order is not kept in the reST files Sphinx will complain, and
|
||||
# have difficulty formatting the TOC correctly.
|
||||
# -------------------------------------------------------------------------
|
||||
TITLE = '='
|
||||
CHAPTER = '*'
|
||||
SECTION = '-'
|
||||
SUBSECTION = '~'
|
||||
SUBSUBSECTION = '^'
|
||||
SUBSUBSUBSECTION = "'"
|
||||
|
||||
header_defs = [
|
||||
TITLE,
|
||||
CHAPTER,
|
||||
SECTION,
|
||||
SUBSECTION,
|
||||
SUBSUBSECTION,
|
||||
SUBSUBSUBSECTION,
|
||||
]
|
||||
|
||||
LV_EXAMPLE_DIRECTIVE = '.. lv_example::'
|
||||
EXAMPLE_HEADING_DIRECTIVE = '.. example_heading:'
|
||||
DIR_ORDER_DIRECTIVE = '.. dir_order:'
|
||||
DIR_SEP = os.sep
|
||||
INDEX_FILENAME = 'index.rst'
|
||||
MAKE_WARNINGS_INTO_ERRORS = False
|
||||
DEBUG_MODE = False
|
||||
THIS_FILE = os.path.basename(__file__)
|
||||
_warning_issued = False
|
||||
_top_level_heading_count = 0
|
||||
|
||||
avoid_dirs = [
|
||||
os.path.join('examples', 'arduino'),
|
||||
os.path.join('examples', 'assets'),
|
||||
]
|
||||
|
||||
|
||||
def make_warnings_into_errors(val: bool = True):
|
||||
global MAKE_WARNINGS_INTO_ERRORS
|
||||
MAKE_WARNINGS_INTO_ERRORS = val
|
||||
|
||||
|
||||
def _default_section_heading(level: int, path: str, is_file: bool) -> str:
|
||||
if is_file:
|
||||
dir_path = os.path.dirname(path)
|
||||
else:
|
||||
dir_path = path
|
||||
|
||||
parent_dir = os.path.basename(dir_path)
|
||||
|
||||
# Compose default section heading based on capitalized words in `parent_dir`.
|
||||
word_list = parent_dir.replace('_', ' ').replace('-', ' ').split(' ')
|
||||
result = ''
|
||||
|
||||
for word in word_list:
|
||||
result += ' ' + word.capitalize()
|
||||
|
||||
# Remove leading space.
|
||||
if result:
|
||||
result = result[1:]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _warn(msg: str):
|
||||
global _warning_issued
|
||||
if MAKE_WARNINGS_INTO_ERRORS:
|
||||
warning_type = 'Error'
|
||||
else:
|
||||
warning_type = 'Warning'
|
||||
|
||||
if is_silent_mode():
|
||||
print(f'{THIS_FILE}: ' + '\x1b[31m' + f'>>> {warning_type}: ' + msg + '\x1b[0m')
|
||||
else:
|
||||
announce_colored(THIS_FILE, 'red', f'>>> {warning_type}: ' + msg)
|
||||
|
||||
_warning_issued = True
|
||||
|
||||
|
||||
def _in_avoid_dirs_list(dir_bep: str) -> bool:
|
||||
result = False
|
||||
|
||||
for avoid_dir in avoid_dirs:
|
||||
if avoid_dir in dir_bep:
|
||||
result = True
|
||||
break
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _validate_sub_dirs(sub_dirs: list[str], index_rst_path: str) -> bool:
|
||||
""" Validate sub-dirs that come from an `index.rst` `.. dir_order:` directive.
|
||||
|
||||
1. Check that that each one is an existing directory.
|
||||
2. Check that there are none missing except those in `avoid_dirs`.
|
||||
|
||||
Issue warning if either fails and set `_warning_issued`.
|
||||
If MAKE_WARNINGS_INTO_ERRORS, this will make script exit with an error
|
||||
code at the end.
|
||||
|
||||
:param sub_dirs: List of sub-dirs to validate
|
||||
:param index_rst_path: Path to index.rst file
|
||||
:return: Whether `sub_dirs` is valid per 1 and 2 above
|
||||
"""
|
||||
result = True
|
||||
|
||||
# Check that each sub-dir is an existing directory.
|
||||
for sub_dir in sub_dirs:
|
||||
if not os.path.isdir(sub_dir):
|
||||
result = False
|
||||
_warn(f'Dir-order directive in {index_rst_path} contains dir [{sub_dir}] that does not exist.')
|
||||
# We won't break here so that all such dirs can be listed.
|
||||
|
||||
# Check that there are none missing except those in `avoid_dirs`.
|
||||
dir_path = os.path.dirname(index_rst_path)
|
||||
actual_dirs = []
|
||||
|
||||
for dir_item in os.listdir(dir_path):
|
||||
path_bep = os.path.join(dir_path, dir_item)
|
||||
if os.path.isdir(path_bep):
|
||||
actual_dirs.append(path_bep)
|
||||
|
||||
# Are there any missing that are not in `avoid_dirs` list?
|
||||
# If so, issue warning about each directory missing.
|
||||
for sub_dir in actual_dirs:
|
||||
if sub_dir not in sub_dirs:
|
||||
if not _in_avoid_dirs_list(sub_dir):
|
||||
_warn(f'Dir-order directive in {index_rst_path} is missing dir [{sub_dir}].')
|
||||
result = False
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _emit_heading(level: int, hdg: str, f: TextIOWrapper):
|
||||
"""
|
||||
Emit reST heading using `header_defs`.
|
||||
|
||||
:param level: Directory depth below the top directory in tree. [0-5]
|
||||
:param hdg: Heading text
|
||||
:param f: Output file (examples.rst)
|
||||
:return:
|
||||
"""
|
||||
assert 0 <= level < len(header_defs), "level out of range"
|
||||
global _top_level_heading_count
|
||||
underline = header_defs[level] * len(hdg)
|
||||
announce(__file__, f'Section heading [{hdg}] at level [{level}].')
|
||||
|
||||
if level == 0:
|
||||
_top_level_heading_count += 1
|
||||
if _top_level_heading_count > 1:
|
||||
f.write('\n\n\n') # 3 extra lines above (doc) root titles, except 1st
|
||||
f.write(underline)
|
||||
f.write('\n')
|
||||
elif level == 1:
|
||||
f.write('\n\n') # 2 extra lines above chapters
|
||||
elif level == 2:
|
||||
f.write('\n') # 1 extra line above sections
|
||||
|
||||
f.write(hdg)
|
||||
f.write('\n')
|
||||
f.write(underline)
|
||||
f.write('\n\n')
|
||||
|
||||
|
||||
def _generate_output_from_dir(level: int,
|
||||
root_len: int,
|
||||
file_or_dir: str,
|
||||
is_file: bool,
|
||||
orig_dir_list: list[str],
|
||||
f: TextIOWrapper) -> list[str]:
|
||||
""" Output to `f` based on contents of `file_or_dir`.
|
||||
|
||||
:param level: Directory depth below the top directory in tree. [0-4]
|
||||
:param root_len: Length of root path -- is deleted from paths so that
|
||||
paths are relative to the `lvgl/examples/` dir.
|
||||
:param file_or_dir: Path to "thing" being processed.
|
||||
:param is_file: True if `file_or_dir` is an `index.rst` file.
|
||||
:param orig_dir_list: List of sub-dirs below dir being processed.
|
||||
Will be returned from this function if a
|
||||
dir-order directive is NOT found in index file.
|
||||
:param f: Output file (examples.rst)
|
||||
:return: `orig_dir_list` or `dir_order_override` if a
|
||||
dir-order directive is found in index file.
|
||||
"""
|
||||
dir_order_override = []
|
||||
result_dir_list = orig_dir_list
|
||||
|
||||
# It is an error to proceed with `level` out of range. Clamping it to be in
|
||||
# range is also an error because it would cause the output to be corrupted with
|
||||
# an invalid section-heading underscore, which would generate an error later.
|
||||
if 0 <= level and level + 1 < len(header_defs):
|
||||
section_heading = _default_section_heading(level, file_or_dir, is_file)
|
||||
example_tuples = []
|
||||
relative_dir = ''
|
||||
|
||||
if is_file:
|
||||
announce(__file__, f'Processing file [{file_or_dir}]...')
|
||||
# We are processing an index.rst file.
|
||||
with open(file_or_dir, 'r', encoding='utf-8') as fidx:
|
||||
# It is important that this is NOT fidx.readlines() because
|
||||
# it leaves blank lines containing '\n' instead of ''.
|
||||
lines = fidx.read().split('\n')
|
||||
|
||||
example_title = ''
|
||||
prev_line = ''
|
||||
dir_path = os.path.dirname(file_or_dir)
|
||||
in_dir_order_directive = False
|
||||
|
||||
# Accumulate data from `index.rst`. This needs to be done
|
||||
# first in case it overrides the default section heading.
|
||||
for line in lines:
|
||||
if in_dir_order_directive:
|
||||
leading_non_blank = (len(line) > 0) and not (line[0] == ' ' or line[0] == '\t')
|
||||
|
||||
if leading_non_blank:
|
||||
# Leading non-blank character ends dir-order directive.
|
||||
in_dir_order_directive = False
|
||||
else:
|
||||
# Still in dir-order directive.
|
||||
stripped_line = line.strip()
|
||||
if stripped_line:
|
||||
dir_order_override.append(os.path.join(dir_path, stripped_line))
|
||||
continue
|
||||
|
||||
stripped_line = line.strip()
|
||||
|
||||
if not stripped_line:
|
||||
continue # Skip blank line.
|
||||
elif stripped_line.startswith(EXAMPLE_HEADING_DIRECTIVE):
|
||||
new_heading = stripped_line.replace(EXAMPLE_HEADING_DIRECTIVE, '').strip()
|
||||
announce(__file__, f'Default section heading [{section_heading}] replaced with [{new_heading}]...')
|
||||
section_heading = new_heading
|
||||
elif stripped_line.startswith('---'):
|
||||
example_title = prev_line
|
||||
announce(__file__, f'Found example [{example_title}]...')
|
||||
elif stripped_line.startswith(LV_EXAMPLE_DIRECTIVE):
|
||||
rel_path_from_examples_dir = stripped_line.replace(LV_EXAMPLE_DIRECTIVE, '').strip()
|
||||
announce(__file__, f' [{rel_path_from_examples_dir}]')
|
||||
example_tuples.append( (example_title, rel_path_from_examples_dir) )
|
||||
elif not in_dir_order_directive and stripped_line.startswith(DIR_ORDER_DIRECTIVE):
|
||||
in_dir_order_directive = True
|
||||
announce(__file__, f'Found DIR-ORDER directive.')
|
||||
|
||||
prev_line = stripped_line
|
||||
|
||||
# Output section heading. This occurs even when we have descended into an
|
||||
# empty directory with example sub-dirs below it.
|
||||
_emit_heading(level, section_heading, f)
|
||||
|
||||
# Output examples, if any. Will be empty when we are in an empty directory
|
||||
# with example sub-dirs below it.
|
||||
for example_tuple in example_tuples:
|
||||
example_title = example_tuple[0]
|
||||
rel_path_from_examples_dir = example_tuple[1]
|
||||
example_hdg_underline = header_defs[level + 1] * len(example_title)
|
||||
announce(__file__, f'Writing example [{rel_path_from_examples_dir}]...')
|
||||
_emit_heading(level + 1, example_title, f)
|
||||
f.write(LV_EXAMPLE_DIRECTIVE + ' ' + rel_path_from_examples_dir)
|
||||
f.write('\n\n')
|
||||
|
||||
if dir_order_override:
|
||||
_validate_sub_dirs(dir_order_override, file_or_dir)
|
||||
result_dir_list = dir_order_override
|
||||
|
||||
return result_dir_list
|
||||
|
||||
|
||||
def process_dir_recursively(level: int, root_len: int, dir_bep: str, f: TextIOWrapper):
|
||||
""" Process dir `dir_bep` recursively, avoiding sub-dirs in `avoid_dirs`.
|
||||
|
||||
:param level: Directory depth below the top directory in tree.
|
||||
:param root_len: Length of root path (gets removed from full path)
|
||||
:param dir_bep: Directory *being processed*
|
||||
:param f: Output file (examples.rst)
|
||||
"""
|
||||
announce(__file__, f'Processing dir [{dir_bep}]...')
|
||||
sub_dirs = []
|
||||
idx_files = []
|
||||
|
||||
if not os.path.isdir(dir_bep):
|
||||
_warn(f'process_dir_recursively: `dir_bep` [{dir_bep}] does not exist.')
|
||||
return
|
||||
|
||||
# For each "thing" found in `dir_bep`, build lists: sub_dirs and idx_files.
|
||||
for dir_item in os.listdir(dir_bep):
|
||||
path_bep = os.path.join(dir_bep, dir_item)
|
||||
if os.path.isdir(path_bep):
|
||||
sub_dirs.append(path_bep)
|
||||
elif path_bep.endswith(INDEX_FILENAME):
|
||||
idx_files.append(path_bep)
|
||||
|
||||
if idx_files:
|
||||
sub_dirs = _generate_output_from_dir(level, root_len, idx_files[0], True, sub_dirs, f)
|
||||
# `sub_dirs` can be replaced if `index.rst` contains a dir-order directive.
|
||||
else:
|
||||
_generate_output_from_dir(level, root_len, dir_bep, False, sub_dirs, f)
|
||||
|
||||
# Now recursively process sub_dirs.
|
||||
for subdir in sub_dirs:
|
||||
if not _in_avoid_dirs_list(subdir):
|
||||
process_dir_recursively(level + 1, root_len, subdir, f)
|
||||
|
||||
|
||||
def exec(intermediate_dir):
|
||||
announce_set_silent_mode(not DEBUG_MODE)
|
||||
output_path = os.path.join(intermediate_dir, 'examples.rst')
|
||||
input_paths = [
|
||||
os.path.join('..', 'examples'),
|
||||
# os.path.join('..', 'demos')
|
||||
]
|
||||
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
f.write('.. _examples:\n')
|
||||
f.write('\n')
|
||||
|
||||
# Recursively walk the directories in `input_paths` array for
|
||||
# ``index.rst`` files.
|
||||
for root_path in input_paths:
|
||||
root_len = len(root_path) + 1
|
||||
process_dir_recursively(0, root_len, root_path, f)
|
||||
|
||||
if MAKE_WARNINGS_INTO_ERRORS and _warning_issued:
|
||||
exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
"""Make module run-able as well as importable."""
|
||||
base_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
os.chdir(base_dir)
|
||||
exec(sys.argv[1])
|
||||
23082
managed_components/lvgl__lvgl/docs/flyers/LVGL-Chinese-Flyer.pdf
Normal file
80
managed_components/lvgl__lvgl/docs/make.bat
Normal file
@@ -0,0 +1,80 @@
|
||||
@ECHO OFF
|
||||
rem -----------------------------------------------------------------------
|
||||
rem This file is intended only to be used after the contents of the
|
||||
rem intermediate directory have been created. Do so by:
|
||||
rem
|
||||
rem $ python build.py intermediate [skip_api]
|
||||
rem
|
||||
rem This is a modified version of the standard Sphinx `make.bat` file.
|
||||
rem Changes:
|
||||
rem - uses these environment variables in the same way `build.py` does
|
||||
rem when they are set:
|
||||
rem - LVGL_DOC_BUILD_INTERMEDIATE_DIR
|
||||
rem - LVGL_DOC_BUILD_OUTPUT_DIR
|
||||
rem - Cleans up locally-created environment variables at end, so they
|
||||
rem do not clutter environment variables.
|
||||
rem -----------------------------------------------------------------------
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
setlocal ENABLEDELAYEDEXPANSION
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
|
||||
if "%LVGL_DOC_BUILD_INTERMEDIATE_DIR%" == "" (
|
||||
set SOURCEDIR=intermediate
|
||||
) else (
|
||||
set SOURCEDIR=%LVGL_DOC_BUILD_INTERMEDIATE_DIR%
|
||||
)
|
||||
|
||||
if "%LVGL_DOC_BUILD_OUTPUT_DIR%" == "" (
|
||||
set BUILDDIR=build
|
||||
) else (
|
||||
set BUILDDIR=%LVGL_DOC_BUILD_OUTPUT_DIR%
|
||||
)
|
||||
if "%SPHINXOPTS%" == "" (
|
||||
rem python ./src/lvgl_version.py >_version_temp.txt
|
||||
rem set /p VER=<_version_temp.txt
|
||||
rem del _version_temp.txt
|
||||
for /F %%v in ('python src\lvgl_version.py') do set VER=%%v
|
||||
echo VERSION [!VER!]
|
||||
rem set SPHINXOPTS=-D version="!VER!" -j 4
|
||||
set SPHINXOPTS=-j 4
|
||||
set VER=
|
||||
)
|
||||
|
||||
echo SOURCEDIR [%SOURCEDIR%]
|
||||
echo BUILDDIR [%BUILDDIR%]
|
||||
echo SPHINXOPTS [%SPHINXOPTS%]
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.https://www.sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
echo %SPHINXBUILD% -M %1 "%SOURCEDIR%" "%BUILDDIR%" %SPHINXOPTS% %2 %3 %4 %5 %6 %7 %8 %9
|
||||
%SPHINXBUILD% -M %1 "%SOURCEDIR%" "%BUILDDIR%" %SPHINXOPTS% %2 %3 %4 %5 %6 %7 %8 %9
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help "%SOURCEDIR%" "%BUILDDIR%" %SPHINXOPTS% %2 %3 %4 %5 %6 %7 %8 %9
|
||||
|
||||
:end
|
||||
rem Clean up.
|
||||
popd
|
||||
set BUILDDIR=
|
||||
set SOURCEDIR=
|
||||
19
managed_components/lvgl__lvgl/docs/requirements.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
Sphinx<=8.2.3
|
||||
breathe
|
||||
imagesize
|
||||
importlib-metadata
|
||||
sphinx-sitemap
|
||||
sphinxcontrib-applehelp
|
||||
sphinxcontrib-devhelp
|
||||
sphinxcontrib-htmlhelp
|
||||
sphinxcontrib-jsmath
|
||||
sphinxcontrib-qthelp
|
||||
sphinxcontrib-serializinghtml
|
||||
sphinxcontrib-mermaid==0.9.2
|
||||
sphinx-copybutton
|
||||
sphinx-design
|
||||
typing-extensions
|
||||
sphinx-reredirects
|
||||
dirsync
|
||||
furo
|
||||
accessible-pygments
|
||||
17
managed_components/lvgl__lvgl/docs/src/API/index.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
.. _api placeholder:
|
||||
|
||||
***************
|
||||
API Placeholder
|
||||
***************
|
||||
|
||||
This document is here merely as a placeholder so it's LACK of presence when
|
||||
building the docs like this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python build.py html skip_api
|
||||
|
||||
(which is done in a doc-development/testing environment) does not generate a warning
|
||||
because this file is not there. When the API portion of the documents DOES get
|
||||
built, this file is replaced with one programmatically generated by ``build.py``
|
||||
making calls on ``api_doc_builder.py`` and ``doxygen_xml.py`` modules.
|
||||
523
managed_components/lvgl__lvgl/docs/src/CHANGELOG.rst
Normal file
@@ -0,0 +1,523 @@
|
||||
.. _changelog:
|
||||
|
||||
Change Log
|
||||
==========
|
||||
|
||||
`v9.5.0 <https://github.com/lvgl/lvgl/compare/v9.4.0...v9.5.0>`__ 18 February 2026
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
LVGL v9.5.0 continues expanding MPU capabilities while maintaining the lightness and efficiency that make LVGL viable on resource-constrained MCUs. This release adds native blur and drop shadow rendering, a rewritten Wayland driver with EGL support, complete OpenGL rendering via NanoVG, and significant 3D rendering improvements.
|
||||
|
||||
Main Features
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
- **Blur and Drop Shadow**. Native software blur and drop shadow support work on all targets without requiring a GPU. Drop shadows add depth to overlays and cards; blur enables frosted-glass effects and background dimming. :ref:`Learn more <style_properties>`.
|
||||
- **Wayland Driver Rewrite**. Complete rewrite with SHM backend supporting double-buffered direct mode rendering and a new EGL backend for hardware-accelerated OpenGL. :ref:`Learn more <wayland_driver>`.
|
||||
- **NanoVG Rendering Backend**. Complete OpenGL draw unit providing GPU-accelerated vector rendering, anti-aliased shapes, and compositing. Auto-initializes when OpenGL context is available. :ref:`Learn more <nanovg_draw_unit>`.
|
||||
- **Bézier Curved Charts**. New ``LV_CHART_TYPE_CURVE`` draws smooth Bézier curves between data points. Requires ``LV_USE_VECTOR_GRAPHICS`` and a compatible draw unit (VGLite, NanoVG or Software with ThorVG). :ref:`Learn more <lv_chart>`.
|
||||
|
||||
GPU Acceleration & Performance
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- **RISC-V Vector Extension Support**. SIMD acceleration for software rendering on RISC-V platforms with V extension support. Speeds up blending operations. Enable with ``LV_USE_DRAW_SW_ASM`` set to ``LV_DRAW_SW_ASM_RISCV_V``.
|
||||
- **SDL EGL Support**. SDL now supports EGL rendering backend, completing EGL coverage across SDL, Wayland, DRM, and GLFW for consistent hardware acceleration.
|
||||
- **OpenGL Improvements**. Matrix transformations, RGBA-only texture format, GLSL 330 support, and scissor optimization for opaque fills.
|
||||
|
||||
3D Rendering
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- **Runtime glTF Manipulation**. Read and modify glTF model nodes at runtime including scale, rotation, translation, and animation state for dynamic 3D scenes.
|
||||
- **Raycasting Utilities**. New API for 3D-to-2D coordinate conversion and ray-object intersection testing, enabling touch interaction with 3D objects.
|
||||
- **Cross-Platform 3D Support**. With EGL now available across all major Linux backends (SDL, Wayland, DRM, GLFW), 3D rendering is fully supported on all platforms.
|
||||
|
||||
Style & Theme System
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- **LV_STATE_ALT**. New widget state for simple dark/light mode switching without managing separate theme trees.
|
||||
- **Theme Management API**. New functions: ``lv_obj_remove_theme``, ``lv_obj_bind_style_prop``, and full theme create/copy/delete API for multi-theme applications and data-driven style binding.
|
||||
|
||||
Widgets & Property Interface
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- **Property Interface Rollout**. Arc, bar, switch, checkbox, LED, line, scale, spinbox, spinner, table, tabview, buttonmatrix, span, menu, and chart now expose uniform property interface for data binding.
|
||||
- **Input Handling**. Key remapping at indev level, configurable gesture thresholds, ``LV_OBJ_FLAG_RADIO_BUTTON`` for radio groups, and keypad events emitted without assigned group.
|
||||
|
||||
Media Support
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
- **GStreamer Audio-Free Sources**. Supports video sources without audio tracks, enabling camera stream embedding in LVGL applications.
|
||||
- **WebP Decoder**. Native WebP image decoding support added alongside existing JPEG, PNG, and GIF support.
|
||||
|
||||
Breaking Changes
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
- **Wayland Client-Side Decorations Removed**. Rewritten driver no longer supports client-side window decorations. Use LVGL widgets (e.g., ``lv_win``) for window chrome.
|
||||
- **XML Engine Removed**. XML UI engine development continues outside the main repository. Separate announcement forthcoming.
|
||||
|
||||
Deprecations
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- **lv_fragment deprecated**. Will be removed in a future release. Plan migration for view lifecycle management.
|
||||
- **lv_wayland_display_close_cb_t deprecated**. Use ``LV_EVENT_DELETE`` on display returned by ``lv_wayland_window_create`` instead.
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- **feat(opengl): throw error if both draw nanovg and opengles draw units are enabled** `9719 <https://github.com/lvgl/lvgl/pull/9719>`__
|
||||
- **feat(gltf): upgrade fastgltf with latest fixes** `9727 <https://github.com/lvgl/lvgl/pull/9727>`__
|
||||
- **feat(obj): add back support for user flags** `9711 <https://github.com/lvgl/lvgl/pull/9711>`__
|
||||
- **feat(style): add lv_obj_remove_theme** `9692 <https://github.com/lvgl/lvgl/pull/9692>`__
|
||||
- **feat(text): skip leading spaces after line wrap** `9639 <https://github.com/lvgl/lvgl/pull/9639>`__
|
||||
- **feat(draw/opengl): support dynamic video textures in OpenGLES** `9704 <https://github.com/lvgl/lvgl/pull/9704>`__
|
||||
- **feat(drm/egl): auto infer drm egl config from use_opengles** `9671 <https://github.com/lvgl/lvgl/pull/9671>`__
|
||||
- **feat(gstreamer): send event on end of stream** `9634 <https://github.com/lvgl/lvgl/pull/9634>`__
|
||||
- **feat(display): send screen load events to display** `9600 <https://github.com/lvgl/lvgl/pull/9600>`__
|
||||
- **feat(chart): add curved type** `9564 <https://github.com/lvgl/lvgl/pull/9564>`__
|
||||
- **feat(indev): emit events for keypad without assigned group** `9656 <https://github.com/lvgl/lvgl/pull/9656>`__
|
||||
- **feat(style): add LV_STATE_ALT for simple dark/light switching** `9691 <https://github.com/lvgl/lvgl/pull/9691>`__
|
||||
- **feat(svg): simplify node attributes inheritance introduce in #9424** `9690 <https://github.com/lvgl/lvgl/pull/9690>`__
|
||||
- **feat(NemaGFX): Add nema libs for cortex M7 and M55** `9374 <https://github.com/lvgl/lvgl/pull/9374>`__
|
||||
- **feat(ibl_sampler): fallback to default env image and remove unnecessary allocation** `9675 <https://github.com/lvgl/lvgl/pull/9675>`__
|
||||
- **feat(msgbox): add support for formatted text** `9583 <https://github.com/lvgl/lvgl/pull/9583>`__
|
||||
- **feat(obj): allow null class names if obj_name isn't set** `9653 <https://github.com/lvgl/lvgl/pull/9653>`__
|
||||
- **feat(opengl): add matrix transformations to opengles rendering** `9654 <https://github.com/lvgl/lvgl/pull/9654>`__
|
||||
- **feat(ppa): make the PPA burst length configurable** `9612 <https://github.com/lvgl/lvgl/pull/9612>`__
|
||||
- **feat(nanovg): add draw 3D support** `9571 <https://github.com/lvgl/lvgl/pull/9571>`__
|
||||
- **feat(xml): remove the XML parser and loader** `9565 <https://github.com/lvgl/lvgl/pull/9565>`__
|
||||
- **feat(indev): add api to set gesture thresholds** `9641 <https://github.com/lvgl/lvgl/pull/9641>`__
|
||||
- **feat(sdl): add EGL support** `9462 <https://github.com/lvgl/lvgl/pull/9462>`__
|
||||
- **feat(calendar): add 2026 to header** `9630 <https://github.com/lvgl/lvgl/pull/9630>`__
|
||||
- **feat(draw): make lv_draw_mask_rect_dsc_t public** `9454 <https://github.com/lvgl/lvgl/pull/9454>`__
|
||||
- **feat(line): allow defining an array of point in the draw task** `9269 <https://github.com/lvgl/lvgl/pull/9269>`__
|
||||
- **feat(svg): support inheriting node attributes** `9424 <https://github.com/lvgl/lvgl/pull/9424>`__
|
||||
- **feat(wayland): add display rotation support for the shm backend** `9386 <https://github.com/lvgl/lvgl/pull/9386>`__
|
||||
- **feat(svg): support inline styles** `9423 <https://github.com/lvgl/lvgl/pull/9423>`__
|
||||
- **feat(draw): add RISCV V extension for software draw** `9504 <https://github.com/lvgl/lvgl/pull/9504>`__
|
||||
- **feat(canvas): add api to skip canvas invalidation when setting pixel** `9592 <https://github.com/lvgl/lvgl/pull/9592>`__
|
||||
- **feat(wayland): add egl support** `9398 <https://github.com/lvgl/lvgl/pull/9398>`__
|
||||
- **feat(gstreamer): add support for sources with no audio** `9551 <https://github.com/lvgl/lvgl/pull/9551>`__
|
||||
- **feat(drm/egl): add nanovg support** `9542 <https://github.com/lvgl/lvgl/pull/9542>`__
|
||||
- **feat(arclabel): support lv_arclabel_get_text_angle to get real rendered text size in degree** `9546 <https://github.com/lvgl/lvgl/pull/9546>`__
|
||||
- **feat(opengl): auto initialize nanovg draw unit** `9543 <https://github.com/lvgl/lvgl/pull/9543>`__
|
||||
- **feat(vg_lite): add support for special format** `9464 <https://github.com/lvgl/lvgl/pull/9464>`__
|
||||
- **feat(dropshadow): add drop shadow support** `9331 <https://github.com/lvgl/lvgl/pull/9331>`__
|
||||
- **feat(draw): add nanovg rendering backend** `8865 <https://github.com/lvgl/lvgl/pull/8865>`__
|
||||
- **feat(vg_lite_tvg): add VG_LITE_BLEND_DST_IN emulation support** `9528 <https://github.com/lvgl/lvgl/pull/9528>`__
|
||||
- **feat(display): add rotate point method** `9513 <https://github.com/lvgl/lvgl/pull/9513>`__
|
||||
- **feat(arclabel): support overflow mode** `9484 <https://github.com/lvgl/lvgl/pull/9484>`__
|
||||
- **feat(demos): allow specifying parent for widgets and music demos** `9444 <https://github.com/lvgl/lvgl/pull/9444>`__
|
||||
- **feat(fragment): deprecate lv_fragment** `9460 <https://github.com/lvgl/lvgl/pull/9460>`__
|
||||
- **feat(xml): add slot support** `9193 <https://github.com/lvgl/lvgl/pull/9193>`__
|
||||
- **feat(jpeg): add support for orientation and CMYK** `9296 <https://github.com/lvgl/lvgl/pull/9296>`__
|
||||
- **feat(opengl): add glsl version 330 support** `9384 <https://github.com/lvgl/lvgl/pull/9384>`__
|
||||
- **feat(group): add user_data getter and setter** `9466 <https://github.com/lvgl/lvgl/pull/9466>`__
|
||||
- **feat(core): add external data and destructor feature** `9112 <https://github.com/lvgl/lvgl/pull/9112>`__
|
||||
- **feat(glfw): remove glew dependency and use glad instead** `9319 <https://github.com/lvgl/lvgl/pull/9319>`__
|
||||
- **feat(obj): add LV_OBJ_FLAG_RADIO_BUTTON to easily create radio buttons** `9328 <https://github.com/lvgl/lvgl/pull/9328>`__
|
||||
- **feat(obj): add scroll x and scroll y properties** `9346 <https://github.com/lvgl/lvgl/pull/9346>`__
|
||||
- **feat(slider): add min_value and max_value setter** `9433 <https://github.com/lvgl/lvgl/pull/9433>`__
|
||||
- **feat(scale): update needles when scale is transformed** `9340 <https://github.com/lvgl/lvgl/pull/9340>`__
|
||||
- **feat(opengl): use only rgba format textures** `9304 <https://github.com/lvgl/lvgl/pull/9304>`__
|
||||
- **feat(nuttx): add mock to the NuttX driver for compilation testing** `9419 <https://github.com/lvgl/lvgl/pull/9419>`__
|
||||
- **feat(xml): add imagebutton support to XML** `9381 <https://github.com/lvgl/lvgl/pull/9381>`__
|
||||
- **feat(gltf): make linear_output optional to enable tonemapping and gamma adjustment** `9260 <https://github.com/lvgl/lvgl/pull/9260>`__
|
||||
- **feat(test): add lv_xml_test_run_to and lv_test_screenshot_result_t** `9189 <https://github.com/lvgl/lvgl/pull/9189>`__
|
||||
- **feat(file_explorer): allow hiding the back button** `9202 <https://github.com/lvgl/lvgl/pull/9202>`__
|
||||
- **feat(obj): allow setting child size to LV_PCT() of LV_SIZE_CONTENT parent by using the size of fixed/clamped children to set parent size** `9243 <https://github.com/lvgl/lvgl/pull/9243>`__
|
||||
- **feat(drm): add return type to set_file** `9365 <https://github.com/lvgl/lvgl/pull/9365>`__
|
||||
- **feat(fbdev): add return type to set_file** `9364 <https://github.com/lvgl/lvgl/pull/9364>`__
|
||||
- **feat(array): add remove_unordered function** `9339 <https://github.com/lvgl/lvgl/pull/9339>`__
|
||||
- **feat(gltf): allow modifying model's nodes at runtime** `9142 <https://github.com/lvgl/lvgl/pull/9142>`__
|
||||
- **feat(wayland): rewrite driver** `9195 <https://github.com/lvgl/lvgl/pull/9195>`__
|
||||
- **feat(blur): add blur support** `9223 <https://github.com/lvgl/lvgl/pull/9223>`__
|
||||
- **feat(examples/ffmpeg_player): specify default decoder** `9218 <https://github.com/lvgl/lvgl/pull/9218>`__
|
||||
- **feat(xml): support selector with local styles** `9184 <https://github.com/lvgl/lvgl/pull/9184>`__
|
||||
- **feat(fs): support multiple littlefs filesystems** `8868 <https://github.com/lvgl/lvgl/pull/8868>`__
|
||||
- **feat(obj): support `LV_SIZE_CONTENT` and `LV_PCT` min width/height in combination with flex grow** `8685 <https://github.com/lvgl/lvgl/pull/8685>`__
|
||||
- **feat(scripts/check_gcov_coverage): add analysis of specified file paths** `9264 <https://github.com/lvgl/lvgl/pull/9264>`__
|
||||
- **feat(gltf): support sharing the background environment across multiple objects** `9009 <https://github.com/lvgl/lvgl/pull/9009>`__
|
||||
- **feat(theme): add api to create, copy and delete themes** `9167 <https://github.com/lvgl/lvgl/pull/9167>`__
|
||||
- **feat(example/style): convert old transform demo to an example** `9050 <https://github.com/lvgl/lvgl/pull/9050>`__
|
||||
- **feat(xml): add color percentage support to animations** `9209 <https://github.com/lvgl/lvgl/pull/9209>`__
|
||||
- **feat(benchmark): show warnings for typical mistakes** `9171 <https://github.com/lvgl/lvgl/pull/9171>`__
|
||||
- **feat(style): add lv_obj_bind_style_prop** `9173 <https://github.com/lvgl/lvgl/pull/9173>`__
|
||||
- **feat(scripts): add automatic gcovr code coverage analysis** `9227 <https://github.com/lvgl/lvgl/pull/9227>`__
|
||||
- **feat(timer): resume timer handler after attribute changes** `9205 <https://github.com/lvgl/lvgl/pull/9205>`__
|
||||
- **feat(image_decoder): add webp decoder** `9175 <https://github.com/lvgl/lvgl/pull/9175>`__
|
||||
- **feat(translate): support translation tags in tabview and list** `9079 <https://github.com/lvgl/lvgl/pull/9079>`__
|
||||
- **feat(libpng): optimize the details of performance measurement** `9179 <https://github.com/lvgl/lvgl/pull/9179>`__
|
||||
- **feat(image_decoder): add performance measurement** `9178 <https://github.com/lvgl/lvgl/pull/9178>`__
|
||||
- **feat(vg_lite): add dynamic input parameter printing control** `9180 <https://github.com/lvgl/lvgl/pull/9180>`__
|
||||
- **feat(indev): implement key remapping (#8455)** `8981 <https://github.com/lvgl/lvgl/pull/8981>`__
|
||||
- **feat(keyboard): add definitions for control mode buttons** `9101 <https://github.com/lvgl/lvgl/pull/9101>`__
|
||||
- **feat(gltf): gltf view raycasting and 3d point to screen point conversion** `9143 <https://github.com/lvgl/lvgl/pull/9143>`__
|
||||
- **feat(gltf): use alternate blending mode for glTF views** `9115 <https://github.com/lvgl/lvgl/pull/9115>`__
|
||||
- **feat(ffmpeg_player): add set_decoder** `9122 <https://github.com/lvgl/lvgl/pull/9122>`__
|
||||
- **feat(xml): add lv_spinner** `9091 <https://github.com/lvgl/lvgl/pull/9091>`__
|
||||
- **feat(translation): const-correct arrays of strings** `9147 <https://github.com/lvgl/lvgl/pull/9147>`__
|
||||
- **feat(fs): add read file with alloc API** `9109 <https://github.com/lvgl/lvgl/pull/9109>`__
|
||||
- **feat(gif): use gif draw raw mode to support stride mode** `9121 <https://github.com/lvgl/lvgl/pull/9121>`__
|
||||
- **feat(class): ensure classes have names** `9097 <https://github.com/lvgl/lvgl/pull/9097>`__
|
||||
- **feat(example/scroll): convert old scroll demo to an example** `9049 <https://github.com/lvgl/lvgl/pull/9049>`__
|
||||
- **feat(spinbox): add property interface support** `0290020 <https://github.com/lvgl/lvgl/commit/029002092ebf6b426a00e2f768de393eee422697>`__
|
||||
- **feat(bar): add property interface support** `0bd6422 <https://github.com/lvgl/lvgl/commit/0bd6422a5e863d54b0cdb953bbe95179d63e5744>`__
|
||||
- **feat(arc): add property API support** `09b3143 <https://github.com/lvgl/lvgl/commit/09b3143eb80850e140ead4d88a863abd42f8a648>`__
|
||||
- **feat(chart): add property interface support** `7801fd2 <https://github.com/lvgl/lvgl/commit/7801fd22e862e82a972f11418897ce6a725724ff>`__
|
||||
- **feat(scale): add property interface support** `54487a9 <https://github.com/lvgl/lvgl/commit/54487a9d50388c4abead176efd36ba6785819730>`__
|
||||
- **feat(span): add property interface support** `8a2b610 <https://github.com/lvgl/lvgl/commit/8a2b610f099c21880d09daa32915b6c2f2dafaa1>`__
|
||||
- **feat(spinner): add property interface support** `bb76fd2 <https://github.com/lvgl/lvgl/commit/bb76fd2129526e3d8863f842adbce9bb4205256c>`__
|
||||
- **feat(tabview): add property interface support** `492770e <https://github.com/lvgl/lvgl/commit/492770e77fc080ecfea87f9d80f86c7762ce14cd>`__
|
||||
- **feat(dropdown): static and non-static setter for text** `af5c3f1 <https://github.com/lvgl/lvgl/commit/af5c3f12f6e9d8db2f7105b461d060615ca33f6d>`__
|
||||
- **feat(table): add property interface support** `f66cc41 <https://github.com/lvgl/lvgl/commit/f66cc4187c02051b39f54e755cbbd21536f26467>`__
|
||||
- **feat(menu): add property interface support** `8bf6952 <https://github.com/lvgl/lvgl/commit/8bf69520b1043b6253948554864328cb94175d6d>`__
|
||||
- **feat(buttonmatrix): add property interface support** `847cc0c <https://github.com/lvgl/lvgl/commit/847cc0c8dea8abb9952e9248a50a6ed9833c4736>`__
|
||||
- **feat(led): add property interface support** `43f35a2 <https://github.com/lvgl/lvgl/commit/43f35a2f3ccc5fb64f873e9f223e41bd77c76660>`__
|
||||
- **feat(line): add property interface support** `5ac2ca4 <https://github.com/lvgl/lvgl/commit/5ac2ca44fff8b82d442ed2bdbcdc4a5a87855f39>`__
|
||||
- **feat(switch): add property interface support** `0fb0f37 <https://github.com/lvgl/lvgl/commit/0fb0f37fa44b8621b98bba69010ecace88142811>`__
|
||||
- **feat(checkbox): add property interface support** `7f924a3 <https://github.com/lvgl/lvgl/commit/7f924a3a7240c8220e06112282cb20b819567786>`__
|
||||
- **feat(textarea): static and non-static setter for accepted_chars** `e20517a <https://github.com/lvgl/lvgl/commit/e20517aa70f9c4e804f9db7ce8959cfcfb23d540>`__
|
||||
- **feat(dave2d): always invalidate cache when using Renesas RZA** `9d14a04 <https://github.com/lvgl/lvgl/commit/9d14a04e8a112a859b7acdc416dd90db717cb3c3>`__
|
||||
- **feat(draw_buf): add missing D-Cache flush** `d703c3a <https://github.com/lvgl/lvgl/commit/d703c3a90b3f1d69e3615777a3384a0f987f6552>`__
|
||||
- **feat(draw_buf_convert): add missing profiler** `4016f35 <https://github.com/lvgl/lvgl/commit/4016f35235912c7582f06f3234dbb8c061275fbb>`__
|
||||
|
||||
Performance
|
||||
~~~~~~~~~~~
|
||||
|
||||
- **perf(draw/opengl): use glScissor for opaque fills** `9222 <https://github.com/lvgl/lvgl/pull/9222>`__
|
||||
- **perf(label): make LAYOUT_COMPLETED a display event** `9215 <https://github.com/lvgl/lvgl/pull/9215>`__
|
||||
- **perf(vg_lite): add bitmap font cache for non-aligned fonts** `9343 <https://github.com/lvgl/lvgl/pull/9343>`__
|
||||
- **perf(line): check that line has at least 2 points before drawing** `9185 <https://github.com/lvgl/lvgl/pull/9185>`__
|
||||
- **perf(gltf): optimize gltf material negotiation** `9038 <https://github.com/lvgl/lvgl/pull/9038>`__
|
||||
- **perf(opengl): remove long delay when destroying shader programs** `9037 <https://github.com/lvgl/lvgl/pull/9037>`__
|
||||
- **perf(label): reduce lv_label_refr_text calls** `9041 <https://github.com/lvgl/lvgl/pull/9041>`__
|
||||
|
||||
Fixes
|
||||
~~~~~
|
||||
|
||||
- **fix(blur): render non-backdrop blur when the main rendering is done** `9752 <https://github.com/lvgl/lvgl/pull/9752>`__
|
||||
- **fix(refr): flag when all tasks are added to screen layers** `9739 <https://github.com/lvgl/lvgl/pull/9739>`__
|
||||
- **fix(cmake): declare `fatfs` as private dependencies** `9742 <https://github.com/lvgl/lvgl/pull/9742>`__
|
||||
- **fix(wayland/g2d): fix busy buffer warnings** `9730 <https://github.com/lvgl/lvgl/pull/9730>`__
|
||||
- **fix(draw/g2d): disable image rendering** `9729 <https://github.com/lvgl/lvgl/pull/9729>`__
|
||||
- **fix(NemaGFX): Add back support for indexed images** `9714 <https://github.com/lvgl/lvgl/pull/9714>`__
|
||||
- **fix(core): add missing includes for external data feature** `9715 <https://github.com/lvgl/lvgl/pull/9715>`__
|
||||
- **fix(freetype): check if ctx is null before deleting font** `9728 <https://github.com/lvgl/lvgl/pull/9728>`__
|
||||
- **fix(opengl): correctly apply matrix transforms** `9726 <https://github.com/lvgl/lvgl/pull/9726>`__
|
||||
- **fix(wayland): read and flush compositor events on a timer** `9720 <https://github.com/lvgl/lvgl/pull/9720>`__
|
||||
- **fix(wayland/shm): damage surface before returning if not last flush** `9721 <https://github.com/lvgl/lvgl/pull/9721>`__
|
||||
- **fix(thorvg): ensure height is always positive** `9712 <https://github.com/lvgl/lvgl/pull/9712>`__
|
||||
- **fix(indev): only reset last point and it's movement only if no previous object existed** `9707 <https://github.com/lvgl/lvgl/pull/9707>`__
|
||||
- **fix(uefi): add missing trailing newline to driver headers** `9710 <https://github.com/lvgl/lvgl/pull/9710>`__
|
||||
- **fix(gles): transpose lv_matrix_t before uploading to shader** `9703 <https://github.com/lvgl/lvgl/pull/9703>`__
|
||||
- **fix(flex): use min size when item is set to grow and parent is LV_SIZE_CONTENT** `8806 <https://github.com/lvgl/lvgl/pull/8806>`__
|
||||
- **fix(gltf): flip vertically by default** `9694 <https://github.com/lvgl/lvgl/pull/9694>`__
|
||||
- **fix(draw/opengles): red/blue channel swap in fill operations** `9693 <https://github.com/lvgl/lvgl/pull/9693>`__
|
||||
- **fix(LTDC): warn when rotating and DRAW_SW is disabled** `9670 <https://github.com/lvgl/lvgl/pull/9670>`__
|
||||
- **fix(arc): handle indicator padding for knob position and arc invalidation area** `9302 <https://github.com/lvgl/lvgl/pull/9302>`__
|
||||
- **fix(dave2d): fix several rendering issues (mostly restore the original alpha)** `9566 <https://github.com/lvgl/lvgl/pull/9566>`__
|
||||
- **fix(draw/helium): include lv_conf_internal to avoid C declarations** `9658 <https://github.com/lvgl/lvgl/pull/9658>`__
|
||||
- **fix(fbdev): use display offset and clip area to display area** `9668 <https://github.com/lvgl/lvgl/pull/9668>`__
|
||||
- **fix(draw/line): fix buffer overflow when point is outside display area** `9669 <https://github.com/lvgl/lvgl/pull/9669>`__
|
||||
- **fix(gltf): avoid resetting value_changed node attribute** `9674 <https://github.com/lvgl/lvgl/pull/9674>`__
|
||||
- **fix(gltf): remove designated initializers causing warnings** `9676 <https://github.com/lvgl/lvgl/pull/9676>`__
|
||||
- **fix(gltf/data): add missing extern "C" to header file** `9679 <https://github.com/lvgl/lvgl/pull/9679>`__
|
||||
- **fix(ibl_sampler): restore gl state and add missing ressources deletion** `9678 <https://github.com/lvgl/lvgl/pull/9678>`__
|
||||
- **fix(stdlib): wrong variable name when mem_add_junk is enabled** `9677 <https://github.com/lvgl/lvgl/pull/9677>`__
|
||||
- **fix(fbdev): add missing errno.h include** `9673 <https://github.com/lvgl/lvgl/pull/9673>`__
|
||||
- **fix(image): add transform support for AL88 color format images** `9627 <https://github.com/lvgl/lvgl/pull/9627>`__
|
||||
- **fix(svg): set stride in decoder info to prevent warning** `9657 <https://github.com/lvgl/lvgl/pull/9657>`__
|
||||
- **fix(g2d): fix hardware version check with LV_USE_PXP** `9644 <https://github.com/lvgl/lvgl/pull/9644>`__
|
||||
- **fix(run_tests.sh): fix gcov versions mismatch issue** `9652 <https://github.com/lvgl/lvgl/pull/9652>`__
|
||||
- **fix(image): incorrect L8 image alpha channel to ARGB8888 blend** `9645 <https://github.com/lvgl/lvgl/pull/9645>`__
|
||||
- **fix(draw/arc): add missing lv_draw.h include** `9640 <https://github.com/lvgl/lvgl/pull/9640>`__
|
||||
- **fix(gstreamer): empty frame queue on destruction** `9633 <https://github.com/lvgl/lvgl/pull/9633>`__
|
||||
- **fix(lovyan_gfx): resolve double rotation in touch coordinates** `9628 <https://github.com/lvgl/lvgl/pull/9628>`__
|
||||
- **fix(property): remove LV_PROPERTY_TEXTAREA_INSERT_REPLACE (#9606)** `9625 <https://github.com/lvgl/lvgl/pull/9625>`__
|
||||
- **fix(property): fix reading style property returns uninitialized if non-local** `9234 <https://github.com/lvgl/lvgl/pull/9234>`__
|
||||
- **fix(blur): fix regression causing VS compiler error** `9620 <https://github.com/lvgl/lvgl/pull/9620>`__
|
||||
- **fix(obj_pos): alignment is not reversed when switching from LTR to RTL** `9616 <https://github.com/lvgl/lvgl/pull/9616>`__
|
||||
- **fix(dropdown): symbol property behaves like IMGSRC instead of TEXT** `9608 <https://github.com/lvgl/lvgl/pull/9608>`__
|
||||
- **fix(drm): set stride for draw buffers** `9609 <https://github.com/lvgl/lvgl/pull/9609>`__
|
||||
- **fix(textarea): scroll to position when style changes** `9407 <https://github.com/lvgl/lvgl/pull/9407>`__
|
||||
- **fix(grid): negative width of the object with column span in the grid using RTL** `9596 <https://github.com/lvgl/lvgl/pull/9596>`__
|
||||
- **fix(obj_pos): incorrect x coordinate in rtl mode** `9598 <https://github.com/lvgl/lvgl/pull/9598>`__
|
||||
- **fix(draw/sw): add missing LV_PROFILER_DRAW_END** `9601 <https://github.com/lvgl/lvgl/pull/9601>`__
|
||||
- **fix(wayland/egl): fix config selector for nanovg** `9603 <https://github.com/lvgl/lvgl/pull/9603>`__
|
||||
- **fix(opengl): fallback to RGB for desktop GL** `9588 <https://github.com/lvgl/lvgl/pull/9588>`__
|
||||
- **fix(gltf): add missing LV_RESULT_INVALID check** `9580 <https://github.com/lvgl/lvgl/pull/9580>`__
|
||||
- **fix(gltf): fix memory leaks caused by incomplete resource cleanup** `9579 <https://github.com/lvgl/lvgl/pull/9579>`__
|
||||
- **fix(opengles_shader): fix index out of bounds** `9573 <https://github.com/lvgl/lvgl/pull/9573>`__
|
||||
- **fix(gltf): fix unused-function warning** `9576 <https://github.com/lvgl/lvgl/pull/9576>`__
|
||||
- **fix(gltf): fix heap use after free caused by timer not being deleted** `9574 <https://github.com/lvgl/lvgl/pull/9574>`__
|
||||
- **fix(widget/span): undefined lv_subject_t if LV_USE_OBSERVER undefined** `9577 <https://github.com/lvgl/lvgl/pull/9577>`__
|
||||
- **fix(glfw): add gl_rgb565 fallback definition** `9575 <https://github.com/lvgl/lvgl/pull/9575>`__
|
||||
- **fix(egl): add missing ctx null check** `9572 <https://github.com/lvgl/lvgl/pull/9572>`__
|
||||
- **fix: remove unused code and fix code signature warning** `9570 <https://github.com/lvgl/lvgl/pull/9570>`__
|
||||
- **fix(lodepng): fix memory leak when cache addition fails** `9569 <https://github.com/lvgl/lvgl/pull/9569>`__
|
||||
- **fix(draw_sw): remove unused code in `lv_draw_sw_blend_to_a8.c`** `9567 <https://github.com/lvgl/lvgl/pull/9567>`__
|
||||
- **fix: format specifier warning in font manager** `9549 <https://github.com/lvgl/lvgl/pull/9549>`__
|
||||
- **fix(test): add missing malloc check to screenshot compare** `9541 <https://github.com/lvgl/lvgl/pull/9541>`__
|
||||
- **fix(xml): pass raw # if there's no constant name** `9418 <https://github.com/lvgl/lvgl/pull/9418>`__
|
||||
- **fix(drm/egl): red and blue channel swap with RGB565** `9461 <https://github.com/lvgl/lvgl/pull/9461>`__
|
||||
- **fix(arclabel): fix arclabel opa set** `9483 <https://github.com/lvgl/lvgl/pull/9483>`__
|
||||
- **fix(refr): restore layer opacity and recolor properties when layer area retrieval fails** `9521 <https://github.com/lvgl/lvgl/pull/9521>`__
|
||||
- **fix(vg_lite): fix the missing handling of rotated vector fonts g->ofs_x** `9519 <https://github.com/lvgl/lvgl/pull/9519>`__
|
||||
- **fix(vg_lite): workaround vg_lite_blit_rect offset x/y hardware bug** `9522 <https://github.com/lvgl/lvgl/pull/9522>`__
|
||||
- **fix(draw_sw_line): fix horizontal line incorrect dash length** `9501 <https://github.com/lvgl/lvgl/pull/9501>`__
|
||||
- **fix(draw): support RGB565_SWAPPED in software blur** `9512 <https://github.com/lvgl/lvgl/pull/9512>`__
|
||||
- **fix(wayland): fix touch support by correctly setting driver data** `9486 <https://github.com/lvgl/lvgl/pull/9486>`__
|
||||
- **fix(vg_lite): fix incomplete coordinate calculation when converting scissor_area to bounding_box_area** `9511 <https://github.com/lvgl/lvgl/pull/9511>`__
|
||||
- **fix(vg_lite): wait for vg_lite_tvg finish before drawing the mask** `9489 <https://github.com/lvgl/lvgl/pull/9489>`__
|
||||
- **fix(anim): ignore large apparent animation duration** `9280 <https://github.com/lvgl/lvgl/pull/9280>`__
|
||||
- **fix(arclabel): fix arclabel arc length calc in recolor mode** `9467 <https://github.com/lvgl/lvgl/pull/9467>`__
|
||||
- **fix(image_header_cache): fix dump iter selection error** `9465 <https://github.com/lvgl/lvgl/pull/9465>`__
|
||||
- **fix(arclabel): fix arc length calculating precise** `9457 <https://github.com/lvgl/lvgl/pull/9457>`__
|
||||
- **fix(opengl): compilation error when using glfw** `9459 <https://github.com/lvgl/lvgl/pull/9459>`__
|
||||
- **fix(image_cache): fix image cache dump memory leaks** `9448 <https://github.com/lvgl/lvgl/pull/9448>`__
|
||||
- **fix(conf_internal): explicitly disable the glTF demo when build_demo is disabled** `9408 <https://github.com/lvgl/lvgl/pull/9408>`__
|
||||
- **fix(gltf): remove fastgltf memory mapped file feature check** `9422 <https://github.com/lvgl/lvgl/pull/9422>`__
|
||||
- **fix(gltf): correct argument type to match declaration** `9421 <https://github.com/lvgl/lvgl/pull/9421>`__
|
||||
- **fix(gltf): add declaration for loading model from bytes** `9420 <https://github.com/lvgl/lvgl/pull/9420>`__
|
||||
- **fix(demo): fix compiler warning of unused variable c** `9370 <https://github.com/lvgl/lvgl/pull/9370>`__
|
||||
- **fix(flex): fix rounding may leave unused space on track with flex_grow** `9217 <https://github.com/lvgl/lvgl/pull/9217>`__
|
||||
- **fix(gstreamer): fix buffer map memory leak** `9378 <https://github.com/lvgl/lvgl/pull/9378>`__
|
||||
- **fix(draw/dma2d): correct cache handling** `9366 <https://github.com/lvgl/lvgl/pull/9366>`__
|
||||
- **fix(gltf): stride mismatch issue** `9385 <https://github.com/lvgl/lvgl/pull/9385>`__
|
||||
- **fix(gltf): force depth mask for transparent items used with refractive materials** `9396 <https://github.com/lvgl/lvgl/pull/9396>`__
|
||||
- **fix(tabview): re-set tab bar size after changing its position** `9399 <https://github.com/lvgl/lvgl/pull/9399>`__
|
||||
- **fix(demo): fix compiler warnings regarding the use of LV_UNUSED** `9403 <https://github.com/lvgl/lvgl/pull/9403>`__
|
||||
- **fix(tiny_ttf): release entry for correct cache** `9429 <https://github.com/lvgl/lvgl/pull/9429>`__
|
||||
- **fix(cache): entry alloc** `9427 <https://github.com/lvgl/lvgl/pull/9427>`__
|
||||
- **fix(xml): allow animating bg_image_opa in XML timelines** `9425 <https://github.com/lvgl/lvgl/pull/9425>`__
|
||||
- **fix(opengles): fix the memory leak when the shader manager is destroyed (#9439)** `9440 <https://github.com/lvgl/lvgl/pull/9440>`__
|
||||
- **fix(rb): make compare result type a 32bit integer** `9442 <https://github.com/lvgl/lvgl/pull/9442>`__
|
||||
- **fix(draw_buf):change the align log level to INFO** `9428 <https://github.com/lvgl/lvgl/pull/9428>`__
|
||||
- **fix(gltf): correctly handle matrices for animation and cameras** `9273 <https://github.com/lvgl/lvgl/pull/9273>`__
|
||||
- **fix(nuttx): fix profiler build break** `9417 <https://github.com/lvgl/lvgl/pull/9417>`__
|
||||
- **fix(blur): fix VS compiler error** `9391 <https://github.com/lvgl/lvgl/pull/9391>`__
|
||||
- **fix(freetype): set pixel size before kerning calculation (#9367)** `9388 <https://github.com/lvgl/lvgl/pull/9388>`__
|
||||
- **fix(xml): fix compile warning of uninitialized value** `9368 <https://github.com/lvgl/lvgl/pull/9368>`__
|
||||
- **fix(gif): compatibility issue when logging uint32_t variables** `9349 <https://github.com/lvgl/lvgl/pull/9349>`__
|
||||
- **fix(display): always have a solid background with non-alpha color formats** `9380 <https://github.com/lvgl/lvgl/pull/9380>`__
|
||||
- **fix(demo): make the Log out and Invite button not overlap on 480 hor. res.** `9383 <https://github.com/lvgl/lvgl/pull/9383>`__
|
||||
- **fix(roller): transformed roller click location** `9212 <https://github.com/lvgl/lvgl/pull/9212>`__
|
||||
- **fix(screen): double free when loading screens** `9276 <https://github.com/lvgl/lvgl/pull/9276>`__
|
||||
- **fix(ime): restrict to lowercase input to avoid overflow** `9320 <https://github.com/lvgl/lvgl/pull/9320>`__
|
||||
- **fix(spinbox): fix stack corruption** `9256 <https://github.com/lvgl/lvgl/pull/9256>`__
|
||||
- **fix(binfont_loader): add include to include missing function from API page** `9344 <https://github.com/lvgl/lvgl/pull/9344>`__
|
||||
- **fix(ESP): fix esp toolchain format specifier edge case** `9336 <https://github.com/lvgl/lvgl/pull/9336>`__
|
||||
- **fix(EVE): update lv_font_fmt_txt.h include path** `9337 <https://github.com/lvgl/lvgl/pull/9337>`__
|
||||
- **fix(gif): fix negative loop count handling** `9241 <https://github.com/lvgl/lvgl/pull/9241>`__
|
||||
- **fix(sdl): do not dereferencing nullptr in lv_sdl_mouse_handler if an invalid windows id (0) has been received** `9299 <https://github.com/lvgl/lvgl/pull/9299>`__
|
||||
- **fix(label): skip label draw if width is negative** `9297 <https://github.com/lvgl/lvgl/pull/9297>`__
|
||||
- **fix(indev): send LV_EVENT_KEY as indev event** `9208 <https://github.com/lvgl/lvgl/pull/9208>`__
|
||||
- **fix(glfw): fix deinitialization order to prevent segfault** `9220 <https://github.com/lvgl/lvgl/pull/9220>`__
|
||||
- **fix(draw/sw): remove param from draw_sw_mask_rect** `9288 <https://github.com/lvgl/lvgl/pull/9288>`__
|
||||
- **fix(property): fix return type of LV_PROPERTY_OBJ_SCROLL_END** `9203 <https://github.com/lvgl/lvgl/pull/9203>`__
|
||||
- **fix(property): fix some non-integer style property types** `9245 <https://github.com/lvgl/lvgl/pull/9245>`__
|
||||
- **fix(indev): ensure timer triggers when elapsed time meets threshold** `9275 <https://github.com/lvgl/lvgl/pull/9275>`__
|
||||
- **fix(gif): add disposal handle to fix gif display error** `9213 <https://github.com/lvgl/lvgl/pull/9213>`__
|
||||
- **fix(scripts/check_gcov_coverage): skip statistics for non-executable lines** `9239 <https://github.com/lvgl/lvgl/pull/9239>`__
|
||||
- **fix(vg_lite): add a path print length limit** `9248 <https://github.com/lvgl/lvgl/pull/9248>`__
|
||||
- **fix(NemaGFX): update lv_font_fmt_txt.h include path** `9235 <https://github.com/lvgl/lvgl/pull/9235>`__
|
||||
- **fix(draw/ppa): fix build and rendering issues** `9162 <https://github.com/lvgl/lvgl/pull/9162>`__
|
||||
- **fix(widgets): make animations on state change more consistent** `9174 <https://github.com/lvgl/lvgl/pull/9174>`__
|
||||
- **fix(workflows): fix commit ID error in push events mode** `9231 <https://github.com/lvgl/lvgl/pull/9231>`__
|
||||
- **fix(gif): add missing D-cache flush** `9228 <https://github.com/lvgl/lvgl/pull/9228>`__
|
||||
- **fix(label): lv_label_mark_need_refr_text not invalidate area** `9176 <https://github.com/lvgl/lvgl/pull/9176>`__
|
||||
- **fix(ffmpeg_player): increase align to 32** `9166 <https://github.com/lvgl/lvgl/pull/9166>`__
|
||||
- **fix(driver/st_ltdc): Add missing lv_os_private.h include** `9191 <https://github.com/lvgl/lvgl/pull/9191>`__
|
||||
- **fix(LTDC): add cache cleaning** `9192 <https://github.com/lvgl/lvgl/pull/9192>`__
|
||||
- **fix(fbdev): Implement proper cleanup from deletion event in FBDEV** `9169 <https://github.com/lvgl/lvgl/pull/9169>`__
|
||||
- **fix(example): correct lv_example_chart_5 display** `9177 <https://github.com/lvgl/lvgl/pull/9177>`__
|
||||
- **fix(canvas): correct RGB565 pixel offset in lv_canvas_get_px** `9188 <https://github.com/lvgl/lvgl/pull/9188>`__
|
||||
- **fix(ffmpeg): for nv12 pix_fmt** `9131 <https://github.com/lvgl/lvgl/pull/9131>`__
|
||||
- **fix(opengles): update fb address after reshaping texture** `9134 <https://github.com/lvgl/lvgl/pull/9134>`__
|
||||
- **fix(obj_tree): fixes exact object name match** `9150 <https://github.com/lvgl/lvgl/pull/9150>`__
|
||||
- **fix(gltf): fix indexation of model binds and and a new uniform scale bind** `9102 <https://github.com/lvgl/lvgl/pull/9102>`__
|
||||
- **fix(fs): set data to NULL if read file failed** `9156 <https://github.com/lvgl/lvgl/pull/9156>`__
|
||||
- **fix(keyboard): remove and add state to text area instead of keyboard** `9105 <https://github.com/lvgl/lvgl/pull/9105>`__
|
||||
- **fix(indev): Abort sending Keypad INDEV_ACT events following invalid return** `9135 <https://github.com/lvgl/lvgl/pull/9135>`__
|
||||
- **fix(xml): correclty use integer format specifier** `9133 <https://github.com/lvgl/lvgl/pull/9133>`__
|
||||
- **fix(test): fix memory leak on failed screenshot compare** `9088 <https://github.com/lvgl/lvgl/pull/9088>`__
|
||||
- **fix(scale): incorrect decrement in lv_scale_set_line_needle_value loop** `9081 <https://github.com/lvgl/lvgl/pull/9081>`__
|
||||
- **fix(vg_lite): fix warning if LV_LOG option is closed** `9094 <https://github.com/lvgl/lvgl/pull/9094>`__
|
||||
- **fix(flex): fix crash with flex_grow on screen** `9090 <https://github.com/lvgl/lvgl/pull/9090>`__
|
||||
- **fix(drm): fix drm driver memory leaks** `31e4138 <https://github.com/lvgl/lvgl/commit/31e41380d19ae70392ffb59eb8041df5f3937978>`__
|
||||
- **fix(gltf): convert baseColorFactor to sRGB for more accurate mid-range colors** `bdb7099 <https://github.com/lvgl/lvgl/commit/bdb7099c3a65029a4399a566340b79e65b069986>`__
|
||||
- **fix(workflows): skip the coverage analysis if it's not a pull request** `b9cdc4a <https://github.com/lvgl/lvgl/commit/b9cdc4a6100a85c01059e098da57d714362b3f93>`__
|
||||
- **fix(dave2d): fix leftover typo from #8725** `abec5b7 <https://github.com/lvgl/lvgl/commit/abec5b7c6ed6e1c24ffda6a0f297a874aea89dcf>`__
|
||||
|
||||
Examples
|
||||
~~~~~~~~
|
||||
|
||||
Docs
|
||||
~~~~
|
||||
|
||||
- **docs(draw_descriptors): fix examples missing code** `9745 <https://github.com/lvgl/lvgl/pull/9745>`__
|
||||
- **docs(draw/sdl): add missing draw_sw requirement** `9747 <https://github.com/lvgl/lvgl/pull/9747>`__
|
||||
- **docs(renesas): update link in docs to Renesas plugin v1.0.1** `9735 <https://github.com/lvgl/lvgl/pull/9735>`__
|
||||
- **docs(overview): remove conflict marker** `9733 <https://github.com/lvgl/lvgl/pull/9733>`__
|
||||
- **docs(wayland): remove server side window decorations promise** `9708 <https://github.com/lvgl/lvgl/pull/9708>`__
|
||||
- **docs(README): document how to work with :c:macro: role limitation** `9700 <https://github.com/lvgl/lvgl/pull/9700>`__
|
||||
- **docs(integration): make the integration more effective and informative** `9507 <https://github.com/lvgl/lvgl/pull/9507>`__
|
||||
- **docs(win): fix link list in API section** `9697 <https://github.com/lvgl/lvgl/pull/9697>`__
|
||||
- **docs(style_api_gen): add missing * to style API documentation** `9684 <https://github.com/lvgl/lvgl/pull/9684>`__
|
||||
- **docs(animation): clarify constraint in animations** `9686 <https://github.com/lvgl/lvgl/pull/9686>`__
|
||||
- **docs(style API): add API documentation to `style_api_gen.py`** `9637 <https://github.com/lvgl/lvgl/pull/9637>`__
|
||||
- **docs(macros): fix many macro links to API docs** `9533 <https://github.com/lvgl/lvgl/pull/9533>`__
|
||||
- **docs(buttonmatrix): fix event name typo** `9635 <https://github.com/lvgl/lvgl/pull/9635>`__
|
||||
- **docs(rt-thread): update BSP list and place the table and links in a form that is easier to maintain** `9611 <https://github.com/lvgl/lvgl/pull/9611>`__
|
||||
- **docs: add missing xml redirects** `9593 <https://github.com/lvgl/lvgl/pull/9593>`__
|
||||
- **docs(canvas): clarify buffer allocation details** `9563 <https://github.com/lvgl/lvgl/pull/9563>`__
|
||||
- **docs(links): fixed broken external links** `9525 <https://github.com/lvgl/lvgl/pull/9525>`__
|
||||
- **docs(display): mention palette in example flush_cb** `9534 <https://github.com/lvgl/lvgl/pull/9534>`__
|
||||
- **docs(API): link api pages to source code header files** `9456 <https://github.com/lvgl/lvgl/pull/9456>`__
|
||||
- **docs(clipping): document how clipping works in drawing** `9446 <https://github.com/lvgl/lvgl/pull/9446>`__
|
||||
- **docs(editor): Zephyr integration guide.** `9360 <https://github.com/lvgl/lvgl/pull/9360>`__
|
||||
- **docs(ICOP): add docs for board manufacturer ICOP** `9413 <https://github.com/lvgl/lvgl/pull/9413>`__
|
||||
- **docs(color): fix unexpected API page links** `9338 <https://github.com/lvgl/lvgl/pull/9338>`__
|
||||
- **docs(layers): clarify how to control Widget layering** `9379 <https://github.com/lvgl/lvgl/pull/9379>`__
|
||||
- **docs(display_controllers): fix erroneous doc cross-references** `9382 <https://github.com/lvgl/lvgl/pull/9382>`__
|
||||
- **docs(examples): fix erroneous example headings** `9355 <https://github.com/lvgl/lvgl/pull/9355>`__
|
||||
- **docs(3dtexture): fix web link with syntax error** `9357 <https://github.com/lvgl/lvgl/pull/9357>`__
|
||||
- **docs(base_widget.rst): add `obj` example to docs** `9356 <https://github.com/lvgl/lvgl/pull/9356>`__
|
||||
- **docs(custom.css): fix 2 CSS color issues** `9330 <https://github.com/lvgl/lvgl/pull/9330>`__
|
||||
- **docs(examples): add back show c code button in widget pages** `9354 <https://github.com/lvgl/lvgl/pull/9354>`__
|
||||
- **docs(redirects): add redirect for renesas XML integration page** `9345 <https://github.com/lvgl/lvgl/pull/9345>`__
|
||||
- **docs(examples): make `example_list.py` robust** `9317 <https://github.com/lvgl/lvgl/pull/9317>`__
|
||||
- **docs(wayland): remove mention of custom timer handler** `9329 <https://github.com/lvgl/lvgl/pull/9329>`__
|
||||
- **docs(redirects): add redirects from URLs in prev READMEs** `9322 <https://github.com/lvgl/lvgl/pull/9322>`__
|
||||
- **docs(redirects): add redirect for prev getting_started page** `9321 <https://github.com/lvgl/lvgl/pull/9321>`__
|
||||
- **docs(build.py): add changes needed with removal of details/ and intro/ dirs** `9315 <https://github.com/lvgl/lvgl/pull/9315>`__
|
||||
- **docs(color_format): add rgb565 swapped format info** `9310 <https://github.com/lvgl/lvgl/pull/9310>`__
|
||||
- **docs(directory structure): simplify by removing details/ and intro/ dirs** `9313 <https://github.com/lvgl/lvgl/pull/9313>`__
|
||||
- **docs(examples): fix libs/, others/ and porting/ missing from examples page.** `9291 <https://github.com/lvgl/lvgl/pull/9291>`__
|
||||
- **docs(images): remove outdated information and reorganize image docs** `9221 <https://github.com/lvgl/lvgl/pull/9221>`__
|
||||
- **docs(config): improve documentation in config template** `9251 <https://github.com/lvgl/lvgl/pull/9251>`__
|
||||
- **docs(examples): make example pathing more robust** `9308 <https://github.com/lvgl/lvgl/pull/9308>`__
|
||||
- **docs(README): fix typo** `9286 <https://github.com/lvgl/lvgl/pull/9286>`__
|
||||
- **docs(libpng): fix documentation typo** `9290 <https://github.com/lvgl/lvgl/pull/9290>`__
|
||||
- **docs(examples/grad): fix missing source code in gradient examples** `9289 <https://github.com/lvgl/lvgl/pull/9289>`__
|
||||
- **docs(Widget Tree): provide data lost from end of doc** `9158 <https://github.com/lvgl/lvgl/pull/9158>`__
|
||||
- **docs(README): add instructions for new documentation features** `9149 <https://github.com/lvgl/lvgl/pull/9149>`__
|
||||
- **docs(editor): Arduino usage guide** `9104 <https://github.com/lvgl/lvgl/pull/9104>`__
|
||||
- **docs(torizon): update torizon os docs to work with latest LVGL** `9095 <https://github.com/lvgl/lvgl/pull/9095>`__
|
||||
- **docs(Guides): add structure to TOC for Guides section** `9281 <https://github.com/lvgl/lvgl/pull/9281>`__
|
||||
- **docs(tinyttf): remove file loading in the examples** `9266 <https://github.com/lvgl/lvgl/pull/9266>`__
|
||||
- **docs(editor): Add brief section on installing e2 Studio plugin to the docs** `9257 <https://github.com/lvgl/lvgl/pull/9257>`__
|
||||
- **docs(Renesas): Add Renesas RZ/G3E and RA8D2 to docs** `9253 <https://github.com/lvgl/lvgl/pull/9253>`__
|
||||
- **docs(threading): simplify and add work-queue concept to Threading doc** `9106 <https://github.com/lvgl/lvgl/pull/9106>`__
|
||||
- **docs(xml): add Renesas Eclipse / E2Studio docs** `9216 <https://github.com/lvgl/lvgl/pull/9216>`__
|
||||
- **docs(debugging): proofread debugging section** `9163 <https://github.com/lvgl/lvgl/pull/9163>`__
|
||||
- **docs(style): add table width enhancements and bold + italic + underline support** `9124 <https://github.com/lvgl/lvgl/pull/9124>`__
|
||||
- **docs: factor out repeated substitution definitions** `9125 <https://github.com/lvgl/lvgl/pull/9125>`__
|
||||
- **docs(macro api links): fix links to macros in API pages** `9161 <https://github.com/lvgl/lvgl/pull/9161>`__
|
||||
- **docs(mipi): clarify generic MIPI with example code** `9099 <https://github.com/lvgl/lvgl/pull/9099>`__
|
||||
- **docs: move ext links to include dir** `9128 <https://github.com/lvgl/lvgl/pull/9128>`__
|
||||
- **docs: fix enumerator expansion upon API page links** `9114 <https://github.com/lvgl/lvgl/pull/9114>`__
|
||||
- **docs(misc): remove last warnings from doc-build with skip_api argument** `9119 <https://github.com/lvgl/lvgl/pull/9119>`__
|
||||
- **docs(misc): fix typos, grammar and add missing function links to api pages** `9126 <https://github.com/lvgl/lvgl/pull/9126>`__
|
||||
- **docs(gif): fix outdated content about using GIFs as C arrays** `9093 <https://github.com/lvgl/lvgl/pull/9093>`__
|
||||
|
||||
CI and tests
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- **test(vector): add more draw vector test case** `9524 <https://github.com/lvgl/lvgl/pull/9524>`__
|
||||
- **test(pinyin): update ref images** `9610 <https://github.com/lvgl/lvgl/pull/9610>`__
|
||||
- **test: fix missing EOL warnings** `9548 <https://github.com/lvgl/lvgl/pull/9548>`__
|
||||
- **test(svg): add svg file testcase** `9535 <https://github.com/lvgl/lvgl/pull/9535>`__
|
||||
- **ci(release): add steps to prepare and upload lite package** `9443 <https://github.com/lvgl/lvgl/pull/9443>`__
|
||||
- **test(canvas): add RGB565 pixel read test** `9516 <https://github.com/lvgl/lvgl/pull/9516>`__
|
||||
- **test(canvas): add canvas test case and fix the null pointer access crash in the draw buffer** `9478 <https://github.com/lvgl/lvgl/pull/9478>`__
|
||||
- **test(slider): add slider test case** `9477 <https://github.com/lvgl/lvgl/pull/9477>`__
|
||||
- **test(async): add async test case** `9475 <https://github.com/lvgl/lvgl/pull/9475>`__
|
||||
- **test(utils): add utils test case** `9474 <https://github.com/lvgl/lvgl/pull/9474>`__
|
||||
- **test(palette): add palette test case** `9473 <https://github.com/lvgl/lvgl/pull/9473>`__
|
||||
- **test(ll): add ll test case** `9472 <https://github.com/lvgl/lvgl/pull/9472>`__
|
||||
- **test(color): add color test case** `9471 <https://github.com/lvgl/lvgl/pull/9471>`__
|
||||
- **test(circle_buf): add circle buffer test case** `9470 <https://github.com/lvgl/lvgl/pull/9470>`__
|
||||
- **test(area): add area test case** `9469 <https://github.com/lvgl/lvgl/pull/9469>`__
|
||||
- **test(arc): add arc test case** `9476 <https://github.com/lvgl/lvgl/pull/9476>`__
|
||||
- **test(fs): add fs test case and add fs mock** `9479 <https://github.com/lvgl/lvgl/pull/9479>`__
|
||||
- **test(snapshot): add snapshot test case** `9481 <https://github.com/lvgl/lvgl/pull/9481>`__
|
||||
- **test(image): add image test case** `9480 <https://github.com/lvgl/lvgl/pull/9480>`__
|
||||
- **test(math): fix lv_pow failure to handle negative numbers exp and add full-feature coverage test** `9450 <https://github.com/lvgl/lvgl/pull/9450>`__
|
||||
- **test(ime_pinyin): fix crash and memory leak and add full-feature coverage test** `9434 <https://github.com/lvgl/lvgl/pull/9434>`__
|
||||
- **test(cache): add cache_entry_alloc** `9438 <https://github.com/lvgl/lvgl/pull/9438>`__
|
||||
- **test(menu): fix double free and add full-feature coverage test** `9432 <https://github.com/lvgl/lvgl/pull/9432>`__
|
||||
- **test(tick): add tick test case** `9416 <https://github.com/lvgl/lvgl/pull/9416>`__
|
||||
- **test: update demo widgets ref image** `9358 <https://github.com/lvgl/lvgl/pull/9358>`__
|
||||
- **ci: deploy doc builds to release folders** `9352 <https://github.com/lvgl/lvgl/pull/9352>`__
|
||||
- **ci(deps): bump actions/checkout from 5 to 6** `9334 <https://github.com/lvgl/lvgl/pull/9334>`__
|
||||
- **ci(deps): bump JamesIves/github-pages-deploy-action from 4.7.3 to 4.7.4** `9333 <https://github.com/lvgl/lvgl/pull/9333>`__
|
||||
- **ci(tests): retain the gcov report for coverage analysis** `9274 <https://github.com/lvgl/lvgl/pull/9274>`__
|
||||
- **test(draw_buf): add draw buf premultiply test** `9259 <https://github.com/lvgl/lvgl/pull/9259>`__
|
||||
- **test(display): improve lv_display test coverage** `9110 <https://github.com/lvgl/lvgl/pull/9110>`__
|
||||
- **test(demo_widgets): add screenshot comparison** `9111 <https://github.com/lvgl/lvgl/pull/9111>`__
|
||||
- **test(theme): improve theme test coverage** `9116 <https://github.com/lvgl/lvgl/pull/9116>`__
|
||||
- **test(mem): improve memory test coverage** `9117 <https://github.com/lvgl/lvgl/pull/9117>`__
|
||||
- **test(vector): add demo vector graphic test** `9130 <https://github.com/lvgl/lvgl/pull/9130>`__
|
||||
- **test(array): improve lv_array test coverage** `9108 <https://github.com/lvgl/lvgl/pull/9108>`__
|
||||
- **test(indev): merge indev testcase** `9071 <https://github.com/lvgl/lvgl/pull/9071>`__
|
||||
|
||||
Others
|
||||
~~~~~~
|
||||
|
||||
- **feat(env): always use the C library when building for QNX** `9738 <https://github.com/lvgl/lvgl/pull/9738>`__
|
||||
- **revert(canvas): remove api to skip canvas invalidation when setting pixel** `9751 <https://github.com/lvgl/lvgl/pull/9751>`__
|
||||
- **chore(cmsis-pack): Prepare for v9.5.0** `9748 <https://github.com/lvgl/lvgl/pull/9748>`__
|
||||
- **build(esp): only add fatfs component if use_fs_fatfs is enabled** `9746 <https://github.com/lvgl/lvgl/pull/9746>`__
|
||||
- **chore(font_gen): replace os.system with subprocess.run** `9689 <https://github.com/lvgl/lvgl/pull/9689>`__
|
||||
- **build(deps): bump dawidd6/action-download-artifact from 12 to 14** `9666 <https://github.com/lvgl/lvgl/pull/9666>`__
|
||||
- **build(deps): bump JamesIves/github-pages-deploy-action from 4.7.6 to 4.8.0** `9667 <https://github.com/lvgl/lvgl/pull/9667>`__
|
||||
- **chore(ppa): update cache alignment error message for 128-byte lines** `9526 <https://github.com/lvgl/lvgl/pull/9526>`__
|
||||
- **chore(gif): move GIF Widget to widgets/ directory** `9617 <https://github.com/lvgl/lvgl/pull/9617>`__
|
||||
- **chore(docs): lock sphinx version to 8.2.3** `9626 <https://github.com/lvgl/lvgl/pull/9626>`__
|
||||
- **chore(msgbox): fix the incorrect return value docs** `9584 <https://github.com/lvgl/lvgl/pull/9584>`__
|
||||
- **chore: fix warning of span testcase** `9547 <https://github.com/lvgl/lvgl/pull/9547>`__
|
||||
- **refactor(opengles): set texture id to layer head on disp creation** `9397 <https://github.com/lvgl/lvgl/pull/9397>`__
|
||||
- **chore(CODEOWNERS): add @FASTSHIFT to default owners** `9531 <https://github.com/lvgl/lvgl/pull/9531>`__
|
||||
- **refactor(canvas): clarify parameter names for lv_canvas_copy_buf** `9414 <https://github.com/lvgl/lvgl/pull/9414>`__
|
||||
- **build(cmake): check if demos and examples exist** `9510 <https://github.com/lvgl/lvgl/pull/9510>`__
|
||||
- **build(esp): add missing lv_demos.c source file to esp build process** `9517 <https://github.com/lvgl/lvgl/pull/9517>`__
|
||||
- **chore(tests): clean up erroneously submitted temporary files** `9515 <https://github.com/lvgl/lvgl/pull/9515>`__
|
||||
- **refactor(gif): add new API and add full testcase** `9452 <https://github.com/lvgl/lvgl/pull/9452>`__
|
||||
- **chore: add codeowners** `9458 <https://github.com/lvgl/lvgl/pull/9458>`__
|
||||
- **build(deps): bump actions/upload-artifact from 5 to 6** `9495 <https://github.com/lvgl/lvgl/pull/9495>`__
|
||||
- **build(deps): bump JamesIves/github-pages-deploy-action from 4.7.4 to 4.7.6** `9496 <https://github.com/lvgl/lvgl/pull/9496>`__
|
||||
- **build(deps): bump dawidd6/action-download-artifact from 11 to 12** `9497 <https://github.com/lvgl/lvgl/pull/9497>`__
|
||||
- **build(deps): bump actions/cache from 4 to 5** `9498 <https://github.com/lvgl/lvgl/pull/9498>`__
|
||||
- **build(Kconfig): auto select LV_USE_GENERIC_MIPI** `9491 <https://github.com/lvgl/lvgl/pull/9491>`__
|
||||
- **chore(image_converter): add AL88 color format support** `9453 <https://github.com/lvgl/lvgl/pull/9453>`__
|
||||
- **build(kconfig): make log level selection more readable** `9409 <https://github.com/lvgl/lvgl/pull/9409>`__
|
||||
- **build(test): ffmpeg compile error on macOS** `9371 <https://github.com/lvgl/lvgl/pull/9371>`__
|
||||
- **chore: fix compile warnings** `9369 <https://github.com/lvgl/lvgl/pull/9369>`__
|
||||
- **refactor(obj_property): use LV_ARRAYLEN for LV_OBJ_SET_PROPERTY_ARRAY** `9395 <https://github.com/lvgl/lvgl/pull/9395>`__
|
||||
- **refactor(indev): remove the unused last_obj field from lv_indev_t** `9219 <https://github.com/lvgl/lvgl/pull/9219>`__
|
||||
- **chore(lvglgdb): show classp name if lv_class name is not set** `9376 <https://github.com/lvgl/lvgl/pull/9376>`__
|
||||
- **chore(vg_lite): minimize the header file inclusion** `9361 <https://github.com/lvgl/lvgl/pull/9361>`__
|
||||
- **chore(lvglgdb): fix TypeError in lv_obj.py while dump specify object** `9375 <https://github.com/lvgl/lvgl/pull/9375>`__
|
||||
- **chore: update version to v9.5.0-dev** `9350 <https://github.com/lvgl/lvgl/pull/9350>`__
|
||||
- **chore(lv_conf_internal): replace the tab and add automatic checks** `9323 <https://github.com/lvgl/lvgl/pull/9323>`__
|
||||
- **chore: update version to v9.4.0-dev** `9316 <https://github.com/lvgl/lvgl/pull/9316>`__
|
||||
- **chore(tests/unity): fix the case discrepancy in the size_t comparison macro definition** `9318 <https://github.com/lvgl/lvgl/pull/9318>`__
|
||||
- **chore: fix changelog generator to be compatible with reST** `9168 <https://github.com/lvgl/lvgl/pull/9168>`__
|
||||
- **build(Kconfig): add missing support_rgb565_swapped config** `9282 <https://github.com/lvgl/lvgl/pull/9282>`__
|
||||
- **chore(scripts/run_tests): remove redundant apt list commands** `9226 <https://github.com/lvgl/lvgl/pull/9226>`__
|
||||
- **refactor(draw_buf): add inline tag for draw buffer flag functions** `9229 <https://github.com/lvgl/lvgl/pull/9229>`__
|
||||
- **chore(test_conf): fix build break if webp library not installed** `9225 <https://github.com/lvgl/lvgl/pull/9225>`__
|
||||
- **refactor(canvas): remove draw_sw include** `9204 <https://github.com/lvgl/lvgl/pull/9204>`__
|
||||
- **refactor(arc): remove redundant code** `9198 <https://github.com/lvgl/lvgl/pull/9198>`__
|
||||
- **refactor: reorganize the others folder** `9164 <https://github.com/lvgl/lvgl/pull/9164>`__
|
||||
- **build(deps): bump actions/upload-artifact from 4 to 5** `9182 <https://github.com/lvgl/lvgl/pull/9182>`__
|
||||
- **Make scroll animation timing configurable via defines** `9160 <https://github.com/lvgl/lvgl/pull/9160>`__
|
||||
- **build(kconfig): add 3d texture and gltf configs** `9132 <https://github.com/lvgl/lvgl/pull/9132>`__
|
||||
- **chore(gdb): add initial project configuration and installation instructions for lvglgdb** `9145 <https://github.com/lvgl/lvgl/pull/9145>`__
|
||||
- **chore(gdb): support rb/cache associate debug obj and commands** `9089 <https://github.com/lvgl/lvgl/pull/9089>`__
|
||||
- **chore(scripts): remove rz-g2l-evkit from port updater as it still uses v8.3** `9092 <https://github.com/lvgl/lvgl/pull/9092>`__
|
||||
- **chore(vg_lite): correct spelling of 'high' in color key structure** `9087 <https://github.com/lvgl/lvgl/pull/9087>`__
|
||||
- **chore(gdb): add gdb cmd for nuttx drivers to support multi-instance** `9068 <https://github.com/lvgl/lvgl/pull/9068>`__
|
||||
- **chore(widgets): use helper for properties in class** `7193931 <https://github.com/lvgl/lvgl/commit/71939310c2642af50483fa65baca3e77ddb021e9>`__
|
||||
- **chore(property): add macro to help property definitions** `55aa15d <https://github.com/lvgl/lvgl/commit/55aa15dddd3495bd4eabe2bcbfd70c4aa2dc10d8>`__
|
||||
- **Revert "fix(workflows): fix commit ID error in push events mode (#9231)"** `cafeb18 <https://github.com/lvgl/lvgl/commit/cafeb18455fd3da679793654e55dbb57cff1f131>`__
|
||||
60
managed_components/lvgl__lvgl/docs/src/_ext/link_roles.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# based on http://protips.readthedocs.io/link-roles.html
|
||||
|
||||
#from __future__ import print_function, unicode_literals
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from collections import namedtuple
|
||||
|
||||
from docutils import nodes
|
||||
from sphinx.transforms.post_transforms import SphinxPostTransform
|
||||
|
||||
URL_BASE = {
|
||||
"zh_CN": "https://lvgl.100ask.net/"
|
||||
}
|
||||
|
||||
class translation_link(nodes.Element):
|
||||
"""Node for "link_to_translation" role."""
|
||||
|
||||
|
||||
# Linking to translation is done at the "writing" stage to avoid issues with the info being cached between builders
|
||||
def link_to_translation(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
node = translation_link()
|
||||
node['expr'] = (rawtext, text, options)
|
||||
return [node], []
|
||||
|
||||
|
||||
class TranslationLinkNodeTransform(SphinxPostTransform):
|
||||
# Transform needs to happen early to ensure the new reference node is also transformed
|
||||
default_priority = 0
|
||||
|
||||
def run(self, **kwargs):
|
||||
# Only output relative links if building HTML
|
||||
for node in self.document.traverse(translation_link):
|
||||
if 'html' in self.app.builder.name:
|
||||
rawtext, text, options = node['expr']
|
||||
(language, link_text) = text.split(':')
|
||||
env = self.document.settings.env
|
||||
docname = env.docname
|
||||
# doc_path = env.doc2path(docname, False)
|
||||
if "LVGL_URLPATH" not in os.environ:
|
||||
os.environ['LVGL_URLPATH'] = 'master'
|
||||
urlpath = os.getenv('LVGL_URLPATH')+'/'
|
||||
return_path = URL_BASE.get(language, "") + urlpath
|
||||
|
||||
url = '{}.html'.format(os.path.join(return_path, docname))
|
||||
|
||||
node.replace_self(nodes.reference(rawtext, link_text, refuri=url, **options))
|
||||
else:
|
||||
node.replace_self([])
|
||||
|
||||
|
||||
def setup(app):
|
||||
|
||||
# link to the current documentation file in specific language version
|
||||
app.add_role('link_to_translation', link_to_translation)
|
||||
app.add_node(translation_link)
|
||||
app.add_post_transform(TranslationLinkNodeTransform)
|
||||
|
||||
return {'parallel_read_safe': True, 'parallel_write_safe': True, 'version': '0.5'}
|
||||
133
managed_components/lvgl__lvgl/docs/src/_ext/lv_example.py
Normal file
@@ -0,0 +1,133 @@
|
||||
import os
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import Directive, directives
|
||||
# from docutils.parsers.rst.directives.images import Image
|
||||
# from sphinx.directives.code import LiteralInclude
|
||||
|
||||
|
||||
def excluded_list(argument):
|
||||
return argument.split(',')
|
||||
|
||||
|
||||
class LvExample(Directive):
|
||||
required_arguments = 1
|
||||
option_spec = {
|
||||
'excluded_languages': excluded_list,
|
||||
'language': directives.unchanged,
|
||||
'description': directives.unchanged
|
||||
}
|
||||
|
||||
def get_example_code_path(self, example_path, language):
|
||||
base_path = os.path.dirname(__file__)
|
||||
examples_path = os.path.abspath(os.path.join(base_path, '..', 'examples'))
|
||||
example_path = os.path.join(examples_path, example_path + '.' + language)
|
||||
return example_path
|
||||
|
||||
def human_language_name(self, language):
|
||||
if language == 'py':
|
||||
return 'MicroPython'
|
||||
elif language == 'c':
|
||||
return 'C'
|
||||
else:
|
||||
return language
|
||||
|
||||
def github_path(self, example_path, language):
|
||||
env = self.state.document.settings.env
|
||||
return f"https://github.com/lvgl/lvgl/blob/{env.config.repo_commit_hash}/examples/{example_path}.{language}"
|
||||
|
||||
def embed_code(self, example_file, example_path, language, buttons={}):
|
||||
toggle = nodes.container('', literal_block=False, classes=['toggle'])
|
||||
header = nodes.container('', literal_block=False, classes=['header'])
|
||||
toggle.append(header)
|
||||
|
||||
try:
|
||||
with open(example_file, 'rb') as f:
|
||||
contents = f.read().decode('utf-8')
|
||||
except FileNotFoundError:
|
||||
print('File Not Found', example_file)
|
||||
contents = 'Error encountered while trying to open ' + example_file
|
||||
|
||||
literal_list = nodes.literal_block(contents, contents)
|
||||
literal_list['language'] = language
|
||||
toggle.append(literal_list)
|
||||
paragraph_node = nodes.raw(text=f"<p>{self.human_language_name(language)} code </p>", format='html')
|
||||
for text, url in buttons.items():
|
||||
paragraph_node.append(nodes.raw(text=f"<a class='lv-example-link-button' onclick=\"event.stopPropagation();\" href='{url}'>{text}</a>", format='html'))
|
||||
header.append(paragraph_node)
|
||||
return toggle
|
||||
|
||||
def run(self):
|
||||
example_path = self.arguments[0]
|
||||
example_name = os.path.split(example_path)[1]
|
||||
excluded_languages = self.options.get('excluded_languages', [])
|
||||
node_list = []
|
||||
|
||||
env = self.state.document.settings.env
|
||||
|
||||
iframe_html = ""
|
||||
|
||||
c_path = self.get_example_code_path(example_path, 'c')
|
||||
py_path = self.get_example_code_path(example_path, 'py')
|
||||
|
||||
if os.path.exists(c_path):
|
||||
c_code = self.embed_code(c_path, example_path, 'c', buttons={
|
||||
'<i class="fa fa-github"></i> View on GitHub': self.github_path(example_path, 'c')
|
||||
})
|
||||
else:
|
||||
c_code = None
|
||||
|
||||
if os.path.exists(py_path):
|
||||
py_code = self.embed_code(py_path, example_path, 'py', buttons={
|
||||
'<i class="fa fa-github"></i> View on GitHub': self.github_path(example_path, 'py'),
|
||||
'<i class="fa fa-play"></i> MicroPython Simulator': f"https://sim.lvgl.io/v{env.config.version}/micropython/ports/javascript/index.html?script_startup=https://raw.githubusercontent.com/lvgl/lvgl/{env.config.repo_commit_hash}/examples/header.py&script=https://raw.githubusercontent.com/lvgl/lvgl/{env.config.repo_commit_hash}/examples/{example_path}.py"
|
||||
})
|
||||
else:
|
||||
py_code = None
|
||||
|
||||
if 'c' not in excluded_languages:
|
||||
if env.app.tags.has('html'):
|
||||
iframe_html = f"<div class='lv-example' data-real-src='/{env.config.version}/_static/built_lv_examples/index.html?example={example_name}&w=320&h=240'></div>"
|
||||
|
||||
description_html = f"<div class='lv-example-description'>{self.options.get('description', '')}</div>"
|
||||
layout_node = nodes.raw(text=f"<div class='lv-example-container'>{iframe_html}{description_html}</div>", format='html')
|
||||
|
||||
node_list.append(layout_node)
|
||||
if 'c' not in excluded_languages and c_code is not None:
|
||||
node_list.append(c_code)
|
||||
if 'py' not in excluded_languages and py_code is not None:
|
||||
node_list.append(py_code)
|
||||
|
||||
trailing_node = nodes.raw(text=f"<hr/>", format='html')
|
||||
node_list.append(trailing_node)
|
||||
|
||||
return node_list
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.add_directive("lv_example", LvExample)
|
||||
# Direct [View on GitHub] links in examples to use current
|
||||
# branch (stored in LVGL_GITCOMMIT environment variable) instead
|
||||
# of the current commit hash as was being done previously.
|
||||
# Default to 'master' if Sphinx is being run outside of `build.py`.
|
||||
# Resulting example link:
|
||||
# [https://github.com/lvgl/lvgl/blob/master/examples/anim/lv_example_anim_1.c].
|
||||
# [https://github.com/lvgl/lvgl/blob/v8.4.0/examples/anim/lv_example_anim_1.c].
|
||||
# [https://github.com/lvgl/lvgl/blob/v9.2.0/examples/anim/lv_example_anim_1.c].
|
||||
if 'LVGL_GITCOMMIT' in os.environ:
|
||||
git_commit = os.environ['LVGL_GITCOMMIT']
|
||||
else:
|
||||
git_commit = 'master'
|
||||
|
||||
app.add_config_value("repo_commit_hash", git_commit, "env")
|
||||
|
||||
# if 'repo_commit_hash' in app.config._options:
|
||||
# print(f"repo_commit_hash from lv_example.py: [{app.config._options['repo_commit_hash']}]")
|
||||
# else:
|
||||
# print("repo_commit_hash not found in [app.config._options] at this time.")
|
||||
|
||||
return {
|
||||
'version': '0.1',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
6
managed_components/lvgl__lvgl/docs/src/_static/css/brands.min.css
vendored
Normal file
1296
managed_components/lvgl__lvgl/docs/src/_static/css/custom.css
Normal file
5
managed_components/lvgl__lvgl/docs/src/_static/css/fontawesome.min.css
vendored
Normal file
6
managed_components/lvgl__lvgl/docs/src/_static/css/solid.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.0.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2022 Fonticons, Inc.
|
||||
*/
|
||||
:host,:root{--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-family:"Font Awesome 6 Free";font-weight:900}
|
||||
BIN
managed_components/lvgl__lvgl/docs/src/_static/images/align.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 86 KiB |
BIN
managed_components/lvgl__lvgl/docs/src/_static/images/bidi.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 127 KiB |
BIN
managed_components/lvgl__lvgl/docs/src/_static/images/home_1.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
managed_components/lvgl__lvgl/docs/src/_static/images/home_2.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
managed_components/lvgl__lvgl/docs/src/_static/images/home_3.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
managed_components/lvgl__lvgl/docs/src/_static/images/home_4.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
managed_components/lvgl__lvgl/docs/src/_static/images/home_5.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
managed_components/lvgl__lvgl/docs/src/_static/images/home_6.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 37 KiB |
BIN
managed_components/lvgl__lvgl/docs/src/_static/images/layers.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,10 @@
|
||||
<svg width="84" height="32" viewBox="0 0 84 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M72.105 24.7871V9.21293H75.3732V22.0722H82V24.7871H72.105Z" fill="white"/>
|
||||
<path d="M66.3305 14.2471C66.2249 13.8771 66.0764 13.5501 65.8852 13.2662C65.694 12.9772 65.46 12.7338 65.1833 12.5361C64.9116 12.3333 64.5996 12.1787 64.2474 12.0722C63.9002 11.9658 63.5153 11.9125 63.0926 11.9125C62.3026 11.9125 61.6082 12.1103 61.0094 12.5057C60.4157 12.9011 59.9528 13.4766 59.6207 14.2319C59.2886 14.9823 59.1225 15.8999 59.1225 16.9848C59.1225 18.0697 59.286 18.9924 59.6131 19.7529C59.9402 20.5133 60.4031 21.0938 61.0019 21.4943C61.6007 21.8897 62.3076 22.0875 63.1228 22.0875C63.8624 22.0875 64.4939 21.9556 65.0172 21.692C65.5456 21.4233 65.9481 21.0456 66.2249 20.5589C66.5066 20.0722 66.6475 19.4968 66.6475 18.8327L67.3117 18.9316H63.3266V16.4525H69.7949V18.4144C69.7949 19.7833 69.5081 20.9594 68.9345 21.943C68.3609 22.9214 67.5709 23.6768 66.5645 24.2091C65.5582 24.7364 64.4059 25 63.1077 25C61.6585 25 60.3855 24.6781 59.2886 24.0342C58.1916 23.3853 57.3362 22.4651 56.7224 21.2738C56.1135 20.0773 55.8091 18.6578 55.8091 17.0152C55.8091 15.7529 55.9902 14.6274 56.3525 13.6388C56.7198 12.6451 57.2331 11.8035 57.8922 11.1141C58.5514 10.4246 59.3188 9.89987 60.1943 9.53992C61.0698 9.17997 62.0183 9 63.0397 9C63.9153 9 64.7304 9.12928 65.4852 9.38783C66.24 9.64132 66.9092 10.0013 67.4929 10.4677C68.0816 10.9341 68.5621 11.4892 68.9345 12.1331C69.3068 12.7719 69.5458 13.4766 69.6515 14.2471H66.3305Z" fill="white"/>
|
||||
<path d="M44.2282 9.21293L47.9642 21.0456H48.1076L51.8513 9.21293H55.4742L50.1455 24.7871H45.9339L40.5977 9.21293H44.2282Z" fill="white"/>
|
||||
<path d="M32 24.7871V9.21293H35.2681V22.0722H41.895V24.7871H32Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.76924 5C1.23984 5 1.31567e-05 6.23982 9.79524e-06 7.76922L1.63168e-06 11.4615C1.63168e-06 11.9713 0.413277 12.3846 0.923079 12.3846H6.46154C7.48114 12.3846 8.30769 13.2112 8.30769 14.2308V19.7692C8.30769 20.279 8.72097 20.6923 9.23077 20.6923H14.7692C15.7888 20.6923 16.6154 21.5189 16.6154 22.5385V28.0769C16.6154 28.5867 17.0287 29 17.5385 29H21.2308C22.7602 29 24 27.7602 24 26.2308V7.76923C24 6.23983 22.7602 5 21.2308 5H2.76924ZM20.7692 9.61538C21.5339 9.61538 22.1538 8.99547 22.1538 8.23077C22.1538 7.46607 21.5339 6.84615 20.7692 6.84615C20.0045 6.84615 19.3846 7.46607 19.3846 8.23077C19.3846 8.99547 20.0045 9.61538 20.7692 9.61538Z" fill="white"/>
|
||||
<path d="M0.00011268 14.6308C0.00011268 14.121 0.413388 13.7077 0.92319 13.7077H6.06165C6.57145 13.7077 6.98473 14.121 6.98473 14.6308V19.7692C6.98473 20.279 6.57145 20.6923 6.06165 20.6923H0.923189C0.413387 20.6923 0.00011268 20.279 0.00011268 19.7692V14.6308Z" fill="white"/>
|
||||
<path d="M0 22.9385C0 22.4287 0.413276 22.0154 0.923077 22.0154H6.06154C6.57134 22.0154 6.98462 22.4287 6.98462 22.9385V28.0769C6.98462 28.5867 6.57134 29 6.06154 29H2.76923C1.23983 29 0 27.7602 0 26.2308V22.9385Z" fill="white"/>
|
||||
<path d="M8.30771 22.9385C8.30771 22.4287 8.72098 22.0154 9.23078 22.0154H14.3692C14.879 22.0154 15.2923 22.4287 15.2923 22.9385V28.0769C15.2923 28.5867 14.879 29 14.3692 29H9.23078C8.72098 29 8.30771 28.5867 8.30771 28.0769V22.9385Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,10 @@
|
||||
<svg width="82" height="32" viewBox="0 0 82 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M72.105 24.7871V9.21293H75.3732V22.0722H82V24.7871H72.105Z" fill="#343839"/>
|
||||
<path d="M66.3305 14.2471C66.2249 13.8771 66.0764 13.5501 65.8852 13.2662C65.694 12.9772 65.46 12.7338 65.1833 12.5361C64.9116 12.3333 64.5996 12.1787 64.2474 12.0722C63.9002 11.9658 63.5153 11.9125 63.0926 11.9125C62.3026 11.9125 61.6082 12.1103 61.0094 12.5057C60.4157 12.9011 59.9528 13.4766 59.6207 14.2319C59.2886 14.9823 59.1225 15.8999 59.1225 16.9848C59.1225 18.0697 59.286 18.9924 59.6131 19.7529C59.9402 20.5133 60.4031 21.0938 61.0019 21.4943C61.6007 21.8897 62.3076 22.0875 63.1228 22.0875C63.8624 22.0875 64.4939 21.9556 65.0172 21.692C65.5456 21.4233 65.9481 21.0456 66.2249 20.5589C66.5066 20.0722 66.6475 19.4968 66.6475 18.8327L67.3117 18.9316H63.3266V16.4525H69.7949V18.4144C69.7949 19.7833 69.5081 20.9594 68.9345 21.943C68.3609 22.9214 67.5709 23.6768 66.5645 24.2091C65.5582 24.7364 64.4059 25 63.1077 25C61.6585 25 60.3855 24.6781 59.2886 24.0342C58.1916 23.3853 57.3362 22.4651 56.7224 21.2738C56.1135 20.0773 55.8091 18.6578 55.8091 17.0152C55.8091 15.7529 55.9902 14.6274 56.3525 13.6388C56.7198 12.6451 57.2331 11.8035 57.8922 11.1141C58.5514 10.4246 59.3188 9.89987 60.1943 9.53992C61.0698 9.17997 62.0183 9 63.0397 9C63.9153 9 64.7304 9.12928 65.4852 9.38783C66.24 9.64132 66.9092 10.0013 67.4929 10.4677C68.0816 10.9341 68.5621 11.4892 68.9345 12.1331C69.3068 12.7719 69.5458 13.4766 69.6515 14.2471H66.3305Z" fill="#343839"/>
|
||||
<path d="M44.2282 9.21293L47.9642 21.0456H48.1076L51.8513 9.21293H55.4742L50.1455 24.7871H45.9339L40.5977 9.21293H44.2282Z" fill="#343839"/>
|
||||
<path d="M32 24.7871V9.21293H35.2681V22.0722H41.895V24.7871H32Z" fill="#343839"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.76924 5C1.23984 5 1.31567e-05 6.23982 9.79524e-06 7.76922L1.63168e-06 11.4615C1.63168e-06 11.9713 0.413277 12.3846 0.923079 12.3846H6.46154C7.48114 12.3846 8.30769 13.2112 8.30769 14.2308V19.7692C8.30769 20.279 8.72097 20.6923 9.23077 20.6923H14.7692C15.7888 20.6923 16.6154 21.5189 16.6154 22.5385V28.0769C16.6154 28.5867 17.0287 29 17.5385 29H21.2308C22.7602 29 24 27.7602 24 26.2308V7.76923C24 6.23983 22.7602 5 21.2308 5H2.76924ZM20.7692 9.61538C21.5339 9.61538 22.1538 8.99547 22.1538 8.23077C22.1538 7.46607 21.5339 6.84615 20.7692 6.84615C20.0045 6.84615 19.3846 7.46607 19.3846 8.23077C19.3846 8.99547 20.0045 9.61538 20.7692 9.61538Z" fill="#343839"/>
|
||||
<path d="M0.00011268 14.6308C0.00011268 14.121 0.413388 13.7077 0.92319 13.7077H6.06165C6.57145 13.7077 6.98473 14.121 6.98473 14.6308V19.7692C6.98473 20.279 6.57145 20.6923 6.06165 20.6923H0.923189C0.413387 20.6923 0.00011268 20.279 0.00011268 19.7692V14.6308Z" fill="#F35F20"/>
|
||||
<path d="M0 22.9385C0 22.4287 0.413276 22.0154 0.923077 22.0154H6.06154C6.57134 22.0154 6.98462 22.4287 6.98462 22.9385V28.0769C6.98462 28.5867 6.57134 29 6.06154 29H2.76923C1.23983 29 0 27.7602 0 26.2308V22.9385Z" fill="#62D367"/>
|
||||
<path d="M8.30771 22.9385C8.30771 22.4287 8.72098 22.0154 9.23078 22.0154H14.3692C14.879 22.0154 15.2923 22.4287 15.2923 22.9385V28.0769C15.2923 28.5867 14.879 29 14.3692 29H9.23078C8.72098 29 8.30771 28.5867 8.30771 28.0769V22.9385Z" fill="#3C65F8"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 973 B |
|
After Width: | Height: | Size: 993 B |
|
After Width: | Height: | Size: 990 B |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 11 KiB |
BIN
managed_components/lvgl__lvgl/docs/src/_static/images/scale.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 76 KiB |
2
managed_components/lvgl__lvgl/docs/src/_static/jquery.js
vendored
Normal file
351
managed_components/lvgl__lvgl/docs/src/_static/js/custom.js
Normal file
@@ -0,0 +1,351 @@
|
||||
/*---------------------------------------------------------------------
|
||||
* Called by 'DOMContentLoaded' event listener below; adds
|
||||
* documentation-version dropdown list just above search form in
|
||||
* upper part of left (nav) panel.
|
||||
*---------------------------------------------------------------------*/
|
||||
|
||||
function add_version_selector() {
|
||||
return fetch("https://raw.githubusercontent.com/lvgl/docs_compiled/gh-pages/versionlist.txt")
|
||||
.then((res) => res.text())
|
||||
.then((text) => {
|
||||
const versionList = text.split("\n").filter((version) => version.trim().length > 0);
|
||||
const versionDropdown = document.getElementById("version_dropdown");
|
||||
versionDropdown.innerHTML = versionList
|
||||
.map((version) => {
|
||||
let versionName = "";
|
||||
if (version == "master") versionName = "Latest";
|
||||
else versionName = "v" + (version.indexOf(".") != -1 ? version : version + " (latest minor)");
|
||||
return `<option value="${version}">${versionName}</option>`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
// Wait for the next animation frame to ensure DOM is updated
|
||||
requestAnimationFrame(() => {
|
||||
const versionDropdownValue = window.location.pathname.split("/")[1];
|
||||
const isValidVersion = versionDropdownValue.match(/^([0-9]+\.[0-9]+|master)$/);
|
||||
versionDropdown.value = isValidVersion ? versionDropdownValue : "master";
|
||||
});
|
||||
|
||||
versionDropdown.addEventListener("change", ver_sel);
|
||||
});
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* Fires when user selects a documentation version from version dropdown.
|
||||
*---------------------------------------------------------------------*/
|
||||
function ver_sel() {
|
||||
var x = document.getElementById("version_dropdown").value;
|
||||
var new_url = window.location.protocol + "//" + window.location.host + "/" + x + "/";
|
||||
|
||||
if (new_url.startsWith("http")) {
|
||||
window.location.href = new_url;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* Once: add documentation-version dropdown list just above search form in
|
||||
* upper part of left panel.
|
||||
*---------------------------------------------------------------------*/
|
||||
document.addEventListener("DOMContentLoaded", (event) => {
|
||||
add_version_selector().then(() => {
|
||||
var value = window.location.pathname.split("/")[1];
|
||||
document.getElementById("version_dropdown").value = value;
|
||||
});
|
||||
});
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* This listener delays loading (slow-to-load) examples until they are
|
||||
* actually in view in the browser's viewport.
|
||||
*
|
||||
* Once: for each "lv-example" class element, adds observer which watches
|
||||
* for that element to come into view in the browser's viewport. When it
|
||||
* does, `onIntersection()` function is fired, causing example to be loaded
|
||||
* if it hasn't already, or removed when its intersectionRatio <= 0.
|
||||
*/
|
||||
document.addEventListener("DOMContentLoaded", (event) => {
|
||||
function onIntersection(entries) {
|
||||
entries.forEach((entry) => {
|
||||
let currentlyLoaded = entry.target.getAttribute("data-is-loaded") == "true";
|
||||
let shouldBeLoaded = entry.intersectionRatio > 0;
|
||||
if (currentlyLoaded != shouldBeLoaded) {
|
||||
entry.target.setAttribute("data-is-loaded", shouldBeLoaded);
|
||||
if (shouldBeLoaded) {
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.src = entry.target.getAttribute("data-real-src");
|
||||
entry.target.appendChild(iframe);
|
||||
} else {
|
||||
let iframe = entry.target.querySelector("iframe");
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
const config = {
|
||||
rootMargin: "600px 0px",
|
||||
threshold: 0.01,
|
||||
};
|
||||
let observer = new IntersectionObserver(onIntersection, config);
|
||||
document.querySelectorAll(".lv-example").forEach((iframe) => {
|
||||
observer.observe(iframe);
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", (event) => {
|
||||
/*---------------------------------------------------------------------
|
||||
* For API pages:
|
||||
*
|
||||
* Documented code elements on API pages each have a structure that looks
|
||||
* like this example for a function:
|
||||
*
|
||||
* <dl class="cpp function _state_> // container
|
||||
* <dt id="_function_identifier_">function signature</dt> // code highlighting done with <span> child elements
|
||||
* <dd>documentation</dd> // documentation, initially closed
|
||||
* </dl>
|
||||
*
|
||||
* where `_state_` is either "expanded" or "unexpanded". When "unexpanded"
|
||||
* class is present, the <dd> element containing the documentation is hidden
|
||||
* by CSS in `custom.css`. Without that class present (i.e. when "expanded"
|
||||
* class is present instead), the <dd> element reverts to its normal state
|
||||
* of being visible.
|
||||
*
|
||||
* The job of the code below is to:
|
||||
* 1. Add "unexpanded" class to all <dl class="cpp ..."> elements...
|
||||
* 2. ...except if the URL had a hash string ("...#identifier_string")
|
||||
* that matches the immediate <dt> child element's id attribute, in which
|
||||
* case the "expanded" class is added instead. (This usually indicates
|
||||
* the user navigated there by clicking a hyperlinked code element in
|
||||
* one of the documentation pages.)
|
||||
* 3. Add an open/close button <span class="lv-api-expansion-button" />
|
||||
* element just before each code element to toggle its expanded/unexpanded
|
||||
* class. (The click-able arrow icon before it is set in `custom.css`
|
||||
* based on the <dl> element's "expanded" or "unexpanded" class.)
|
||||
*---------------------------------------------------------------------*/
|
||||
document.querySelectorAll("dl.cpp").forEach((cppListing) => {
|
||||
const dt = cppListing.querySelector("dt");
|
||||
let exClass = "expanded";
|
||||
let unExClass = "unexpanded";
|
||||
let shouldBeExpanded = false;
|
||||
if (dt.id == document.location.hash.substring(1)) shouldBeExpanded = true;
|
||||
if (shouldBeExpanded) {
|
||||
cppListing.classList.add(exClass);
|
||||
|
||||
/* If `dt.id` is for an enumerator, also expand its parent
|
||||
* <dl class="cpp enum unexpanded"> element. */
|
||||
let parentDlNode = cppListing.parentNode.parentNode;
|
||||
if (
|
||||
parentDlNode != null
|
||||
&& parentDlNode.classList.contains("cpp")
|
||||
&& parentDlNode.classList.contains("enum")
|
||||
&& parentDlNode.classList.contains(unExClass)
|
||||
) {
|
||||
parentDlNode.classList.remove(unExClass);
|
||||
parentDlNode.classList.add(exClass);
|
||||
}
|
||||
|
||||
/* Have browser scroll `cppListing` into view if it is not already. */
|
||||
cppListing.scrollIntoView();
|
||||
} else {
|
||||
cppListing.classList.add(unExClass);
|
||||
}
|
||||
const button = document.createElement("span");
|
||||
button.classList.add("lv-api-expansion-button");
|
||||
button.addEventListener("click", () => {
|
||||
cppListing.classList.toggle(unExClass);
|
||||
cppListing.classList.toggle(exClass);
|
||||
});
|
||||
|
||||
dt.insertBefore(button, dt.firstChild);
|
||||
});
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* Display any current custom banner in `banner.json` at top of each page.
|
||||
*---------------------------------------------------------------------
|
||||
* Custom banners are inserted between these two elements at top of page.
|
||||
<a class="skip-to-content muted-link" href="#furo-main-content">Skip to content</a>
|
||||
|
||||
<div class="lv-custom-banner-list">
|
||||
<p class="lv-custom-banner">
|
||||
<em>Important</em> announcement one!
|
||||
</p>
|
||||
<p class="lv-custom-banner">
|
||||
<em>Important</em> announcement two!
|
||||
</p>
|
||||
<p class="lv-custom-banner">
|
||||
<em>Important</em> announcement three!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="page">
|
||||
...page content...
|
||||
*---------------------------------------------------------------------*/
|
||||
let bannerJsonUrl = "https://lvgl.io/data/banner.json";
|
||||
let bannerContainerClass = "lv-custom-banner-list";
|
||||
let bannerClass = "lv-custom-banner";
|
||||
/* Note: banner priority property can have only one of these values:
|
||||
* ("highest" | "high" | "normal" | "low" | "lowest").
|
||||
* If not present, the default is "normal-priority". This controls banner styling. */
|
||||
let priorityPropVals = ["highest", "high", "normal", "low", "lowest"];
|
||||
let defaultPrioPropVal = priorityPropVals[2];
|
||||
let priorityClassSuffix = "-priority";
|
||||
|
||||
/* Sorting json banners in priority order.
|
||||
* `a` and `b` are BANNER objects from incoming `banner.json`. */
|
||||
function prio_compare(a, b) {
|
||||
let aPrioPropStr = a.hasOwnProperty("priority") ? a.priority : defaultPrioPropVal;
|
||||
let bPrioPropStr = b.hasOwnProperty("priority") ? b.priority : defaultPrioPropVal;
|
||||
let aPrio = 0;
|
||||
let bPrio = 0;
|
||||
|
||||
/* Establish numeric values for `a` and `b`. */
|
||||
for (var i = 0; i < 5; i++) {
|
||||
if (aPrioPropStr === priorityPropVals[i]) {
|
||||
aPrio = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; i++) {
|
||||
if (bPrioPropStr === priorityPropVals[i]) {
|
||||
bPrio = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Correctness Proof
|
||||
* -----------------
|
||||
* < 0 = `a` should come before `b`.
|
||||
* > 0 = `a` should come after `b`.
|
||||
* 0 or NaN = a === b.
|
||||
*
|
||||
* Example: a === "highest-priority"; b === "normal-priority".
|
||||
* aPrio === 0 ; bPrio === 2.
|
||||
* aPrio - bPrio === -2 means (`a` should come before `b`).
|
||||
*/
|
||||
return aPrio - bPrio;
|
||||
}
|
||||
|
||||
fetch(bannerJsonUrl)
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
} else {
|
||||
/* Note: per OOSC2, it is not appropriate to throw an exception for a
|
||||
* situation that is being checked for. Sometimes the banner file will
|
||||
* not be there, in which case, we simply return an empty array object. */
|
||||
return [];
|
||||
}
|
||||
})
|
||||
/* JSON file was fetched successfully.... */
|
||||
.then((json) => {
|
||||
if (json.constructor !== Array) {
|
||||
/* Data structure not recognized. */
|
||||
} else {
|
||||
/* console.log('JSON is an array.'); */
|
||||
/* Does it contain any banners? */
|
||||
if (json.length === 0) {
|
||||
console.log("JSON has no banners -- nothing to do.");
|
||||
} else {
|
||||
/* Note: `div.page` is unique to Furo theme. */
|
||||
|
||||
/* Create and insert banner container. */
|
||||
const newDiv = document.createElement("div");
|
||||
newDiv.classList.add(bannerContainerClass);
|
||||
let bannerCount = 0;
|
||||
|
||||
/* Create a <p> or an <a> element for each banner.
|
||||
* First, sort them in priority order with "highest-priority" being
|
||||
* at the top. The JSON is an ARRAY of BANNER objects.
|
||||
* `prio_compare()` knows how to compare them.
|
||||
*
|
||||
* If the BANNER object has a "url" property, then
|
||||
* encapsulate banner in an anchor element that will send
|
||||
* user to designated URL.
|
||||
*/
|
||||
json.sort(prio_compare);
|
||||
|
||||
for (var i = 0; i < json.length; i++) {
|
||||
let banner = json[i];
|
||||
|
||||
if (banner.hasOwnProperty("label")) {
|
||||
bannerCount++;
|
||||
let priorityClass = "";
|
||||
let newElement = null;
|
||||
|
||||
if (banner.hasOwnProperty("url")) {
|
||||
newElement = document.createElement("a");
|
||||
newElement.setAttribute("href", banner.url);
|
||||
} else {
|
||||
newElement = document.createElement("p");
|
||||
}
|
||||
|
||||
if (banner.hasOwnProperty("priority")) {
|
||||
priorityClass = banner.priority + priorityClassSuffix;
|
||||
} else {
|
||||
priorityClass = defaultPrioPropVal + priorityClassSuffix;
|
||||
}
|
||||
|
||||
newElement.innerHTML = banner.label;
|
||||
newElement.classList.add(bannerClass);
|
||||
newElement.classList.add(priorityClass);
|
||||
newDiv.appendChild(newElement);
|
||||
}
|
||||
}
|
||||
|
||||
if (bannerCount > 0) {
|
||||
const page = document.querySelector("div.page");
|
||||
const pgParent = page.parentElement;
|
||||
pgParent.insertBefore(newDiv, page);
|
||||
|
||||
/* Finally, we need to tell the page element that its `min-hight`
|
||||
* is 100% minus the hight of all the banners, including the one
|
||||
* supplied by `conf.py` in `conf.html_theme_options.announcement`
|
||||
* if one is present === var(--header-height).
|
||||
*
|
||||
* This extends short pages by just enough to place [PREV] and [NEXT]
|
||||
* buttoms and footer at bottom of page without scrolling.
|
||||
*
|
||||
* Note: this overrides the `min-height` property set for this
|
||||
* element in `furo.css`, which is: calc(100% - var(--header-height)).
|
||||
* It additionally subtracts height of banner list.
|
||||
* */
|
||||
let height = newDiv.offsetHeight;
|
||||
page.style["min-height"] = `calc(100% - var(--header-height) - ${height}px)`;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Fetch error: " + error.message);
|
||||
});
|
||||
});
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* This listener adds a click handler to all .toggle elements.
|
||||
* When a .toggle is clicked, all children are hidden except .header.
|
||||
* When .header is clicked, all children are toggled.
|
||||
*---------------------------------------------------------------------*/
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
document.querySelectorAll(".toggle").forEach(function (toggle) {
|
||||
Array.from(toggle.children).forEach(function (child) {
|
||||
if (!child.classList.contains("header")) {
|
||||
child.style.display = "none";
|
||||
}
|
||||
});
|
||||
var header = toggle.querySelector(".header");
|
||||
if (header) {
|
||||
header.addEventListener("click", function (e) {
|
||||
const toggle = e.target.closest(".toggle");
|
||||
Array.from(toggle.children).forEach(function (child) {
|
||||
if (!child.classList.contains("header")) {
|
||||
if (child.style.display === "none") {
|
||||
child.style.display = "";
|
||||
} else {
|
||||
child.style.display = "none";
|
||||
}
|
||||
}
|
||||
});
|
||||
header.classList.toggle("open");
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
/*https://www.w3schools.com/howto/howto_html_include.asp*/
|
||||
function includeHTML() {
|
||||
var z, i, elmnt, file, xhttp;
|
||||
/*loop through a collection of all HTML elements:*/
|
||||
z = document.getElementsByTagName("*");
|
||||
for (i = 0; i < z.length; i++) {
|
||||
elmnt = z[i];
|
||||
/*search for elements with a certain attribute:*/
|
||||
file = elmnt.getAttribute("include-html");
|
||||
if (file) {
|
||||
/*make an HTTP request using the attribute value as the file name:*/
|
||||
xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4) {
|
||||
if (this.status == 200) {elmnt.innerHTML = this.responseText;}
|
||||
if (this.status == 404) {elmnt.innerHTML = "Page not found.";}
|
||||
/*remove the attribute, and call this function once more:*/
|
||||
elmnt.removeAttribute("w3-include-html");
|
||||
includeHTML();
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", file, true);
|
||||
xhttp.send();
|
||||
/*exit the function:*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
{% extends "furo/components/view-this-page.html" %}
|
||||
{% from "basic-ng/components/view-this-page.html" import determine_page_view_link with context %}
|
||||
|
||||
{#- Only this block is redefined (overridden) from furo/components/view-this-page.html.
|
||||
All else remains intact. -#}
|
||||
{% block link_available -%}
|
||||
{#- Ensure `page_source_suffix` exists, else `determine_page_view_link()` fails
|
||||
during generation of the `genindex` page at the end. -#}
|
||||
{%- if page_source_suffix -%}
|
||||
{%- set page_link = determine_page_view_link() -%}
|
||||
{%- if "docs/src/API/" in page_link -%}
|
||||
{#- Adjust page_link from fictional API pages to point to real .h files. -#}
|
||||
{%- set page_link = page_link.replace("docs/src/API/", "src/") -%}
|
||||
{%- set page_link = page_link.replace("_h.rst", ".h") -%}
|
||||
{%- set page_link = page_link.replace("?plain=true", "") -%}
|
||||
{#- Redirect "src/lv_conf.h" => "lv_conf_template.h" -#}
|
||||
{%- if page_link.endswith("/src/lv_conf.h") -%}
|
||||
{%- set page_link = page_link.replace("/src/lv_conf.h", "/lv_conf_template.h") -%}
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{{ furo_view_button(page_link) }}
|
||||
{%- endif -%}
|
||||
{%- endblock %}
|
||||
@@ -0,0 +1,202 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none">
|
||||
<symbol id="svg-toc" width="20" height="20" viewBox="0 0 16 16">
|
||||
<title>Contents</title>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M9.5 14H4C2.89543 14 2 13.1046 2 12V4C2 2.89543 2.89543 2 4 2H9.5V14ZM12 2C13.1046 2 14 2.89543 14 4V12C14 13.1046 13.1046 14 12 14H10.5V2H12ZM7.30664 5.90137C7.01379 5.60882 6.53889 5.60884 6.24609 5.90137L4.40039 7.74805L4.34863 7.80566C4.10869 8.10016 4.12612 8.53408 4.40039 8.80859L6.24316 10.6533L6.30078 10.7051C6.59511 10.9451 7.02907 10.9283 7.30371 10.6543C7.57829 10.3799 7.59634 9.94504 7.35645 9.65039L7.30469 9.59277L5.99121 8.27832L7.30664 6.96289C7.59937 6.66997 7.59942 6.19418 7.30664 5.90137Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-menu" width="20" height="20" viewBox="0 0 16 16">
|
||||
<title>Menu</title>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.5 4H13.5" />
|
||||
<path d="M2.5 8.5H13.5" />
|
||||
<path d="M2.5 13H13.5" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-arrow-right" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>Expand</title>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M7.00001 11L9.99999 8L6.99999 5.00001"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</symbol>
|
||||
|
||||
<symbol id="svg-sun" width="20" height="20" viewBox="0 0 16 16">
|
||||
<title>Light mode</title>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="8" cy="8" r="3" />
|
||||
<path
|
||||
d="M7.25 1.75C7.25 1.33579 7.58579 1 8 1C8.41421 1 8.75 1.33579 8.75 1.75V3.25C8.75 3.66421 8.41421 4 8 4C7.58579 4 7.25 3.66421 7.25 3.25V1.75Z" />
|
||||
<path
|
||||
d="M7.25 12.75C7.25 12.3358 7.58579 12 8 12C8.41421 12 8.75 12.3358 8.75 12.75V14.25C8.75 14.6642 8.41421 15 8 15C7.58579 15 7.25 14.6642 7.25 14.25V12.75Z" />
|
||||
<path
|
||||
d="M1.75 8.75C1.33579 8.75 1 8.41421 1 8C1 7.58579 1.33579 7.25 1.75 7.25L3.25 7.25C3.66421 7.25 4 7.58579 4 8C4 8.41421 3.66421 8.75 3.25 8.75L1.75 8.75Z" />
|
||||
<path
|
||||
d="M12.75 8.75C12.3358 8.75 12 8.41421 12 8C12 7.58579 12.3358 7.25 12.75 7.25L14.25 7.25C14.6642 7.25 15 7.58579 15 8C15 8.41421 14.6642 8.75 14.25 8.75L12.75 8.75Z" />
|
||||
<path
|
||||
d="M3.05026 4.11091C2.75736 3.81802 2.75736 3.34314 3.05026 3.05025C3.34315 2.75736 3.81803 2.75736 4.11092 3.05025L5.17158 4.11091C5.46447 4.40381 5.46447 4.87868 5.17158 5.17157C4.87869 5.46447 4.40381 5.46447 4.11092 5.17157L3.05026 4.11091Z" />
|
||||
<path
|
||||
d="M10.8284 11.8891C10.5355 11.5962 10.5355 11.1213 10.8284 10.8284C11.1213 10.5355 11.5962 10.5355 11.8891 10.8284L12.9498 11.8891C13.2426 12.182 13.2426 12.6569 12.9498 12.9497C12.6569 13.2426 12.182 13.2426 11.8891 12.9497L10.8284 11.8891Z" />
|
||||
<path
|
||||
d="M11.8891 3.05024C12.182 2.75734 12.6568 2.75734 12.9497 3.05024C13.2426 3.34313 13.2426 3.818 12.9497 4.1109L11.8891 5.17156C11.5962 5.46445 11.1213 5.46445 10.8284 5.17156C10.5355 4.87866 10.5355 4.40379 10.8284 4.1109L11.8891 3.05024Z" />
|
||||
<path
|
||||
d="M4.11089 10.8284C4.40378 10.5355 4.87866 10.5355 5.17155 10.8284C5.46444 11.1213 5.46444 11.5962 5.17155 11.8891L4.11089 12.9497C3.818 13.2426 3.34312 13.2426 3.05023 12.9497C2.75734 12.6568 2.75734 12.182 3.05023 11.8891L4.11089 10.8284Z" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-moon" width="20" height="20" viewBox="0 0 16 16">
|
||||
<title>Dark mode</title>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12.5446 11.9176C12.8733 11.5367 12.5031 11 12 11C8.68629 11 6 8.3137 6 4.99999C6 4.72807 6.01809 4.46037 6.05313 4.19803C6.16641 3.34993 5.44091 2.50445 4.72444 2.97218C3.08409 4.04303 2 5.89491 2 8C2 11.3137 4.68629 14 8 14C9.81644 14 11.4443 13.1928 12.5446 11.9176Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-moon-with-sun" width="20" height="20" viewBox="0 0 16 16">
|
||||
<title>System, in dark mode</title>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
stroke="currentColor"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M4.5 3.5H11.5C12.3283 3.5 13 4.17146 13 5V8C13 8.82843 12.3284 9.5 11.5 9.5H4.5C3.67157 9.5 3 8.82843 3 8V5C3 4.17145 3.6717 3.5 4.5 3.5Z" />
|
||||
<path
|
||||
d="M6.75 11.5H9.25C9.66409 11.5 10 11.8357 10 12.25C10 12.6642 9.66421 13 9.25 13H6.75C6.33579 13 6 12.6642 6 12.25C6 11.8357 6.33591 11.5 6.75 11.5Z" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-sun-with-moon" width="20" height="20" viewBox="0 0 16 16">
|
||||
<title>System, in light mode</title>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
stroke="currentColor"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M4.5 3.5H11.5C12.3283 3.5 13 4.17146 13 5V8C13 8.82843 12.3284 9.5 11.5 9.5H4.5C3.67157 9.5 3 8.82843 3 8V5C3 4.17145 3.6717 3.5 4.5 3.5Z" />
|
||||
<path
|
||||
d="M6.75 11.5H9.25C9.66409 11.5 10 11.8357 10 12.25C10 12.6642 9.66421 13 9.25 13H6.75C6.33579 13 6 12.6642 6 12.25C6 11.8357 6.33591 11.5 6.75 11.5Z" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-pencil" width="20" height="20" viewBox="0 0 24 24">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon-tabler-pencil-code">
|
||||
<path d="M4 20h4l10.5 -10.5a2.828 2.828 0 1 0 -4 -4l-10.5 10.5v4" />
|
||||
<path d="M13.5 6.5l4 4" />
|
||||
<path d="M20 21l2 -2l-2 -2" />
|
||||
<path d="M17 17l-2 2l2 2" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-eye" width="20" height="20">
|
||||
<title>View documentation source on GitHub</title>
|
||||
<svg width="20" height="20" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M8 1C4.1325 1 1 4.21174 1 8.17704C1 11.3529 3.00375 14.0354 5.78625 14.9863C6.13625 15.0491 6.2675 14.8338 6.2675 14.6454C6.2675 14.4749 6.25875 13.9098 6.25875 13.3087C4.5 13.6406 4.045 12.8691 3.905 12.4654C3.82625 12.259 3.485 11.6221 3.1875 11.4516C2.9425 11.317 2.5925 10.9851 3.17875 10.9761C3.73 10.9672 4.12375 11.4965 4.255 11.7118C4.885 12.7973 5.89125 12.4923 6.29375 12.3039C6.355 11.8374 6.53875 11.5234 6.74 11.3439C5.1825 11.1645 3.555 10.5455 3.555 7.80027C3.555 7.01976 3.82625 6.37383 4.2725 5.87143C4.2025 5.692 3.9575 4.95636 4.3425 3.96951C4.3425 3.96951 4.92875 3.78111 6.2675 4.70516C6.8275 4.54368 7.4225 4.46293 8.0175 4.46293C8.6125 4.46293 9.2075 4.54368 9.7675 4.70516C11.1062 3.77214 11.6925 3.96951 11.6925 3.96951C12.0775 4.95636 11.8325 5.692 11.7625 5.87143C12.2087 6.37383 12.48 7.01079 12.48 7.80027C12.48 10.5545 10.8438 11.1645 9.28625 11.3439C9.54 11.5682 9.75875 11.9988 9.75875 12.6717C9.75875 13.6316 9.75 14.4032 9.75 14.6454C9.75 14.8338 9.88125 15.0581 10.2312 14.9863C11.6209 14.5053 12.8284 13.5896 13.6839 12.3681C14.5393 11.1466 14.9996 9.68085 15 8.17704C15 4.21174 11.8675 1 8 1Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</symbol>
|
||||
|
||||
<symbol id="svg-home-intro" width="32" height="32" viewBox="0 0 32 32">
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M26 2C28.2091 2 30 3.79086 30 6V26C30 28.2091 28.2091 30 26 30H6C3.79086 30 2 28.2091 2 26V6C2 3.79086 3.79086 2 6 2H26ZM8.00781 18.5C6.91797 18.5 6 19.1719 6 19.9336C6 20.2812 6.26562 20.5312 6.64062 20.5312C6.90234 20.5312 7.07422 20.4297 7.3125 20.1328C7.51953 19.875 7.6875 19.7812 7.92188 19.7812C8.22656 19.7812 8.4375 19.9766 8.4375 20.2656C8.4375 20.5234 8.25781 20.7734 7.85156 21.1562L6.65625 22.2812C6.17578 22.7305 6.00781 22.9883 6.00781 23.2773C6.00781 23.6602 6.30078 23.9219 6.73047 23.9219H9.45312C9.91406 23.9219 10.1875 23.6875 10.1875 23.293C10.1875 22.8984 9.90625 22.6562 9.45312 22.6562H8.14453V22.5938L9.06641 21.7734C9.6875 21.2227 9.99219 20.6758 9.99219 20.1016C9.99219 19.1836 9.14453 18.5 8.00781 18.5ZM13 20C12.4477 20 12 20.4477 12 21C12 21.5523 12.4477 22 13 22H24C24.5523 22 25 21.5523 25 21C25 20.4477 24.5523 20 24 20H13ZM13 15C12.4477 15 12 15.4477 12 16C12 16.5523 12.4477 17 13 17H24C24.5523 17 25 16.5523 25 16C25 15.4477 24.5523 15 24 15H13ZM8.23438 8.5C7.91016 8.5 7.55078 8.60938 7.21484 8.8125L6.66406 9.14453C6.39062 9.30859 6.25 9.51562 6.25 9.75391C6.25 10.0742 6.47656 10.3008 6.79688 10.3008C6.95312 10.3008 7.07812 10.2539 7.33594 10.1016L7.55469 9.97266H7.5625V13.0625C7.5625 13.6172 7.85547 13.9297 8.37891 13.9297C8.89844 13.9297 9.1875 13.6211 9.1875 13.0625V9.47656C9.1875 8.88281 8.8125 8.5 8.23438 8.5ZM13 10C12.4477 10 12 10.4477 12 11C12 11.5523 12.4477 12 13 12H24C24.5523 12 25 11.5523 25 11C25 10.4477 24.5523 10 24 10H13Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-home-getting-started" width="32" height="32" viewBox="0 0 32 32">
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M24 2C26.2091 2 28 3.79086 28 6V20.4941C27.9999 21.4443 27.5615 22.3414 26.8115 22.9248C25.1702 24.2014 25.2396 26.7041 26.9492 27.8877L27.5947 28.335C28.3308 28.8451 27.97 29.9999 27.0742 30H8C5.79086 30 4 28.2091 4 26V6C4 3.79086 5.79086 2 8 2H24ZM8 23C6.89543 23 6 23.8954 6 25V26C6 27.1046 6.89543 28 8 28H23C23.5523 28 24 27.5523 24 27V24C24 23.4477 23.5523 23 23 23H8ZM8 5C7.44772 5 7 5.44772 7 6V19C7 19.5523 7.44772 20 8 20C8.55228 20 9 19.5523 9 19V6C9 5.44772 8.55228 5 8 5ZM17.5205 8.60059C16.5361 8.60059 16.0029 9.04492 15.6338 10.1523L13.5693 16.2021C13.4121 16.6602 13.3506 16.9199 13.3506 17.1455C13.3506 17.6924 13.7744 18.0752 14.3896 18.0752C14.9912 18.0752 15.3125 17.7676 15.5381 16.9746L15.9004 15.8604H19.0381L19.3936 16.9746C19.6191 17.7471 19.9678 18.0752 20.5693 18.0752C21.2188 18.0752 21.6426 17.6924 21.6426 17.0977C21.6426 16.8584 21.5811 16.585 21.458 16.2021L19.4004 10.1523C19.0244 9.03809 18.5049 8.60059 17.5205 8.60059ZM17.5342 10.6924L18.5801 14.2266H16.3652L17.4248 10.6924H17.5342Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 25C6 23.8954 6.89543 23 8 23L23 23C23.5523 23 24 23.4477 24 24V27C24 27.5523 23.5523 28 23 28L8 28C6.89543 28 6 27.1046 6 26L6 25Z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.1" />
|
||||
<path
|
||||
d="M6 25C6 23.8954 6.89543 23 8 23L23 23C23.5523 23 24 23.4477 24 24V27C24 27.5523 23.5523 28 23 28L8 28C6.89543 28 6 27.1046 6 26L6 25Z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.1" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-home-play" width="32" height="32" viewBox="0 0 32 32">
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M16 31C24.2843 31 31 24.2843 31 16C31 7.71573 24.2843 1 16 1C7.71573 1 1 7.71573 1 16C1 24.2843 7.71573 31 16 31ZM14.5932 10.1739C13.9329 9.68743 13 10.1588 13 10.979V20.8889C13 21.7327 13.9806 22.1972 14.6335 21.6626L21.0041 16.4469C21.509 16.0335 21.4892 15.2552 20.9638 14.8681L14.5932 10.1739Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-home-integration" width="32" height="32" viewBox="0 0 32 32">
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M10 5C10 5.55228 10.4477 6 11 6C11.5523 6 12 5.55228 12 5V4H15V5C15 5.55228 15.4477 6 16 6C16.5523 6 17 5.55228 17 5V4H20V5C20 5.55228 20.4477 6 21 6C21.5523 6 22 5.55228 22 5V4H23C25.7614 4 28 6.23858 28 9V10H27C26.4477 10 26 10.4477 26 11C26 11.5523 26.4477 12 27 12H28V15H27C26.4477 15 26 15.4477 26 16C26 16.5523 26.4477 17 27 17H28V20H27C26.4477 20 26 20.4477 26 21C26 21.5523 26.4477 22 27 22H28V23C28 25.7614 25.7614 28 23 28H22V27C22 26.4477 21.5523 26 21 26C20.4477 26 20 26.4477 20 27V28H17V27C17 26.4477 16.5523 26 16 26C15.4477 26 15 26.4477 15 27V28H12V27C12 26.4477 11.5523 26 11 26C10.4477 26 10 26.4477 10 27V28H9C6.23858 28 4 25.7614 4 23V22H5C5.55228 22 6 21.5523 6 21C6 20.4477 5.55228 20 5 20H4V17H5C5.55228 17 6 16.5523 6 16C6 15.4477 5.55228 15 5 15H4V12H5C5.55228 12 6 11.5523 6 11C6 10.4477 5.55228 10 5 10H4V9C4 6.23858 6.23858 4 9 4H10V5ZM13 10C11.3431 10 10 11.3431 10 13V19C10 20.6569 11.3431 22 13 22H19C20.6569 22 22 20.6569 22 19V13C22 11.3431 20.6569 10 19 10H13Z"
|
||||
fill="currentColor" />
|
||||
<rect opacity="0.2" x="10" y="10" width="12" height="12" rx="3" fill="currentColor" />
|
||||
<g opacity="0.4">
|
||||
<rect x="12" y="2" width="4" height="2" rx="1" transform="rotate(90 12 2)" fill="currentColor" />
|
||||
<rect x="17" y="2" width="4" height="2" rx="1" transform="rotate(90 17 2)" fill="currentColor" />
|
||||
<rect x="22" y="2" width="4" height="2" rx="1" transform="rotate(90 22 2)" fill="currentColor" />
|
||||
<rect x="30" y="12" width="4" height="2" rx="1" transform="rotate(-180 30 12)" fill="currentColor" />
|
||||
<rect x="30" y="17" width="4" height="2" rx="1" transform="rotate(-180 30 17)" fill="currentColor" />
|
||||
<rect x="30" y="22" width="4" height="2" rx="1" transform="rotate(-180 30 22)" fill="currentColor" />
|
||||
<rect x="20" y="30" width="4" height="2" rx="1" transform="rotate(-90 20 30)" fill="currentColor" />
|
||||
<rect x="15" y="30" width="4" height="2" rx="1" transform="rotate(-90 15 30)" fill="currentColor" />
|
||||
<rect x="10" y="30" width="4" height="2" rx="1" transform="rotate(-90 10 30)" fill="currentColor" />
|
||||
<rect x="2" y="20" width="4" height="2" rx="1" fill="currentColor" />
|
||||
<rect x="2" y="15" width="4" height="2" rx="1" fill="currentColor" />
|
||||
<rect x="2" y="10" width="4" height="2" rx="1" fill="currentColor" />
|
||||
</g>
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-home-widgets" width="32" height="32" viewBox="0 0 32 32">
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.2" x="2" y="17" width="13" height="13" rx="2" fill="currentColor" />
|
||||
<path
|
||||
d="M11.7266 21.2664C11.3622 20.9112 10.7713 20.9112 10.4067 21.2664L7.80008 23.8052L6.59332 22.63C6.22884 22.275 5.63783 22.275 5.27336 22.63C4.90888 22.985 4.90888 23.5606 5.27336 23.9156L7.14001 25.7338C7.5045 26.0888 8.09551 26.0888 8.45998 25.7338L11.7266 22.552C12.0911 22.1968 12.0911 21.6214 11.7266 21.2664Z"
|
||||
fill="currentColor" />
|
||||
<rect opacity="0.2" x="17" y="17" width="13" height="13" rx="6.5" fill="currentColor" />
|
||||
<rect x="19.9375" y="19.9375" width="7" height="7" rx="3.5" fill="currentColor" />
|
||||
<path
|
||||
d="M28 2C29.1046 2 30 2.89543 30 4V13C30 14.1046 29.1046 15 28 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H28ZM8.5 5C6.567 5 5 6.567 5 8.5C5 10.433 6.567 12 8.5 12H14.5C16.433 12 18 10.433 18 8.5C18 6.567 16.433 5 14.5 5H8.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-home-contributing" width="32" height="32" viewBox="0 0 32 32">
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<ellipse opacity="0.6" cx="9.889" cy="11.9469" rx="4.44442" ry="4.63131" fill="currentColor" />
|
||||
<ellipse cx="21" cy="10.2102" rx="4.99997" ry="5.21023" fill="currentColor" />
|
||||
<path
|
||||
d="M30.9999 24.0309C30.9999 27.8304 28.647 26.8974 20.9999 26.8974C13.3529 26.8974 11 27.8304 11 24.0309C11 20.2315 15.4771 16.5781 20.9999 16.5781C26.5228 16.5781 30.9999 20.2315 30.9999 24.0309Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
opacity="0.6"
|
||||
d="M9.88867 17.7363C10.7113 17.7363 11.5076 17.8294 12.2637 17.9971C10.118 19.6601 8.77832 21.9142 8.77832 24.1045C8.77837 25.4207 8.99363 26.3104 9.56055 26.9111C3.02414 26.9364 1.00012 27.6833 1 24.3613C1 20.9841 4.97958 17.7364 9.88867 17.7363Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,6 @@
|
||||
<form class="sidebar-search-container" method="get" action="{{ pathto('search') }}" role="search">
|
||||
<input class="sidebar-search" placeholder="{{ _("Search Documentation") }}" name="q" aria-label="{{ _("Search" ) }}">
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
<div id="searchbox"></div>
|
||||
@@ -0,0 +1,4 @@
|
||||
<div class="version-selector">
|
||||
<label for="version_dropdown">Select LVGL version</label>
|
||||
<select name="version" id="version_dropdown"></select>
|
||||
</div>
|
||||
@@ -0,0 +1,226 @@
|
||||
.. _file_explorer:
|
||||
|
||||
=============
|
||||
File Explorer
|
||||
=============
|
||||
|
||||
``lv_file_explorer`` provides a UI enabling the end user to browse the contents of a
|
||||
file system. Its main area is called the "Browsing Area" and provides the list of
|
||||
files contained in the currently-viewed directory.
|
||||
|
||||
When enabled, there is also a "Quick-Access" panel on the left, which provides a
|
||||
convenient way to reach parts of the file system that are frequently accessed.
|
||||
Available "Quick-Access" destinations are:
|
||||
|
||||
- File System,
|
||||
- HOME,
|
||||
- Video,
|
||||
- Pictures,
|
||||
- Music, and
|
||||
- Documents.
|
||||
|
||||
You specify what paths these lead to during ``lv_file_explorer``\ 's initialization.
|
||||
|
||||
``lv_file_explorer`` only provides the file browsing and events caused by user
|
||||
activity (e.g. clicking a file), but does not provide the actual file operations.
|
||||
Client code must hook various events and decide what to do when they are emitted
|
||||
(e.g. a click or double-click on a file). The actions taken might to open the file,
|
||||
display it, send it to some other part of the application, etc..
|
||||
``lv_file_explorer`` passes the full path and name of file that was clicked to the
|
||||
event callback functions. What happens next is up to the application designer.
|
||||
|
||||
``lv_file_explorer`` uses the :ref:`lv_table` Widget for the "Browsing Area", and the
|
||||
:ref:`lv_list` Widget for the "Quick-Access" panel when it is enabled. Thus,
|
||||
:c:macro:`LV_USE_TABLE` macro must be set to a non-zero value in ``lv_conf.h`` in
|
||||
order to use ``lv_file_explorer``, and and :c:macro:`LV_USE_LIST` must be set to a
|
||||
non-zero value to use the "Quick-Access" panel.
|
||||
|
||||
.. note::
|
||||
|
||||
In order to use File Explorer, :ref:`file_system` has to be set up and
|
||||
know about all the drive letters you use when passing paths to File System
|
||||
(described below).
|
||||
|
||||
|
||||
|
||||
Prerequisites
|
||||
*************
|
||||
|
||||
If you haven't already done so, you will need to learn about the LVGL :ref:`File
|
||||
System abstraction <file_system>`, since it must be set up and be functional
|
||||
for File Explorer to work.
|
||||
|
||||
|
||||
|
||||
.. _file_explorer_usage:
|
||||
|
||||
Usage
|
||||
*****
|
||||
|
||||
Set :c:macro:`LV_USE_FILE_EXPLORER` to a non-zero value in ``lv_conf.h``.
|
||||
|
||||
First use :cpp:expr:`lv_file_explorer_create(lv_screen_active())` to create a File
|
||||
Explorer. The default size is the screen size. After that, you can
|
||||
customize the style like any Widget.
|
||||
|
||||
The size of the ``current_path`` buffer is set by :c:macro:`LV_FILE_EXPLORER_PATH_MAX_LEN`
|
||||
in ``lv_conf.h``.
|
||||
|
||||
The object hierarchy of a freshly-created File Explorer looks like this:
|
||||
|
||||
- ``File Explorer``: occupies full area of parent Widget, typically a Screen (Flex-Flow COLUMN)
|
||||
|
||||
- ``Container``: occupies full area of File Explorer (Flex grow 1)
|
||||
|
||||
- ``Quick-Access Panel``:
|
||||
|
||||
- ``Device List``: grows to accommodate children
|
||||
|
||||
- ``File System``: button
|
||||
|
||||
- ``Places List``: grows to accommodate children
|
||||
|
||||
- ``HOME``: button
|
||||
- ``Video``: button
|
||||
- ``Pictures``: button
|
||||
- ``Music``: button
|
||||
- ``Documents``: button
|
||||
|
||||
- ``Browser Panel``:
|
||||
|
||||
- ``Header``: 14% of ``Browser Panel`` height
|
||||
|
||||
- ``Current Path``: label
|
||||
|
||||
- ``File Table``: with 1 column, 86% of ``Browser Panel`` height
|
||||
|
||||
- Fields:
|
||||
|
||||
- ``home_dir`` = NULL
|
||||
- ``video_dir`` = NULL
|
||||
- ``pictures_dir`` = NULL
|
||||
- ``music_dir`` = NULL
|
||||
- ``docs_dir`` = NULL
|
||||
- ``fs_dir`` = NULL
|
||||
- ``current_path`` = [empty buffer]
|
||||
- ``sel_fn`` (selected file)
|
||||
- ``sort`` (default :cpp:enumerator:`LV_EXPLORER_SORT_NONE`)
|
||||
|
||||
|
||||
Accessing the Parts
|
||||
-------------------
|
||||
|
||||
This list of functions provides access to the parts shown in diagram above:
|
||||
|
||||
- :cpp:expr:`lv_file_explorer_get_selected_file_name(explorer)` (pointer
|
||||
to NUL-terminated string containing file-path user selected; typically used inside
|
||||
an :cpp:enumerator:`LV_EVENT_CLICKED` event)
|
||||
- :cpp:expr:`lv_file_explorer_get_current_path(explorer)` (pointer to ``current_path`` ``char`` buffer)
|
||||
- :cpp:expr:`lv_file_explorer_get_file_table(explorer)` (pointer to ``File Table`` :ref:`lv_table` Widget)
|
||||
- :cpp:expr:`lv_file_explorer_get_header(explorer)` (pointer to ``Header`` :ref:`base_widget` Widget)
|
||||
- :cpp:expr:`lv_file_explorer_get_path_label(explorer)` (pointer to ``Current Path Label`` :ref:`lv_label` Widget)
|
||||
- :cpp:expr:`lv_file_explorer_get_quick_access_area(explorer)` (pointer to ``Quick-Access Panel`` :ref:`base_widget`)
|
||||
- :cpp:expr:`lv_file_explorer_get_places_list(explorer)` (pointer to ``Places List`` :ref:`lv_list` Widget)
|
||||
- :cpp:expr:`lv_file_explorer_get_device_list(explorer)` (pointer to ``Device List`` :ref:`lv_list` Widget)
|
||||
|
||||
|
||||
Quick-Access Panel
|
||||
------------------
|
||||
|
||||
The ``Quick-Access Panel`` behaves like a typical navigation panel and appears on the
|
||||
left, while the ``Browser Panel`` appears on the right
|
||||
|
||||
This panel is optional. If you set :c:macro:`LV_FILE_EXPLORER_QUICK_ACCESS` to ``0``
|
||||
in ``lv_conf.h``, the ``Quick-Access Panel`` will not be created. This saves only a
|
||||
little bit of memory.
|
||||
|
||||
Soon after the File Explorer is created, you typically use
|
||||
:cpp:expr:`lv_file_explorer_set_quick_access_path(explorer, LV_EXPLORER_XXX_DIR, "path")`
|
||||
to set the path that will be navigated to when the buttons in the ``Quick-Access Panel``
|
||||
are clicked, which is currently a fixed list. The corresponding values you will need
|
||||
to pass as the 2nd argument are the following:
|
||||
|
||||
- :cpp:enumerator:`LV_EXPLORER_HOME_DIR`
|
||||
- :cpp:enumerator:`LV_EXPLORER_MUSIC_DIR`
|
||||
- :cpp:enumerator:`LV_EXPLORER_PICTURES_DIR`
|
||||
- :cpp:enumerator:`LV_EXPLORER_VIDEO_DIR`
|
||||
- :cpp:enumerator:`LV_EXPLORER_DOCS_DIR`
|
||||
- :cpp:enumerator:`LV_EXPLORER_FS_DIR`
|
||||
|
||||
|
||||
.. _file_explorer_sort:
|
||||
|
||||
Sort
|
||||
----
|
||||
|
||||
You can use
|
||||
:cpp:expr:`lv_file_explorer_set_sort(explorer, LV_EXPLORER_SORT_XX)` to set
|
||||
the sorting method.
|
||||
|
||||
These are the possible sorting methods:
|
||||
|
||||
- :cpp:enumerator:`LV_EXPLORER_SORT_NONE` (default)
|
||||
- :cpp:enumerator:`LV_EXPLORER_SORT_KIND`
|
||||
|
||||
:cpp:expr:`lv_file_explorer_get_sort(explorer)` returns the current sorting method.
|
||||
|
||||
|
||||
|
||||
.. _file_explorer_events:
|
||||
|
||||
Events
|
||||
******
|
||||
|
||||
- :cpp:enumerator:`LV_EVENT_READY` Sent when a directory is opened, which can happen:
|
||||
|
||||
- when the File Explorer is initially opened,
|
||||
- after a user clicks on a ``Quick-Access Panel`` navigation button, and
|
||||
- after the user clicks on a directory displayed in the ``Browser Panel``.
|
||||
|
||||
You can use it to, for example, customize the file sort.
|
||||
|
||||
- :cpp:enumerator:`LV_EVENT_VALUE_CHANGED` Sent once when any item (file) in the
|
||||
``Browser Panel``\ 's file list is clicked.
|
||||
|
||||
- :cpp:enumerator:`LV_EVENT_CLICKED` Sent twice when an item in the ``Browser Panel``
|
||||
is clicked: once as a result of the input-device :cpp:enumerator:`LV_EVENT_RELEASED`
|
||||
event and a second as a result of the input device :cpp:enumerator:`LV_EVENT_CLICKED`
|
||||
event. This applies to files, directories, and the "< Back" item in the ``Browser Panel``.
|
||||
|
||||
In these events you can use :cpp:func:`lv_file_explorer_get_current_path` to get the
|
||||
current path and :cpp:func:`lv_file_explorer_get_selected_file_name` to get the name
|
||||
of the currently selected file in the event processing function. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static void file_explorer_event_handler(lv_event_t * e)
|
||||
{
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
lv_obj_t * obj = lv_event_get_target(e);
|
||||
|
||||
if(code == LV_EVENT_VALUE_CHANGED) {
|
||||
char * cur_path = lv_file_explorer_get_current_path(widget);
|
||||
char * sel_fn = lv_file_explorer_get_selected_file_name(widget);
|
||||
LV_LOG_USER("%s%s", cur_path, sel_fn);
|
||||
}
|
||||
}
|
||||
|
||||
You can also save the obtained **path** and **file** name into an array
|
||||
through functions such as :cpp:func:`strcpy` and :cpp:func:`strcat` for later use.
|
||||
|
||||
|
||||
|
||||
.. _file_explorer_example:
|
||||
|
||||
Examples
|
||||
********
|
||||
|
||||
.. include:: /examples/others/file_explorer/index.rst
|
||||
|
||||
|
||||
|
||||
.. _file_explorer_api:
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
.. _fragment:
|
||||
|
||||
========
|
||||
Fragment
|
||||
========
|
||||
|
||||
.. warning::
|
||||
|
||||
This module is now deprecated and will be removed in an upcoming release.
|
||||
|
||||
Fragment is a concept copied from
|
||||
`Android <https://developer.android.com/guide/fragments>`__.
|
||||
|
||||
It represents a reusable portion of your app's UI. A fragment defines
|
||||
and manages its own layout, has its own lifecycle, and can handle its
|
||||
own events. Like Android's Fragment that must be hosted by an activity
|
||||
or another fragment, Fragment in LVGL needs to be hosted by a Widget,
|
||||
or another fragment. The fragment's view hierarchy becomes part of, or
|
||||
attaches to, the host's view hierarchy.
|
||||
|
||||
Such concept also has some similarities to `UiViewController on
|
||||
iOS <https://developer.apple.com/documentation/uikit/uiviewcontroller>`__.
|
||||
|
||||
Fragment Manager is a manager holding references to fragments attached
|
||||
to it, and has an internal stack to achieve forward and backwards navigation. You can use
|
||||
fragment manager to build a navigation stack, or a multi-pane application
|
||||
easily.
|
||||
|
||||
|
||||
|
||||
.. _fragment_usage:
|
||||
|
||||
Usage
|
||||
*****
|
||||
|
||||
Enable :c:macro:`LV_USE_FRAGMENT` in ``lv_conf.h``.
|
||||
|
||||
Create Fragment Class
|
||||
---------------------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct sample_fragment_t {
|
||||
/* IMPORTANT: don't miss this part */
|
||||
lv_fragment_t base;
|
||||
/* States, object references and data fields for this fragment */
|
||||
const char *title;
|
||||
};
|
||||
|
||||
const lv_fragment_class_t sample_cls = {
|
||||
/* Initialize something needed */
|
||||
.constructor_cb = sample_fragment_ctor,
|
||||
/* Create view objects */
|
||||
.create_obj_cb = sample_fragment_create_obj,
|
||||
/* IMPORTANT: size of your fragment struct */
|
||||
.instance_size = sizeof(struct sample_fragment_t),
|
||||
};
|
||||
|
||||
Use ``lv_fragment_manager``
|
||||
---------------------------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Create fragment instance, and Widgets will be added to container */
|
||||
lv_fragment_manager_t *manager = lv_fragment_manager_create(container, NULL);
|
||||
/* Replace current fragment with instance of sample_cls, and init_argument is user defined pointer */
|
||||
lv_fragment_manager_replace(manager, &sample_cls, init_argument);
|
||||
|
||||
Fragment Based Navigation
|
||||
-------------------------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Add one instance into manager stack. View object of current fragment will be destroyed,
|
||||
* but instances created in class constructor will be kept.
|
||||
*/
|
||||
lv_fragment_manager_push(manager, &sample_cls, NULL);
|
||||
|
||||
/* Remove the top most fragment from the stack, and bring back previous one. */
|
||||
lv_fragment_manager_pop(manager);
|
||||
|
||||
|
||||
|
||||
.. _fragment_example:
|
||||
|
||||
Examples
|
||||
********
|
||||
|
||||
.. include:: /examples/others/fragment/index.rst
|
||||
|
||||
|
||||
|
||||
.. _fragment_api:
|
||||
|
||||
API
|
||||
***
|
||||
@@ -0,0 +1,11 @@
|
||||
.. _auxiliary_modules:
|
||||
|
||||
=================
|
||||
Auxiliary Modules
|
||||
=================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
file_explorer
|
||||
fragment
|
||||
@@ -0,0 +1,134 @@
|
||||
================
|
||||
API Conventions
|
||||
================
|
||||
|
||||
In most cases, the API functions of LVGL widgets are structured like:
|
||||
|
||||
- ``lv_ + <widget_name> + create(parent)``
|
||||
- ``lv_ + <widget_name> + set + <property>(widget, value)``
|
||||
- ``lv_ + <widget_name> + get + <property>(widget)``
|
||||
- ``lv_ + <widget_name> + add + <property>(widget)``
|
||||
|
||||
|
||||
|
||||
Basic Attributes
|
||||
****************
|
||||
|
||||
All widget types share some basic attributes:
|
||||
|
||||
- Position
|
||||
- Size
|
||||
- Parent
|
||||
- Styles
|
||||
- Event callbacks
|
||||
- Flags like *Clickable*, *Scrollable*, etc.
|
||||
- Etc.
|
||||
|
||||
You can set/get these attributes with ``lv_obj_set_...`` and
|
||||
``lv_obj_get_...`` functions. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Set basic widget attributes */
|
||||
lv_obj_set_size(btn1, 100, 50); /* Set a button's size */
|
||||
lv_obj_set_pos(btn1, 20, 30); /* Set a button's position */
|
||||
|
||||
For complete details on position, size, coordinates, and layouts, see :ref:`coord`.
|
||||
|
||||
|
||||
|
||||
Widget-Specific Attributes
|
||||
**************************
|
||||
|
||||
The widget types have special attributes as well. For example, a slider has:
|
||||
|
||||
- Minimum and maximum values
|
||||
- Current value
|
||||
|
||||
For these special attributes, every widget type may have unique API functions. For
|
||||
example, for a :ref:`Slider <lv_slider>`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Set slider-specific attributes */
|
||||
lv_slider_set_range(slider1, 0, 100); /* Set the min and max values */
|
||||
lv_slider_set_value(slider1, 40, LV_ANIM_ON); /* Set the current value (position) */
|
||||
|
||||
The API of the Widgets is described in their :ref:`Documentation <widgets>`, but you
|
||||
can also consult each Widget's respective header file (e.g., *widgets/lv_slider.h*) to
|
||||
find a quick reference to function prototypes with brief documentation about each.
|
||||
|
||||
|
||||
|
||||
Widget Creation
|
||||
***************
|
||||
|
||||
Widgets can be created and deleted dynamically at runtime. Only currently created
|
||||
(existing) Widgets consume RAM.
|
||||
|
||||
This allows you to create a Screen only when a button is clicked to open it, and to
|
||||
delete Screens when a new screen is loaded.
|
||||
|
||||
UIs can be created based on the current environment of the device. For example, you
|
||||
can create meters, charts, bars, and sliders based on the currently attached sensors.
|
||||
|
||||
Every widget has its own **create** function with a prototype like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_t * lv_<widget>_create(lv_obj_t * parent)
|
||||
|
||||
The create functions only have a ``parent`` parameter specifying on which widget to
|
||||
create the new widget.
|
||||
|
||||
The return value is a pointer to the created widget of type ``lv_obj_t *``.
|
||||
|
||||
|
||||
|
||||
Widget Deletion
|
||||
***************
|
||||
|
||||
There is a common **delete** function for all widget types. It deletes the widget and
|
||||
all of its children.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void lv_obj_delete(lv_obj_t * widget);
|
||||
|
||||
:cpp:func:`lv_obj_delete` deletes the widget immediately. If for any reason you can't
|
||||
delete the widget immediately, you can use :cpp:expr:`lv_obj_delete_async(widget)`
|
||||
which will perform the deletion on the next call of :cpp:func:`lv_timer_handler`. This
|
||||
is useful, for example, if you want to delete the parent of a widget in the child's
|
||||
:cpp:enumerator:`LV_EVENT_DELETE` handler. Once deleted, the RAM a Widget occupies is
|
||||
freed.
|
||||
|
||||
You can remove all the children of a widget (but not the widget itself) using
|
||||
:cpp:expr:`lv_obj_clean(widget)`.
|
||||
|
||||
You can use :cpp:expr:`lv_obj_delete_delayed(widget, 1000)` to delete a widget after
|
||||
some time. The delay is expressed in milliseconds.
|
||||
|
||||
By calling :cpp:expr:`lv_obj_null_on_delete(&widget)`, the ``lv_obj_t *`` variable of
|
||||
the widget will be set to NULL when the widget is deleted. This makes it easy to check
|
||||
whether the widget exists or not.
|
||||
|
||||
Here is an example that uses some of the functions above:
|
||||
|
||||
.. code:: c
|
||||
|
||||
static lv_obj_t * my_label; /* Static in the file so it stays valid */
|
||||
|
||||
/* Call it every 2000 ms */
|
||||
void some_timer_callback(lv_timer_t * t)
|
||||
{
|
||||
/* If the label is not created yet, create it and also delete it after 1000 ms */
|
||||
if(my_label == NULL) {
|
||||
my_label = lv_label_create(lv_screen_active());
|
||||
lv_obj_delete_delayed(my_label, 1000);
|
||||
lv_obj_null_on_delete(&my_label);
|
||||
}
|
||||
/* Move the label if it exists */
|
||||
else {
|
||||
lv_obj_set_x(my_label, lv_obj_get_x(my_label) + 1);
|
||||
}
|
||||
}
|
||||