You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
360 lines
14 KiB
360 lines
14 KiB
#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 |