docs: modernize to .md/.mdx for new Fumadocs-based docs engine (#9993)
Co-authored-by: André Costa <andre_miguel_costa@hotmail.com>
@@ -1,3 +1,140 @@
|
||||
name: Build Docs
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- 'release/*'
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'src/**'
|
||||
- 'examples/**'
|
||||
- 'demos/**'
|
||||
- 'configs/ci/docs/**'
|
||||
- 'scripts/build_html_examples.sh'
|
||||
- 'scripts/find_version.sh'
|
||||
- 'lv_conf_template.h'
|
||||
- 'lv_version.h'
|
||||
- 'lvgl.h'
|
||||
|
||||
# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency
|
||||
# Ensure that only one commit will be running tests at a time on each PR
|
||||
concurrency:
|
||||
group: ${{ github.ref }}-${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
EM_VERSION: 2.0.4
|
||||
EM_CACHE_FOLDER: 'emsdk-cache'
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Emscripten cache
|
||||
id: cache-system-libraries
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{env.EM_CACHE_FOLDER}}
|
||||
key: ${{env.EM_VERSION}}-${{ runner.os }}
|
||||
|
||||
- uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: ${{env.EM_VERSION}}
|
||||
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
|
||||
- name: Build examples (with cache)
|
||||
run: |
|
||||
# Grab the current name in case the LVGL folder is not called lvgl
|
||||
# as it could be the case if this is running from a fork
|
||||
LVGL_FOLDER=$(pwd)
|
||||
# Move to the parent folder to fetch emscripten port.
|
||||
cd ..
|
||||
./lvgl/scripts/build_html_examples.sh --symlink $LVGL_FOLDER
|
||||
|
||||
- name: Install Doxygen
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends doxygen
|
||||
|
||||
# Parses the source code and generates XML files from the documentation
|
||||
- name: Generate Doxygen XML
|
||||
run: |
|
||||
cd docs
|
||||
doxygen
|
||||
|
||||
# Tool used to convert Doxygen XML to .mdx API pages
|
||||
- name: Install doxymark
|
||||
if: ${{ github.event_name == 'push' (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release/')) }}
|
||||
run: |
|
||||
npm install github:mutahharmkhan/doxymark
|
||||
|
||||
# Generate Documentation API pages
|
||||
- name: Generate API pages
|
||||
if: ${{ github.event_name == 'push' (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release/')) }}
|
||||
run: |
|
||||
npx doxymark \
|
||||
--input docs/doxygen/xml
|
||||
--output docs/api
|
||||
--index docs/api-index.json
|
||||
--preset fumadocs
|
||||
--auto-group
|
||||
--source-url https://github.com/lvgl/lvgl/tree/${{ github.sha }}/src
|
||||
rm -rf docs/doxygen
|
||||
|
||||
- name: Install Example Documentation
|
||||
run: npm i @lvgl/examples-generator
|
||||
|
||||
- name: Check Example Documentation
|
||||
run: |
|
||||
npx -p @lvgl/examples-generator lvgl-examples-check-about --src examples
|
||||
npx -p @lvgl/examples-generator lvgl-examples-check-examples --src examples
|
||||
|
||||
- name: Generate Example Documentation
|
||||
if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release/')) }}
|
||||
run: |
|
||||
npx -p @lvgl/examples-generator lvgl-examples-gen \
|
||||
--src examples \
|
||||
--out docs/examples
|
||||
|
||||
- name: Retrieve version
|
||||
id: version
|
||||
run: |
|
||||
echo "VERSION_NAME=$(scripts/find_version.sh)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Deploy to subfolder
|
||||
if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release/')) }}
|
||||
uses: JamesIves/github-pages-deploy-action@v4.8.0
|
||||
with:
|
||||
token: ${{ secrets.LVGL_BOT_TOKEN }}
|
||||
repository-name: lvgl/open-docs
|
||||
branch: gh-pages # The branch the action should deploy to.
|
||||
folder: docs # The folder the action should deploy.
|
||||
target-folder: ${{ steps.version.outputs.VERSION_NAME }} # needs to match what is inside `docs/version_list.json`
|
||||
git-config-name: lvgl-bot
|
||||
git-config-email: lvgl-bot@users.noreply.github.com
|
||||
commit: true
|
||||
|
||||
- name: Deploy to master
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: JamesIves/github-pages-deploy-action@v4.8.0
|
||||
with:
|
||||
token: ${{ secrets.LVGL_BOT_TOKEN }}
|
||||
repository-name: lvgl/open-docs
|
||||
branch: gh-pages # The branch the action should deploy to.
|
||||
folder: docs # The folder the action should deploy.
|
||||
target-folder: latest # needs to match what is inside `docs/version_list.json`
|
||||
git-config-name: lvgl-bot
|
||||
git-config-email: lvgl-bot@users.noreply.github.com
|
||||
commit: true
|
||||
name: Build docs
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
@@ -435,7 +435,7 @@ LOOKUP_CACHE_SIZE = 0
|
||||
# normally produced when WARNINGS is set to YES.
|
||||
# The default value is: NO.
|
||||
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_ALL = YES
|
||||
|
||||
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
|
||||
# be included in the documentation.
|
||||
@@ -1907,7 +1907,7 @@ MAN_LINKS = NO
|
||||
# captures the structure of the code including all documentation.
|
||||
# The default value is: NO.
|
||||
|
||||
GENERATE_XML = NO
|
||||
GENERATE_XML = YES
|
||||
|
||||
# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
|
||||
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
|
||||
@@ -2070,7 +2070,195 @@ PREDEFINED = DOXYGEN \
|
||||
LV_ATTRIBUTE_LARGE_RAM_ARRAY= \
|
||||
LV_ATTRIBUTE_FAST_MEM= \
|
||||
LV_ATTRIBUTE_EXTERN_DATA= \
|
||||
LV_FORMAT_ATTRIBUTE(fmt,va)=
|
||||
LV_FORMAT_ATTRIBUTE(fmt,va)= \
|
||||
LV_USE_3DTEXTURE=1 \
|
||||
LV_USE_ANIMIMG=1 \
|
||||
LV_USE_ARABIC_PERSIAN_CHARS=1 \
|
||||
LV_USE_ARC=1 \
|
||||
LV_USE_ARCLABEL=1 \
|
||||
LV_USE_ASSERT_MALLOC=1 \
|
||||
LV_USE_ASSERT_MEM_INTEGRITY=1 \
|
||||
LV_USE_ASSERT_NULL=1 \
|
||||
LV_USE_ASSERT_OBJ=1 \
|
||||
LV_USE_ASSERT_STYLE=1 \
|
||||
LV_USE_BAR=1 \
|
||||
LV_USE_BARCODE=1 \
|
||||
LV_USE_BIDI=1 \
|
||||
LV_USE_BMP=1 \
|
||||
LV_USE_BUILTIN_MALLOC=1 \
|
||||
LV_USE_BUILTIN_SPRINTF=1 \
|
||||
LV_USE_BUILTIN_STRING=1 \
|
||||
LV_USE_BUTTON=1 \
|
||||
LV_USE_BUTTONMATRIX=1 \
|
||||
LV_USE_CALENDAR=1 \
|
||||
LV_USE_CALENDAR_CHINESE=1 \
|
||||
LV_USE_CALENDAR_HEADER_ARROW=1 \
|
||||
LV_USE_CALENDAR_HEADER_DROPDOWN=1 \
|
||||
LV_USE_CANVAS=1 \
|
||||
LV_USE_CHART=1 \
|
||||
LV_USE_CHECKBOX=1 \
|
||||
LV_USE_COLOR_FILTER=1 \
|
||||
LV_USE_DRAW_ARM2D_SYNC=1 \
|
||||
LV_USE_DRAW_DAVE2D=1 \
|
||||
LV_USE_DRAW_DMA2D=1 \
|
||||
LV_USE_DRAW_DMA2D_INTERRUPT=1 \
|
||||
LV_USE_DRAW_EVE=1 \
|
||||
LV_USE_DRAW_NANOVG=1 \
|
||||
LV_USE_DRAW_OPENGLES=1 \
|
||||
LV_USE_DRAW_PXP=1 \
|
||||
LV_USE_DRAW_SDL=1 \
|
||||
LV_USE_DRAW_SW=1 \
|
||||
LV_USE_DRAW_SW_ASM=1 \
|
||||
LV_USE_DRAW_SW_COMPLEX_GRADIENTS=1 \
|
||||
LV_USE_DRAW_VG_LITE=1 \
|
||||
LV_USE_DROPDOWN=1 \
|
||||
LV_USE_EGL=1 \
|
||||
LV_USE_EVDEV=1 \
|
||||
LV_USE_EXT_DATA=1 \
|
||||
LV_USE_FFMPEG=1 \
|
||||
LV_USE_FILE_EXPLORER=1 \
|
||||
LV_USE_FLEX=1 \
|
||||
LV_USE_FLOAT=1 \
|
||||
LV_USE_FONT_COMPRESSED=1 \
|
||||
LV_USE_FONT_MANAGER=1 \
|
||||
LV_USE_FONT_PLACEHOLDER=1 \
|
||||
LV_USE_FRAGMENT=1 \
|
||||
LV_USE_FREERTOS_TASK_NOTIFY=1 \
|
||||
LV_USE_FREETYPE=1 \
|
||||
LV_USE_FS_ARDUINO_ESP_LITTLEFS=1 \
|
||||
LV_USE_FS_ARDUINO_SD=1 \
|
||||
LV_USE_FS_FATFS=1 \
|
||||
LV_USE_FS_FROGFS=1 \
|
||||
LV_USE_FS_LITTLEFS=1 \
|
||||
LV_USE_FS_MEMFS=1 \
|
||||
LV_USE_FS_POSIX=1 \
|
||||
LV_USE_FS_STDIO=1 \
|
||||
LV_USE_FS_UEFI=1 \
|
||||
LV_USE_FS_WIN32=1 \
|
||||
LV_USE_FT81X=1 \
|
||||
LV_USE_G2D=1 \
|
||||
LV_USE_G2D_ASSERT=1 \
|
||||
LV_USE_GENERIC_MIPI=1 \
|
||||
LV_USE_GESTURE_RECOGNITION=1 \
|
||||
LV_USE_GIF=1 \
|
||||
LV_USE_GLFW=1 \
|
||||
LV_USE_GLTF=1 \
|
||||
LV_USE_GRID=1 \
|
||||
LV_USE_GRIDNAV=1 \
|
||||
LV_USE_GSTREAMER=1 \
|
||||
LV_USE_ILI9341=1 \
|
||||
LV_USE_IMAGE=1 \
|
||||
LV_USE_IMAGEBUTTON=1 \
|
||||
LV_USE_IME_PINYIN=1 \
|
||||
LV_USE_IMGFONT=1 \
|
||||
LV_USE_KEYBOARD=1 \
|
||||
LV_USE_LABEL=1 \
|
||||
LV_USE_LAYER_DEBUG=1 \
|
||||
LV_USE_LED=1 \
|
||||
LV_USE_LIBINPUT=1 \
|
||||
LV_USE_LIBJPEG_TURBO=1 \
|
||||
LV_USE_LIBPNG=1 \
|
||||
LV_USE_LIBWEBP=1 \
|
||||
LV_USE_LINE=1 \
|
||||
LV_USE_LINUX_DRM=1 \
|
||||
LV_USE_LINUX_FBDEV=1 \
|
||||
LV_USE_LIST=1 \
|
||||
LV_USE_LODEPNG=1 \
|
||||
LV_USE_LOG=1 \
|
||||
LV_USE_LOTTIE=1 \
|
||||
LV_USE_LOVYAN_GFX=1 \
|
||||
LV_USE_LZ4=1 \
|
||||
LV_USE_LZ4_EXTERNAL=1 \
|
||||
LV_USE_LZ4_INTERNAL=1 \
|
||||
LV_USE_MATRIX=1 \
|
||||
LV_USE_MEM_MONITOR=1 \
|
||||
LV_USE_MENU=1 \
|
||||
LV_USE_MONKEY=1 \
|
||||
LV_USE_MSGBOX=1 \
|
||||
LV_USE_NANOVG=1 \
|
||||
LV_USE_NATIVE_HELIUM_ASM=1 \
|
||||
LV_USE_NEMA_GFX=1 \
|
||||
LV_USE_NEMA_LIB=1 \
|
||||
LV_USE_NEMA_VG=1 \
|
||||
LV_USE_NUTTX=1 \
|
||||
LV_USE_NUTTX_CUSTOM_INIT=1 \
|
||||
LV_USE_NUTTX_LCD=1 \
|
||||
LV_USE_NUTTX_LIBUV=1 \
|
||||
LV_USE_NUTTX_MOUSE=1 \
|
||||
LV_USE_NUTTX_TOUCHSCREEN=1 \
|
||||
LV_USE_NV3007=1 \
|
||||
LV_USE_NXP_ELCDIF=1 \
|
||||
LV_USE_OBJ_ID=1 \
|
||||
LV_USE_OBJ_ID_BUILTIN=1 \
|
||||
LV_USE_OBJ_NAME=1 \
|
||||
LV_USE_OBJ_PROPERTY=1 \
|
||||
LV_USE_OBJ_PROPERTY_NAME=1 \
|
||||
LV_USE_OBSERVER=1 \
|
||||
LV_USE_OPENGLES=1 \
|
||||
LV_USE_OPENGLES_DEBUG=1 \
|
||||
LV_USE_OS=1 \
|
||||
LV_USE_PARALLEL_DRAW_DEBUG=1 \
|
||||
LV_USE_PERF_MONITOR=1 \
|
||||
LV_USE_PPA=1 \
|
||||
LV_USE_PRIVATE_API=1 \
|
||||
LV_USE_PROFILER=1 \
|
||||
LV_USE_PROFILER_BUILTIN=1 \
|
||||
LV_USE_PROFILER_BUILTIN_POSIX=1 \
|
||||
LV_USE_PXP=1 \
|
||||
LV_USE_PXP_ASSERT=1 \
|
||||
LV_USE_QNX=1 \
|
||||
LV_USE_QRCODE=1 \
|
||||
LV_USE_REFR_DEBUG=1 \
|
||||
LV_USE_RENESAS_GLCDC=1 \
|
||||
LV_USE_RLE=1 \
|
||||
LV_USE_RLOTTIE=1 \
|
||||
LV_USE_ROLLER=1 \
|
||||
LV_USE_ROTATE_G2D=1 \
|
||||
LV_USE_ROTATE_PXP=1 \
|
||||
LV_USE_SCALE=1 \
|
||||
LV_USE_SDL=1 \
|
||||
LV_USE_SLIDER=1 \
|
||||
LV_USE_SNAPSHOT=1 \
|
||||
LV_USE_SPAN=1 \
|
||||
LV_USE_SPINBOX=1 \
|
||||
LV_USE_SPINNER=1 \
|
||||
LV_USE_ST_LTDC=1 \
|
||||
LV_USE_ST7735=1 \
|
||||
LV_USE_ST7789=1 \
|
||||
LV_USE_ST7796=1 \
|
||||
LV_USE_STDLIB_MALLOC=1 \
|
||||
LV_USE_STDLIB_SPRINTF=1 \
|
||||
LV_USE_STDLIB_STRING=1 \
|
||||
LV_USE_SVG=1 \
|
||||
LV_USE_SVG_ANIMATION=1 \
|
||||
LV_USE_SVG_DEBUG=1 \
|
||||
LV_USE_SWITCH=1 \
|
||||
LV_USE_SYSMON=1 \
|
||||
LV_USE_TABLE=1 \
|
||||
LV_USE_TABVIEW=1 \
|
||||
LV_USE_TEMPL=1 \
|
||||
LV_USE_TEST=1 \
|
||||
LV_USE_TEST_SCREENSHOT_COMPARE=1 \
|
||||
LV_USE_TEXTAREA=1 \
|
||||
LV_USE_TFT_ESPI=1 \
|
||||
LV_USE_THEME_DEFAULT=1 \
|
||||
LV_USE_THEME_MONO=1 \
|
||||
LV_USE_THEME_SIMPLE=1 \
|
||||
LV_USE_THORVG=1 \
|
||||
LV_USE_THORVG_EXTERNAL=1 \
|
||||
LV_USE_THORVG_INTERNAL=1 \
|
||||
LV_USE_TILEVIEW=1 \
|
||||
LV_USE_TINY_TTF=1 \
|
||||
LV_USE_TJPGD=1 \
|
||||
LV_USE_TRANSLATION=1 \
|
||||
LV_USE_UEFI=1 \
|
||||
LV_USE_VECTOR_GRAPHIC=1 \
|
||||
LV_USE_VG_LITE_DRIVER=1 \
|
||||
LV_USE_VG_LITE_THORVG=1 \
|
||||
LV_USE_WAYLAND=1 \
|
||||
LV_USE_WIN=1 \
|
||||
LV_USE_WINDOWS=1 \
|
||||
LV_USE_X11=1
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||
# tag can be used to specify a list of macro names that should be expanded. The
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
# 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)
|
||||
@@ -1,412 +1,49 @@
|
||||
# Documentation
|
||||
|
||||
LVGL documentation is authored in **MDX**. The rendering site that serves these pages is maintained separately by the LVGL team — contributors here author and review `.mdx` content under `./src/`.
|
||||
|
||||
## 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.
|
||||
> **Local preview Docker image — *coming soon*.** We will publish an image on GHCR (`ghcr.io/lvgl/lvgl-docs` — exact tag TBD) that bundles the docs site and serves this `./src/` content at `http://localhost:3000`.
|
||||
|
||||
|
||||
## Everything Must Be Documented
|
||||
|
||||
## 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.
|
||||
Our firm policy: ***EVERYTHING MUST BE DOCUMENTED***. Public APIs, widgets, features, and configuration options all need an MDX page or section. When in doubt, add it.
|
||||
|
||||
|
||||
## Where Content Lives
|
||||
|
||||
## reStructuredText Content
|
||||
All MDX pages live under `./src/`. The directory structure drives the URL, and sidebar ordering is controlled by `meta.json` files inside each directory.
|
||||
|
||||
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:
|
||||
A page is a `.mdx` file with YAML frontmatter:
|
||||
|
||||
| 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/) |
|
||||
```mdx
|
||||
---
|
||||
title: Animations
|
||||
description: Animate widget properties over time with the LVGL animation engine.
|
||||
---
|
||||
|
||||
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.
|
||||
# Animations
|
||||
|
||||
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).
|
||||
Animations change a property's value over a period of time...
|
||||
|
||||
|
||||
|
||||
### 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
|
||||
<LvglExample name="lv_example_anim_1" path="anim/lv_example_anim_1" />
|
||||
```
|
||||
|
||||
|
||||
Explanation:
|
||||
## Common Components
|
||||
|
||||
```rst
|
||||
.. _layouts: <=== Creates an explicit link target
|
||||
<=== Empty line -- important!
|
||||
=======
|
||||
Layouts <=== Document title, seen in documentation
|
||||
=======
|
||||
A small set of components covers most authoring needs:
|
||||
|
||||
<=== any text introducing this topic and the TOC below
|
||||
- `<Callout type="info|warn|error" title="...">` — notes, warnings, tips.
|
||||
- `<LvglExample name="..." path="..." />` — embed a runnable code example.
|
||||
- `<ApiLink name="lv_label_create" />` — inline link to an API symbol.
|
||||
- `<ApiLinkList items={["lv_label"]} />` — link out to related API pages at the end of a page.
|
||||
- `<Figure src="/_static/images/..." alt="..." caption="..." />` — images with captions.
|
||||
- `<DirectoryIndex />` — auto-generated list of child pages on index pages.
|
||||
|
||||
.. toctree:: <=== Table of contents directive
|
||||
:maxdepth: 2 <=== Internal use and needs to always be set this way
|
||||
The **full component catalog**, formatting rules, `meta.json` examples, and icon list live in [Writing Docs](./src/contributing/writing_docs.mdx). Start there for anything beyond the components above.
|
||||
|
||||
overview <=== relative path to .rst files located in the same directory
|
||||
flex
|
||||
grid
|
||||
```
|
||||
|
||||
## More on Contributing
|
||||
|
||||
|
||||
### 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.
|
||||
For coding style, DCO, pull requests, and other contribution guidelines, see the pages under [`./src/contributing/`](./src/contributing).
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 519 KiB |
|
Before Width: | Height: | Size: 312 KiB |
|
Before Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
@@ -1,50 +0,0 @@
|
||||
#!/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)
|
||||
@@ -1,123 +0,0 @@
|
||||
"""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
|
||||
@@ -1,76 +0,0 @@
|
||||
"""
|
||||
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()
|
||||
@@ -1,429 +0,0 @@
|
||||
"""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
|
||||
@@ -1,80 +0,0 @@
|
||||
@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=
|
||||
@@ -1,19 +0,0 @@
|
||||
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
|
||||
@@ -1,17 +0,0 @@
|
||||
.. _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.
|
||||
@@ -1,60 +0,0 @@
|
||||
# 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'}
|
||||
@@ -1,133 +0,0 @@
|
||||
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,
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{% 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 %}
|
||||
@@ -1,202 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 16 KiB |
@@ -1,6 +0,0 @@
|
||||
<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>
|
||||
@@ -1,4 +0,0 @@
|
||||
<div class="version-selector">
|
||||
<label for="version_dropdown">Select LVGL version</label>
|
||||
<select name="version" id="version_dropdown"></select>
|
||||
</div>
|
||||
@@ -0,0 +1,201 @@
|
||||
---
|
||||
title: File Explorer
|
||||
description: "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-v..."
|
||||
---
|
||||
|
||||
`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 [Table (lv_table)](/widgets/table) Widget for the "Browsing Area", and the
|
||||
[List (lv_list)](/widgets/list) Widget for the "Quick-Access" panel when it is enabled. Thus,
|
||||
<ApiLink name="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 <ApiLink name="LV_USE_LIST" /> must be set to a
|
||||
non-zero value to use the "Quick-Access" panel.
|
||||
|
||||
<Callout type="info">
|
||||
In order to use File Explorer, [File System (lv_fs_drv)](/main-modules/fs) has to be set up and
|
||||
know about all the drive letters you use when passing paths to File System
|
||||
(described below).
|
||||
</Callout>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
If you haven't already done so, you will need to learn about the LVGL [File
|
||||
System abstraction](/main-modules/fs), since it must be set up and be functional
|
||||
for File Explorer to work.
|
||||
|
||||
## Usage
|
||||
|
||||
Set <ApiLink name="LV_USE_FILE_EXPLORER" /> to a non-zero value in `lv_conf.h`.
|
||||
|
||||
First use <ApiLink name="lv_file_explorer_create" display="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 <ApiLink name="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 <ApiLink name="LV_EXPLORER_SORT_NONE" />)
|
||||
|
||||
### Accessing the Parts
|
||||
|
||||
This list of functions provides access to the parts shown in diagram above:
|
||||
|
||||
- <ApiLink name="lv_file_explorer_get_selected_file_name" display="lv_file_explorer_get_selected_file_name(explorer)" /> (pointer
|
||||
to NUL-terminated string containing file-path user selected; typically used inside
|
||||
an <ApiLink name="LV_EVENT_CLICKED" /> event)
|
||||
- <ApiLink name="lv_file_explorer_get_current_path" display="lv_file_explorer_get_current_path(explorer)" /> (pointer to `current_path` `char` buffer)
|
||||
- <ApiLink name="lv_file_explorer_get_file_table" display="lv_file_explorer_get_file_table(explorer)" /> (pointer to `File Table` [Table (lv_table)](/widgets/table) Widget)
|
||||
- <ApiLink name="lv_file_explorer_get_header" display="lv_file_explorer_get_header(explorer)" /> (pointer to `Header` [base widget](/widgets/base_widget) Widget)
|
||||
- <ApiLink name="lv_file_explorer_get_path_label" display="lv_file_explorer_get_path_label(explorer)" /> (pointer to `Current Path Label` [Label (lv_label)](/widgets/label) Widget)
|
||||
- <ApiLink name="lv_file_explorer_get_quick_access_area" display="lv_file_explorer_get_quick_access_area(explorer)" /> (pointer to `Quick-Access Panel` [base widget](/widgets/base_widget))
|
||||
- <ApiLink name="lv_file_explorer_get_places_list" display="lv_file_explorer_get_places_list(explorer)" /> (pointer to `Places List` [List (lv_list)](/widgets/list) Widget)
|
||||
- <ApiLink name="lv_file_explorer_get_device_list" display="lv_file_explorer_get_device_list(explorer)" /> (pointer to `Device List` [List (lv_list)](/widgets/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 <ApiLink name="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
|
||||
<ApiLink name="lv_file_explorer_set_quick_access_path" display="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:
|
||||
|
||||
- <ApiLink name="LV_EXPLORER_HOME_DIR" />
|
||||
- <ApiLink name="LV_EXPLORER_MUSIC_DIR" />
|
||||
- <ApiLink name="LV_EXPLORER_PICTURES_DIR" />
|
||||
- <ApiLink name="LV_EXPLORER_VIDEO_DIR" />
|
||||
- <ApiLink name="LV_EXPLORER_DOCS_DIR" />
|
||||
- <ApiLink name="LV_EXPLORER_FS_DIR" />
|
||||
|
||||
### Sort
|
||||
|
||||
You can use
|
||||
<ApiLink name="lv_file_explorer_set_sort" display="lv_file_explorer_set_sort(explorer, LV_EXPLORER_SORT_XX)" /> to set
|
||||
the sorting method.
|
||||
|
||||
These are the possible sorting methods:
|
||||
|
||||
- <ApiLink name="LV_EXPLORER_SORT_NONE" /> (default)
|
||||
- <ApiLink name="LV_EXPLORER_SORT_KIND" />
|
||||
|
||||
<ApiLink name="lv_file_explorer_get_sort" display="lv_file_explorer_get_sort(explorer)" /> returns the current sorting method.
|
||||
|
||||
## Events
|
||||
|
||||
- <ApiLink name="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.
|
||||
- <ApiLink name="LV_EVENT_VALUE_CHANGED" /> Sent once when any item (file) in the
|
||||
`Browser Panel`'s file list is clicked.
|
||||
- <ApiLink name="LV_EVENT_CLICKED" /> Sent twice when an item in the `Browser Panel`
|
||||
is clicked: once as a result of the input-device <ApiLink name="LV_EVENT_RELEASED" />
|
||||
event and a second as a result of the input device <ApiLink name="LV_EVENT_CLICKED" />
|
||||
event. This applies to files, directories, and the "< Back" item in the `Browser Panel`.
|
||||
|
||||
In these events you can use <ApiLink name="lv_file_explorer_get_current_path" /> to get the
|
||||
current path and <ApiLink name="lv_file_explorer_get_selected_file_name" /> to get the name
|
||||
of the currently selected file in the event processing function. For example:
|
||||
|
||||
```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 <ApiLink name="strcpy" /> and <ApiLink name="strcat" /> for later use.
|
||||
|
||||
## Examples
|
||||
|
||||
### Simple File Explorer
|
||||
|
||||
<LvglExample name="lv_example_file_explorer_1" path="others/file_explorer/lv_example_file_explorer_1" />
|
||||
|
||||
### Control File Explorer
|
||||
|
||||
<LvglExample name="lv_example_file_explorer_2" path="others/file_explorer/lv_example_file_explorer_2" />
|
||||
|
||||
### Custom sort
|
||||
|
||||
<LvglExample name="lv_example_file_explorer_3" path="others/file_explorer/lv_example_file_explorer_3" />
|
||||
|
||||
## API
|
||||
@@ -1,226 +0,0 @@
|
||||
.. _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,83 @@
|
||||
---
|
||||
title: Fragment
|
||||
description: Fragment is a concept copied from Android.
|
||||
---
|
||||
|
||||
<Callout type="warn">
|
||||
This module is now deprecated and will be removed in an upcoming release.
|
||||
</Callout>
|
||||
|
||||
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.
|
||||
|
||||
## Usage
|
||||
|
||||
Enable <ApiLink name="LV_USE_FRAGMENT" /> in `lv_conf.h`.
|
||||
|
||||
### Create Fragment Class
|
||||
|
||||
```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`
|
||||
|
||||
```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
|
||||
|
||||
```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);
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic fragment usage
|
||||
|
||||
<LvglExample name="lv_example_fragment_1" path="others/fragment/lv_example_fragment_1" />
|
||||
|
||||
### Stack navigation example
|
||||
|
||||
<LvglExample name="lv_example_fragment_2" path="others/fragment/lv_example_fragment_2" />
|
||||
|
||||
## API
|
||||
@@ -1,96 +0,0 @@
|
||||
.. _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,5 @@
|
||||
---
|
||||
title: Auxiliary Modules
|
||||
---
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
.. _auxiliary_modules:
|
||||
|
||||
=================
|
||||
Auxiliary Modules
|
||||
=================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
file_explorer
|
||||
fragment
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "Auxiliary Modules",
|
||||
"pages": [
|
||||
"file_explorer",
|
||||
"fragment"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
---
|
||||
title: API Conventions
|
||||
description: "In most cases, the API functions of LVGL widgets are structured like:"
|
||||
---
|
||||
|
||||
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:
|
||||
|
||||
```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 [Position and Size](/common-widget-features/coordinates).
|
||||
|
||||
## 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 [Slider](/widgets/slider):
|
||||
|
||||
```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 [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:
|
||||
|
||||
```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.
|
||||
|
||||
```c
|
||||
void lv_obj_delete(lv_obj_t * widget);
|
||||
```
|
||||
|
||||
<ApiLink name="lv_obj_delete" /> deletes the widget immediately. If for any reason you can't
|
||||
delete the widget immediately, you can use <ApiLink name="lv_obj_delete_async" display="lv_obj_delete_async(widget)" />
|
||||
which will perform the deletion on the next call of <ApiLink name="lv_timer_handler" />. This
|
||||
is useful, for example, if you want to delete the parent of a widget in the child's
|
||||
<ApiLink name="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
|
||||
<ApiLink name="lv_obj_clean" display="lv_obj_clean(widget)" />.
|
||||
|
||||
You can use <ApiLink name="lv_obj_delete_delayed" display="lv_obj_delete_delayed(widget, 1000)" /> to delete a widget after
|
||||
some time. The delay is expressed in milliseconds.
|
||||
|
||||
By calling <ApiLink name="lv_obj_null_on_delete" display="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:
|
||||
|
||||
```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);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,134 +0,0 @@
|
||||
================
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
title: Overview
|
||||
description: A Widget is the basic building block of the LVGL user interface.
|
||||
---
|
||||
|
||||
A Widget is the **basic building block** of the LVGL user interface.
|
||||
|
||||
Examples of Widgets: [Base Widget (and Screen)](/widgets/base_widget),
|
||||
[Button](/widgets/button), [Label](/widgets/label),
|
||||
[Image](/widgets/image), [List](/widgets/list),
|
||||
[Chart](/widgets/chart), and [Text Area](/widgets/textarea).
|
||||
|
||||
See [All Widgets](/widgets) to view all widget types.
|
||||
|
||||
The following pages will introduce features that are common to all widgets.
|
||||
For example, any widget's size and position can be changed. They can have
|
||||
styles, events, layouts, and many other features.
|
||||