/*
  non blocking scrolling on any LCD line
  
  https://forum.arduino.cc/t/help-on-my-simple-lcd-project/1094641/5
 
  2023-02-25 noiasca

  ... and yes I know - that's awful code...

*/

#include <LiquidCrystal_I2C.h>
#include <Wire.h>

LiquidCrystal_I2C lcd(32, 16, 2); // set the LCD address to 0x3F for a 16 chars and 2 line display
int PB = 2;
/*
void scrollMessage(int row, String message, int delayTime, int totalColumns)
{
  for (int i = 0; i < totalColumns; i++)
  {
    message = " " + message;
  }

  message = message + " ";

  for (int position = 0; position < message.length(); position++)
  {
    lcd.setCursor(0, row);
    lcd.print(message.substring(position, position + totalColumns));
    delay(delayTime);
  }
}
*/

struct Scroll {
  String message;
  uint32_t previousMillis = 0;
  uint16_t interval = 250;  // former delayTime
  uint8_t position = 0;
} scroll[2]; // two rows

void scrollMessageSet(byte row, String msg) {
  scroll[row].message = msg;
}

void scrollMessageDo (byte row, uint32_t currentMillis = millis()) {
  if (currentMillis - scroll[row].previousMillis > scroll[row].interval) {
    scroll[row].previousMillis = currentMillis;
    byte totalColumns = 16;   // hardcoded, but you could make an parameter also
    lcd.setCursor(0, row);
    String message;
    for (int i = 0; i < totalColumns; i++) {
      message = " " + message;
    }
    message += scroll[row].message + "  ";
    lcd.print(message.substring(scroll[row].position, scroll[row].position + totalColumns));
    if (scroll[row].position < message.length()) 
      scroll[row].position++; 
    else 
      scroll[row].position = 0; 
  }
}

void setup() {
  pinMode(PB, INPUT_PULLUP);
  lcd.init();
  lcd.clear();
  lcd.backlight();
  for (auto & i : scroll) i.message.reserve(16);
}

void loop() {
  static uint8_t previousButtonState = LOW;
  uint8_t currentButtonState = digitalRead(PB);

  if (previousButtonState == LOW && currentButtonState == HIGH) {
    lcd.setCursor(1, 0);
    lcd.print("Hello World");
    scrollMessageSet (1, "Welcome!");
    delay(50); // dirty delay to debounce
  } else if (previousButtonState == HIGH && currentButtonState == LOW) {
    lcd.clear();
    lcd.setCursor(1, 0);
    lcd.print("Let's begin!");
    delay(50); // dirty delay to debounce
  }
  if (currentButtonState == HIGH) {
    scrollMessageDo(1);  // call the this to let the text scroll
  }
  previousButtonState = currentButtonState; // remember button state for next loop
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r