Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/The-Young-Maker/OpenMenuOS/llms.txt

Use this file to discover all available pages before exploring further.

This guide walks through the OpenMenuOS_Simple example sketch step by step. By the end you will have a working menu with settings, sub-screens, and popup dialogs running on your ESP32 or ESP8266.
1

Wire the hardware

OpenMenuOS relies on TFT_eSPI for display communication — pin assignments for SPI, DC, CS, and RST are set in TFT_eSPI’s User_Setup.h, not in your sketch.For input, you need to know which GPIO pins your buttons or encoder are connected to. The example below uses a rotary encoder:
SignalGPIO (example)
Encoder CLK5
Encoder DT2
Encoder button (SELECT)19
Pass -1 for any button pin you don’t have connected.
If you’re using buttons instead of an encoder, pass all three pins directly to the OpenMenuOS constructor: OpenMenuOS menu(BTN_UP, BTN_DOWN, BTN_SELECT). With an encoder, construct the object without arguments and call setEncoderPin() and setSelectPin() in setup().
2

Include the library and declare objects

At the top of your sketch, include the library and create one instance of OpenMenuOS plus one screen object for each screen you need.
#include "OpenMenuOS.h"

// Menu system instance (button pins configured later via setters)
OpenMenuOS menu;

// Screens
MenuScreen mainMenu("Main Menu");
MenuScreen testScreen("Test Menu");
CustomScreen customScreen("Custom Screen");
SettingsScreen settingsScreen("Settings");
SettingsScreen speakerSettingsScreen("Advanced Settings");
MenuScreen, SettingsScreen, and CustomScreen all accept an optional title string. The title appears at the top of the screen when the menu is rendered.
3

Configure screens in setup()

Build the menu hierarchy, configure appearance, and call menu.begin() to initialize the display.
void setup() {
  Serial.begin(921600);

  // Custom screen: assign a draw lambda
  customScreen.customDraw = []() {
    canvas.drawSmoothRoundRect(-15, 50, 40, 0, 50, 50, TFT_BLUE, TFT_BLACK);
    canvas.setTextColor(TFT_WHITE, TFT_BLACK);
    canvas.drawString("Press UP for popup demo", 10, 30);
  };

  // Add items to the main menu
  mainMenu.addItem("Settings", &settingsScreen, nullptr, (const uint16_t *)Menu_icon_1);
  mainMenu.addItem(&testScreen);                              // auto-uses testScreen title
  mainMenu.addItem("Redirect", nullptr, redirectToCustomScreen);
  mainMenu.addItem("Info Popup", nullptr, showInfoPopup);
  mainMenu.addItem("Question Popup", nullptr, showQuestionPopup);

  // Configure test sub-menu
  testScreen.addItem("First Test Page");
  testScreen.addItem("Second Test Page");
  testScreen.addItem(&customScreen);

  // Appearance
  menu.useStylePreset("Rabbit_R1");  // "Default" or "Rabbit_R1"
  menu.setScrollbar(true);
  menu.setScrollbarStyle(1);         // 0 = default, 1 = modern
  menu.setButtonsMode("low");        // "low" or "high" depending on button wiring

  // Encoder input
  menu.setEncoderPin(5, 2);         // CLK, DT
  menu.setSelectPin(19);

  menu.setDisplayRotation(0);

  // Start the menu system
  menu.begin(&mainMenu);
}
menu.begin() initializes TFT_eSPI, draws the boot screen if configured, and renders the main menu for the first time.
4

Drive the loop

Your loop() function must call PopupManager::update() every iteration, then menu.loop(). PopupManager::update() returns the result of any active popup interaction.
void loop() {
  // Process popup input first — returns NONE while no popup is active
  PopupResult popupResult = PopupManager::update();

  // Run menu logic
  menu.loop();

  // React to popup results
  if (popupResult != PopupResult::NONE) {
    switch (popupResult) {
      case PopupResult::OK:
        Serial.println("User clicked OK/Yes");
        break;
      case PopupResult::CANCEL:
        Serial.println("User clicked Cancel/No");
        break;
      default:
        break;
    }
  }

  // Read settings values and apply them at runtime
  menu.setAnimation(settingsScreen.getSettingValue("Animations"));
  menu.setOptimizeDisplayUpdates(settingsScreen.getSettingValue("Optimize Display Updates"));
}
Do not call menu.loop() inside a blocking while or delay(). Any blocking code in loop() prevents popup input from being processed and makes the UI unresponsive.
5

Add settings

SettingsScreen supports four setting types. Add them in setup() before calling menu.begin().
// Boolean toggle (animated switch)
settingsScreen.addBooleanSetting("Animations", true);

// Numeric range with a unit label
settingsScreen.addRangeSetting("Brightness", 0, 100, 75, "%");

// Option list
const char *styleOptions[] = {"Default", "Modern"};
settingsScreen.addOptionSetting("Style", styleOptions, 2, 1);

// Link to another settings screen
speakerSettingsScreen.addRangeSetting("Speaker Power", 1, 30, 5, "dB");
speakerSettingsScreen.addBooleanSetting("Sound", false);
settingsScreen.addSubscreenSetting("Speaker", &speakerSettingsScreen);
Read a setting’s current value by name anywhere in your sketch:
uint8_t brightness = settingsScreen.getSettingValue("Brightness");
Values are automatically persisted to Preferences (ESP32) or EEPROM (ESP8266) when the user changes them.
6

Show a popup from a callback

Attach an ActionCallback function to any menu item. When the user selects that item, the library calls your function. Trigger any popup type from inside the callback.
void showInfoPopup() {
  PopupManager::showInfo("This is an information message!", "Info Demo");
}

void showQuestionPopup() {
  // Result is handled asynchronously via PopupManager::update() in loop()
  PopupManager::showQuestion(
    "Are you sure you want to delete all data?",
    "Confirm Delete"
  );
}

void showCustomPopup() {
  PopupConfig config;
  config.title = "Custom Popup";
  config.message = "This popup will close automatically after 5 seconds.";
  config.type = PopupType::INFO;
  config.autoClose = true;
  config.autoCloseDelay = 5000;
  config.customColor = 0x07E0;  // Green header (RGB565)
  PopupManager::show(config);
}
Then wire the callbacks to menu items:
mainMenu.addItem("Info Popup",     nullptr, showInfoPopup);
mainMenu.addItem("Question Popup", nullptr, showQuestionPopup);
mainMenu.addItem("Custom Popup",   nullptr, showCustomPopup);
The five available popup types and their default behaviors:
FunctionTypeAuto-close
PopupManager::showInfo()Info (blue)No
PopupManager::showSuccess()Success (green)Yes, 3 s
PopupManager::showWarning()Warning (orange)No
PopupManager::showError()Error (red)No
PopupManager::showQuestion()Question (cyan)No — returns OK or CANCEL
  • Introduction — full feature list and hardware requirements
  • Installation — Library Manager and ZIP install instructions

Build docs developers (and LLMs) love