#include "MenuSystem.h" #include "MenuGraphics.h" MenuSystem::MenuSystem(U8G2_SSD1306_128X64_NONAME_F_HW_I2C* display) { _display = display; _itemCount = 0; _selectedItem = 0; _screen = 0; _btnUp = false; _btnSelect = false; _btnDown = false; _prevBtnUp = false; _prevBtnSelect = false; _prevBtnDown = false; // Initialize arrays for (int i = 0; i < MAX_ITEMS; i++) { _itemNames[i][0] = '\0'; _itemIcons[i] = nullptr; _itemScreens[i] = nullptr; _itemCallbacks[i] = nullptr; } } void MenuSystem::begin() { // Ensure display is properly initialized _display->begin(); _display->clearBuffer(); _display->sendBuffer(); delay(100); // Short delay to ensure display is ready } void MenuSystem::addMenuItem(const char* name, const uint8_t* icon) { if (_itemCount < MAX_ITEMS) { strncpy(_itemNames[_itemCount], name, MAX_NAME_LEN-1); _itemNames[_itemCount][MAX_NAME_LEN-1] = '\0'; // Ensure null termination _itemIcons[_itemCount] = icon; _itemCount++; } } void MenuSystem::setItemCallback(int index, void (*callback)()) { if (index >= 0 && index < _itemCount) { _itemCallbacks[index] = callback; } } void MenuSystem::setButtons(bool up, bool select, bool down) { // Save previous button states _prevBtnUp = _btnUp; _prevBtnSelect = _btnSelect; _prevBtnDown = _btnDown; // Set new button states _btnUp = up; _btnSelect = select; _btnDown = down; } void MenuSystem::update() { // Process button inputs before drawing handleButtons(); // Simple drawing approach (not using page buffer mode) _display->clearBuffer(); if (_screen == 0) { // Draw the main menu screen drawMenu(); } else if (_screen == 1 && _itemScreens[_selectedItem] != nullptr) { // Draw the full-screen bitmap for the selected item _display->drawXBM(0, 0, 128, 64, _itemScreens[_selectedItem]); } _display->sendBuffer(); } void MenuSystem::drawMenu() { if (_itemCount == 0) return; // Nothing to draw // Calculate which items to show (previous, current, next) int prevItem = (_selectedItem > 0) ? _selectedItem - 1 : _itemCount - 1; int nextItem = (_selectedItem < _itemCount - 1) ? _selectedItem + 1 : 0; // Draw the background with the item selector outline (if enabled) // _display->drawXBM(0, 0, 128, 64, bitmap_item_sel_outline); // Instead, draw a simple selection highlight _display->drawFrame(0, 20, 128, 24); // Highlight the middle selection // Draw previous item (top position) _display->setFont(u8g2_font_6x10_tf); // Use a different, simpler font _display->drawStr(25, 15, _itemNames[prevItem]); if (_itemIcons[prevItem] != nullptr) { _display->drawXBM(4, 2, 16, 16, _itemIcons[prevItem]); } // Draw selected item (middle position) _display->setFont(u8g2_font_6x10_tf); // Use same font for consistency _display->drawStr(25, 35, _itemNames[_selectedItem]); if (_itemIcons[_selectedItem] != nullptr) { _display->drawXBM(4, 24, 16, 16, _itemIcons[_selectedItem]); } // Draw next item (bottom position) _display->setFont(u8g2_font_6x10_tf); // Use same font for consistency _display->drawStr(25, 55, _itemNames[nextItem]); if (_itemIcons[nextItem] != nullptr) { _display->drawXBM(4, 46, 16, 16, _itemIcons[nextItem]); } // Draw a simple scrollbar instead of using bitmap if (_itemCount > 1) { _display->drawVLine(125, 0, 64); // Scrollbar background int barHeight = 64 / _itemCount; int barY = (_selectedItem * 64) / _itemCount; _display->drawBox(123, barY, 4, barHeight); // Scrollbar handle } } void MenuSystem::handleButtons() { // Only respond to button press events (not holds) // Button rising edge detection for up if (_btnUp && !_prevBtnUp) { _selectedItem = (_selectedItem > 0) ? _selectedItem - 1 : _itemCount - 1; Serial.print("Selected item: "); Serial.println(_selectedItem); } // Button rising edge detection for down if (_btnDown && !_prevBtnDown) { _selectedItem = (_selectedItem < _itemCount - 1) ? _selectedItem + 1 : 0; Serial.print("Selected item: "); Serial.println(_selectedItem); } // Button rising edge detection for select if (_btnSelect && !_prevBtnSelect) { // Execute callback if it exists if (_itemCallbacks[_selectedItem] != nullptr) { _itemCallbacks[_selectedItem](); } // Toggle between menu and item screen if screen exists if (_itemScreens[_selectedItem] != nullptr) { _screen = (_screen == 0) ? 1 : 0; Serial.print("Screen changed to: "); Serial.println(_screen); } } }