#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