#include "LiquidCrystal_I2C.h"

LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);

// Pin assignments for digital push buttons
#define BUTTON_ENTER 2
#define BUTTON_UP    3
#define BUTTON_DOWN  4
#define BUTTON_LEFT  5

// Definitions:
#define DISPLAY_ROWS      2
#define PER_SPACE         1

#define KEYPAD_ROWS       4
#define KEYPAD_COLS       4

unsigned char selected = 1;
unsigned char prev_key;
bool isKeyDisabled = false;

char buttonPressed = '0';
char lastButtonState = '0';
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 100; 

// ####################################
unsigned long checkButtonTaskTimer = 0;
const unsigned long checkButtonTaskInterval = 300;
unsigned long updateLCDTaskTimer = 0;
const unsigned long updateLCDTaskInterval = 400;

typedef const struct MenuStructure
{
  const char *text;
  unsigned char num_menupoints;
  unsigned char up;
  unsigned char down;
  unsigned char enter;
  void (*fp) (void);
} MenuEntry;


void start(void);
void show_menu(void);
void checkButton();

const char menu_000[] = " Settings:    ";    // 0
const char menu_001[] = "  Set Area    ";    // 1
const char menu_002[] = "  Set Date    ";    // 2
const char menu_003[] = "  Set Time    ";    // 3
const char menu_004[] = "  FactoryReset";    // 4

const char menu_100[] = " Set Area:     ";   // 5
const char menu_101[] = "  Rectangle    ";   // 6
const char menu_102[] = "  Circle       ";   // 7
const char menu_103[] = "  Return       ";   // 8

const char menu_104[] = " In mm..       ";   // 9
const char menu_105[] = "  Length       ";   // 10
const char menu_106[] = "  Bredth       ";   // 11
const char menu_107[] = "  Return       ";   // 12

const char menu_108[] = " In mm..       ";   // 13
const char menu_109[] = "  Diameter     ";   // 14
const char menu_110[] = "  Return       ";   // 15

MenuEntry menu[] =
{
  // text, num_menupoints, up, down, enter, *fp
  {menu_000, 5, 0, 0, 0, 0},       // 0
  {menu_001, 5, 1, 2, 6, 0},      // 1
  {menu_002, 5, 1, 3, 2, 0},      // 2
  {menu_003, 5, 2, 4, 3, 0},      // 3
  {menu_004, 5, 3, 4, 4, 0},       // 4

  {menu_100, 4, 0, 0, 0, 0},   // 5
  {menu_101, 4, 6, 7, 10, 0},   // 6
  {menu_102, 4, 6, 8, 14, 0},   // 7
  {menu_103, 4, 7, 8, 1, 0},   // 8

  {menu_104, 4, 0, 0, 0, 0},   // 9
  {menu_105, 4, 10, 11, 10, 0},   // 10
  {menu_106, 4, 10, 12, 11, 0},   // 11
  {menu_107, 4, 11, 12, 6, 0},   // 12

  {menu_108, 3, 0, 0, 0, 0},   // 13
  {menu_109, 3, 14, 15, 14, 0},   // 14
  {menu_110, 3, 14, 15, 6, 0},   // 15
};

void setup() {
  // put your set code here, to run once:
  lcd.clear();
  lcd.begin(16, 2);

  pinMode(BUTTON_ENTER, INPUT_PULLUP);
  pinMode(BUTTON_UP, INPUT_PULLUP);
  pinMode(BUTTON_DOWN, INPUT_PULLUP);
  pinMode(BUTTON_LEFT, INPUT_PULLUP);

  Serial.begin(9600);
  show_menu();
  Serial.println("Setup DONE");
}

void loop() {
  if(millis() >= checkButtonTaskTimer + checkButtonTaskInterval){
    checkButtonTaskTimer += checkButtonTaskInterval;
    // do the task
    checkButton();
  }

  if(millis() >= updateLCDTaskTimer + updateLCDTaskInterval){
    updateLCDTaskTimer += updateLCDTaskInterval;
    // do the task
    show_menu();
  }
}

void show_menu(void)
{
  unsigned char line_cnt = 0;
  unsigned char from = 0;
  unsigned char till = 0;
  unsigned char temp = 0;
  while (till <= selected)
  {
    till += menu[till].num_menupoints;   
  }   
  from = till - menu[selected].num_menupoints;  
  till--;                     
  temp = from;                
  // browsing somewhere in the middle
  if ((selected >= (from+PER_SPACE)) && (selected <= till ))
  {
    from = selected-PER_SPACE;
    till = from + (DISPLAY_ROWS-1);
    for (from; from<=till; from++)
    {
      lcd.setCursor(0, line_cnt);
      lcd.print(menu[from].text);
      line_cnt = line_cnt + 1;
    }
  }
  
  // browsing somewhere in the top or the bottom
  else
  {
    // top of the menu
    if (selected < (from+PER_SPACE))  // 2 lines
    {
      //till = from + 3;
      till = from + (DISPLAY_ROWS-1); // 2 lines
      for (from; from<=till; from++)
      {
        lcd.setCursor(0, line_cnt);
        lcd.print(menu[from].text);
        line_cnt = line_cnt + 1;
      }
    }

    // bottom of the menu
    if (selected == till)
    {
      from = till - (DISPLAY_ROWS-1); // 2 lines
      
      for (from; from<=till; from++)
      {
        lcd.setCursor(0, line_cnt);
        lcd.print(menu[from].text);
        line_cnt = line_cnt + 1;     
      }
    }
  }
  lcd.setCursor(0, selected - from);
  lcd.print(">");
}

void checkButton() {
  // Read the state of digital push buttons
  int buttonEnterState = digitalRead(BUTTON_ENTER);
  int buttonUpState = digitalRead(BUTTON_UP);
  int buttonDownState = digitalRead(BUTTON_DOWN);
  int buttonLeftState = digitalRead(BUTTON_LEFT);

  // Determine which button is pressed based on the state
  if (buttonEnterState == LOW) {
    buttonPressed = 'E';
  } else if (buttonUpState == LOW) {
    buttonPressed = 'U';
  } else if (buttonDownState == LOW) {
    buttonPressed = 'D';
  } else if (buttonLeftState == LOW) {
    buttonPressed = 'L';
  } else {
    buttonPressed = '0';
  }

  processButton(buttonPressed);
}

void processButton(char buttonPressed) {
  switch ( buttonPressed ) {
    case 'E': 
      if (isKeyDisabled) {
      } else {
        if (menu[selected].fp != 0)
        {
          menu[selected].fp();
        }
        prev_key = selected;
        selected = menu[selected].enter;
        show_menu();
      }
      break;
    case 'U': // U
      if (isKeyDisabled) {
      } else {
        prev_key = selected;
        selected = menu[selected].up; 
        show_menu();
      }
      break;
    case 'D': // D
      if (isKeyDisabled) {
      } else {
        prev_key = selected;
        selected = menu[selected].down; 
        show_menu();
      }
      break;
    case 'L': // L
      if (isKeyDisabled) {
        isKeyDisabled = false;
      }
      show_menu();
      break;
    default:
      break;
  }  
}
nano:12
nano:11
nano:10
nano:9
nano:8
nano:7
nano:6
nano:5
nano:4
nano:3
nano:2
nano:GND.2
nano:RESET.2
nano:0
nano:1
nano:13
nano:3.3V
nano:AREF
nano:A0
nano:A1
nano:A2
nano:A3
nano:A4
nano:A5
nano:A6
nano:A7
nano:5V
nano:RESET
nano:GND.1
nano:VIN
nano:12.2
nano:5V.2
nano:13.2
nano:11.2
nano:RESET.3
nano:GND.3
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
btn3:1.l
btn3:2.l
btn3:1.r
btn3:2.r
btn4:1.l
btn4:2.l
btn4:1.r
btn4:2.r
led1:A
led1:C
r1:1
r1:2