commit
f4a2c4a797
2 changed files with 564 additions and 0 deletions
@ -0,0 +1,204 @@
|
||||
#ifndef LCD_MENU_C |
||||
#define LCD_MENU_C |
||||
|
||||
#include "lcd_menu.h" |
||||
|
||||
Menu menu; |
||||
LiquidCrystal_I2C lcd(0x27,16, 2); |
||||
|
||||
|
||||
|
||||
//init menu//
|
||||
void Menu::init(uint8_t width, uint8_t height){ |
||||
//Serial.println("=============[init:start]==============");
|
||||
menu_data_head = new menu_data; |
||||
menu_data_end = menu_data_head; |
||||
menu_data_head->next_data = NULL; |
||||
setDataValue(menu_data_head, NULL, NULL, 0, 0); |
||||
setDataIndex(menu_data_head, NULL, 255); |
||||
lcd_width = width; |
||||
lcd_height = height; |
||||
lcd.init(); |
||||
lcd.backlight(); |
||||
//Serial.print("[init]first data index: "); Serial.println(first_data_idx);
|
||||
//Serial.println("=============[init:end]==============");
|
||||
} |
||||
|
||||
//add element//
|
||||
void Menu::add(uint8_t new_gid, uint8_t new_id, const __FlashStringHelper* new_title){ |
||||
//Serial.println("=============[add:start]==============");
|
||||
//Serial.print("[add]static: "); Serial.println(new_title);
|
||||
menu_data* new_data = getInsertDataAddress(new_gid, new_id); |
||||
//Serial.print("[add]: "); Serial.println(unsigned(new_data));
|
||||
setDataValue(new_data, new_title, NULL, new_gid, new_id); |
||||
//debugPrint(new_data);
|
||||
|
||||
updateScreen(); |
||||
//Serial.println("=============[add:end]==============\n");
|
||||
} |
||||
|
||||
//add element//
|
||||
void Menu::add(uint8_t new_gid, uint8_t new_id, const char* new_title){ |
||||
//Serial.println("=============[add:start]==============");
|
||||
//Serial.print("[add]dynamic: "); Serial.println(new_title);
|
||||
menu_data* new_data = getInsertDataAddress(new_gid, new_id); |
||||
//Serial.print("[add]: "); Serial.println(unsigned(new_data));
|
||||
setDataValue(new_data, NULL , new_title, new_gid, new_id); |
||||
//debugPrint(new_data);
|
||||
|
||||
updateScreen(); |
||||
//Serial.println("=============[add:end]==============\n");
|
||||
} |
||||
|
||||
//link element to group//
|
||||
void Menu::link(uint8_t src_gid, uint8_t src_id, uint8_t dst_gid){ |
||||
//Serial.println("=======================");
|
||||
menu_data* data_src = getDataAddress(src_gid, src_id); |
||||
data_src->sub_group = dst_gid; |
||||
getDataAddress(data_src->sub_group,0)->parent = data_src; |
||||
menu_data* finder = getDataAddress(data_src->sub_group,0); |
||||
//Serial.print("[link]src gid: "); //Serial.print(src_gid); //Serial.print(" id: "); //Serial.println(src_id);
|
||||
//debugPrint(data_src);
|
||||
//Serial.print("[link]dst gid: "); //Serial.println(dst_gid);
|
||||
//debugPrint(data_src->sub_group);
|
||||
do{ |
||||
finder->parent = data_src; |
||||
finder = getNextMemberAddress(finder); |
||||
}while(finder != NULL); |
||||
//Serial.println("=======================");
|
||||
} |
||||
|
||||
//remove element//
|
||||
void Menu::remove(uint8_t del_gid, uint8_t del_id){ |
||||
//Serial.println("=============[remove:start]==============");
|
||||
menu_data* group_head = getDataAddress(del_gid, 0); |
||||
menu_data* del_data = getDataAddress(del_gid, del_id); |
||||
menu_data* next_del_data = del_data; |
||||
|
||||
//if del all group, show parent
|
||||
if(del_data == group_head && screen_select_line->gid == del_data->gid){ |
||||
//Serial.println("[Remove]del group");
|
||||
back(); |
||||
} |
||||
//if del screen top line or screen select line
|
||||
if(screen_top_line == del_data){ |
||||
//Serial.println("[Remove]change top line");
|
||||
//show pre data
|
||||
if(getPreMemberAddress(screen_top_line) != NULL){ |
||||
screen_top_line = getPreMemberAddress(screen_top_line); |
||||
//show next data
|
||||
}else if(getNextMemberAddress(screen_top_line) != NULL){ |
||||
screen_top_line = getNextMemberAddress(screen_top_line); |
||||
} |
||||
} |
||||
if(screen_select_line == del_data){ |
||||
//Serial.println("[Remove]change select line");
|
||||
//show pre data
|
||||
if(getPreMemberAddress(screen_select_line) != NULL){ |
||||
screen_select_line = getPreMemberAddress(screen_select_line); |
||||
//show next data
|
||||
}else if(getNextMemberAddress(screen_select_line) != NULL){ |
||||
screen_select_line = getNextMemberAddress(screen_select_line); |
||||
} |
||||
} |
||||
|
||||
//Serial.print("[Remove]: "); Serial.println((unsigned)del_data);
|
||||
//if del group head, del this group
|
||||
if(del_data == group_head){ |
||||
//Serial.println("[Remove]del group");
|
||||
do{ |
||||
del_data = next_del_data; |
||||
next_del_data = getNextMemberAddress(next_del_data); |
||||
//Serial.print("[Remove]: "); Serial.println((unsigned)del_data);
|
||||
deleteData(del_data); |
||||
}while(next_del_data != NULL); |
||||
}else{ |
||||
deleteData(del_data); |
||||
} |
||||
updateScreen(); |
||||
//Serial.println("=============[remove:end]==============");
|
||||
} |
||||
|
||||
//start menu//
|
||||
void Menu::start(){ |
||||
//Serial.println("[start]start");
|
||||
menu_started = 1; |
||||
initScreenHead(0); |
||||
} |
||||
|
||||
//rollup//
|
||||
void Menu::rollUp(){ |
||||
//Serial.println("[rollup]start");
|
||||
//if can rollup
|
||||
if(getPreMemberAddress(screen_select_line) != NULL){ |
||||
screen_select_line = getPreMemberAddress(screen_select_line); |
||||
//Serial.print("[rollup]select_line: "); Serial.println((unsigned)screen_select_line);
|
||||
} |
||||
updateScreen(); |
||||
//printf("[rollup] end\n");
|
||||
} |
||||
|
||||
//rolldown//
|
||||
void Menu::rollDown(){ |
||||
//Serial.println("[rolldown]start");
|
||||
//if only one member
|
||||
if(getNextMemberAddress(screen_select_line) != NULL){ |
||||
screen_select_line = getNextMemberAddress(screen_select_line); |
||||
} |
||||
updateScreen(); |
||||
} |
||||
|
||||
//back to parent element//
|
||||
void Menu::back(){ |
||||
screen_select_line = screen_select_line->parent; |
||||
screen_top_line = screen_select_line; |
||||
updateScreen(); |
||||
} |
||||
|
||||
//enter select element//
|
||||
void Menu::enter(){ |
||||
//Serial.println("[enter]start");
|
||||
//soft back
|
||||
String buffer; |
||||
|
||||
if(screen_select_line->dynamic_title != NULL){ |
||||
buffer = screen_select_line->dynamic_title; |
||||
}else if(screen_select_line->static_title != NULL){ |
||||
buffer = screen_select_line->static_title; |
||||
} |
||||
|
||||
menu_select_gid = screen_select_line->gid; |
||||
menu_select_id = screen_select_line->id; |
||||
if(soft_back){ |
||||
if(!buffer.compareTo("...")){ |
||||
back(); |
||||
onSelect(); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
if(screen_select_line->sub_group != 255){ |
||||
screen_select_line = getDataAddress(screen_select_line->sub_group,0); |
||||
screen_top_line = screen_select_line; |
||||
} |
||||
updateScreen(); |
||||
onSelect(); |
||||
} |
||||
|
||||
//check select element//
|
||||
bool Menu::checkSelect(uint8_t dst_gid, uint8_t dst_id){ |
||||
if(dst_gid == menu_select_gid && dst_id == menu_select_id){ |
||||
return 1; |
||||
}else{ |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
//jump to group//
|
||||
void Menu::jump(uint8_t dst_gid, uint8_t dst_id){ |
||||
screen_top_line = getDataAddress(dst_gid, dst_id); |
||||
screen_select_line = screen_top_line; |
||||
updateScreen(); |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,360 @@
|
||||
#ifndef LCD_MENU_H |
||||
#define LCD_MENU_H |
||||
|
||||
#include <LiquidCrystal_I2C.h> |
||||
#include <Arduino.h> |
||||
|
||||
extern LiquidCrystal_I2C lcd; |
||||
|
||||
class Menu{ |
||||
public: |
||||
|
||||
//init
|
||||
void init(uint8_t width, uint8_t height); |
||||
|
||||
//add
|
||||
void add(uint8_t new_gid, uint8_t new_id, const __FlashStringHelper* new_title); |
||||
void add(uint8_t new_gid, uint8_t new_id, const char* new_title); |
||||
|
||||
//link
|
||||
void link(uint8_t src_gid, uint8_t src_id, uint8_t dst_gid); |
||||
|
||||
//remove
|
||||
void remove(uint8_t del_gid, uint8_t del_id); |
||||
|
||||
//onSelect
|
||||
void onSelect(); |
||||
|
||||
//start
|
||||
void start(); |
||||
|
||||
//rollUp
|
||||
void rollUp(); |
||||
|
||||
//rollDown
|
||||
void rollDown(); |
||||
|
||||
//back
|
||||
void back(); |
||||
|
||||
//enter
|
||||
void enter(); |
||||
|
||||
//checkSelect
|
||||
bool checkSelect(uint8_t check_gid, uint8_t check_id); |
||||
|
||||
//jump
|
||||
void jump(uint8_t dst_gid, uint8_t dst_id); |
||||
|
||||
//softBack
|
||||
//if set to 1, title = "..." be selected will call back() function
|
||||
bool soft_back = 0; |
||||
|
||||
|
||||
private: |
||||
|
||||
//if menu start() function have be called, set to 1
|
||||
bool menu_started = 0; |
||||
|
||||
//now select gid
|
||||
uint8_t menu_select_gid = 0; |
||||
|
||||
//now select id
|
||||
uint8_t menu_select_id = 0; |
||||
|
||||
//lcd size
|
||||
uint8_t lcd_height = 0; |
||||
uint8_t lcd_width = 0; |
||||
|
||||
//data struct
|
||||
struct menu_data{ |
||||
const __FlashStringHelper* static_title; |
||||
const char* dynamic_title; |
||||
uint8_t gid; |
||||
uint8_t id; |
||||
menu_data* parent; |
||||
uint8_t sub_group; |
||||
menu_data* next_data; |
||||
}; |
||||
|
||||
menu_data* menu_data_head; |
||||
menu_data* menu_data_end; |
||||
|
||||
menu_data* screen_top_line = 0; |
||||
menu_data* screen_select_line = 0; |
||||
|
||||
|
||||
//function//
|
||||
|
||||
//set data value
|
||||
//input data addr & new value
|
||||
//no return
|
||||
void setDataValue(menu_data* dst_data, const __FlashStringHelper* static_title, const char* dynamic_title, uint8_t new_gid, uint8_t new_id){ |
||||
dst_data->static_title = static_title; |
||||
dst_data->dynamic_title = dynamic_title; |
||||
dst_data->gid = new_gid; |
||||
dst_data->id = new_id; |
||||
} |
||||
|
||||
//set data index
|
||||
//input data addr & new index
|
||||
//no return
|
||||
void setDataIndex(menu_data* dst_data, menu_data* new_parent, uint8_t new_sub_group){ |
||||
dst_data->parent = new_parent; |
||||
dst_data->sub_group = new_sub_group; |
||||
} |
||||
|
||||
//add new data
|
||||
//no input
|
||||
//return new data address
|
||||
menu_data* addData(){ |
||||
//Serial.print("[add_data]old menu_end: "); Serial.println((unsigned)menu_data_end);
|
||||
menu_data* new_data = new menu_data; |
||||
menu_data_end->next_data = new_data; |
||||
new_data->next_data = NULL; |
||||
menu_data_end = new_data; |
||||
//Serial.print("[add_data]new data: "); Serial.println((unsigned)new_data);
|
||||
//Serial.print("[add_data]new menu_end: "); Serial.println((unsigned)menu_data_end);
|
||||
return new_data; |
||||
} |
||||
|
||||
//get data address
|
||||
//input gid
|
||||
//return data address which gid & id match
|
||||
menu_data* getDataAddress(uint8_t dst_gid, uint8_t dst_id){ |
||||
//find match data
|
||||
menu_data* finder = menu_data_head; |
||||
while(finder != NULL){ |
||||
if(finder->gid == dst_gid && finder->id == dst_id){ |
||||
return finder; |
||||
} |
||||
finder = finder->next_data; |
||||
} |
||||
|
||||
//cannot find group
|
||||
return NULL; |
||||
} |
||||
|
||||
//get data pre address
|
||||
//input data address
|
||||
//return data pre address
|
||||
menu_data* getPreMemberAddress(menu_data* dst_data){ |
||||
menu_data* finder = menu_data_head; |
||||
menu_data* pre_data = NULL; |
||||
uint8_t pre_data_id = 0; |
||||
|
||||
do{ |
||||
//if finder->gid match && pre_data_id < finder->id < dst_data->id
|
||||
//Serial.print("[gpma]finder: "); Serial.println((unsigned)finder);
|
||||
//Serial.print("[gpma]q1 "); Serial.println((unsigned)finder->gid == dst_data->gid);
|
||||
//Serial.print("[gpma]q2 "); Serial.println((unsigned)finder->id < dst_data->id);
|
||||
//Serial.print("[gpma]q3 "); Serial.println((unsigned)finder->id >= pre_data_id);
|
||||
if(finder->gid == dst_data->gid && finder->id < dst_data->id && finder->id >= pre_data_id){ |
||||
pre_data = finder; |
||||
pre_data_id = finder->id; |
||||
}
|
||||
finder = finder->next_data; |
||||
}while(finder != NULL); |
||||
|
||||
return pre_data; |
||||
} |
||||
|
||||
//get data pre address
|
||||
//input data address
|
||||
//return data pre address
|
||||
menu_data* getNextMemberAddress(menu_data* dst_data){ |
||||
menu_data* finder = menu_data_head; |
||||
menu_data* next_data = NULL; |
||||
uint8_t next_data_id = 255; |
||||
|
||||
do{ |
||||
//if finder->gid match && pre_data_id < finder->id < dst_data->id
|
||||
//Serial.print("[gnma]finder: "); Serial.println((unsigned)finder);
|
||||
//Serial.print("[gnma]q1 "); Serial.println((unsigned)finder->gid == dst_data->gid);
|
||||
//Serial.print("[gnma]q2 "); Serial.println((unsigned)finder->id > dst_data->id);
|
||||
//Serial.print("[gnma]q3 "); Serial.println((unsigned)finder->id < next_data_id);
|
||||
if(finder->gid == dst_data->gid && finder->id > dst_data->id && finder->id <= next_data_id){ |
||||
next_data = finder; |
||||
next_data_id = finder->id; |
||||
} |
||||
finder = finder->next_data; |
||||
}while(finder != NULL); |
||||
|
||||
return next_data; |
||||
} |
||||
|
||||
//delete data
|
||||
//input del data address
|
||||
//no return
|
||||
void deleteData(menu_data* del_data){ |
||||
//if del group, clear parent's sub group
|
||||
if(del_data->parent != NULL && del_data->id == 0){ |
||||
//Serial.println("[delD]del_group");
|
||||
del_data->parent->sub_group = 255; |
||||
} |
||||
menu_data* finder = menu_data_head; |
||||
//loop until finder->next_data = del_data
|
||||
while(finder->next_data != del_data){ |
||||
finder = finder->next_data; |
||||
} |
||||
//set finder->next_data to del_data->next_data
|
||||
finder->next_data = del_data->next_data; |
||||
|
||||
if(finder->next_data == NULL){ |
||||
menu_data_end = finder; |
||||
} |
||||
|
||||
delete del_data; |
||||
} |
||||
|
||||
//get insert data addr
|
||||
//input gid, id
|
||||
//return new data address
|
||||
menu_data* getInsertDataAddress(uint8_t new_gid, uint8_t new_id){ |
||||
//Serial.print("[gida]start: "); Serial.print(new_gid); Serial.print(" "); Serial.println(new_id);
|
||||
menu_data* finder = getDataAddress(new_gid, 0); |
||||
menu_data* new_data; |
||||
//Serial.print("[gida]group_head: "); Serial.println((unsigned)finder);
|
||||
|
||||
//group not exist
|
||||
if(finder == NULL){ |
||||
//Serial.println("[gida]not exist");
|
||||
//add at data end
|
||||
new_data = addData(); |
||||
setDataIndex(new_data, NULL, 255); |
||||
return new_data; |
||||
|
||||
//normal
|
||||
}else{ |
||||
do{ |
||||
//Serial.print("[gida]finder: "); Serial.println((unsigned)finder);
|
||||
//insert at exist data
|
||||
if(finder->id == new_id){ |
||||
//Serial.println("[gida]exist");
|
||||
return finder; |
||||
} |
||||
|
||||
//insert at group end
|
||||
if(finder->next_data == NULL){ |
||||
//Serial.println("[gida]at end");
|
||||
new_data = addData(); |
||||
setDataIndex(new_data, finder->parent, 255); |
||||
return new_data; |
||||
|
||||
//insert between two data
|
||||
}else if(new_id < finder->id){ |
||||
//Serial.println("[gida]between");
|
||||
//set new data
|
||||
new_data = addData(); |
||||
setDataIndex(new_data, finder->parent, 255); |
||||
return new_data; |
||||
|
||||
//go to next memeber
|
||||
}else{ |
||||
finder = getNextMemberAddress(finder); |
||||
//Serial.print("[gida]new_finder: "); Serial.println((unsigned)finder);
|
||||
} |
||||
}while(finder != NULL); |
||||
} |
||||
//Serial.println("[gida]error");
|
||||
return NULL; |
||||
} |
||||
|
||||
//update screen function
|
||||
//no input
|
||||
//no return
|
||||
void updateScreen(){ |
||||
//if menu doesn't start
|
||||
if(!menu_started){ |
||||
//Serial.println("[updsc]not start");
|
||||
return; |
||||
} |
||||
|
||||
//Serial.println("[updsc]start");
|
||||
lcd.clear(); |
||||
|
||||
menu_data* finder = getDataAddress(screen_top_line->gid, 0); |
||||
uint8_t members = 0; |
||||
uint8_t top_line_order = 0; |
||||
uint8_t select_line_order = 0; |
||||
|
||||
//count group element quantity
|
||||
while(finder != NULL){ |
||||
members ++; |
||||
if(finder == screen_top_line){ |
||||
top_line_order = (members - 1); |
||||
} |
||||
if(finder == screen_select_line){ |
||||
select_line_order = (members - 1); |
||||
} |
||||
finder = getNextMemberAddress(finder); |
||||
} |
||||
|
||||
if((top_line_order + lcd_height - 1) < select_line_order){ |
||||
screen_top_line = getNextMemberAddress(screen_top_line); |
||||
top_line_order ++; |
||||
} |
||||
if(top_line_order > select_line_order){ |
||||
screen_top_line = getPreMemberAddress(screen_top_line); |
||||
top_line_order --; |
||||
} |
||||
|
||||
|
||||
|
||||
//Serial.print("[updsc]quantity: "); Serial.println(member_quantity);
|
||||
//Serial.print("[updsc]top line order: "); Serial.println(top_line_order);
|
||||
//Serial.print("[updsc]select: "); Serial.println(menu_select);
|
||||
finder = screen_top_line; |
||||
for(uint8_t now_line = 0; now_line < lcd_height; now_line++){ |
||||
if(finder != NULL){ |
||||
//debugPrint(line_data);
|
||||
//Serial.print("[updsc]show: "); Serial.println(line_data->dynamic_title);
|
||||
//Serial.print("[updsc]now line: "); Serial.println(now_line);
|
||||
if((now_line + top_line_order) == select_line_order){ |
||||
//Serial.println("[updsc]select");
|
||||
lcd.setCursor(0,now_line); |
||||
lcd.print(">"); |
||||
} |
||||
lcd.setCursor(1,now_line); |
||||
if(finder->dynamic_title != NULL){ |
||||
lcd.print(finder->dynamic_title); |
||||
}else if(finder->static_title != NULL){ |
||||
lcd.print(finder->static_title); |
||||
}else{ |
||||
lcd.print(""); |
||||
} |
||||
}else{ |
||||
break; |
||||
} |
||||
//Serial.println((unsigned)line_data->next_member);
|
||||
finder = getNextMemberAddress(finder); |
||||
} |
||||
} |
||||
|
||||
//init screen head function
|
||||
//input gid
|
||||
//no return
|
||||
void initScreenHead(uint8_t dst_gid){ |
||||
screen_top_line = getDataAddress(dst_gid, 0); |
||||
screen_select_line = screen_top_line; |
||||
////Serial.println(menu_line_0->title);
|
||||
////Serial.println(menu_line_1->title);
|
||||
updateScreen(); |
||||
} |
||||
|
||||
|
||||
void debugPrint(menu_data* dst_data){ |
||||
//Serial.println("=============[debug:start]==============");
|
||||
//Serial.print("[debug]addr: "); Serial.println(unsigned(dst_data));
|
||||
//Serial.print("[debug]sub_group: "); Serial.println((unsigned)dst_data->sub_group);
|
||||
//Serial.print("[debug]parent: "); Serial.println((unsigned)dst_data->parent);
|
||||
//Serial.print("[debug]pre_member: "); Serial.println((unsigned)getPreMemberAddress(dst_data));
|
||||
//Serial.print("[debug]next_member: "); Serial.println((unsigned)getNextMemberAddress(dst_data));
|
||||
//Serial.print("[debug]next_data: "); Serial.println((unsigned)dst_data->next_data);
|
||||
//Serial.println("=============[debug:end]==============");
|
||||
} |
||||
}; |
||||
|
||||
extern Menu menu; |
||||
|
||||
#endif |
Loading…
Reference in new issue