Skip to content

CardputerZero/template

Repository files navigation

CardputerZero Template Project

A simple starter template for building embedded Linux GUI applications with LVGL and CMake. It is intended to be used as a clean development baseline: desktop builds use SDL for fast UI preview, while device builds use the Linux/LVGL platform drivers.

Project Overview

In this example project, we used small MVVM-style structure around LVGL:

  • UI layer: screens and widgets are implemented with LVGL objects. BaseScreen owns the page root, title bar, nav bar, and page content. Widgets derive from BaseWidgets and expose a build() entry point.
  • Data model: BaseModel stores application state such as current page and theme mode.
  • View model: BaseViewModel exposes model state as LVGL observer subjects and provides UI actions such as page switching, counter updates, theme toggle, and quit request.
  • Reactive/data binding: src/reactive wraps LVGL observer subjects and common bindings so labels, styles, flags, widget values, and events can be connected to application state.
  • Data flow: user input triggers widget callbacks, callbacks update BaseViewModel, view model publishes subjects, and bound UI objects refresh automatically through LVGL observers.
  • Platform layer: platform code owns Linux input integration and other hardware-facing services. The nav bar maps hardware/keyboard keys 4 to 8, plus ESC for quit.

Current demo UI:

  • Page 1: Hello World, font weight toggle, LVGL version info, light/dark theme toggle, page navigation.
  • Page 2: Counter page, increment/decrement actions with a non-negative lower bound, light/dark theme toggle, page navigation.

Repository Layout

.
├── assets/                 # Runtime assets used by the app
│   ├── applications/       # Desktop/app launcher metadata
│   ├── audio/              # Audio resources
│   ├── fonts/              # TTF fonts loaded through FreeType
│   └── images/             # Image resources
├── screenshot/             # Simulator screenshots for supported desktop platforms
├── src/
│   ├── app/                # Application lifecycle, asset loading, screen management
│   ├── config/             # LVGL config headers for desktop and device builds
│   ├── logger/             # Project logging wrapper
│   ├── model/              # Base application data model
│   ├── platform/           # Platform input/hardware integration
│   ├── reactive/           # LVGL observer subjects and binding helpers
│   ├── view/               # Theme, UI constants, screens, and widgets
│   │   ├── screens/        # Page-level LVGL screens
│   │   └── widgets/        # Reusable LVGL widgets such as nav bar and icon button
│   ├── viewmodel/          # BaseViewModel and UI-facing actions/state subjects
│   └── main.cpp            # Program entry point
├── CMakeLists.txt          # Build graph, dependencies, options, targets
├── CMakePresets.json       # Desktop/device configure and build presets
└── README.md

Modules

  • src/app/asset_manager.*: resolves runtime assets from the optional CMake asset root, source tree assets/, and installed /usr/share/<APP_NAME>/ path.
  • src/app/screen_namager.cpp: switches LVGL screens when the current page subject changes.
  • src/config/lv_conf_desktop.h: desktop SDL simulator LVGL settings.
  • src/config/lv_conf_cm0.h: embedded Linux/CardputerZero LVGL settings.
  • src/platform/linux_input.*: Linux evdev keypad support and desktop SDL keyboard routing for nav buttons.
  • src/reactive/subjects.*: typed wrappers around LVGL subjects.
  • src/reactive/bindings.*: helper bindings for labels, theme, widget values, flags, states, and events.
  • src/view/widgets/navbar.*: bottom navigation bar and icon-button action mapping.
  • src/view/widgets/icon_button.*: transparent icon button with font/color/theme support.

Build Options

Common CMake cache options:

Option Default Description
USE_DESKTOP ON Build SDL desktop simulator when ON; build embedded Linux target when OFF.
APP_NAME template_app Application name used by installed asset lookup.
APP_ASSETS_ROOT empty Optional runtime asset root. Expected layout includes fonts/, images/, etc.
APP_KEY_INPUT_DEVICE empty Optional Linux evdev device path, e.g. /dev/input/event0. Empty means auto-scan /dev/input/event*.
APP_FRAMEBUFFER_DEVICE /dev/fb0 Linux framebuffer device used by embedded builds when APP_USE_DRM=OFF.
APP_USE_DRM OFF Use LVGL's Linux DRM/KMS backend instead of fbdev for embedded builds.
APP_DRM_DEVICE /dev/dri/card0 DRM device path used when APP_USE_DRM=ON.
APP_DRM_CONNECTOR_ID -1 DRM connector id used when APP_USE_DRM=ON; -1 auto-selects.

Asset lookup order:

  1. APP_ASSETS_ROOT when provided by CMake
  2. source-tree assets/ for development
  3. /usr/share/<APP_NAME>/ for installed deployments

Desktop Builds

Desktop builds are intended for fast UI development and use SDL as the LVGL display/input backend.

Simulator Preview

macOS simulator Debian simulator Windows simulator
macOS simulator screenshot Debian simulator screenshot Windows simulator screenshot

Current dependencies info:

Dependency Version Source Notes
LVGL v9.5.0 CMakeLists.txt FetchContent Main GUI framework.
fmt 12.1.0 System package manager or vcpkg.json override Logging and formatted strings.
libpng 1.6.48 System package manager or vcpkg.json override PNG image decoding support for LVGL.
libjpeg-turbo 3.1.3 System package manager or vcpkg.json override JPEG image decoding support for LVGL.
zlib 1.3.1 System package manager or vcpkg.json override Compression dependency used by image libraries.
SDL2 2.32.54 System package manager or vcpkg.json override Desktop simulator display and input backend.
FreeType 2.13.3 System package manager or vcpkg.json override Runtime TTF font rendering.

Windows vcpkg installs use the versions above through manifest mode, with the registry baseline pinned in vcpkg-configuration.json.

Linux Desktop

Debian/Ubuntu dependencies:

sudo apt update
sudo apt install -y \
  build-essential \
  cmake \
  ninja-build \
  libpng-dev \
  libjpeg-dev \
  libfmt-dev \
  libsdl2-dev \
  libfreetype-dev \
  zlib1g-dev

Note

Minimal CMake version is 3.31.0 (in coordinate with Debian 13 trixie), for Ubuntu user you can install latest cmake via snap and run following cmake command with /snap/bin/cmake.

Configure:

cmake --preset linux-x86-64

Build:

cmake --build --preset linux-x86-64-dbg
# alternatively, you can run release build
# cmake --build --preset linux-x86-64-rel

Run:

./build/linux-x86-64/Debug/template_app
# or launch release build
# ./build/linux-x86-64/Release/template_app

macOS Desktop

Install the Apple command-line tools:

xcode-select --install

Install dependencies with Homebrew:

brew install \
  cmake \
  ninja \
  libpng \
  jpeg \
  fmt \
  sdl2 \
  freetype \
  dpkg \
  zlib

Configure for Apple Silicon:

cmake --preset darwin-arm64

Build:

cmake --build --preset darwin-arm64-dbg
# alternatively, you can run release build
# cmake --build --preset darwin-arm64-rel

Run:

./build/darwin-arm64/Debug/template_app
# or launch release build
# ./build/darwin-arm64/Release/template_app

For Intel macOS, use the darwin-x86-64 configure preset and matching build preset:

cmake --preset darwin-x86-64
cmake --build --preset darwin-x86-64-dbg
# alternatively, you can run release build
# cmake --build --preset darwin-x86-64-rel
./build/darwin-x86-64/Debug/template_app
# or launch release build
# ./build/darwin-x86-64/Release/template_app

Windows Desktop

Install CMake and Ninja:

winget install Kitware.CMake
winget install Ninja-build.Ninja

Install a C++ toolchain. Choose one of the following.

MSVC Build Tools:

winget install Microsoft.VisualStudio.BuildTools

In the Visual Studio installer, enable Desktop development with C++ and make sure MSVC and a Windows SDK are selected.

MinGW-w64:

winget install BrechtSanders.WinLibs.POSIX.UCRT

Alternatively, you can download from winlibs.

Install vcpkg:

git clone https://github.com/microsoft/vcpkg.git C:\vcpkg
C:\vcpkg\bootstrap-vcpkg.bat -disableMetrics

Configure environmental variables for current terminal:

$env:VCPKG_ROOT="C:\vcpkg"
$env:PATH="$env:VCPKG_ROOT;$env:PATH"

Tip

Change VCPKG_ROOT to your vcpkg installation directory if it is located elsewhere.

These environment variables are session-scoped, meaning they only apply to the current terminal session. Once the terminal is closed, the variables will be lost and need to be set again in a new session. If you want to a persist environment variable

setx VCPKG_ROOT "C:\vcpkg"

Configure and build with MSVC:

Important

These steps require launching CMake from a Developer Command Prompt or Developer PowerShell provided by Visual Studio.

This ensures that the MSVC environment (compiler, linker, and Windows SDK paths) is properly initialized.

Without this environment setup, CMake may fail to detect or correctly configure the MSVC toolchain.

cmake --preset win32-msvc
cmake --build --preset win32-msvc-dbg
.\build\msvc\Debug\template_app.exe

# alternatively for release build
# cmake --build --preset win32-msvc-rel
# .\build\msvc\Release\template_app.exe

Configure and build with MinGW-w64:

Important

These steps require a properly configured MinGW-w64 toolchain in your system PATH.

Please ensure the following compilers are available in the current terminal session:

  • gcc
  • g++
  • ld
  • ar

You can verify the setup by running:

gcc --version
g++ --version

If these commands are not recognized, you must add MinGW-w64 bin directory to your PATH before configuring CMake.

cmake --preset win32-mingw64
cmake --build --preset win32-mingw64-dbg
.\build\mingw64\Debug\template_app.exe

# alternatively for release build
# cmake --build --preset win32-mingw64-rel
#.\build\mingw64\Release\template_app.exe

Note

VCPKG will handle the dependencies during CMake configuration process automatically, this may take several minutes depend on you network connection.

CardputerZero Cross Build

This preset builds an aarch64 Linux target from a host machine with an aarch64-linux-gnu-gcc/g++ toolchain. The BSP at .cache/sdk_bsp-src is treated as a sysroot: headers, libraries, startup objects, and pkg-config metadata are resolved from that directory first. If that directory does not exist on the first configure, the toolchain downloads and extracts sdk_bsp.tar.gz automatically before CMake runs compiler checks.

Install a cross compile toolchain:

  • Debian
sudo apt install crossbuild-essential-arm64
  • MacOS
brew install aarch64-unknown-linux-gnu

Note

On Windows, it's recommended to use WSL for cross build or you can download cross compile tools and configure the PATH yourself

Configure:

cmake --preset cp0-cross

Build:

cmake --build --preset cp0-cross-dbg
# or release build
# cmake --build --preset cp0-cross-rel

If your BSP sysroot is in another location, pass it explicitly:

cmake --preset cp0-cross -DCM0_SDK_ROOT=/path/to/sdk_bsp-src

To force an offline configure and fail when the BSP is missing, use:

cmake --preset cp0-cross -DCM0_ALLOW_FETCH_DEPS=OFF

Development Guide

Navigation Keys

The bottom nav bar maps hardware/keyboard keys from left to right:

Key Nav item
4 First icon button
5 Second icon button
6 Third icon button
7 Fourth icon button
8 Fifth icon button
ESC First icon button / quit

Adding a Screen

  1. Add a new page enum value in src/model/base_model.h.
  2. Add the page transition/state logic in BaseModel and BaseViewModel.
  3. Create a screen under src/view/screens/ deriving from BaseScreen.
  4. Extend ScreenManager to load the new screen when the page subject changes.
  5. Update NavBar icons and callbacks as needed.

Adding a Widget

  1. Derive from BaseWidgets.
  2. Implement build() and create LVGL objects under parent_.
  3. Use reactive::bind_* helpers for text, style, state, or event bindings.
  4. Keep LVGL observer lifetimes object-bound whenever possible with lv_subject_add_observer_obj or reactive::observe_obj.

Fonts and Assets

Fonts are loaded at runtime through FreeType. Place development fonts in:

assets/fonts/

Installed deployments can place fonts in:

/usr/share/<APP_NAME>/fonts/

You can also provide an asset root at configure time:

cmake --preset darwin-arm64 -DAPP_ASSETS_ROOT=/path/to/assets

Debian Package

Debian packages are produced with CPack and written to dist/. The package file name follows:

<AppName>_<Version>_m5stack1_arm64.deb

Default example:

dist/TemplateApp_0.0.1_m5stack1_arm64.deb

Package layout:

Path Content
/usr/bin/template_app Application executable.
/usr/share/template_app/ Runtime assets: fonts, images, audio.
/usr/share/APPLaunch/applications/template_app.desktop APPLaunch launcher entry.
/usr/share/APPLaunch/share/images/template*.png APPLaunch launcher icons/fallbacks.
/usr/lib/systemd/system/template_app.service Optional systemd service for embedded autostart.
/usr/share/doc/template_app/ README and third-party asset license notes.

Build and package:

cmake --preset cp0-cross
cmake --build --preset cp0-cross-rel
cpack --preset cp0-cross-deb

Or run the full configure, release build, and package flow with one workflow preset:

cmake --workflow --preset cp0-cross-package

Note

Use Debian based Linux host with CPack generator as other OS may not resolve the dependencies correctly no full dpkg, dpkg-shlibdeps, objdump and readelf support

Contributing

If you have better framework designs on Embedded Linux or build system practice, feel free to let us know.

License

Project released under MIT license. More license information can be found in assets folder.

About

The template project for CardputerZero

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors