#define _CRT_SECURE_NO_WARNINGS
#include <Arduino.h>
#include <LiquidCrystal_I2C.h>
typedef void (func_t)();
namespace LcdUi {
enum class EleType : uint8_t {
NONE,
OPT,
TEXT
};
template <uint8_t COL, uint8_t ROW>
class LcdUi_I2C : public LiquidCrystal_I2C {
public:
LcdUi_I2C(uint8_t addr) :
LiquidCrystal_I2C(addr, COL, ROW)
{
for (uint8_t i = 0; i < ROW; i++) {
memset(this->ele[i], 0, ROW);
}
memset(this->ele_type, 0, sizeof(EleType) * ROW);
}
~LcdUi_I2C() = default;
private:
char ele[ROW][COL];
EleType ele_type[ROW];
// which OPT element type is being select
uint8_t sel_opt;
func_t *opt_comm[ROW];
public:
uint8_t set_ele(const char* opt, uint8_t ind, EleType type) {
if (strlen(opt) >= COL || ind >= ROW) return 1;
strncpy(ele[ind], opt, COL - 1);
ele_type[ind] = type;
return 0;
}
void set_opt_comm(func_t command, uint8_t ind) {
opt_comm[ind] = command;
}
void update_ui() {
// set sel_opt to the first OPT element type
for (uint8_t i = 0; i < ROW; i++) {
if (ele_type[i] == EleType::OPT) {
sel_opt = i;
break;
}
}
}
void show_ele() {
// a string buffer use to indicate opt
// that is being select
char sel_opt_str[COL + 1];
for (int8_t i = 0; i < ROW; i++) {
setCursor(0, i);
if (i == sel_opt) {
sprintf(sel_opt_str, ">%s", ele[i]);
print(sel_opt_str);
} else {
print(ele[i]);
}
}
}
void move_up_opt() {
// move up to the closest OPT element type and
// skip other types
for (int8_t i = sel_opt; i >= 0; i--) {
if (ele_type[i] == EleType::OPT) {
sel_opt = i;
}
}
}
void move_down_opt() {
// move down to the closest OPT element type and
// skip other types
for (uint8_t i = sel_opt; i < ROW; i++) {
if (ele_type[i] == EleType::OPT) {
sel_opt = i;
}
}
}
void select_ui_opt() {
opt_comm[sel_opt]();
}
};
}
LcdUi::LcdUi_I2C<20, 4> lcd_ui(0x27);
void command_test() {
Serial.println("Hello");
}
void setup() {
Serial.begin(9600);
lcd_ui.init();
lcd_ui.clear();
lcd_ui.backlight();
lcd_ui.set_ele("Text", 0, LcdUi::EleType::TEXT);
lcd_ui.set_ele("First", 1, LcdUi::EleType::OPT);
lcd_ui.set_opt_comm(command_test, 1);
lcd_ui.set_ele("Second", 2, LcdUi::EleType::OPT);
lcd_ui.update_ui();
lcd_ui.show_ele();
}
void loop() {
delay(1000);
lcd_ui.select_ui_opt();
delay(1000);
lcd_ui.move_down_opt();
lcd_ui.show_ele();
delay(1000);
lcd_ui.move_up_opt();
lcd_ui.show_ele();
}