Add menu items with function?
Closed this issue · 2 comments
Hello, I was curious if it is possible to create menu items programmatically by using a function. One section of my menu I want to be the names of files on an SD card (which will be limited), which I only know at runtime. This is something that would only happen once in the program's lifetime.
Hi,
at the moment it is not possible because some items are saved in flash (PROGMEM), not in ram. I check tomorrow, if i can create a dynamic menu function, thats locks like a tree.
In next beta i add an example for dynamic lists with scrollbars. The current code is not perfektly commented. It can be that there are variables without a function. I have no time to optimaze the code.
I hope the code can help.
DISP function code looks like this.
// this needs some bytes in ram
#define MAX_FILES_IN_LIST 20
uint8_t scroll_row;
uint8_t cursor_real_pos;
uint8_t current_max_list_count;
uint8_t cursor_position_cur;
char file_name_buffer[20];
static char filelist[MAX_FILES_IN_LIST][20];
// *********************************************************************
void LCDML_DISP_setup(LCDML_FUNC_list_files)
// *********************************************************************
{
// set max file counter
current_max_list_count = 0;
// set current cursor position
cursor_position_cur = 0;
//
scroll_row = 0;
cursor_real_pos = 0;
// read sd card files here
uint8_t n=0;
// for example, here with a for loop
for(uint8_t i = 0; i<10; i++) {
if(i < MAX_FILES_IN_LIST) {
memcpy(filelist[i], "File .txt", 10);
filelist[i][5] = i+48;
current_max_list_count++;
}
}
}
void LCDML_DISP_loop(LCDML_FUNC_list_files)
{
// loop function, can be run in a loop when LCDML_DISP_triggerMenu(xx) is set
// the quit button works in every DISP function without any checks; it starts the loop_end function
uint8_t n_max = (current_max_list_count >= _LCDML_DISP_rows) ? _LCDML_DISP_rows : (current_max_list_count);;
uint8_t scrollbar_min = 0;
uint8_t scrollbar_max = current_max_list_count;
//uint8_t scrollbar_cur_pos = cursor_position_cur;
uint8_t scroll_pos = ((1.*n_max * _LCDML_DISP_rows) / (scrollbar_max - 1) * cursor_position_cur);
// clear display
// ================
lcd.clear();
// display content
// ==================
for (uint8_t n = scroll_row; n < (scroll_row+_LCDML_DISP_rows); n++)
{
// set cursor
lcd.setCursor(1, n-scroll_row);
// set content
lcd.print(filelist[n]);
}
// set cursor and scrollbar
// =============================
for (uint8_t n = scroll_row; n <(scroll_row+_LCDML_DISP_rows); n++)
{
lcd.setCursor(0, n-scroll_row);
// set cursor
// =====================
if (n == cursor_position_cur) {
lcd.write(_LCDML_DISP_cfg_cursor);
cursor_real_pos = n-scroll_row;
} else {
lcd.write(' ');
}
// display scrollbar
// ==============================
// delete or reset scrollbar
if (scrollbar_max > n_max) {
lcd.setCursor((_LCDML_DISP_cols - 1), n-scroll_row);
lcd.write((uint8_t)0);
}
else {
lcd.setCursor((_LCDML_DISP_cols - 1), n-scroll_row);
lcd.print(' ');
}
// set scrollbar
if (scrollbar_max > n_max) {
//set scroll position
if (cursor_position_cur == scrollbar_min) {
// min pos
lcd.setCursor((_LCDML_DISP_cols - 1), 0);
lcd.write((uint8_t)1);
} else if (cursor_position_cur == (scrollbar_max - 1)) {
// max pos
lcd.setCursor((_LCDML_DISP_cols - 1), (n_max - 1));
lcd.write((uint8_t)4);
} else {
// between
lcd.setCursor((_LCDML_DISP_cols - 1), scroll_pos / n_max);
lcd.write((uint8_t)(scroll_pos % n_max) + 1);
}
}
}
// control
// =====================================
if(LCDML_BUTTON_checkUp()) {
LCDML_BUTTON_resetAll();
// scroll up
if(cursor_position_cur > 0) {
cursor_position_cur--;
if(cursor_real_pos == 0) {
scroll_row--;
}
}
// update content above or remove this line and copy button checks on top of this function
LCDML_BACK_start(LCDML_BACKEND_menu);
}
if(LCDML_BUTTON_checkDown()) {
LCDML_BUTTON_resetAll();
// scroll down
if(cursor_position_cur < (current_max_list_count-1)) {
cursor_position_cur++;
if(cursor_position_cur > (_LCDML_DISP_rows-1)) {
scroll_row++;
}
}
// update content above or remove this line and copy button checks on top of this function
LCDML_BACK_start(LCDML_BACKEND_menu);
}
if(LCDML_BUTTON_checkEnter()) {
LCDML_BUTTON_resetAll();
// save selected file (serial.print)
LCDML_DISP_funcend();
// output of current line
Serial.println(filelist[cursor_position_cur]);
}
}
void LCDML_DISP_loop_end(LCDML_FUNC_list_files)
{
// this functions is ever called when a DISP function is quit
// you can here reset some global vars or do nothing
// Display selected file name
}