commit f4a2c4a7979b338d19bafc237aebd2f19ac30cb9 Author: iansun2 Date: Wed Jun 2 11:40:48 2021 +0800 first upload diff --git a/lcd_menu.cpp b/lcd_menu.cpp new file mode 100644 index 0000000..40c5c72 --- /dev/null +++ b/lcd_menu.cpp @@ -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 \ No newline at end of file diff --git a/lcd_menu.h b/lcd_menu.h new file mode 100644 index 0000000..9eaff1d --- /dev/null +++ b/lcd_menu.h @@ -0,0 +1,360 @@ +#ifndef LCD_MENU_H +#define LCD_MENU_H + + #include + #include + + 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 \ No newline at end of file