Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c12e81f
ci: scope ST7920 compile checks to ESP32
forntoh Apr 2, 2026
7b2219b
ci: scope ST7920 compile checks to ESP32 (#406)
forntoh Apr 3, 2026
03ba999
refactor: add RTTI-free renderer extension core
forntoh Apr 3, 2026
b86a846
test: expose frame lifecycle extension in tracking renderer
forntoh Apr 3, 2026
aa872b2
fix: flush polled redraws via draw-owned frame lifecycle
forntoh Apr 23, 2026
7ed981f
test: stabilize frame lifecycle unit assertions
forntoh Apr 23, 2026
195dcdf
refactor: add RTTI-free renderer extension core (#407)
forntoh Apr 23, 2026
2b06445
feat: add graphical renderer foundation with U8g2 adapter
forntoh Apr 23, 2026
87024f9
test: align MenuScreen expectations with clamped viewport behavior
forntoh Apr 23, 2026
17267e9
refactor: slim graphical renderer and restore baseline screen flow
forntoh Apr 23, 2026
6234a28
refactor: trim graphical renderer extension surface
forntoh Apr 23, 2026
46bb13a
fix: align list glyph bitmap height with drawXbm
forntoh Apr 23, 2026
2494032
feat: add graphical renderer foundation with U8g2 adapter (#408)
forntoh Apr 23, 2026
e6dbb99
refactor: add graphical viewport context to MenuScreen
forntoh Apr 23, 2026
cea88e3
refactor: extract MenuScreen viewport preparation helper
forntoh Apr 24, 2026
4f9d9b2
refactor: add graphical viewport context to MenuScreen (#409)
forntoh Apr 24, 2026
56953c9
feat: add graphical capabilities to core items and widgets
forntoh Apr 24, 2026
21b03d0
test: fix graphical capability assertions in item tests
forntoh Apr 24, 2026
2677d2e
feat: add graphical capabilities to core items and widgets (#410)
forntoh Apr 24, 2026
9cf0214
feat: add graphical selection support for input items
forntoh Apr 24, 2026
1a1da7e
fix: align input selection clearing and preview intent
forntoh Apr 24, 2026
5c8bb40
feat: add graphical selection support for input items (#411)
forntoh Apr 25, 2026
c0768d1
feat: expose graphical value selection renderer hook (#412)
forntoh May 18, 2026
7e7828a
Refine graphical renderer parity (#414)
forntoh May 18, 2026
8f9a78f
Harden graphical scrollbar rendering (#415)
forntoh May 19, 2026
7413a59
Refine graphical effective columns (#416)
forntoh May 26, 2026
0ec0ecb
Centralize graphical frame lifecycle (#418)
forntoh May 26, 2026
91f40a1
Complete graphical renderer parity (#419)
forntoh May 26, 2026
da36936
Align input graphical selection docs (#420)
forntoh May 26, 2026
21ee38a
Fix input item first character crash (#422)
forntoh May 27, 2026
ae07c0c
Document graphical display renderer (#421)
forntoh May 27, 2026
0cc6eec
docs: remove redundant link to graphical display rendering
forntoh May 27, 2026
01b473f
fix: address graphical display review comments
forntoh May 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions .github/workflows/compile-arduino.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
- name: SSD1803A_I2C
- name: DHT sensor library
- name: Adafruit Unified Sensor
- name: U8g2

UNIVERSAL_SKETCH_PATHS: |
- examples/Basic
Expand All @@ -43,6 +44,11 @@ jobs:

SKETCHES_REPORTS_PATH: sketches-reports

# Board-scoped sketches are appended at runtime in "Prepare sketch paths"
# to avoid compiling hardware-specific examples on incompatible targets.
ESP32_ONLY_SKETCH_PATHS: |
- examples/ST7920_SPI

strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -114,6 +120,23 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Prepare sketch paths
shell: bash
run: |
{
echo "COMPILE_SKETCH_PATHS<<EOF"
echo "${{ matrix.sketch-paths }}"
echo "${{ env.UNIVERSAL_SKETCH_PATHS }}"

# ST7920_SPI is hardware-specific. Compile it only for ESP32 jobs
# and only when the example exists on the current branch.
if [[ "${{ matrix.board.type }}" == "esp32" && -d "examples/ST7920_SPI" ]]; then
echo "${{ env.ESP32_ONLY_SKETCH_PATHS }}"
fi

echo "EOF"
} >> "$GITHUB_ENV"
Comment thread
forntoh marked this conversation as resolved.

- name: Compile sketches
uses: arduino/compile-sketches@v1
with:
Expand All @@ -123,9 +146,7 @@ jobs:
libraries: |
${{ env.UNIVERSAL_LIBRARIES }}
${{ matrix.libraries }}
sketch-paths: |
${{ matrix.sketch-paths }}
${{ env.UNIVERSAL_SKETCH_PATHS }}
sketch-paths: ${{ env.COMPILE_SKETCH_PATHS }}
enable-deltas-report: true
enable-warnings-report: true

Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@
</a>
</p>

LcdMenu is an open-source Arduino library for creating menu systems. It is designed to be easy to use and flexible enough to support a wide range of use cases.
LcdMenu is an open-source Arduino library for creating menu systems on character LCDs and graphical/OLED displays. It is designed to be easy to use and flexible enough to support a wide range of use cases.

With LcdMenu, you can create a menu system for your Arduino project with minimal effort. The library provides a simple API for creating menus and handling user input. There are also a number of built-in [display interfaces](reference/api/display/index) to choose from, including LCD displays and OLED displays _(coming soon)_.
With LcdMenu, you can create a menu system for your Arduino project with minimal effort. The library provides a simple API for creating menus and handling user input. There are also a number of built-in [display interfaces](https://lcdmenu.forntoh.dev/reference/api/display/index) and renderers to choose from, including classic character LCDs and graphical displays powered by `GraphicalDisplayRenderer` and U8g2 (for example SSD1306 and ST7920 modules).

Graphical displays are first-class targets: use custom fonts and glyphs, highlighted rows and values, checkboxes and toggles, list/submenu indicators, scrollbars, and frame-buffered rendering where supported.

<p align="center">
<img src="https://i.imgur.com/nViET8b.gif" alt="Example of a menu system created with LcdMenu">
</p>

<p align="center">
<img src="docs/source/images/home-graphical-display.gif" alt="Example of a menu system created with LcdMenu on a graphical display">
</p>

## Quick Start

LcdMenu is a simple but powerful library for creating menu systems on embedded devices. It is designed to be easy to use and to work with a wide range of display interfaces and provide various helpers for handling user input like rotary encoders and buttons.
Expand Down
Binary file added docs/source/images/home-graphical-display.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 22 additions & 6 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,29 @@ It is designed to be easy to use and flexible enough to support a wide range of

With |project|, you can create a menu system for your Arduino project with minimal effort.
The library provides a simple API for creating menus and handling user input.
There are also a number of built-in :doc:`display interfaces <reference/api/display/index>` to choose from,
including LCD displays and OLED displays *(coming soon)*.
There are also built-in :doc:`display interfaces <reference/api/display/index>` for
:doc:`character LCD displays <overview/rendering/character-display>`, including 16x2-style targets,
and :doc:`graphical displays <overview/rendering/graphical-display>`, including OLED targets.

.. image:: https://i.imgur.com/nViET8b.gif
:alt: Example of a menu system created with |project|
:align: center
.. grid:: 1 1 2 2

.. grid-item::
:columns: 12 12 6 6

**Character display**

.. image:: https://i.imgur.com/nViET8b.gif
:alt: Example of a menu system created with |project| on a character display
:align: center

.. grid-item::
:columns: 12 12 6 6

**Graphical display**

.. image:: images/home-graphical-display.gif
:alt: Example of a menu system created with |project| on a graphical display
:align: center

.. grid:: 1 2 2 2

Expand Down Expand Up @@ -86,4 +103,3 @@ including LCD displays and OLED displays *(coming soon)*.
reference/api/index
reference/migration/index
reference/faq

20 changes: 15 additions & 5 deletions docs/source/overview/items/basic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,20 @@ A basic menu item can be created using the following syntax:

ITEM_BASIC("Item 1")

This is how a basic menu item is rendered on a 16x2 LCD screen:
This is how a basic menu item can be rendered:

.. image:: images/item-basic.png
:width: 400px
:alt: Basic menu item
.. tab-set::

Find more information about the basic menu item in the :cpp:class:`API reference <MenuItem>`.
.. tab-item:: 16x2 I2C character display

.. image:: images/item-basic.png
:width: 400px
:alt: Basic menu item

.. tab-item:: Graphical display

.. image:: images/graphical-item-basic.png
:width: 400px
:alt: Basic menu item on a graphical display

Find more information about the basic menu item in the :cpp:class:`API reference <MenuItem>`.
16 changes: 13 additions & 3 deletions docs/source/overview/items/command.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@ Let's take a look at an example of a toggle command menu item that toggles an LE

When the "Toggle LED" menu item is selected, the LED connected to the ``LED_PIN`` pin will be toggled on and off.

.. image:: images/item-toggle.png
:width: 400px
:alt: Toggle menu item
.. tab-set::

.. tab-item:: 16x2 I2C character display

.. image:: images/item-toggle.png
:width: 400px
:alt: Toggle menu item

.. tab-item:: Graphical display

.. image:: images/graphical-item-toggle.png
:width: 400px
:alt: Toggle menu item on a graphical display
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 14 additions & 4 deletions docs/source/overview/items/input-charset.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,20 @@ The charset input item can be created using the following syntax:
When the ``Pass`` menu item is selected, an input field will be displayed on the screen, allowing the user to enter a string value.
The input value will be restricted to the characters specified in the charset.

.. image:: images/item-charset-input.gif
:width: 400px
:alt: Example of a charset input menu item
.. tab-set::

.. tab-item:: 16x2 I2C character display

.. image:: images/item-charset-input.gif
:width: 400px
:alt: Example of a charset input menu item

.. tab-item:: Graphical display

.. image:: images/graphical-item-charset-input.gif
:width: 400px
:alt: Charset input menu item on a graphical display

You can create multiple charset input items in the same menu screen, each with its own label, default value, and charset.

For more information about the charset input item, check the :cpp:class:`API reference <ItemInputCharset>`.
For more information about the charset input item, check the :cpp:class:`API reference <ItemInputCharset>`.
16 changes: 13 additions & 3 deletions docs/source/overview/items/input.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,19 @@ You can create an input item by specifying the label and the default value:

When the ``Name`` menu item is selected, an input field will be displayed on the screen, allowing the user to enter a string value.

.. image:: images/item-input.gif
:width: 400px
:alt: Example of an input menu item
.. tab-set::

.. tab-item:: 16x2 I2C character display

.. image:: images/item-input.gif
:width: 400px
:alt: Example of an input menu item

.. tab-item:: Graphical display

.. image:: images/graphical-item-input.gif
:width: 400px
:alt: Input menu item on a graphical display

You can create multiple input items in the same menu screen, each with its own label and default value.

Expand Down
2 changes: 1 addition & 1 deletion docs/source/overview/items/item-bool.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ When using :cpp:class:`ItemBool`, consider the following best practices:
- Use meaningful labels for the toggle states (e.g., "On" and "Off") to improve user experience.
- When using :cpp:class:`ITEM_BOOL_REF`, be aware that external changes to the referenced value will be reflected in the menu display.

For more details, refer to the :doc:`../widgets/widget-bool` documentation.
For more details, refer to the :doc:`../widgets/widget-bool` documentation.
16 changes: 15 additions & 1 deletion docs/source/overview/items/item-list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ Example: Simple List

In this example, the :cpp:class:`ItemList` allows the user to select a color from the list. The selected color is printed to the serial monitor.

.. tab-set::

.. tab-item:: 16x2 I2C character display

.. image:: images/item-list.gif
:width: 400px
:alt: Example of a list menu item

.. tab-item:: Graphical display

.. image:: images/graphical-item-list.gif
:width: 400px
:alt: List menu item on a graphical display

Example: List with Reference
############################

Expand Down Expand Up @@ -66,4 +80,4 @@ When using :cpp:class:`ItemList`, consider the following best practices:
- The list values are stored in memory, so ensure that the list is not too large to avoid memory issues.
- When using :cpp:func:`ITEM_LIST_REF`, be aware that external changes to the referenced value will be reflected in the menu display.

For more details, refer to the :cpp:class:`WidgetList` documentation: :doc:`../widgets/widget-list`.
For more details, refer to the :cpp:class:`WidgetList` documentation: :doc:`../widgets/widget-list`.
24 changes: 23 additions & 1 deletion docs/source/overview/items/item-range.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,28 @@ Both functions are wrappers around the :cpp:class:`ItemWidget` class with a :cpp

In this example, the :cpp:class:`ItemRange` allows the user to select a volume level between 0% and 100% in steps of 5%. The selected value is printed to the serial monitor.

.. tab-set::

.. tab-item:: 16x2 I2C character display

.. image:: images/item-int-range.gif
:width: 400px
:alt: Example of an integer range menu item

.. image:: images/item-float-range.png
:width: 400px
:alt: Example of a float range menu item

.. tab-item:: Graphical display

.. image:: images/graphical-item-int-range.gif
:width: 400px
:alt: Integer range menu item on a graphical display

.. image:: images/graphical-item-float-range.png
:width: 400px
:alt: Float range menu item on a graphical display

Example: Range with Reference
#############################

Expand Down Expand Up @@ -60,4 +82,4 @@ When using :cpp:class:`ItemRange`, consider the following best practices:
- For performance-critical applications, use simple numeric types (int, float) rather than complex types.
- When using :cpp:func:`ITEM_RANGE_REF`, be aware that external changes to the referenced value will be reflected in the menu display.

For more details, refer to the :cpp:class:`WidgetRange` documentation: :doc:`../widgets/widget-range`.
For more details, refer to the :cpp:class:`WidgetRange` documentation: :doc:`../widgets/widget-range`.
66 changes: 53 additions & 13 deletions docs/source/overview/items/item-widget.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,19 @@ The following are examples of how to create ItemWidget widgets.
WIDGET_LIST(options, 0, "%s", 0, true),
WIDGET_BOOL(false, "Yes", "No", ",%s")),

.. image:: images/item-widget-auto.gif
:width: 400px
:alt: Example of an item widget with a list and a boolean widget
.. tab-set::

.. tab-item:: 16x2 I2C character display

.. image:: images/item-widget-auto.gif
:width: 400px
:alt: Example of an item widget with a list and a boolean widget

.. tab-item:: Graphical display

.. image:: images/graphical-item-widget-auto.gif
:width: 400px
:alt: List and boolean item widget on a graphical display

Note: The callback receives the index of the selected option (0-based), not the actual string value.

Expand All @@ -60,9 +70,19 @@ The user is able to select if the option (Buy or Sell) is carried out automatica
WIDGET_RANGE(1.0f, 0.1f, 0.1f, 100.0f, "%.1f", 0),
WIDGET_RANGE(10, 1, 0, 100, "\002%d%%", 1)),

.. image:: images/item-widget-qty.gif
:width: 400px
:alt: Example of an item widget with two range widgets
.. tab-set::

.. tab-item:: 16x2 I2C character display

.. image:: images/item-widget-qty.gif
:width: 400px
:alt: Example of an item widget with two range widgets

.. tab-item:: Graphical display

.. image:: images/graphical-item-widget-qty.gif
:width: 400px
:alt: Multiple range item widget on a graphical display

In the above example, the ItemWidget allows the user to select a quantity between 1.0 and 100.0 in steps of 0.1 and also select a tolerance between 0 and 100 in steps of 1.
The selected quantity will be displayed as **"1.0±10%"**, **"1.1±14%"**, **"1.2±17%"**, etc.
Expand All @@ -79,9 +99,19 @@ The user is able to select the quantity and tolerance for a particular trade.
WIDGET_RANGE(0, 1, 0, 59, ":%02d", 0, false),
WIDGET_LIST(days, 0, " on %s", 0, true)),

.. image:: images/item-widget-freq.gif
:width: 400px
:alt: Example of an item widget with two range widgets and a list widget
.. tab-set::

.. tab-item:: 16x2 I2C character display

.. image:: images/item-widget-freq.gif
:width: 400px
:alt: Example of an item widget with two range widgets and a list widget

.. tab-item:: Graphical display

.. image:: images/graphical-item-widget-freq.gif
:width: 400px
:alt: Range and list item widget on a graphical display

Note: The callback receives the index of the selected option (0-based), not the actual string value.

Expand All @@ -98,9 +128,19 @@ The selected frequency will be displayed as **"00:00 on Mon"**, **"00:01 on Tue"
WIDGET_RANGE(1, 1, 1, 12, "/%02d", 0, true),
WIDGET_RANGE(2021, 1, 2020, 2050, "/%04d", 0, true)),

.. image:: images/item-widget-date.gif
:width: 400px
:alt: Example of an item widget with three range widgets
.. tab-set::

.. tab-item:: 16x2 I2C character display

.. image:: images/item-widget-date.gif
:width: 400px
:alt: Example of an item widget with three range widgets

.. tab-item:: Graphical display

.. image:: images/graphical-item-widget-date.gif
:width: 400px
:alt: Date range item widget on a graphical display

In the above example, the ItemWidget allows the user to select a start date for a particular task.
The user is able to select the day, month, and year for the task.
Expand All @@ -124,4 +164,4 @@ In the above example, the ItemWidget allows the user to select a 4-digit pin.
The user is able to select each digit of the pin from the list of characters "123456789ABCDEF".
The selected pin will be displayed as **"1234"**, **"5678"**, **"9ABC"**, etc.

For more information about the widget item, check the :cpp:class:`API reference <ItemWidget>` or this :doc:`example </reference/samples/Widgets>`.
For more information about the widget item, check the :cpp:class:`API reference <ItemWidget>` or this :doc:`example </reference/samples/Widgets>`.
Loading
Loading