### Get Started with LiquidMenu Source: https://github.com/vasilkalchev/liquidmenu/blob/master/doc/Doxygen/mainpage.dox Demonstrates how to create a menu with two screens and dynamically changing information. This is a good starting point for new users. ```cpp #include // Define the LCD dimensions and pins const int LCD_WIDTH = 16; const int LCD_HEIGHT = 2; LiquidCrystal lcd(8, 9, 10, 11, 12, 13, 14); // Create a menu object Menu menu(lcd); // Create screens Screen screen1(menu); Screen screen2(menu); // Create lines for screen 1 LiquidLine line1_1("Hello", 0, 0); LiquidLine line1_2(screen2, "Next", 1, 0); // Create lines for screen 2 LiquidLine line2_1(screen1, "Back", 0, 0); LiquidLine line2_2("World!", 1, 0); void setup() { lcd.begin(LCD_WIDTH, LCD_HEIGHT); // Add lines to screens screen1.add_line(line1_1); screen1.add_line(line1_2); screen2.add_line(line2_1); screen2.add_line(line2_2); // Set the menu to start on screen 1 menu.set_screen(screen1); } void loop() { menu.update(); } ``` -------------------------------- ### Basic LiquidMenu Setup Example Source: https://github.com/vasilkalchev/liquidmenu/blob/master/README.md Demonstrates the basic setup of the LiquidMenu library, including initializing the LCD, creating lines and screens, and updating the menu in the loop. ```c++ // ... // First we need to instantiate the LiquidCrystal object. LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7); // a variable that will be updated periodically somewhere in our code float temperature = 0.0f; // ----- WELCOME SCREEN ----- // a line of one string literal LiquidLine lineHello(2, 0, "Hello world!"); LiquidLine lineRight(7, 1, ">"); // create a screen from the above lines LiquidScreen screenMain(lineHello, lineRight); // -------------------------- // ----- STATUS SCREEN ----- // a line of two string literals and a float variable LiquidLine lineTemp(0, 0, "Temp: ", temperature, "C"); LiquidScreen screenStatus(lineTemp); // ------------------------- // ----- MENU ----- // create a menu from the screens LiquidMenu menu(lcd, screenMain, screenStatus); // ---------------- void setup() { lcd.begin(16, 2); // ... } void loop() { temperature = readTemperature(); menu.update(); // update the display to show the new information if (rightButton()) { menu.next_screen(); } if (leftButton()) { menu.previous_screen(); } // ... } ``` -------------------------------- ### Building a Menu System Source: https://github.com/vasilkalchev/liquidmenu/blob/master/doc/Doxygen/mainpage.dox Demonstrates how to construct a hierarchical menu system. This example shows how to link multiple screens to create a navigation structure. ```cpp #include // Define the LCD dimensions and pins const int LCD_WIDTH = 16; const int LCD_HEIGHT = 2; LiquidCrystal lcd(8, 9, 10, 11, 12, 13, 14); // Create a menu object Menu menu(lcd); // Create screens Screen mainMenu(menu); Screen settingsMenu(menu); Screen aboutMenu(menu); // Main Menu Lines LiquidLine mainMenu_1("Settings", 0, 0); LiquidLine mainMenu_2("About", 1, 0); // Settings Menu Lines LiquidLine settingsMenu_1(mainMenu, "Back", 0, 0); LiquidLine settingsMenu_2("Option 1", 1, 0); // About Menu Lines LiquidLine aboutMenu_1(mainMenu, "Back", 0, 0); LiquidLine aboutMenu_2("Version 1.0", 1, 0); void setup() { lcd.begin(LCD_WIDTH, LCD_HEIGHT); // Add lines to Main Menu mainMenu.add_line(mainMenu_1); mainMenu.add_line(mainMenu_2); // Add lines to Settings Menu settingsMenu.add_line(settingsMenu_1); settingsMenu.add_line(settingsMenu_2); // Add lines to About Menu aboutMenu.add_line(aboutMenu_1); aboutMenu.add_line(aboutMenu_2); // Link screens mainMenu_1.set_next_screen(settingsMenu); mainMenu_2.set_next_screen(aboutMenu); // Set the menu to start on the main menu menu.set_screen(mainMenu); } void loop() { menu.update(); } ``` -------------------------------- ### Initialize LiquidMenu with I2C Displays Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Call `menu.init()` in `setup()` after initializing the I2C display object. Requires setting `LIQUIDMENU_LIBRARY` and `DisplayClass` in `LiquidMenu_config.h`. ```cpp // LiquidMenu_config.h changes needed: // #define LIQUIDMENU_LIBRARY LiquidCrystal_I2C_LIBRARY // #define DisplayClass LiquidCrystal_I2C #include #include #include LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27 unsigned short sensor = 0; LiquidLine sensorLine(0, 0, "Sensor: ", sensor); LiquidScreen screen(sensorLine); LiquidMenu menu(lcd); void setup() { lcd.init(); lcd.backlight(); menu.init(); // required for I2C menu.add_screen(screen); menu.update(); } void loop() { sensor = analogRead(A1); menu.update(); delay(500); } ``` -------------------------------- ### I2C Configuration for Menu Source: https://github.com/vasilkalchev/liquidmenu/blob/master/doc/Doxygen/mainpage.dox This example shows how to configure the LiquidMenu library to work with an LCD connected via I2C. Ensure your I2C LCD is correctly wired. ```cpp #include #include #include // Define the LCD dimensions and I2C address const int LCD_WIDTH = 16; const int LCD_HEIGHT = 2; const int LCD_ADDRESS = 0x27; // Common I2C address, check yours // Create an I2C LCD object LiquidCrystal_I2C lcd(LCD_ADDRESS, LCD_WIDTH, LCD_HEIGHT); // Create a menu object Menu menu(lcd); // Create screens Screen screen1(menu); Screen screen2(menu); // Create lines for screen 1 LiquidLine line1_1("Hello I2C", 0, 0); LiquidLine line1_2(screen2, "Next", 1, 0); // Create lines for screen 2 LiquidLine line2_1(screen1, "Back", 0, 0); LiquidLine line2_2("World!", 1, 0); void setup() { // Initialize I2C and LCD Wire.begin(); lcd.init(); lcd.backlight(); // Add lines to screens screen1.add_line(line1_1); screen1.add_line(line1_2); screen2.add_line(line2_1); screen2.add_line(line2_2); // Set the menu to start on screen 1 menu.set_screen(screen1); } void loop() { menu.update(); } ``` -------------------------------- ### Serial Communication Menu Source: https://github.com/vasilkalchev/liquidmenu/blob/master/doc/Doxygen/mainpage.dox This example uses serial communication to execute commands within the menu system. Ensure your Arduino is connected to a serial monitor. ```cpp #include // Define the LCD dimensions and pins const int LCD_WIDTH = 16; const int LCD_HEIGHT = 2; LiquidCrystal lcd(8, 9, 10, 11, 12, 13, 14); // Create a menu object Menu menu(lcd); // Create screens Screen screen1(menu); Screen screen2(menu); // Create lines for screen 1 LiquidLine line1_1("Execute", 0, 0); LiquidLine line1_2(screen2, "Command", 1, 0); // Create lines for screen 2 LiquidLine line2_1(screen1, "Back", 0, 0); LiquidLine line2_2("Serial", 1, 0); // Function to be called via serial void execute_command() { Serial.println("Command executed!"); } void setup() { lcd.begin(LCD_WIDTH, LCD_HEIGHT); Serial.begin(9600); // Add lines to screens screen1.add_line(line1_1); screen1.add_line(line1_2); screen2.add_line(line2_1); screen2.add_line(line2_2); // Attach function to a line line1_1.attach_function(execute_command); // Set the menu to start on screen 1 menu.set_screen(screen1); } void loop() { menu.update(); // Check for serial input if (Serial.available()) { char command = Serial.read(); if (command == 'e') { execute_command(); } } } ``` -------------------------------- ### LiquidLine Constructor Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Constructs a LiquidLine object, which represents a single row of text and/or variables on the LCD. It takes the starting column and row, followed by optional variable references. ```APIDOC ## LiquidLine Constructor `LiquidLine` represents one row of text and/or variables on the LCD. The first two parameters are the starting column and row; up to four variable/constant references follow. Supported types include all integer widths, `float`/`double`, `char`, `char[]`, `const char*`, and zero-argument getter function pointers. ```cpp #include #include LiquidCrystal lcd(12, 11, 5, 4, 3, 2); float temperature = 23.5f; unsigned int rpm = 1200; // Static label at column 0, row 0 LiquidLine titleLine(0, 0, "Sensor Data"); // Label + live float variable at column 0, row 1 LiquidLine tempLine(0, 1, "Temp: ", temperature, "C"); // Label + live integer at column 0, row 0 LiquidLine rpmLine(0, 0, "RPM: ", rpm); void setup() { lcd.begin(16, 2); } ``` ``` -------------------------------- ### Initialize LiquidLine with Static and Dynamic Content Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Demonstrates initializing a LiquidLine with static text and live variables. Ensure LiquidCrystal and LiquidMenu libraries are included. Variables can be of various types including floats and unsigned integers. ```cpp #include #include LiquidCrystal lcd(12, 11, 5, 4, 3, 2); float temperature = 23.5f; unsigned int rpm = 1200; // Static label at column 0, row 0 LiquidLine titleLine(0, 0, "Sensor Data"); // Label + live float variable at column 0, row 1 LiquidLine tempLine(0, 1, "Temp: ", temperature, "C"); // Label + live integer at column 0, row 0 LiquidLine rpmLine(0, 0, "RPM: ", rpm); void setup() { lcd.begin(16, 2); } ``` -------------------------------- ### Button Input and Callback Functions Source: https://github.com/vasilkalchev/liquidmenu/blob/master/doc/Doxygen/mainpage.dox Demonstrates using buttons for navigation, executing callback functions, and changing text variables. Ensure buttons are correctly wired to the specified pins. ```cpp #include // Define the LCD dimensions and pins const int LCD_WIDTH = 16; const int LCD_HEIGHT = 2; LiquidCrystal lcd(8, 9, 10, 11, 12, 13, 14); // Define button pins const int UP_PIN = 2; const int DOWN_PIN = 3; const int ENTER_PIN = 4; const int BACK_PIN = 5; // Create a menu object Menu menu(lcd); // Create screens Screen screen1(menu); Screen screen2(menu); // Create lines for screen 1 LiquidLine line1_1("Option A", 0, 0); LiquidLine line1_2(screen2, "Option B", 1, 0); // Create lines for screen 2 LiquidLine line2_1(screen1, "Back", 0, 0); LiquidLine line2_2("Selected!", 1, 0); // Callback function for Option A void option_a_selected() { line2_2.set_text("A Chosen"); } // Callback function for Option B void option_b_selected() { line2_2.set_text("B Chosen"); } void setup() { lcd.begin(LCD_WIDTH, LCD_HEIGHT); Serial.begin(9600); // Set button pins menu.set_up_button(UP_PIN); menu.set_down_button(DOWN_PIN); menu.set_enter_button(ENTER_PIN); menu.set_back_button(BACK_PIN); // Add lines to screens screen1.add_line(line1_1); screen1.add_line(line1_2); screen2.add_line(line2_1); screen2.add_line(line2_2); // Attach callback functions line1_1.attach_function(option_a_selected); line1_2.attach_function(option_b_selected); // Set the menu to start on screen 1 menu.set_screen(screen1); } void loop() { menu.update(); } ``` -------------------------------- ### Configure LiquidMenu Library Options Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt All capacity limits and behavioral flags are set in `LiquidMenu_config.h`. Edit before compiling to tune memory usage or enable I2C. ```cpp // LiquidMenu_config.h (excerpt with non-default values shown) // Switch to I2C library: #define LIQUIDMENU_LIBRARY LiquidCrystal_I2C_LIBRARY #define DisplayClass LiquidCrystal_I2C // Increase variables per line (default: 5) const uint8_t MAX_VARIABLES = 8; // Increase functions per line (default: 8) const uint8_t MAX_FUNCTIONS = 4; // Increase lines per screen (default: 12) const uint8_t MAX_LINES = 16; // Increase screens per menu (default: 14) const uint8_t MAX_SCREENS = 20; // Increase menus per system (default: 8) const uint8_t MAX_MENUS = 4; // Disable focus indicator ghosting (default: true) #define LM_FOCUS_INDICATOR_GHOSTING false // Enable debug output over Serial (default: false) #define LIQUIDMENU_DEBUG true ``` -------------------------------- ### Attaching Functions to Menu Lines Source: https://github.com/vasilkalchev/liquidmenu/blob/master/doc/Doxygen/mainpage.dox Demonstrates how to attach functions to menu lines, allowing for interactive elements. Ensure the function signature matches the expected callback. ```cpp #include // Define the LCD dimensions and pins const int LCD_WIDTH = 16; const int LCD_HEIGHT = 2; LiquidCrystal lcd(8, 9, 10, 11, 12, 13, 14); // Create a menu object Menu menu(lcd); // Create screens Screen screen1(menu); Screen screen2(menu); // Create lines for screen 1 LiquidLine line1_1("Action 1", 0, 0); LiquidLine line1_2(screen2, "Action 2", 1, 0); // Create lines for screen 2 LiquidLine line2_1(screen1, "Back", 0, 0); LiquidLine line2_2("Another", 1, 0); // Functions to be attached void function1() { Serial.println("Function 1 called!"); } void function2() { Serial.println("Function 2 called!"); } void setup() { lcd.begin(LCD_WIDTH, LCD_HEIGHT); Serial.begin(9600); // Add lines to screens screen1.add_line(line1_1); screen1.add_line(line1_2); screen2.add_line(line2_1); screen2.add_line(line2_2); // Attach functions to lines line1_1.attach_function(function1); line1_2.attach_function(function2); // Set the menu to start on screen 1 menu.set_screen(screen1); } void loop() { menu.update(); } ``` -------------------------------- ### LiquidMenu Class Constructors Source: https://github.com/vasilkalchev/liquidmenu/blob/master/README.md Demonstrates the constructors for the core LiquidMenu classes: LiquidLine, LiquidScreen, LiquidMenu, and LiquidSystem. These define how menu elements are structured and initialized. ```c++ // Takes column and row for the position and 1 to 4 variable references. These variable // references are what is going to be printed on the display. They can be integers, // string literals or char[] arrays for dynamic text. LiquidLine(byte column, byte row, A &variableA...); // Takes 0 to 4 LiquidLine objects. LiquidScreen(LiquidLine &liquidLine1...); // Takes a reference to the LiquidCrystal object, 0 to 4 LiquidScreen objects and // optionally the number of the screen that will be shown first. LiquidMenu(LiquidCrystal &liquidCrystal, LiquidScreen &liquidScreen1..., byte startingScreen = 1); // Takes 0 to 4 LiquidMenu objects and optionally the number of the menu that will be shown first. LiquidSystem(LiquidMenu &liquidMenu1..., byte startingMenu = 1); ``` -------------------------------- ### Implement Multi-Menu System with LiquidSystem Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt `LiquidSystem` combines multiple `LiquidMenu` objects and exposes the same navigation/focus/callback API. Use `change_menu()` to switch between menus (typically from a callback function). ```cpp LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // --- Main menu --- LiquidLine goSettings(0, 0, "> Settings"); LiquidScreen mainScreen(goSettings); LiquidMenu mainMenu(lcd, mainScreen); // --- Settings menu --- LiquidLine backLine(0, 1, "< Back"); LiquidLine brightnessLine(0, 0, "Brightness"); LiquidScreen settingsScreen(brightnessLine, backLine); LiquidMenu settingsMenu(lcd, settingsScreen); // Combine into a system LiquidSystem menuSystem(mainMenu, settingsMenu); void gotoSettings() { menuSystem.change_menu(settingsMenu); } void gotoMain() { menuSystem.change_menu(mainMenu); } void setup() { lcd.begin(16, 2); goSettings.attach_function(1, gotoSettings); backLine.attach_function(1, gotoMain); backLine.attach_function(2, gotoMain); menuSystem.update(); } void loop() { if (digitalRead(10) == LOW) menuSystem.switch_focus(); if (digitalRead(8) == LOW) menuSystem.call_function(1); if (digitalRead(7) == LOW) menuSystem.next_screen(); if (digitalRead(A0) == LOW) menuSystem.previous_screen(); } ``` -------------------------------- ### Create LiquidScreen with Constructor or add_line Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt LiquidScreen organizes LiquidLine objects for display views, supporting up to MAX_LINES. Lines can be provided during construction or added dynamically using add_line. ```cpp LiquidCrystal lcd(12, 11, 5, 4, 3, 2); float voltage = 3.7f; byte current = 42; LiquidLine voltLine(0, 0, "V: ", voltage); LiquidLine currLine(0, 1, "I: ", current, "mA"); // Constructor form (up to 4 lines) LiquidScreen statusScreen(voltLine, currLine); // Or add dynamically LiquidScreen dynScreen; // dynScreen.add_line(voltLine); // dynScreen.add_line(currLine); LiquidMenu menu(lcd, statusScreen); void setup() { lcd.begin(16, 2); menu.update(); } ``` -------------------------------- ### Using Getter Functions in Menu Source: https://github.com/vasilkalchev/liquidmenu/blob/master/doc/Doxygen/mainpage.dox Demonstrates using getter functions instead of direct variables in LiquidScreen objects. This allows for dynamic data retrieval. ```cpp #include // Define the LCD dimensions and pins const int LCD_WIDTH = 16; const int LCD_HEIGHT = 2; LiquidCrystal lcd(8, 9, 10, 11, 12, 13, 14); // Create a menu object Menu menu(lcd); // Create screens Screen screen1(menu); Screen screen2(menu); // Variable to be accessed by getter int counter = 0; // Getter function String get_counter_value() { return String("Count: ") + counter; } // Create lines using getter functions LiquidLine line1_1(get_counter_value, 0, 0); LiquidLine line1_2(screen2, "Next", 1, 0); // Create lines for screen 2 LiquidLine line2_1(screen1, "Back", 0, 0); LiquidLine line2_2("Increment", 1, 0); void setup() { lcd.begin(LCD_WIDTH, LCD_HEIGHT); // Add lines to screens screen1.add_line(line1_1); screen1.add_line(line1_2); screen2.add_line(line2_1); screen2.add_line(line2_2); // Set the menu to start on screen 1 menu.set_screen(screen1); } void loop() { menu.update(); // Increment counter periodically if (millis() % 1000 < 50) { // Update roughly every second counter++; } } ``` -------------------------------- ### LiquidMenu Navigation Methods Source: https://github.com/vasilkalchev/liquidmenu/blob/master/README.md Shows the methods for navigating through screens within a LiquidMenu or LiquidSystem. These functions allow cycling through screens or jumping to a specific one. ```c++ void LiquidMenu::next_screen(); void LiquidMenu::previous_screen(); bool LiquidMenu::change_screen(LiquidScreen &liquidScreen); ``` -------------------------------- ### Displaying Strings from Flash Memory Source: https://github.com/vasilkalchev/liquidmenu/blob/master/doc/Doxygen/mainpage.dox Demonstrates how to display strings stored in flash memory (PROGMEM) to save RAM. This is useful for large or static text. ```cpp #include #include // Define the LCD dimensions and pins const int LCD_WIDTH = 16; const int LCD_HEIGHT = 2; LiquidCrystal lcd(8, 9, 10, 11, 12, 13, 14); // Create a menu object Menu menu(lcd); // Create screens Screen screen1(menu); Screen screen2(menu); // Define strings in PROGMEM const char PROGMEM string1[] = "Flash String 1"; const char PROGMEM string2[] = "Flash String 2"; // Create lines using strings from PROGMEM LiquidLine line1_1(string1, 0, 0); LiquidLine line1_2(screen2, "Next", 1, 0); LiquidLine line2_1(screen1, "Back", 0, 0); LiquidLine line2_2(string2, 1, 0); void setup() { lcd.begin(LCD_WIDTH, LCD_HEIGHT); // Add lines to screens screen1.add_line(line1_1); screen1.add_line(line1_2); screen2.add_line(line2_1); screen2.add_line(line2_2); // Set the menu to start on screen 1 menu.set_screen(screen1); } void loop() { menu.update(); } ``` -------------------------------- ### LiquidScreen Constructor and add_line Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt The `LiquidScreen` class groups `LiquidLine` objects into a display view. Lines can be initialized via the constructor or added dynamically using the `add_line` method. ```APIDOC ## LiquidScreen — Constructor and add_line `LiquidScreen` groups up to `MAX_LINES` (default 12) `LiquidLine` objects into a single display view. Lines can be passed in the constructor (up to 4) or added later via `add_screen`. ### Constructor ```cpp LiquidScreen(LiquidLine& line1, LiquidLine& line2, ...); ``` ### Method ```cpp void add_line(LiquidLine& line); ``` ### Parameters * **line1, line2, ...** (LiquidLine&) - `LiquidLine` objects to be included in the screen (constructor only). * **line** (LiquidLine&) - A `LiquidLine` object to add to the screen (using `add_line`). ``` -------------------------------- ### Navigate Screens with LiquidMenu Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Cycle through screens using next_screen() and previous_screen(), or jump directly to a specific screen by index or pointer. ```cpp LiquidCrystal lcd(12, 11, 5, 4, 3, 2); LiquidLine s1l(0, 0, "Screen 1"); LiquidLine s2l(0, 0, "Screen 2"); LiquidLine s3l(0, 0, "Screen 3"); LiquidScreen screen1(s1l), screen2(s2l), screen3(s3l); LiquidMenu menu(lcd, screen1, screen2, screen3, 1); // start on screen 1 void setup() { lcd.begin(16, 2); menu.update(); } void loop() { if (digitalRead(7) == LOW) menu.next_screen(); // forward if (digitalRead(A0) == LOW) menu.previous_screen(); // backward if (digitalRead(8) == LOW) menu.change_screen(2); // jump to screen 2 if (digitalRead(9) == LOW) menu.change_screen(&screen3); // jump by pointer } ``` -------------------------------- ### Scrolling Lines in Menu Source: https://github.com/vasilkalchev/liquidmenu/blob/master/doc/Doxygen/mainpage.dox Demonstrates how to implement scrolling lines within the menu. This is useful when text exceeds the available screen width. ```cpp #include // Define the LCD dimensions and pins const int LCD_WIDTH = 16; const int LCD_HEIGHT = 2; LiquidCrystal lcd(8, 9, 10, 11, 12, 13, 14); // Create a menu object Menu menu(lcd); // Create screens Screen screen1(menu); Screen screen2(menu); // Create lines for screen 1 LiquidLine line1_1("Scrolling Text Example", 0, 0); LiquidLine line1_2(screen2, "Next", 1, 0); // Create lines for screen 2 LiquidLine line2_1(screen1, "Back", 0, 0); LiquidLine line2_2("This line scrolls", 1, 0); void setup() { lcd.begin(LCD_WIDTH, LCD_HEIGHT); // Enable scrolling for line2_2 line2_2.set_scrolling(true); // Add lines to screens screen1.add_line(line1_1); screen1.add_line(line1_2); screen2.add_line(line2_1); screen2.add_line(line2_2); // Set the menu to start on screen 1 menu.set_screen(screen1); } void loop() { menu.update(); } ``` -------------------------------- ### Update Display with LiquidMenu Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Use update() for a full screen redraw and softUpdate() for a faster redraw without clearing, suitable when new content completely overwrites old content. ```cpp LiquidCrystal lcd(12, 11, 5, 4, 3, 2); unsigned int counter = 0; LiquidLine cntLine(0, 0, "Count: ", counter); LiquidScreen screen(cntLine); LiquidMenu menu(lcd, screen); void setup() { lcd.begin(16, 2); menu.update(); } void loop() { static unsigned long last = 0; if (millis() - last > 500) { last = millis(); counter++; menu.update(); // full clear + redraw (safe for any content) // menu.softUpdate(); // no clear (use when new text covers old exactly) } } ``` -------------------------------- ### LiquidMenu Navigation: next_screen, previous_screen, change_screen Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Manages screen cycling and direct screen jumps. Screens can be advanced using `next_screen()` or `previous_screen()`, or changed directly using `change_screen()` with a screen index or pointer. ```APIDOC ## LiquidMenu Navigation: next_screen / previous_screen / change_screen Manages screen cycling and direct screen jumps. Screens can be advanced using `next_screen()` or `previous_screen()`, or changed directly using `change_screen()` with a screen index or pointer. ### Method - `next_screen()` - `previous_screen()` - `change_screen(uint8_t screenIndex)` - `change_screen(LiquidScreen* screen)` ### Example Usage ```cpp // Assuming 'menu' is an initialized LiquidMenu object menu.next_screen(); // forward to the next screen menu.previous_screen(); // backward to the previous screen menu.change_screen(2); // jump directly to screen with index 2 menu.change_screen(&screen3); // jump directly to screen pointed to by screen3 ``` ``` -------------------------------- ### Customizing the Focus Indicator Source: https://github.com/vasilkalchev/liquidmenu/blob/master/doc/Doxygen/mainpage.dox Demonstrates how to customize the focus indicator used in the menu. This allows for visual changes to highlight the selected item. ```cpp #include // Define the LCD dimensions and pins const int LCD_WIDTH = 16; const int LCD_HEIGHT = 2; LiquidCrystal lcd(8, 9, 10, 11, 12, 13, 14); // Create a menu object Menu menu(lcd); // Create screens Screen screen1(menu); Screen screen2(menu); // Create lines for screen 1 LiquidLine line1_1("Option 1", 0, 0); LiquidLine line1_2(screen2, "Option 2", 1, 0); // Create lines for screen 2 LiquidLine line2_1(screen1, "Back", 0, 0); LiquidLine line2_2("Details", 1, 0); void setup() { lcd.begin(LCD_WIDTH, LCD_HEIGHT); // Customize focus indicator menu.set_focus_indicator(">"); // Use '>' as the focus indicator // Add lines to screens screen1.add_line(line1_1); screen1.add_line(line1_2); screen2.add_line(line2_1); screen2.add_line(line2_2); // Set the menu to start on screen 1 menu.set_screen(screen1); } void loop() { menu.update(); } ``` -------------------------------- ### Creating Custom Glyphs Source: https://github.com/vasilkalchev/liquidmenu/blob/master/doc/Doxygen/mainpage.dox Demonstrates how to create and use custom characters (glyphs) within LiquidLine objects. This allows for unique visual elements in your menu. ```cpp #include // Define the LCD dimensions and pins const int LCD_WIDTH = 16; const int LCD_HEIGHT = 2; LiquidCrystal lcd(8, 9, 10, 11, 12, 13, 14); // Create a menu object Menu menu(lcd); // Create screens Screen screen1(menu); Screen screen2(menu); // Define a custom glyph (e.g., a heart) byte heart[8] = { 0b00000, 0b01010, 0b11111, 0b11111, 0b01110, 0b00100, 0b00000, 0b00000 }; // Create lines for screen 1 LiquidLine line1_1("Heart", 0, 0); LiquidLine line1_2(screen2, "Next", 1, 0); // Create lines for screen 2 LiquidLine line2_1(screen1, "Back", 0, 0); LiquidLine line2_2("Glyph", 1, 0); void setup() { lcd.begin(LCD_WIDTH, LCD_HEIGHT); // Create the custom character lcd.createChar(0, heart); // Use the custom character in a LiquidLine line2_2.set_text("Glyph "); line2_2.add_glyph(0); // Add lines to screens screen1.add_line(line1_1); screen1.add_line(line1_2); screen2.add_line(line2_1); screen2.add_line(line2_2); // Set the menu to start on screen 1 menu.set_screen(screen1); } void loop() { menu.update(); } ``` -------------------------------- ### Add Variables to LiquidLine at Runtime Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Shows how to add more variables to an existing LiquidLine after its initial creation using `add_variable()`. This is useful for dynamically updating lines with multiple data points. Returns true on success, false if the variable limit is reached. ```cpp LiquidCrystal lcd(12, 11, 5, 4, 3, 2); byte humidity = 60; float pressure = 1013.25f; // Start with one variable, add more in setup LiquidLine sensorLine(0, 0, "H:"); void setup() { lcd.begin(16, 2); sensorLine.add_variable(humidity); // now prints "H: 60" sensorLine.add_variable(pressure); // now prints "H: 60 1013.25" } ``` -------------------------------- ### Attach Callback Functions to LiquidLine Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Demonstrates attaching callback functions to a LiquidLine using `attach_function()`. These functions are invoked via `LiquidMenu::call_function(number)` when the line is focused, allowing interactive menu elements. Ensure button inputs are handled in `loop()` to trigger these functions. ```cpp LiquidCrystal lcd(12, 11, 5, 4, 3, 2); byte brightness = 128; void increaseBrightness() { if (brightness < 230) brightness += 25; analogWrite(6, brightness); } void decreaseBrightness() { if (brightness > 25) brightness -= 25; analogWrite(6, brightness); } LiquidLine brightnessLine(0, 0, "Bright: ", brightness); LiquidScreen settingsScreen(brightnessLine); LiquidMenu menu(lcd, settingsScreen); void setup() { lcd.begin(16, 2); brightnessLine.attach_function(1, increaseBrightness); // called by call_function(1) brightnessLine.attach_function(2, decreaseBrightness); // called by call_function(2) menu.update(); } void loop() { // UP button -> call_function(1), DOWN button -> call_function(2) if (digitalRead(8) == LOW) { menu.call_function(1); } if (digitalRead(9) == LOW) { menu.call_function(2); } } ``` -------------------------------- ### Manage Focus and Call Functions Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Cycle focus between lines on the current screen using switch_focus() and execute the function attached to the focused line with call_function(). Retrieve the current focus index with get_focusedLine(). ```cpp LiquidCrystal lcd(12, 11, 5, 4, 3, 2); void toggleLED() { digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); } void doNothing() {} LiquidLine line1(0, 0, "> LED toggle"); LiquidLine line2(0, 1, "> No-op"); LiquidScreen screen(line1, line2); LiquidMenu menu(lcd, screen); void setup() { lcd.begin(16, 2); pinMode(LED_BUILTIN, OUTPUT); line1.attach_function(1, toggleLED); line2.attach_function(1, doNothing); menu.update(); } void loop() { if (digitalRead(10) == LOW) menu.switch_focus(); // cycle focus if (digitalRead(8) == LOW) menu.call_function(1); // execute focused line's fn // Read current focus index: uint8_t idx = menu.get_focusedLine(); // 0-based // Jump directly to line index 1: // menu.set_focusedLine(1); } ``` -------------------------------- ### LiquidMenu Display Update: update, softUpdate Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Manages screen redrawing. `update()` clears the display and redraws the current screen, suitable for any content change. `softUpdate()` redraws without clearing, which is faster and avoids flicker when new content fully covers old content. ```APIDOC ## LiquidMenu Display Update: update / softUpdate Manages screen redrawing. `update()` clears the display and redraws the current screen, suitable for any content change. `softUpdate()` redraws without clearing, which is faster and avoids flicker when new content fully covers old content. ### Method - `update()` - `softUpdate()` ### Example Usage ```cpp // Assuming 'menu' is an initialized LiquidMenu object menu.update(); // full clear + redraw (safe for any content) menu.softUpdate(); // no clear (use when new text covers old exactly) ``` ``` -------------------------------- ### Switch Focus Between Lines Source: https://github.com/vasilkalchev/liquidmenu/blob/master/README.md Cycles the focus through the lines displayed on the screen. Use this to select interactive lines. ```c++ void LiquidMenu::switch_focus(bool forward = true); ``` -------------------------------- ### Configure LiquidLine Focus Indicator Position Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Illustrates setting the position of the focus indicator (cursor) for a LiquidLine using `set_focusPosition()`. Options include `Position::LEFT`, `Position::RIGHT` (default), and `Position::CUSTOM` for specific coordinates. ```cpp LiquidCrystal lcd(12, 11, 5, 4, 3, 2); LiquidLine line1(2, 0, "Option A"); LiquidLine line2(2, 1, "Option B"); void setup() { lcd.begin(16, 2); line1.set_focusPosition(Position::LEFT); // indicator appears left of text line2.set_focusPosition(Position::CUSTOM, 15, 1); // indicator at col 15, row 1 } ``` -------------------------------- ### Set Decimal Places for Floating-Point Variables Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Shows how to control the number of decimal places displayed for floating-point variables on a LiquidLine using `set_decimalPlaces()`. The default is 2 decimal places. ```cpp LiquidCrystal lcd(12, 11, 5, 4, 3, 2); const float pi = 3.14159265f; LiquidLine piLine(0, 0, "Pi=", pi); // default shows "Pi=3.14" LiquidScreen screen(piLine); LiquidMenu menu(lcd, screen); void setup() { lcd.begin(16, 2); piLine.set_decimalPlaces(5); // now shows "Pi=3.14159" menu.update(); } ``` -------------------------------- ### LiquidMenu Focus Management: switch_focus, set_focusedLine, get_focusedLine Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Controls the focus indicator on the current screen. `switch_focus()` cycles through focusable lines, `set_focusedLine()` jumps focus to a specific line index, and `get_focusedLine()` retrieves the index of the currently focused line. ```APIDOC ## LiquidMenu Focus Management: switch_focus / set_focusedLine / get_focusedLine Controls the focus indicator on the current screen. `switch_focus()` cycles through focusable lines, `set_focusedLine()` jumps focus to a specific line index, and `get_focusedLine()` retrieves the index of the currently focused line. ### Method - `switch_focus()` - `set_focusedLine(uint8_t lineIndex)` - `get_focusedLine()` ### Example Usage ```cpp // Assuming 'menu' is an initialized LiquidMenu object menu.switch_focus(); // cycle focus to the next focusable line menu.set_focusedLine(1); // jump focus directly to line with index 1 uint8_t currentFocus = menu.get_focusedLine(); // get the index of the currently focused line ``` ``` -------------------------------- ### Use Getter Functions in LiquidLine Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Instead of passing variable references, zero-argument getter functions can be used directly. LiquidMenu calls them at render time, eliminating the need to update a cached variable and reducing memory footprint. ```cpp LiquidCrystal lcd(12, 11, 5, 4, 3, 2); int readSensor() { return analogRead(A0); } const char* getSensorState() { int v = analogRead(A0); if (v < 100) return "LOW"; if (v < 900) return "MID"; return "HIGH"; } // Pass function pointer (no parentheses) as a variable LiquidLine valueLine(0, 0, "ADC: ", readSensor); LiquidLine stateLine(0, 1, getSensorState); LiquidScreen screen(valueLine, stateLine); LiquidMenu menu(lcd, screen); void setup() { lcd.begin(16, 2); menu.update(); } void loop() { delay(300); menu.update(); // getters are called automatically on each update } ``` -------------------------------- ### Hide Screens with LiquidScreen::hide Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Use LiquidScreen::hide to control screen visibility, preventing them from being cycled through by next_screen() or previous_screen(). Hidden screens can still be accessed directly via change_screen(). ```cpp LiquidCrystal lcd(12, 11, 5, 4, 3, 2); LiquidLine mainLine(0, 0, "Main"); LiquidLine debugLine(0, 0, "Debug info"); LiquidScreen mainScreen(mainLine); LiquidScreen debugScreen(debugLine); LiquidMenu menu(lcd, mainScreen, debugScreen); bool debugMode = false; void setup() { lcd.begin(16, 2); debugScreen.hide(true); // hidden by default menu.update(); } void loop() { if (digitalRead(7) == LOW) { // toggle debug screen visibility debugMode = !debugMode; debugScreen.hide(!debugMode); } } ``` -------------------------------- ### LiquidMenu Focus Indicator Customization: set_focusSymbol, set_focusPosition Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Allows customization of the focus indicator. `set_focusPosition()` sets the indicator's position (left or right) for the entire menu. `set_focusSymbol()` allows defining a custom glyph for the indicator at a specified position. ```APIDOC ## LiquidMenu Focus Indicator Customization: set_focusSymbol / set_focusPosition Allows customization of the focus indicator. `set_focusPosition()` sets the indicator's position (left or right) for the entire menu. `set_focusSymbol()` allows defining a custom glyph for the indicator at a specified position. ### Method - `set_focusPosition(Position position)` - `set_focusSymbol(Position position, const uint8_t* glyph)` ### Parameters - `position` (Position): Specifies whether to set for `Position::LEFT` or `Position::RIGHT`. - `glyph` (const uint8_t*): A pointer to an 8x8 byte array representing the custom glyph. ### Example Usage ```cpp // Assuming 'menu' is an initialized LiquidMenu object and 'arrowRight' is a defined glyph menu.set_focusPosition(Position::LEFT); // show indicator on the left side of lines menu.set_focusSymbol(Position::LEFT, arrowRight); // use custom glyph for the left indicator ``` ``` -------------------------------- ### Store Strings in Flash with LiquidLine::set_asProgmem Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Employ set_asProgmem to designate a const char[] variable as stored in AVR flash (PROGMEM). This is crucial for displaying large strings without consuming valuable RAM. The number parameter is 1-based. ```cpp #include #include #include LiquidCrystal lcd(12, 11, 5, 4, 3, 2); const char msgA[] PROGMEM = "Flash string A!"; const char msgB[] PROGMEM = "Flash string B!"; LiquidLine lineA(0, 0, msgA); LiquidLine lineB(0, 1, msgB); LiquidScreen screen(lineA, lineB); LiquidMenu menu(lcd, screen); void setup() { lcd.begin(16, 2); lineA.set_asProgmem(1); // variable #1 lives in PROGMEM lineB.set_asProgmem(1); menu.update(); } ``` -------------------------------- ### Use Custom Glyphs with LiquidLine::set_asGlyph Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Use set_asGlyph to treat a byte variable as a glyph index, enabling custom characters created with lcd.createChar() to be displayed. Ensure the glyph is created before calling set_asGlyph. ```cpp #include #include LiquidCrystal lcd(12, 11, 5, 4, 3, 2); uint8_t heartGlyph[8] = { 0b00000, 0b01010, 0b11111, 0b11111, 0b01110, 0b00100, 0b00000, 0b00000 }; byte heartIndex = 0; // glyph slot 0 LiquidLine glyphLine(0, 0, heartIndex, " Alive!"); LiquidScreen screen(glyphLine); LiquidMenu menu(lcd, screen); void setup() { lcd.createChar(heartIndex, heartGlyph); lcd.begin(16, 2); glyphLine.set_asGlyph(1); // variable #1 is a glyph index menu.update(); // displays heart symbol + " Alive!" } ``` -------------------------------- ### Attach Callback Function to LiquidLine Source: https://github.com/vasilkalchev/liquidmenu/blob/master/README.md Attaches a callback function to a specific line number on the display. Up to 8 functions can be attached per line. ```c++ bool LiquidLine::attach_function(byte number, void (*function)(void)); ``` -------------------------------- ### LiquidLine::set_asGlyph Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Configures a LiquidLine to interpret a byte variable as a glyph index, enabling the display of custom characters and simple animations on the LCD. ```APIDOC ## LiquidLine::set_asGlyph Tells LiquidLine that a `byte` variable is a glyph index (created via `lcd.createChar()`) rather than a numeric value to print. Enables custom characters and simple animations. ### Usage ```cpp void set_asGlyph(uint8_t variable_number); ``` ### Parameters * **variable_number** (uint8_t) - The 1-based index of the variable within the LiquidLine that should be treated as a glyph index. ``` -------------------------------- ### LiquidLine::set_asProgmem Source: https://context7.com/vasilkalchev/liquidmenu/llms.txt Marks a `const char[]` variable within a LiquidLine as stored in AVR flash memory (PROGMEM). This is useful for displaying large strings without consuming valuable RAM. ```APIDOC ## LiquidLine::set_asProgmem Marks a `const char[]` variable as stored in AVR flash (PROGMEM), enabling large string menus without consuming RAM. The `number` parameter is the 1-based position of the PROGMEM variable within the line. ### Usage ```cpp void set_asProgmem(uint8_t variable_number); ``` ### Parameters * **variable_number** (uint8_t) - The 1-based index of the variable within the LiquidLine that is stored in PROGMEM. ```