diff --git a/Csource/README.md b/Csource/README.md index 0f47163..06257d1 100644 --- a/Csource/README.md +++ b/Csource/README.md @@ -8,4 +8,4 @@ |---UITest(页面展示的例子,基本上所有页面类型都有用到) |---src(主要的源代码文件,7个文件,不包含oled_port.c) ``` - +需要注意,本文件夹中的文件会持续更新到每个小版本。 diff --git a/Csource/example/LittleClock/LittleClockUI.c b/Csource/example/LittleClock/LittleClockUI.c index d5526d3..54094e1 100644 --- a/Csource/example/LittleClock/LittleClockUI.c +++ b/Csource/example/LittleClock/LittleClockUI.c @@ -1,26 +1,22 @@ #include "LittleClockUI.h" #include "string.h" -#include "System.h" -#include "BATADC.h" +#include "../WouoUIPage/oled_ui.h" +#include "time.h" + +//-------两个闹钟(结合time.h实现的闹钟) +#define CLEAR_FLAG(flag,msk) ((flag)&=(~msk)) +#define SET_FLAG(flag,msk) ((flag)|=(msk)) +#define FLAG_IS_SET(flag,msk) ((flag&msk) == msk) +#define ALARM1_ENABLE_MSK 0x01 +#define ALARM2_ENABLE_MSK 0x02 +#define ALARM1_UPDATE_MSK 0x10 +#define ALARM2_UPDATE_MSK 0x20 +uint8_t alarm_flag = 0x00; //闹钟是否开启的标志位 +struct tm alarm1,alarm2; +void Set_Alarm(struct tm* alarm,DigitalPage* alarm_page,uint8_t flag); +void Check_Alarm(struct tm* alarm,DigitalPage* alarm_page,uint8_t flag); -//定义的跨文件的全局变量 -uint16_t fps = 0; //帧率 -uint8_t update_flag = 0; - -//-------枚举id,唯一标识一个页面,防止有两个页面使用同一id -enum -{ - main_page_id = 0x00, - calendar_page_id, - clock_page_id, - alarm_list_page_id, - alarm1_page_id, - alarm2_page_id, - about_page_id, - - ring_page_id, //这个页面是单独游离的,只有闹钟时才会调出来 -}; //--------定义页面对象 TitlePage main_page; DigitalPage calendar_page; @@ -134,8 +130,6 @@ Option alarm2_option_array[3]= [Digital_Pos_IndexLeft] = { .item_max = 23, .item_min = 0, .step = 1, .text = "Hour"}, [Digital_Pos_IndexMid] = { .item_max = 59, .item_min = 0, .step = 1, .text = "Minute"}, [Digital_Pos_IndexRight] = { .item_max = 59, .item_min = 0, .step = 0, .text = "Second"}, - //DS3231只有两个闹钟,且闹钟2的秒无效,所以alarm2的step为0,为不可编辑模式 - //(因为air001的内存不够,也不想做软件闹钟了) }; String alarm12_label_array[3] = { "Close", "Open", "Delete"}; @@ -174,49 +168,22 @@ RaderPic qrcode_raderpic[ABOUT_PAGE_NUM] = }; //--------定义每个页面的回调函数 -void MainPage_CallBack(uint8_t self_page_id,Option* select_item) +void MainPage_CallBack(const Page* cur_page_addr,Option* select_item) { switch (select_item->order) { - case 0: OLED_UIJumpToPage(self_page_id,&calendar_page); break; - case 1: OLED_UIJumpToPage(self_page_id,&clock_page); break; - case 2: OLED_UIJumpToPage(self_page_id,&alarm_list_page); break; + case 0: OLED_UIJumpToPage((PageAddr)cur_page_addr,&calendar_page); break; + case 1: OLED_UIJumpToPage((PageAddr)cur_page_addr,&clock_page); break; + case 2: OLED_UIJumpToPage((PageAddr)cur_page_addr,&alarm_list_page); break; case 3: //更新电量 - select_item->val = BATADC_Read(); + select_item->val = 50; break; - case 4: OLED_UIJumpToPage(self_page_id,&about_page); break; + case 4: OLED_UIJumpToPage((PageAddr)cur_page_addr,&about_page); break; default: break; } } -void CalendarPage_CallBack(uint8_t self_page_id,Option* select_item) -{ - uint8_t month_days[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; - switch (select_item->order) - { - case Digital_Pos_Complete : //全部数据设置完成后,也会检测一次数据 - SET_FLAG(update_flag,DATE_UPDATE_MSK); //同时会通知main函数设置rtc芯片 - case Digital_Pos_IndexRight: //更正日期数据 - if( calendar_page.option_array[Digital_Pos_IndexRight].val > //大于每个月的最大月数,更正日期 - month_days[calendar_page.option_array[Digital_Pos_IndexMid].val -1]) - OLED_DigitalPage_UpdateDigitalNumAnimation(&calendar_page, - calendar_page.option_array[Digital_Pos_IndexLeft].val, - calendar_page.option_array[Digital_Pos_IndexMid].val, - month_days[calendar_page.option_array[Digital_Pos_IndexMid].val -1], Digital_Direct_Decrease); - break; - default:break; - } - -} - -void ClockPage_CallBack(uint8_t self_page_id,Option* select_item) -{ - if(select_item->order == Digital_Pos_Complete) //时间设置完成 - SET_FLAG(update_flag,TIME_UPDATE_MSK); //通知主函数更新时间 -} - - -void AlarmList_CallBack(uint8_t self_page_id,Option* select_item) +void AlarmList_CallBack(const Page* cur_page_addr,Option* select_item) { switch (select_item->order) { @@ -224,40 +191,38 @@ void AlarmList_CallBack(uint8_t self_page_id,Option* select_item) // OLED_UIJumpToPage(self_page_id, &ring_page); //只是作为绘制页面的跳转测试 // break; case 1: - OLED_UIJumpToPage(self_page_id, &alarm1_page); - //设置其标签 - alarm1_page.select_label_index = (!!FLAG_IS_SET(update_flag, ALARM1_ENABLE_MSK)); //将数值变量转为逻辑 + OLED_UIJumpToPage((PageAddr)cur_page_addr, &alarm1_page); break; case 2: - OLED_UIJumpToPage(self_page_id, &alarm2_page); - alarm2_page.select_label_index = (!!FLAG_IS_SET(update_flag, ALARM2_ENABLE_MSK)); //将数值变量转为逻辑 + OLED_UIJumpToPage((PageAddr)cur_page_addr, &alarm2_page); break; default :break; } } -void Alarm12_CallBack(uint8_t self_page_id,Option* select_item) +void Alarm12_CallBack(const Page* cur_page_addr,Option* select_item) { uint8_t update_msk = 0; uint8_t enable_msk = 0; - if(self_page_id == alarm1_page_id){update_msk = ALARM1_UPDATE_MSK;enable_msk = ALARM1_ENABLE_MSK;} - else if(self_page_id == alarm2_page_id){update_msk = ALARM2_UPDATE_MSK;enable_msk = ALARM2_ENABLE_MSK;} + if((DigitalPage*)cur_page_addr == &alarm1_page){update_msk = ALARM1_UPDATE_MSK;enable_msk = ALARM1_ENABLE_MSK;} + else if((DigitalPage*)cur_page_addr == &alarm2_page){update_msk = ALARM2_UPDATE_MSK;enable_msk = ALARM2_ENABLE_MSK;} switch (select_item->order) { case Digital_Pos_Complete: //编辑完成 - SET_FLAG(update_flag, update_msk); + SET_FLAG(alarm_flag, update_msk); break; case Digital_Pos_IndexLabel: //click标签时 if(strcmp(select_item->text, alarm12_label_array[0]) == 0) //close - CLEAR_FLAG(update_flag,enable_msk); + CLEAR_FLAG(alarm_flag,enable_msk); else if(strcmp(select_item->text, alarm12_label_array[1]) == 0) //open - SET_FLAG(update_flag,enable_msk); - else if(strcmp(select_item->text, alarm12_label_array[2]) == 0) //Delete + SET_FLAG(alarm_flag,enable_msk); + else + if(strcmp(select_item->text, alarm12_label_array[2]) == 0) //Delete { - CLEAR_FLAG(update_flag,enable_msk); //闹钟标志位关闭 - if(self_page_id == alarm1_page_id) + CLEAR_FLAG(alarm_flag,enable_msk); //闹钟标志位关闭 + if((DigitalPage*)cur_page_addr == &alarm1_page) OLED_DigitalPage_UpdateDigitalNumAnimation(&alarm1_page, 0,0,0,Digital_Direct_Decrease); - else if(self_page_id == alarm2_page_id) + else if((DigitalPage*)cur_page_addr == &alarm2_page) OLED_DigitalPage_UpdateDigitalNumAnimation(&alarm2_page, 0,0,0,Digital_Direct_Decrease); } default: @@ -266,10 +231,9 @@ void Alarm12_CallBack(uint8_t self_page_id,Option* select_item) } -void About_CallBack(uint8_t self_page_id,Option* select_item) +void About_CallBack(const Page* cur_page_addr,Option* select_item) { uint8_t buff[10] = {0}; - sprintf((char*)buff, "fps:%d",fps); if(select_item->order == ABOUT_PAGE_NUM) //图像绘制完成后 { OLED_WinDrawStr(&w_all, 64, 7, 16, buff); @@ -278,7 +242,7 @@ void About_CallBack(uint8_t self_page_id,Option* select_item) } } -void Ring_CallBack(uint8_t self_page_id,Option* select_item) +void Ring_CallBack(const Page* cur_page_addr,Option* select_item) { static float x = 2; static float x_trg = 12; @@ -294,12 +258,14 @@ void Ring_CallBack(uint8_t self_page_id,Option* select_item) if(x_trg == 12){x_trg = 2;color =! color;} else if(x_trg == 2){x_trg = 12;color =! color;} } - if(FLAG_IS_SET(update_flag, ALARM1_RING_MSK)) + uint8_t ALARM1_RING_MSK = ALARM1_ENABLE_MSK<<2; + uint8_t ALARM2_RING_MSK = ALARM2_ENABLE_MSK<<2; + if(FLAG_IS_SET(alarm_flag,ALARM1_RING_MSK)) OLED_WinDrawStr(&w_all, 60, 8, 16, "Alarm1"); - else if((FLAG_IS_SET(update_flag, ALARM2_RING_MSK))) + else if(FLAG_IS_SET(alarm_flag,ALARM2_RING_MSK)) OLED_WinDrawStr(&w_all, 60, 8, 16, "Alarm2"); - OLED_WinDrawStr(&w_all, 60, 34, 8, "Press Any"); - OLED_WinDrawStr(&w_all, 60, 44, 8, "Key to exit!"); + OLED_WinDrawStr(&w_all, 60, 34, 8, (uint8_t*)"Press Any"); + OLED_WinDrawStr(&w_all, 60, 44, 8, (uint8_t*)"Key to exit!"); } @@ -309,30 +275,95 @@ void Ring_CallBack(uint8_t self_page_id,Option* select_item) void LittleClockUI_Init(void) { - OLED_Init(); //硬件的初始化 - LL_mDelay(100); + // OLED_Init(); //硬件的初始化 + // LL_mDelay(100); OLED_ClearBuff(); //清空缓存 OLED_RefreshBuff(); //刷新屏幕(清空屏幕) OLED_SetPointColor(1); //设置绘制颜色 - OLED_UiInit(); //必要的ui参数初始化 - OLED_TitlePageInit(&main_page, main_page_id, MAIN_PAGE_NUM, mian_option_array, main_icon_array, MainPage_CallBack); - OLED_DigitalPageInit(&calendar_page, calendar_page_id, calendar_option_array, CALENDAR_LABEL_NUM, week_str, '-', 0, 100, CalendarPage_CallBack); - OLED_DigitalPageInit(&clock_page, clock_page_id, clock_option_array, CALENDAR_LABEL_NUM, week_str, ':', 50, 100, ClockPage_CallBack); //时钟页面的标签也显示周 - OLED_ListPageInit(&alarm_list_page, alarm_list_page_id, ALARM_LIST_PAGE_NUM, alarm_list_option_array, AlarmList_CallBack); - OLED_DigitalPageInit(&alarm1_page, alarm1_page_id, alarm1_option_array, ALARM12_LABEL_NUM, alarm12_label_array, ':', 50, 100, Alarm12_CallBack); - OLED_DigitalPageInit(&alarm2_page, alarm2_page_id, alarm2_option_array, ALARM12_LABEL_NUM, alarm12_label_array, ':', 50, 100, Alarm12_CallBack); - OLED_RaderPicPageInit(&about_page, about_page_id, ABOUT_PAGE_NUM, qrcode_raderpic, Rader_Pic_Mode_Hold, About_CallBack); - OLED_RaderPicPageInit(&ring_page, ring_page_id, 0, NULL, Rader_Pic_Mode_Hold, Ring_CallBack); //相当于一个空的页面可以自由绘制 - + OLED_TitlePageInit(&main_page, MAIN_PAGE_NUM, mian_option_array, main_icon_array, MainPage_CallBack); + OLED_DigitalPageInit(&calendar_page, calendar_option_array, CALENDAR_LABEL_NUM, week_str, '-', 0, 100, NULL); + OLED_DigitalPageInit(&clock_page, clock_option_array, CALENDAR_LABEL_NUM, week_str, ':', 50, 100, NULL); //时钟页面的标签也显示周 + OLED_ListPageInit(&alarm_list_page, ALARM_LIST_PAGE_NUM, alarm_list_option_array, AlarmList_CallBack); + OLED_DigitalPageInit(&alarm1_page, alarm1_option_array, ALARM12_LABEL_NUM, alarm12_label_array, ':', 50, 100, Alarm12_CallBack); + OLED_DigitalPageInit(&alarm2_page, alarm2_option_array, ALARM12_LABEL_NUM, alarm12_label_array, ':', 50, 100, Alarm12_CallBack); + OLED_RaderPicPageInit(&about_page, ABOUT_PAGE_NUM, qrcode_raderpic, Rader_Pic_Mode_Hold, About_CallBack); + OLED_RaderPicPageInit(&ring_page, 0, NULL, Rader_Pic_Mode_Hold, Ring_CallBack); //相当于一个空的页面可以自由绘制 } void LittleClockUI_Proc(void) { OLED_UIProc(); - //由updataflag接管 alarmlist中两个选框的选中与否 - if(FLAG_IS_SET(update_flag,ALARM1_ENABLE_MSK))alarm_list_option_array[1].val = 1; - else alarm_list_option_array[1].val = 0; - if(FLAG_IS_SET(update_flag,ALARM2_ENABLE_MSK))alarm_list_option_array[2].val = 1; - else alarm_list_option_array[2].val = 0; + if((DigitalPage*)OLED_GetCurrentPage() == &calendar_page) + { + time_t t = time(NULL); + struct tm *local_time = localtime(&t); + OLED_DigitalPage_UpdateDigitalNumAnimation(&calendar_page, + local_time->tm_year-100, local_time->tm_mon + 1, local_time->tm_mday, Digital_Direct_Increase); + } + if((DigitalPage*)OLED_GetCurrentPage() == &clock_page) + { + time_t t = time(NULL); + struct tm *local_time = localtime(&t); + OLED_DigitalPage_UpdateDigitalNumAnimation(&clock_page, + local_time->tm_hour, local_time->tm_min, local_time->tm_sec, Digital_Direct_Increase); + } + Set_Alarm(&alarm1,&alarm1_page,ALARM1_UPDATE_MSK); + Set_Alarm(&alarm2,&alarm2_page,ALARM2_UPDATE_MSK); + Check_Alarm(&alarm1,&alarm1_page,ALARM1_ENABLE_MSK); + Check_Alarm(&alarm2,&alarm2_page,ALARM2_ENABLE_MSK); + // printf("当前时间:%d-%02d-%02d %02d:%02d:%02d\n", + // local_time->tm_year + 1900, + // local_time->tm_mon + 1, + // local_time->tm_mday, + // local_time->tm_hour, + // local_time->tm_min, + // local_time->tm_sec); +} +void Set_Alarm(struct tm* alarm,DigitalPage* alarm_page,uint8_t msk) +{ + if(FLAG_IS_SET(alarm_flag,msk)) + { + time_t t = time(NULL); + struct tm *local_time = localtime(&t); + *alarm = *local_time; //同步日期 + alarm->tm_hour = alarm_page->option_array[Digital_Pos_IndexLeft].val; + alarm->tm_min = alarm_page->option_array[Digital_Pos_IndexMid].val; + alarm->tm_sec = alarm_page->option_array[Digital_Pos_IndexRight].val; + CLEAR_FLAG(alarm_flag,msk); + } +} +void Check_Alarm(struct tm* alarm,DigitalPage* alarm_page,uint8_t msk) +{ + uint8_t temp_msk = msk<<2; + time_t t = 0; + struct tm *local_time = NULL; + printf("0x%X\r\n",alarm_flag); + printf("alarm1 = %02d:%02d:%02d\r\n",alarm1.tm_hour,alarm1.tm_min,alarm1.tm_sec); + // printf("localtime = %02d:%02d:%02d\r\n",local_time->tm_hour,local_time->tm_min,local_time->tm_sec); + if(FLAG_IS_SET(alarm_flag,msk) || FLAG_IS_SET(alarm_flag,temp_msk)) + { + t = time(NULL); + local_time = localtime(&t); + if(FLAG_IS_SET(alarm_flag,msk)) + alarm_list_page.option_array[msk].val = 1; + else + alarm_list_page.option_array[msk].val = 0; + if(alarm->tm_hour == local_time->tm_hour && alarm->tm_min == local_time->tm_min && alarm->tm_sec == local_time->tm_sec) + { + CLEAR_FLAG(alarm_flag,msk); + SET_FLAG(alarm_flag,temp_msk); + OLED_UIChangeCurrentPage(&ring_page); + } + if(FLAG_IS_SET(alarm_flag,temp_msk)) + { + if(alarm->tm_hour == local_time->tm_hour && alarm->tm_sec == local_time->tm_sec + && (alarm->tm_min+1 == local_time->tm_min ||(alarm->tm_min == 59 && alarm->tm_min+1 == local_time->tm_min == 0))) + { + CLEAR_FLAG(alarm_flag,temp_msk); + OLED_UIChangeCurrentPage((PageAddr)alarm_page); + } + } + + } } diff --git a/Csource/example/LittleClock/LittleClockUI.h b/Csource/example/LittleClock/LittleClockUI.h index 3700410..78729bc 100644 --- a/Csource/example/LittleClock/LittleClockUI.h +++ b/Csource/example/LittleClock/LittleClockUI.h @@ -1,33 +1,36 @@ #ifndef __LITTLECLOCKUI_H__ #define __LITTLECLOCKUI_H__ -#include "oled_ui.h" -#include "oled_g.h" -#include "oled_port.h" +#ifdef __cplusplus +extern "C" { +#endif void LittleClockUI_Init(void); void LittleClockUI_Proc(void); -#define DATE_UPDATE_MSK 0x01 -#define TIME_UPDATE_MSK 0x02 -#define ALARM1_UPDATE_MSK 0x04 -#define ALARM2_UPDATE_MSK 0x08 //用于检测update flag的置位 -#define ALARM1_ENABLE_MSK 0x10 -#define ALARM2_ENABLE_MSK 0x20 //用于检测update flag的置位 - -#define ALARM1_RING_MSK 0x40 -#define ALARM2_RING_MSK 0x80 //主函数中置位,在响铃页面检测 - - -#define SET_FLAG(flag, msk) (flag|=msk) -#define FLAG_IS_SET(flag, msk) (flag&msk) -#define CLEAR_FLAG(flag, msk) (flag&= (~msk)) - -extern uint16_t fps; // 外界需要提供一个变量,统计一秒内UIproc能刷新几次,粗略估计帧率' -extern uint8_t update_flag; //用于主函数中判断是否需要更新rtc芯片的数据 -extern DigitalPage calendar_page; -extern DigitalPage clock_page; //用于主函数中,1秒更新一次时间 -extern DigitalPage alarm1_page; -extern DigitalPage alarm2_page; -extern RaderPicPage ring_page; +#ifdef __cplusplus +} +#endif +// #define DATE_UPDATE_MSK 0x01 +// #define TIME_UPDATE_MSK 0x02 +// #define ALARM1_UPDATE_MSK 0x04 +// #define ALARM2_UPDATE_MSK 0x08 //用于检测update flag的置位 +// #define ALARM1_ENABLE_MSK 0x10 +// #define ALARM2_ENABLE_MSK 0x20 //用于检测update flag的置位 + +// #define ALARM1_RING_MSK 0x40 +// #define ALARM2_RING_MSK 0x80 //主函数中置位,在响铃页面检测 + + +// #define SET_FLAG(flag, msk) (flag|=msk) +// #define FLAG_IS_SET(flag, msk) (flag&msk) +// #define CLEAR_FLAG(flag, msk) (flag&= (~msk)) + +// extern uint16_t fps; // 外界需要提供一个变量,统计一秒内UIproc能刷新几次,粗略估计帧率' +// extern uint8_t update_flag; //用于主函数中判断是否需要更新rtc芯片的数据 +// extern DigitalPage calendar_page; +// extern DigitalPage clock_page; //用于主函数中,1秒更新一次时间 +// extern DigitalPage alarm1_page; +// extern DigitalPage alarm2_page; +// extern RaderPicPage ring_page; #endif diff --git a/Csource/example/UITest/TestUI.c b/Csource/example/UITest/TestUI.c index fdc96ef..92818e0 100644 --- a/Csource/example/UITest/TestUI.c +++ b/Csource/example/UITest/TestUI.c @@ -1,26 +1,14 @@ #include "TestUI.h" +#include "../WouoUIPage/oled_ui.h" #include "string.h" #include "math.h" -#include "System.h" -//-------枚举id,唯一标识一个页面,防止有两个页面使用同一id -enum -{ - main_page_id = 0x00, - logo_page_id, - setting_page_id, - curve_page_id, - lock_page_id, - about_page_id, - about_wououi_page_id, - about_page_version_id, -}; //--------定义页面对象 TitlePage main_page; RaderPicPage logo_page; ListPage setting_page; WavePage curve_page; -DigitalPage lock_page; +DigitalPage lock_page,lock_page2; ListPage about_page; RadioPage about_wououi_page; //这两个相关页使用单选项RadioPage类型只是为了展示单选项页面而已 RadioPage about_page_version_page; @@ -170,7 +158,13 @@ int16_t n = 0; //曲线横坐标自增变量 //Lock页面参数 Option lock_option_array[3] = //由于Digital页面有三个数字选项,所以,digital页面选项数组大小必须为3 {//{ order,max,min,step,int_val,text,} //option的成员顺序 + {.item_max = 59 , .item_min = 0, .step = 1, .val = 0, .text = NULL}, {.item_max = 99 , .item_min = 0, .step = 1, .val = 0, .text = NULL}, + {.item_max = 99 , .item_min = 0, .step = 1, .val = 0, .text = NULL}, //设置每一个数字的上限值和步长 +} ; +Option lock_option_array2[3] = //由于Digital页面有三个数字选项,所以,digital页面选项数组大小必须为3 +{//{ order,max,min,step,int_val,text,} //option的成员顺序 + {.item_max = 77 , .item_min = 0, .step = 1, .val = 0, .text = NULL}, {.item_max = 99 , .item_min = 0, .step = 1, .val = 0, .text = NULL}, {.item_max = 99 , .item_min = 0, .step = 1, .val = 0, .text = NULL}, //设置每一个数字的上限值和步长 } ; @@ -213,41 +207,41 @@ Option about_pageversion_array[ABOUT_PAGEVERSION_NUM] = }; //--------定义每个页面的回调函数 -void MainPage_CallBack(uint8_t self_page_id,Option* select_item) +void MainPage_CallBack(const Page* cur_page_addr,Option* select_item) { switch (select_item->order) { - case 0: OLED_UIJumpToPage(self_page_id,&logo_page); break; - case 1: OLED_UIJumpToPage(self_page_id,&setting_page); break; - case 2: OLED_UIJumpToPage(self_page_id,&curve_page); break; - case 3: OLED_UIJumpToPage(self_page_id,&lock_page); break; - case 4: OLED_UIJumpToPage(self_page_id,&about_page); break; + case 0: OLED_UIJumpToPage((PageAddr)cur_page_addr,&logo_page); break; + case 1: OLED_UIJumpToPage((PageAddr)cur_page_addr,&setting_page); break; + case 2: OLED_UIJumpToPage((PageAddr)cur_page_addr,&curve_page); break; + case 3: OLED_UIJumpToPage((PageAddr)cur_page_addr,&lock_page); break; + case 4: OLED_UIJumpToPage((PageAddr)cur_page_addr,&about_page); break; default: break; } } -void SettingPage_CallBack(uint8_t self_page_id,Option* select_item) +void SettingPage_CallBack(const Page* cur_page_addr,Option* select_item) { switch (select_item->order) //对选中项的真实参数值赋值 { //由于第0项是说明文字“Setting” - case 1: ui_para.ani_param[TILE_ANI] = select_item->val;break;//ani_tile - case 2: ui_para.ani_param[LIST_ANI] = select_item->val;break;//ani_list - case 3: ui_para.ufd_param[TILE_UFD] = select_item->val;break;//ani_tile - case 4: ui_para.ufd_param[LIST_UFD] = select_item->val;break;//ani_list - case 5: ui_para.loop_param[TILE_UFD] = select_item->val;break;//loop_tile - case 6: ui_para.loop_param[LIST_UFD] = select_item->val;break;//loop_list - case 7: ui_para.valwin_broken = select_item->val;break;//ValWin Broken - case 8: ui_para.conwin_broken = select_item->val;break;//ConWin Broken - case 9: ui_para.digital_ripple = select_item->val;break;//Digital Ripple Enable/not - case 10: ui_para.raderpic_scan_mode = select_item->val;break;//RaderPic scan mode - case 11: ui_para.raderpic_scan_rate = select_item->val;break;//RaderPic scan rate - case 12: ui_para.raderpic_move_rate = select_item->val;break;//RaderPic move rate + case 1: g_default_ui_para.ani_param[TILE_ANI] = select_item->val;break;//ani_tile + case 2: g_default_ui_para.ani_param[LIST_ANI] = select_item->val;break;//ani_list + case 3: g_default_ui_para.ufd_param[TILE_UFD] = select_item->val;break;//ani_tile + case 4: g_default_ui_para.ufd_param[LIST_UFD] = select_item->val;break;//ani_list + case 5: g_default_ui_para.loop_param[TILE_UFD] = select_item->val;break;//loop_tile + case 6: g_default_ui_para.loop_param[LIST_UFD] = select_item->val;break;//loop_list + case 7: g_default_ui_para.valwin_broken = select_item->val;break;//ValWin Broken + case 8: g_default_ui_para.conwin_broken = select_item->val;break;//ConWin Broken + case 9: g_default_ui_para.digital_ripple = select_item->val;break;//Digital Ripple Enable/not + case 10: g_default_ui_para.raderpic_scan_mode = select_item->val;break;//RaderPic scan mode + case 11: g_default_ui_para.raderpic_scan_rate = select_item->val;break;//RaderPic scan rate + case 12: g_default_ui_para.raderpic_move_rate = select_item->val;break;//RaderPic move rate default: break; } } -void LockPage_CallBack(uint8_t self_page_id,Option* select_item) +void LockPage_CallBack(const Page* cur_page_addr,Option* select_item) { switch (select_item->order) { @@ -260,18 +254,19 @@ void LockPage_CallBack(uint8_t self_page_id,Option* select_item) } else if(strcmp(select_item->text, lock_label_array[1]) == 0) //“Clear All” OLED_DigitalPage_UpdateDigitalNumAnimation(&lock_page, 0, 0, 0, Digital_Direct_Increase); - break; + break; default: break; } } -void About_CallBack(uint8_t self_page_id,Option* select_item) +void About_CallBack(const Page* cur_page_addr,Option* select_item) { switch (select_item->order) {//第0项是说明文字 - case 1: OLED_UIJumpToPage(self_page_id,&about_wououi_page); break; - case 2: OLED_UIJumpToPage(self_page_id,&about_page_version_page); break; + case 0: OLED_UIChangeCurrentPage(&lock_page2);break; //两个数字页面的测试 + case 1: OLED_UIJumpToPage((PageAddr)cur_page_addr,&about_wououi_page); break; + case 2: OLED_UIJumpToPage((PageAddr)cur_page_addr,&about_page_version_page); break; default: break; } } @@ -288,45 +283,50 @@ int16_t Triangle_Func(int16_t x) } //--------------给主函数调用的接口函数 - void TestUI_Init(void) { - OLED_Init(); //硬件的初始化 - LL_mDelay(100); + + //OLED_Init(); //硬件的初始化 OLED_ClearBuff(); //清空缓存 OLED_RefreshBuff(); //刷新屏幕(清空屏幕) OLED_SetPointColor(1); //设置绘制颜色 - OLED_UiInit(); //必要的ui参数初始化 //补充列表页面的初值 - setting_option_array[1].val = ui_para.ani_param[TILE_ANI]; - setting_option_array[2].val = ui_para.ani_param[LIST_ANI]; - setting_option_array[3].val = ui_para.ani_param[TILE_UFD]; - setting_option_array[4].val = ui_para.ani_param[LIST_UFD]; - setting_option_array[5].val = ui_para.ani_param[TILE_LOOP]; - setting_option_array[6].val = ui_para.ani_param[LIST_LOOP]; - setting_option_array[7].val = ui_para.valwin_broken; - setting_option_array[8].val = ui_para.conwin_broken; - setting_option_array[9].val = ui_para.digital_ripple; - setting_option_array[10].val = ui_para.raderpic_scan_mode; - setting_option_array[11].val = ui_para.raderpic_scan_rate; - setting_option_array[12].val = ui_para.raderpic_move_rate; + setting_option_array[1].val = g_default_ui_para.ani_param[TILE_ANI]; + setting_option_array[2].val = g_default_ui_para.ani_param[LIST_ANI]; + setting_option_array[3].val = g_default_ui_para.ani_param[TILE_UFD]; + setting_option_array[4].val = g_default_ui_para.ani_param[LIST_UFD]; + setting_option_array[5].val = g_default_ui_para.ani_param[TILE_LOOP]; + setting_option_array[6].val = g_default_ui_para.ani_param[LIST_LOOP]; + setting_option_array[7].val = g_default_ui_para.valwin_broken; + setting_option_array[8].val = g_default_ui_para.conwin_broken; + setting_option_array[9].val = g_default_ui_para.digital_ripple; + setting_option_array[10].val = g_default_ui_para.raderpic_scan_mode; + setting_option_array[11].val = g_default_ui_para.raderpic_scan_rate; + setting_option_array[12].val = g_default_ui_para.raderpic_move_rate; //设置界面选项 - OLED_TitlePageInit(&main_page, main_page_id, MAIN_PAGE_NUM, mian_option_array, main_icon_array, MainPage_CallBack); - OLED_RaderPicPageInit(&logo_page, logo_page_id, LOGO_PAGE_NUM, logo_rpp_array,Rader_Pic_Mode_Loop, NULL); - OLED_ListPageInit(&setting_page, setting_page_id, SETTING_PAGE_NUM, setting_option_array, SettingPage_CallBack); - OLED_WavePageInit(&curve_page, curve_page_id, CURVE_PAGE_NUM, curve_option_array, NULL); - OLED_DigitalPageInit(&lock_page, lock_page_id, lock_option_array, LOCK_PAGE_LABEL_NUM, lock_label_array, '-', 0, 50, LockPage_CallBack); - OLED_ListPageInit(&about_page, about_page_id, ABOUT_PAGE_NUM, about_option_array, About_CallBack); - OLED_RadioPageInit(&about_wououi_page, about_wououi_page_id, ABOUT_WOUOUI_PAGE_NUM, about_wououi_option_array, NULL); - OLED_RadioPageInit(&about_page_version_page,about_page_version_id, ABOUT_PAGEVERSION_NUM, about_pageversion_array, NULL); + OLED_TitlePageInit(&main_page, MAIN_PAGE_NUM, mian_option_array, main_icon_array, MainPage_CallBack); + OLED_RaderPicPageInit(&logo_page, LOGO_PAGE_NUM, logo_rpp_array,Rader_Pic_Mode_Loop, NULL); + OLED_ListPageInit(&setting_page, SETTING_PAGE_NUM, setting_option_array, SettingPage_CallBack); + OLED_WavePageInit(&curve_page, CURVE_PAGE_NUM, curve_option_array, NULL); + OLED_DigitalPageInit(&lock_page, lock_option_array, LOCK_PAGE_LABEL_NUM, lock_label_array, '-', 0, 50, LockPage_CallBack); + OLED_ListPageInit(&about_page, ABOUT_PAGE_NUM, about_option_array, About_CallBack); + OLED_RadioPageInit(&about_wououi_page, ABOUT_WOUOUI_PAGE_NUM, about_wououi_option_array, NULL); + OLED_RadioPageInit(&about_page_version_page, ABOUT_PAGEVERSION_NUM, about_pageversion_array, NULL); + OLED_DigitalPageInit(&lock_page2, lock_option_array2, LOCK_PAGE_LABEL_NUM, lock_label_array, '-', 0, 50, LockPage_CallBack); } void TestUI_Proc(void) { + static uint16_t count = 0; //延时计数变量(用于波形的延时) OLED_UIProc(); - OLED_UIWaveUpdateVal(&(curve_option_array[0]), sin(0.1*n)*(curve_option_array[0].item_max)*0.75); - OLED_UIWaveUpdateVal(&(curve_option_array[1]), Triangle_Func(n)); - n++; + if(count == 10) + { + OLED_UIWaveUpdateVal(&(curve_option_array[0]), sin(0.04*n)*(curve_option_array[0].item_max)*0.9); + // OLED_UIWaveUpdateVal(&(curve_option_array[1]), Triangle_Func(n)); + n++; + count = 0; + } + count++; } diff --git a/Csource/example/UITest/TestUI.h b/Csource/example/UITest/TestUI.h index 74fc637..5960000 100644 --- a/Csource/example/UITest/TestUI.h +++ b/Csource/example/UITest/TestUI.h @@ -1,12 +1,16 @@ #ifndef __TEST_UI_H__ #define __TEST_UI_H__ -#include "oled_port.h" -#include "oled_g.h" -#include "oled_ui.h" - +#ifdef __cplusplus +extern "C" { +#endif void TestUI_Init(void); void TestUI_Proc(void); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/Csource/src/oled_conf.h b/Csource/src/oled_conf.h index bb9b094..934a1d7 100644 --- a/Csource/src/oled_conf.h +++ b/Csource/src/oled_conf.h @@ -2,12 +2,11 @@ #define __OLED_CONF_H__ #define UI_CONWIN_ENABLE 1 //是否使能 以"$ " 为开头的选项使用确认弹窗 -#define UI_MAX_PAGE_NUM 32 //页面的最大数量,这个数字需要大于所有页面的page_id #define UI_INPUT_MSG_QUNEE_SIZE 4 //ui内部消息对列的大小(至少需要是2) //页面类型使能宏,使用对应的页面类型,则需要开启该宏,将宏置为1,默认都开启 -#define PAGE_WAVE_ENABLE 1 -#define PAGE_RADIO_ENABLE 1 +#define PAGE_WAVE_ENABLE 0 +#define PAGE_RADIO_ENABLE 0 #define PAGE_RADERPIC_ENABLE 1 #define PAGE_DIGITAL_ENABLE 1 diff --git a/Csource/src/oled_g.c b/Csource/src/oled_g.c index 8c0d1c8..1804a5b 100644 --- a/Csource/src/oled_g.c +++ b/Csource/src/oled_g.c @@ -415,6 +415,8 @@ void OLED_WinDrawLine(window* win,int16_t x1, int16_t y1, int16_t x2, int16_t y2 * @param : [in] win 显示的窗口对象 * @param : [in] pic 显示的图片对象 * @param : [in] start_x,start_y,width,height,图片的左上角(x,y) 和宽高 +* @param : [in&out] p_end_point,传入图片的扫描停止点的计数变量 ,用于标志当前图片扫描停止在哪一个点, + 若扫描完成该变量置0,方便下一次扫描;若传入为0,则表示刚开始扫描 * @param : [in] direct 射线方向,枚举类型RaderDirection * @param : [in] enable_all_point_scan true/Fasle,Fasle的话,只有图片亮的点才会生成射线扫描 * @param : [in] scan_rate 扫描的速度,值越大越快 @@ -423,19 +425,20 @@ void OLED_WinDrawLine(window* win,int16_t x1, int16_t y1, int16_t x2, int16_t y2 * @author : Sheep * @date : 23/11/15 */ -uint8_t OLED_WinDrawRaderPic(window * win,const uint8_t* pic,int16_t start_x, uint16_t start_y, uint8_t width, uint8_t height, RaderDirection direct, uint8_t enable_all_point_scan, uint8_t scan_rate) +uint8_t OLED_WinDrawRaderPic(window * win,const uint8_t* pic,int16_t start_x, uint16_t start_y, uint8_t width, uint8_t height, uint16_t * p_end_point, + RaderDirection direct, uint8_t enable_all_point_scan, uint8_t scan_rate) { - static uint16_t now_end_point = 1; //静态计数变量(允许在描文字的过程中被打断) uint8_t mask = 1, horizon_line_flag = 0, ret = 0; int16_t x = 0, y = 0; uint16_t i = 0,array_index = 0; + if(*p_end_point == 0 )*p_end_point = 1; //传入图片的扫描停止点的计数变量(允许在描文字的过程中被打断) if(pic == NULL) return 0; //如果图像为null,直接返回0,表示未完成 //绘制前面绘制好的图形 - for(i = 0; i < now_end_point; i++) + for(i = 0; i < *p_end_point; i++) { if((i % width == 0) && (i!=0)) if(mask == 0x80){mask = 1;} - else {mask <<= 1;array_index-=width;} + else {mask <<= 1;array_index-=width;} //由图片取模方式决定的数组扫描方式 if(pic[array_index]&mask) OLED_WinDrawPoint(win,start_x + i%width, start_y + i/width); array_index++; @@ -464,8 +467,8 @@ uint8_t OLED_WinDrawRaderPic(window * win,const uint8_t* pic,int16_t start_x, ui else OLED_WinDrawVLine(win,x,y,start_y+i/width); } //终点自增 - if(now_end_point < (width*height-1)){now_end_point+=scan_rate;ret = 0;} - else {now_end_point = 1;ret= 1;} //图像绘制结束 + if(*p_end_point < (width*height-1)){(*p_end_point)+=scan_rate;ret = 0;} + else {*p_end_point = 0;ret= 1;} //图像绘制结束 return ret; } diff --git a/Csource/src/oled_g.h b/Csource/src/oled_g.h index 47d4e43..be33732 100644 --- a/Csource/src/oled_g.h +++ b/Csource/src/oled_g.h @@ -1,6 +1,9 @@ #ifndef __OLED_G_H__ #define __OLED_G_H__ +#ifdef __cplusplus +extern "C" { +#endif #include "oled_port.h" @@ -44,5 +47,12 @@ void OLED_WinDrawLine(window* win,int16_t x1, int16_t y1, int16_t x2, int16_t y2 uint8_t OLED_GetStrWidth(const char * str, uint8_t size); void OLED_Animation(float *a, float *a_trg, float n); void OLED_AllSrcFade(uint8_t Odd0OrEven1,uint8_t byte); -uint8_t OLED_WinDrawRaderPic(window * win,const uint8_t* pic,int16_t start_x, uint16_t start_y, uint8_t width, uint8_t height, RaderDirection direct, uint8_t enable_all_point_scan, uint8_t scan_rate); +uint8_t OLED_WinDrawRaderPic(window * win,const uint8_t* pic,int16_t start_x, uint16_t start_y, uint8_t width, uint8_t height, uint16_t * p_end_point, + RaderDirection direct, uint8_t enable_all_point_scan, uint8_t scan_rate); + +#ifdef __cplusplus +} +#endif + + #endif diff --git a/Csource/src/oled_port.h b/Csource/src/oled_port.h index 543a9a2..8965a3e 100644 --- a/Csource/src/oled_port.h +++ b/Csource/src/oled_port.h @@ -1,6 +1,11 @@ #ifndef __OLED_PORT_H__ #define __OLED_PORT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + #include "stdio.h" #include "stdint.h" @@ -10,7 +15,11 @@ void OLED_Init(void); //初始化驱动 void OLED_SendBuff(uint8_t buff[8][128]); //将8*128字节的buff一次性全部发送的函数 -//void OLED_PowerCtrl(uint8_t on1_off0); +void drawBigPixel(int x, int y, uint8_t value); + +#ifdef __cplusplus +} +#endif #endif diff --git a/Csource/src/oled_ui.c b/Csource/src/oled_ui.c index 373f5ff..4f8a500 100644 --- a/Csource/src/oled_ui.c +++ b/Csource/src/oled_ui.c @@ -1,9 +1,9 @@ #include "oled_ui.h" #include "string.h" #include "stdio.h" -//===============================类型声明(和一次性变量定义)=================================== - -typedef struct +//===============================类型声明(内部静态函数声明)=================================== +//弹窗类型 +typedef struct _Win { uint8_t state:2; //弹窗的状态 不再弹窗内0,参数初始化1,弹窗动画轮询2 uint8_t l; // = (DISP_W - WIN_W) / 2; @@ -19,61 +19,213 @@ typedef struct //有一个全局数值弹窗变量vwin在ui结构体中,用于每次弹窗使用(对于数值弹窗来说,不论是上下、还是确认,都会调用一次回调,方便数值实时更新) //有一个全局确认弹窗变量cwin在ui结构体中,用于每次确认弹窗使用(对于确认弹窗来说,只有按下确认键,才会触发回调,确认的意义所在) +//Listpage 需要的共用变量集合 +struct TitlePageVar +{ //因为Title选中项一直在中间,所以不需要有每个页面变量记录它真实页面的偏移位置 + float icon_x; //图标的x坐标距选中目标的间距的变量 + float icon_x_trg;//图标的x坐标距选中目标的间距的变量目标 + float icon_y;//图标的y坐标 + float icon_y_trg;//图标的y坐标目标 + float indi_x; //指示器的x坐标 + float indi_x_trg;//指示器的x坐标目标值 + float title_y;//标题的y坐标 + float title_y_trg;//标题的y坐标目标值 +}; + +//Listpage 需要的共用变量集合 +struct ListPageVar +{ + uint8_t slip_flag; //切换动画是否完成的标志位 + float y; //列表中每个选项的间隔值(过度动画后作为正真页面的起始y坐标值,以屏幕原点为0) + float y_trg; //列表中每个选项间隔的目标值 + float box_x; //选中框x + float box_x_trg; //选中框x的目标值 + float box_y; //选中框y(以屏幕原点为0的box_y值) + // float box_y_trg; //选中框y的目标值(这个变量放在每一个页面中,用于推算正真的页面的起始y坐标值) + float bar_y; //进度条的y值 + float bar_y_trg; //进度条的y目标值 +}; + #if PAGE_WAVE_ENABLE -struct +//波形曲线标签全局变量,用于记录波形页面中标签的移动 +struct WaveTag { int16_t data_que[WAVE_W-1]; //用于记录波形全程队列 uint8_t p_head; //队列头部指针,表征队列最起始的位置 uint8_t p_rear; //出队列指针 uint8_t p_font; //入队列指针 uint8_t change_flag; // 切换过的标志 - float text_bg_r; + float text_bg_r; //文本框动态宽度 float text_bg_r_trg; -} wave_tag; //波形曲线标签全局变量,用于记录波形页面中标签的移动 +} ; #endif #if PAGE_RADIO_ENABLE -uint8_t radio_click_flag = False; //标志位,用于标记在单选项页面内是否单击了Click +//单选项页面共用变量集合 +struct RadioPageVar +{ + uint8_t radio_click_flag:1; //标志位,用于标记在单选项页面内是否单击了Click +}; +#endif + +#if PAGE_RADERPIC_ENABLE +//RaderPage的共用变量集合 +struct RaderPicPageVar +{ + float move_x; + float move_y;// 图片绘制x y坐标的移动倍率(-1~0) +}; #endif #if PAGE_DIGITAL_ENABLE -//6个单位数字的横坐标存储数组 -uint8_t digital_num_xindex[DIGITAL_NUM_INDEX_MAX] = {12+24+12+24+12, 12+24+12+24, 12+24+12, 12+24, 12, 0}; -// uint8_t digital_num_pos = 0; //0表示没有选中位置,1-7bit每一位置1表示该位被选中 -// uint8_t temp_ripple_index = 0; //用于在ripple时记录选中位置(选中最低位位置开始,慢慢往上增) -static uint8_t Gap_shine_time = 0 ; //全局闪烁时间递减变量 -static uint8_t Uline_shine_time = 0 ; //全局闪烁时间递减变量 -typedef struct +//只有单个位的数据,用于存储单个位的数据 +typedef struct _SigleBit { - uint8_t num:4; //只有单个位的数据,用于存储单个位的数据 + uint8_t num:4; } SingleBit; -SingleBit num_array[6]; //显示的6个单个位数据 -uint8_t last_or_next_label_index = 0; //用来记录上次显示的label的index +//Digital页面变量集合 +struct DigitalPageVar +{ + uint8_t digital_num_pos; //0表示没有选中位置,1-7bit每一位置1表示该位被选中 + uint8_t temp_ripple_index; //用于在ripple时记录选中位置(选中最低位位置开始,慢慢往上增) + DigitalDirect dir:2; //用于Digital Show和React函数间传递信号 + window w_digtal[2]; //用限制数字时钟的窗口(1个数字窗口+1个label窗口) 2个窗口 + float rect_y; //移动外框的顶点坐标 + float rect_y_trg; //移动外框的顶点坐标目标 + float label_y; //移动外框的顶点坐标 + float label_y_trg; //移动外框的顶点坐标目标 + float num_y; //移动数字的顶点坐标 + float num_y_trg; //移动数字的顶点坐标目标 + uint8_t digital_num_xindex[DIGITAL_NUM_INDEX_MAX];//6个单位数字的横坐标存储数组 + uint8_t Gap_shine_time; //全局闪烁时间递减变量 + uint8_t Uline_shine_time; //全局闪烁时间递减变量 + SingleBit num_array[6]; //显示的6个单个位数据 + uint8_t last_or_next_label_index; //用来记录上次显示的label的index + uint8_t temp_num_pos; //用于在show函数内暂时装载num_pos变量,实现同时运动动画和ripple动画的切换 + DigitalDirect temp_dir; //记录下运动方向 + DigitalDirect temp_label_dir; //记录下label运动方向,防止数字和label同时需要运动的情况出现 +}; #endif +//WouoUI类型,整个UI类型 +struct _WouoUI +{ + uint8_t init_finish_flag ; //页面是否正在初始化完成的标志位,即是否完成过度页面的初始化 + PageAddr home_page; //主页面的地址 + PageAddr current_page; //当前页面的地址 + UIState state ; //ui状态变量 + UiPara* upara; //ui参数集合 + InputMsg msg_queue[INPUT_MSG_QUNEE_SIZE];//消息队列 + uint8_t msg_que_font ; + uint8_t msg_que_rear; //消息队列的头尾指针 + struct TitlePageVar tp_var; //TitlePage共用变量集合 + struct ListPageVar lp_var; //List页面的共用变量集合(包括Radio和Wave的列表的变量也使用这个共用变量) + struct DigitalPageVar dp_var; //digital页面的共用变量集合 + Win vwin; //数值弹窗插件 +#if PAGE_RADIO_ENABLE + struct RadioPageVar rp_var; //Radio页面共用变量集合 +#endif +#if PAGE_WAVE_ENABLE + struct WaveTag wt_var; //波形显示区域的共用变量集合 +#endif +#if PAGE_RADERPIC_ENABLE + struct RaderPicPageVar rrp_var; //RaderPicPage的共用变量集合 +#endif +#if UI_CONWIN_ENABLE + Win cwin; //确认弹窗插件 +#endif +}; + +//静态函数声明(方便全局变量初始化函数指针) +static void OLED_ValWinAnimInit(PageAddr bg); +static void OLED_ValWinShow(Option* win); +static void OLED_ValWinReact(PageAddr bg, Option* select_win); +#if UI_CONWIN_ENABLE +static void OLED_ConWinAnimInit(PageAddr bg); +static void OLED_ConWinShow(Option* win); +static void OLED_ConWinReact(PageAddr bg,Option* win); +#endif //===================================全局变量================================== -UiPara ui_para; //全局UI参数集合变量,这个UI的相关参数都在这个集合中定义 -struct +//全局UI参数集合对象(同时初始化),这个UI的相关参数都在这个集合中定义 +UiPara g_default_ui_para = { - uint8_t init_finish_flag ; //页面是否正在初始化完成的标志位,即是否完成过度页面的初始化 - uint8_t current_page_id ; //当前页面id - UIState state ; //ui状态变量 - UiPara* upara; //ui参数集合 - Win vwin; //数值弹窗插件 + .ani_param = { + [TILE_ANI] = 120, //磁贴动画速度 + [LIST_ANI] = 120, //列表动画速度 + [WIN_ANI] = 120, //弹窗动画速度 + [TAG_ANI] = 120, //标签动画速度 + [DIGI_ANI] = 100, //数字动画滚动速度 + }, + .ufd_param = { + [TILE_UFD] = True, //磁贴图标从头展开开关 + [LIST_UFD] = True, //菜单列表从头展开开关 + }, + .loop_param = { + [TILE_LOOP] = True, //磁贴图标循环模式开关 + [LIST_LOOP] = True, //菜单列表循环模式开关 + }, + .valwin_broken = True, //弹窗背景虚化开关 + .conwin_broken = True, //确认弹窗背景虚化开关 + .digital_ripple = True, //digital页面波纹递增动画开关 + .raderpic_scan_mode = False, //镭射文字只扫描亮处 + .raderpic_scan_rate = 4, //镭射文字扫描速度 + .raderpic_move_rate = 50, //镭射文字移动速度 +}; +//默认UI对象(同时进行初始化) +WouoUI default_ui = { + .init_finish_flag = False, //初始时需要先开启过度动画 + .current_page = NULL, + .home_page = NULL, //初始化当前页面和主页面均是NULL + .state = ui_layer_in, //从没页面进入主页面,所以是lay_in + .msg_queue = {msg_none}, + .msg_que_rear = 0, + .msg_que_font = 0, //消息队列相关的初始化 + .vwin = { //弹窗里的默认参数 + .l = (OLED_WIDTH - WIN_W)/2, + .u = (OLED_HEIGHT - WIN_H)/2, + .state = 0, //默认弹窗是关闭的 + .anim_init = OLED_ValWinAnimInit, + .show = OLED_ValWinShow, + .react = OLED_ValWinReact,//关联相关的处理函数 + }, #if UI_CONWIN_ENABLE - Win cwin; //确认弹窗插件 + .cwin = { + .l = (OLED_WIDTH - WIN_W)/2, //不管选框宽度,以字体宽度为准 + .u = (OLED_HEIGHT - WIN_H)/2, //确认弹窗里的默认参数 + .state = 0, //默认弹窗是关闭的 + .anim_init = OLED_ConWinAnimInit, + .show = OLED_ConWinShow, + .react = OLED_ConWinReact, //关联相关的处理函数 + }, #endif -} ui; //整个ui对象 - -PageAddr page_array[UI_MAX_PAGE_NUM] = {NULL}; //页面地址的数组,方便记录不同页面用于切换 - +#if PAGE_DIGITAL_ENABLE + .upara = &g_default_ui_para, //将默认参数赋值给default_ui + .dp_var = { //初始化Digital页面共用变量的初始化 + .Gap_shine_time = 0, + .Uline_shine_time = 0, + .last_or_next_label_index = 0, + .temp_dir = Digital_Direct_None, + .temp_label_dir = Digital_Direct_None, + .temp_num_pos = 0, + .w_digtal = { //数字Label窗口的坐标设置 + [0] = {.start_x = 16, .h = 24, .w = 96}, //确定数字窗口的一些参数 + [1] = {.start_x = 0, .h = 16, .w = 128}, //确定标签窗口的一些参数 + }, + .num_array = { + {0},{0},{0},{0},{0},{0} + }, + .digital_num_xindex = {12+24+12+24+12, 12+24+12+24, 12+24+12,12+24, 12,0} + //数字框的横坐标数组{12+24+12+24+12, 12+24+12+24, 12+24+12,12+24, 12,0} + }, +#endif +#if PAGE_RADIO_ENABLE //初始化radio页面共用变量的初始化 + .rp_var = {.radio_click_flag = False} +#endif +}; +WouoUI* p_current_ui = &default_ui; //当前操作的ui对象的指针(默认使用defaultui) +// PageAddr page_array[UI_MAX_PAGE_NUM] = {NULL}; //页面地址的数组,方便记录不同页面用于切换 window w_all = {0,0,OLED_WIDTH,OLED_HEIGHT}; //全局窗口变量,所有的绘制都在这个窗口内进行 - -InputMsg msg_queue[INPUT_MSG_QUNEE_SIZE] = {msg_none}; -uint8_t msg_que_font = 0, msg_que_rear = 0; //消息队列的头尾指针 - - //===================================对应函数================================== //--------通用页面函数 @@ -82,19 +234,23 @@ uint8_t msg_que_font = 0, msg_que_rear = 0; //消息队列的头尾指针 static void OLED_PageReturn(PageAddr page_addr) { Page* p = (Page*)page_addr; - ui.current_page_id = p->last_page_id; - ui.state = ui_layer_in; //将状态机置为页面初始化状态 - ui.init_finish_flag = False; //启用过度页面动画 + p_current_ui->current_page = p->last_page; //将UI页面设置为上一级页面 + p_current_ui->state = ui_layer_in; //将状态机置为页面初始化状态 + p_current_ui->init_finish_flag = False; //启用过度页面动画 } //最基本的页面成员初始化,并加入到页面队列中,注意,没有进行页面类型初始化,因为这个由各自初始化函数执行 -static void OLED_PageInit(PageAddr page_addr, uint8_t page_id, CallBackFunc call_back) +static void OLED_PageInit(PageAddr page_addr, CallBackFunc call_back) { Page* p = (Page*)page_addr; - p->page_id = page_id; - p->last_page_id = 0; //没有确认上一个id时,默认返回page_id为0的页面,即默认把0页面当作主(home)页面 + if(p_current_ui->home_page == NULL) //第一个页面初始化 + { + p_current_ui->home_page = page_addr; //将其初始化为主页面 + p_current_ui->current_page = page_addr; //同时作为当前页面 + } + p->last_page = p_current_ui->home_page; + //页面初始化时没有上一级页面,只有在页面跳转时才确定页面的上下级关系,默认将主页面(第一个初始化的页面)作为上一级页面 p->cb = call_back; - page_array[p->page_id] = page_addr; //加入页面数组 } /** @@ -144,16 +300,16 @@ char * ftoa(float num) //--------msg_que处理相关函数 -#define OLED_MsgQueIsEmpty (msg_que_font == msg_que_rear) //队列空 -#define OLED_MsgQueIsFull ((msg_que_rear + 1)%INPUT_MSG_QUNEE_SIZE == msg_que_font) //队列满 +#define OLED_MsgQueIsEmpty (p_current_ui->msg_que_font == p_current_ui->msg_que_rear) //队列空 +#define OLED_MsgQueIsFull ((p_current_ui->msg_que_rear + 1)%INPUT_MSG_QUNEE_SIZE == p_current_ui->msg_que_font) //队列满 //向msg队列发送消息和读msg队列函数,参数和返回值均是InputMsg类型 void OLED_MsgQueSend(InputMsg msg) { if(!OLED_MsgQueIsFull) { - msg_queue[msg_que_rear] = msg; - msg_que_rear++; - if(msg_que_rear == INPUT_MSG_QUNEE_SIZE )msg_que_rear = 0; + p_current_ui->msg_queue[p_current_ui->msg_que_rear] = msg; + p_current_ui->msg_que_rear++; + if(p_current_ui->msg_que_rear == INPUT_MSG_QUNEE_SIZE )p_current_ui->msg_que_rear = 0; } } InputMsg OLED_MsgQueRead(void) @@ -161,9 +317,9 @@ InputMsg OLED_MsgQueRead(void) InputMsg msg = msg_none; if(!OLED_MsgQueIsEmpty) { - msg = msg_queue[msg_que_font]; - msg_que_font++; - if(msg_que_font == INPUT_MSG_QUNEE_SIZE)msg_que_font = 0; + msg = p_current_ui->msg_queue[p_current_ui->msg_que_font]; + p_current_ui->msg_que_font++; + if(p_current_ui->msg_que_font == INPUT_MSG_QUNEE_SIZE)p_current_ui->msg_que_font = 0; } return msg; } @@ -174,15 +330,14 @@ InputMsg OLED_MsgQueRead(void) static void OLED_TitlePageAnimInit(PageAddr page_addr) { - TitlePage * title_page = (TitlePage *)page_addr; - title_page->icon_x = 0; - title_page->icon_x_trg = TILE_ICON_S; - title_page->icon_y = -TILE_ICON_H; - title_page->icon_y_trg = 0; - title_page->indi_x = 0; - title_page->indi_x_trg = TILE_INDI_W; - title_page->title_y = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2 + TILE_B_TITLE_H; - title_page->title_y_trg = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2; + p_current_ui->tp_var.icon_x = 0; + p_current_ui->tp_var.icon_x_trg = TILE_ICON_S; + p_current_ui->tp_var.icon_y = -TILE_ICON_H; + p_current_ui->tp_var.icon_y_trg = 0; + p_current_ui->tp_var.indi_x = 0; + p_current_ui->tp_var.indi_x_trg = TILE_INDI_W; + p_current_ui->tp_var.title_y = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2 + TILE_B_TITLE_H; + p_current_ui->tp_var.title_y_trg = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2; } static void OLED_TitlePageShow(PageAddr page_addr) @@ -190,38 +345,38 @@ static void OLED_TitlePageShow(PageAddr page_addr) TitlePage * tp = (TitlePage *)page_addr; float temp = 0; //用于存放临时的icon的x坐标 //计算动画参数 - OLED_Animation(&tp->icon_x,&tp->icon_x_trg,ui.upara->ani_param[TILE_ANI]); - OLED_Animation(&tp->icon_y,&tp->icon_y_trg,ui.upara->ani_param[TILE_ANI]); - OLED_Animation(&tp->indi_x,&tp->indi_x_trg,ui.upara->ani_param[TILE_ANI]); - OLED_Animation(&tp->title_y,&tp->title_y_trg,ui.upara->ani_param[TILE_ANI]); + OLED_Animation(&p_current_ui->tp_var.icon_x,&p_current_ui->tp_var.icon_x_trg,p_current_ui->upara->ani_param[TILE_ANI]); + OLED_Animation(&p_current_ui->tp_var.icon_y,&p_current_ui->tp_var.icon_y_trg,p_current_ui->upara->ani_param[TILE_ANI]); + OLED_Animation(&p_current_ui->tp_var.indi_x,&p_current_ui->tp_var.indi_x_trg,p_current_ui->upara->ani_param[TILE_ANI]); + OLED_Animation(&p_current_ui->tp_var.title_y,&p_current_ui->tp_var.title_y_trg,p_current_ui->upara->ani_param[TILE_ANI]); String show_str = tp->option_array[tp->select_item].text; //绘制title OLED_WinDrawStr(&w_all, ((OLED_WIDTH - TILE_INDI_W) - OLED_GetStrWidth(&(show_str[2]),TILE_B_TITLE_H)) / 2 + TILE_INDI_W, - tp->title_y,TILE_B_TITLE_H,(uint8_t*)&(show_str[2])); + p_current_ui->tp_var.title_y,TILE_B_TITLE_H,(uint8_t*)&(show_str[2])); //绘制title指示器 - OLED_WinDrawRBox(&w_all,0,TILE_ICON_S,tp->indi_x,TILE_INDI_H,0); + OLED_WinDrawRBox(&w_all,0,TILE_ICON_S,p_current_ui->tp_var.indi_x,TILE_INDI_H,0); //绘制图标 - if(!ui.init_finish_flag) //过度动画尚未完成 + if(!p_current_ui->init_finish_flag) //过度动画尚未完成 { for (uint8_t i = 0; i < tp->item_num; i++) { - if(ui.upara->ufd_param[TILE_UFD]) - temp = (OLED_WIDTH - TILE_ICON_W) / 2 + i * tp->icon_x - TILE_ICON_S * tp->select_item; + if(p_current_ui->upara->ufd_param[TILE_UFD]) + temp = (OLED_WIDTH - TILE_ICON_W) / 2 + i * p_current_ui->tp_var.icon_x - TILE_ICON_S * tp->select_item; //从第一个选项开始展开,最终保持选中在中间 else - temp = (OLED_WIDTH - TILE_ICON_W) / 2 + (i - tp->select_item) * tp->icon_x; + temp = (OLED_WIDTH - TILE_ICON_W) / 2 + (i - tp->select_item) * p_current_ui->tp_var.icon_x; //保证选中的选项在中间,向两侧展开 - OLED_WinDrawBMP(&w_all,(int16_t)temp,(int16_t)(tp->icon_y),TILE_ICON_W,TILE_ICON_H,tp->icon_array[i],1); + OLED_WinDrawBMP(&w_all,(int16_t)temp,(int16_t)(p_current_ui->tp_var.icon_y),TILE_ICON_W,TILE_ICON_H,tp->icon_array[i],1); } - if(tp->icon_x == tp->icon_x_trg) + if(p_current_ui->tp_var.icon_x == p_current_ui->tp_var.icon_x_trg) { - ui.init_finish_flag = True; //设置过度动画已经结束 - tp->icon_x = tp->icon_x_trg = -1*tp->select_item * TILE_ICON_S; + p_current_ui->init_finish_flag = True; //设置过度动画已经结束 + p_current_ui->tp_var.icon_x = p_current_ui->tp_var.icon_x_trg = -1*tp->select_item * TILE_ICON_S; } } else for(uint8_t i = 0; i < tp->item_num; i++) //过度动画完成后一般选择时的切换动画 - OLED_WinDrawBMP(&w_all,(OLED_WIDTH - TILE_ICON_W)/2 + (int16_t)(tp->icon_x) + i*TILE_ICON_S, + OLED_WinDrawBMP(&w_all,(OLED_WIDTH - TILE_ICON_W)/2 + (int16_t)(p_current_ui->tp_var.icon_x) + i*TILE_ICON_S, 0,TILE_ICON_W,TILE_ICON_H,tp->icon_array[i],1); } @@ -234,50 +389,50 @@ static void OLED_TitlePageReact(PageAddr page_addr) switch (msg) { case msg_up: - if(ui.init_finish_flag) //已经完成过渡动画了 + if(p_current_ui->init_finish_flag) //已经完成过渡动画了 { if(tp->select_item > 0) { //第一个icon与中心的距离减小S tp->select_item --; - tp->icon_x_trg += TILE_ICON_S; + p_current_ui->tp_var.icon_x_trg += TILE_ICON_S; //切换动画动作,动indi 和title - tp->indi_x = 0; - tp->title_y = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2 + TILE_B_TITLE_H; + p_current_ui->tp_var.indi_x = 0; + p_current_ui->tp_var.title_y = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2 + TILE_B_TITLE_H; } else { - if(ui.upara->loop_param[TILE_LOOP]) //开启循环的话 + if(p_current_ui->upara->loop_param[TILE_LOOP]) //开启循环的话 { tp->select_item = tp->item_num -1; - tp->icon_x_trg = -1*TILE_ICON_S*(tp->item_num -1); + p_current_ui->tp_var.icon_x_trg = -1*TILE_ICON_S*(tp->item_num -1); //切换动画动作,动indi 和title - tp->indi_x = 0; - tp->title_y = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2 + TILE_B_TITLE_H; + p_current_ui->tp_var.indi_x = 0; + p_current_ui->tp_var.title_y = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2 + TILE_B_TITLE_H; } } } break; case msg_down: - if(ui.init_finish_flag) + if(p_current_ui->init_finish_flag) { if(tp->select_item < (tp->item_num - 1)) { tp->select_item ++; - tp->icon_x_trg -= TILE_ICON_S; + p_current_ui->tp_var.icon_x_trg -= TILE_ICON_S; //切换动画动作,动indi 和title - tp->indi_x = 0; - tp->title_y = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2 + TILE_B_TITLE_H; + p_current_ui->tp_var.indi_x = 0; + p_current_ui->tp_var.title_y = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2 + TILE_B_TITLE_H; } else { - if(ui.upara->loop_param[TILE_LOOP]) + if(p_current_ui->upara->loop_param[TILE_LOOP]) { tp->select_item = 0; - tp->icon_x_trg = 0; + p_current_ui->tp_var.icon_x_trg = 0; //切换动画动作,动indi 和title - tp->indi_x = 0; - tp->title_y = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2 + TILE_B_TITLE_H; + p_current_ui->tp_var.indi_x = 0; + p_current_ui->tp_var.title_y = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2 + TILE_B_TITLE_H; } } } @@ -289,15 +444,15 @@ static void OLED_TitlePageReact(PageAddr page_addr) if(selcet_string[0] == '~') {//数值弹窗的话,进入数值弹窗这个动作不触发回调,但弹窗内不论点击什么都会实时触发回调 //当数值弹窗step设为0为只读是,进入数值弹窗前会调用一次回调,以便外界更改val值 - ui.vwin.state = 1; //进入弹窗初始化 + p_current_ui->vwin.state = 1; //进入弹窗初始化 if((tp->option_array[tp->select_item].step == 0) && (tp->page.cb != NULL)) - tp->page.cb(tp->page.page_id, &(tp->option_array[tp->select_item])); + tp->page.cb(&(tp->page), &(tp->option_array[tp->select_item])); } #if UI_CONWIN_ENABLE - else if(selcet_string[0] == '$') ui.cwin.state = 1; //进入确认弹窗初始化 + else if(selcet_string[0] == '$') p_current_ui->cwin.state = 1; //进入确认弹窗初始化 //确认弹窗内只有确认弹窗内的click才会触发回调 #endif - else if(tp->page.cb !=NULL)tp->page.cb(tp->page.page_id,&(tp->option_array[tp->select_item])); + else if(tp->page.cb !=NULL)tp->page.cb(&(tp->page),&(tp->option_array[tp->select_item])); //当前页面id和确认选中项的指针传入 break; default: @@ -307,7 +462,6 @@ static void OLED_TitlePageReact(PageAddr page_addr) void OLED_TitlePageInit( TitlePage * title_page, //磁贴页面对象 - uint8_t page_id, //为该页面分配一个唯一的id uint8_t item_num, //选项个数,需与title数组大小,icon数组大小一致 Option *option_array, //整个页面的选项数组(数组大小需与item_num一致) Icon *icon_array, //整个页面的icon数组(数组大小需与item_num一致) @@ -315,7 +469,7 @@ void OLED_TitlePageInit( { //缺少选项个数检查,Icon个数检查, title_page->page.page_type = type_title; - OLED_PageInit((PageAddr)title_page, page_id, call_back); + OLED_PageInit((PageAddr)title_page, call_back); title_page->page.ani_init = OLED_TitlePageAnimInit; title_page->page.show = OLED_TitlePageShow; title_page->page.react = OLED_TitlePageReact; //关联处理函数(方法) @@ -335,39 +489,39 @@ void OLED_TitlePageInit( static void OLED_ValWinAnimInit(PageAddr bg) { UNUSED_PARAMETER(bg); - ui.vwin.bar = 0; - ui.vwin.y = WIN_Y; - ui.vwin.y_trg = ui.vwin.u; + p_current_ui->vwin.bar = 0; + p_current_ui->vwin.y = WIN_Y; + p_current_ui->vwin.y_trg = p_current_ui->vwin.u; } static void OLED_ValWinShow(Option* win) { - if(ui.upara->valwin_broken) //如果要背景虚化的话 + if(p_current_ui->upara->valwin_broken) //如果要背景虚化的话 { OLED_SetPointColor(0); OLED_AllSrcFade(0,0x55); OLED_AllSrcFade(1,0xAA); OLED_SetPointColor(1); } - ui.vwin.bar_trg = (float)(win->val - win->item_min)/(float)(win->item_max - win->item_min)*(WIN_BAR_W - 4); + p_current_ui->vwin.bar_trg = (float)(win->val - win->item_min)/(float)(win->item_max - win->item_min)*(WIN_BAR_W - 4); - OLED_Animation(&ui.vwin.bar, &ui.vwin.bar_trg,ui.upara->ani_param[WIN_ANI]); - OLED_Animation(&ui.vwin.y, &ui.vwin.y_trg,ui.upara->ani_param[WIN_ANI]); + OLED_Animation(&p_current_ui->vwin.bar, &p_current_ui->vwin.bar_trg,p_current_ui->upara->ani_param[WIN_ANI]); + OLED_Animation(&p_current_ui->vwin.y, &p_current_ui->vwin.y_trg,p_current_ui->upara->ani_param[WIN_ANI]); OLED_SetPointColor(0); - OLED_WinDrawRBox(&w_all, ui.vwin.l, (int16_t)ui.vwin.y, WIN_W, WIN_H, 2); //弹窗背景黑边 + OLED_WinDrawRBox(&w_all, p_current_ui->vwin.l, (int16_t)p_current_ui->vwin.y, WIN_W, WIN_H, 2); //弹窗背景黑边 OLED_SetPointColor(1); - OLED_WinDrawRBoxEmpty(&w_all, ui.vwin.l, (int16_t)ui.vwin.y, WIN_W, WIN_H, 2); //弹窗外框 - OLED_WinDrawRBoxEmpty(&w_all, ui.vwin.l + 5, (int16_t)ui.vwin.y + 20,WIN_BAR_W, WIN_BAR_H, 1); //进度条外框 - OLED_WinDrawRBox(&w_all, ui.vwin.l+7, (int16_t)ui.vwin.y+22, ui.vwin.bar, WIN_BAR_H - 4,1); //绘制进度条 - OLED_WinDrawStr(&w_all, ui.vwin.l + 5,(int16_t)ui.vwin.y+2, WIN_FNOT_H, (uint8_t*)&(win->text[2])); //提示文本跳过“~ ” - OLED_WinDrawStr(&w_all, ui.vwin.l + 6 + OLED_GetStrWidth((char*)&(win->text[2]),WIN_FNOT_H), - (int16_t)ui.vwin.y+2,WIN_FNOT_H, (uint8_t*)(itoa(win->val))); //数值 + OLED_WinDrawRBoxEmpty(&w_all, p_current_ui->vwin.l, (int16_t)p_current_ui->vwin.y, WIN_W, WIN_H, 2); //弹窗外框 + OLED_WinDrawRBoxEmpty(&w_all, p_current_ui->vwin.l + 5, (int16_t)p_current_ui->vwin.y + 20,WIN_BAR_W, WIN_BAR_H, 1); //进度条外框 + OLED_WinDrawRBox(&w_all, p_current_ui->vwin.l+7, (int16_t)p_current_ui->vwin.y+22, p_current_ui->vwin.bar, WIN_BAR_H - 4,1); //绘制进度条 + OLED_WinDrawStr(&w_all, p_current_ui->vwin.l + 5,(int16_t)p_current_ui->vwin.y+2, WIN_FNOT_H, (uint8_t*)&(win->text[2])); //提示文本跳过“~ ” + OLED_WinDrawStr(&w_all, p_current_ui->vwin.l + 6 + OLED_GetStrWidth((char*)&(win->text[2]),WIN_FNOT_H), + (int16_t)p_current_ui->vwin.y+2,WIN_FNOT_H, (uint8_t*)(itoa(win->val))); //数值 } static void OLED_ValWinReact(PageAddr bg, Option* select_win) { - if(ui.vwin.y == ui.vwin.y_trg && ui.vwin.y != WIN_Y_TRG) //弹窗进场动画结束时 + if(p_current_ui->vwin.y == p_current_ui->vwin.y_trg && p_current_ui->vwin.y != WIN_Y_TRG) //弹窗进场动画结束时 { InputMsg msg = OLED_MsgQueRead(); switch (msg) @@ -382,15 +536,15 @@ static void OLED_ValWinReact(PageAddr bg, Option* select_win) break; case msg_click: //点击确认也会退出弹窗,不过,点击确认是会触发一次回调,点击返回则不会 case msg_return: - ui.vwin.y_trg = WIN_Y_TRG; //弹窗退场 - ui.vwin.state = 0; //状态标志,退出弹窗 + p_current_ui->vwin.y_trg = WIN_Y_TRG; //弹窗退场 + p_current_ui->vwin.state = 0; //状态标志,退出弹窗 break; default:break; } if (msg != msg_none && msg != msg_return) //只有弹窗内有动作,就会实时触发回调 { Page * p = (Page*)bg; - if(p->cb != NULL)p->cb(p->page_id, select_win); + if(p->cb != NULL)p->cb(p, select_win); } } } @@ -401,14 +555,14 @@ static void OLED_ValWinReact(PageAddr bg, Option* select_win) static void OLED_ConWinAnimInit(PageAddr bg) { UNUSED_PARAMETER(bg); - ui.cwin.y = CON_WIN_Y; - ui.cwin.y_trg = ui.cwin.u; - ui.cwin.bar = ui.cwin.l; + p_current_ui->cwin.y = CON_WIN_Y; + p_current_ui->cwin.y_trg = p_current_ui->cwin.u; + p_current_ui->cwin.bar = p_current_ui->cwin.l; } static void OLED_ConWinShow(Option* win) { - if(ui.upara->conwin_broken) //如果要背景虚化的话 + if(p_current_ui->upara->conwin_broken) //如果要背景虚化的话 { OLED_SetPointColor(0); OLED_AllSrcFade(0,0x55); @@ -416,31 +570,31 @@ static void OLED_ConWinShow(Option* win) OLED_SetPointColor(1); } //对应的动画 - OLED_Animation(&ui.cwin.y, &ui.cwin.y_trg,ui.upara->ani_param[WIN_ANI]); - // OLED_Animation(&ui.cwin.bar, &ui.cwin.bar_trg,ui.upara->ani_param[WIN_ANI]); //ConWin的选项不用横向移动 + OLED_Animation(&p_current_ui->cwin.y, &p_current_ui->cwin.y_trg,p_current_ui->upara->ani_param[WIN_ANI]); + // OLED_Animation(&p_current_ui->cwin.bar, &p_current_ui->cwin.bar_trg,p_current_ui->upara->ani_param[WIN_ANI]); //ConWin的选项不用横向移动 OLED_SetPointColor(0);//绘制外围黑框 - OLED_WinDrawRBox(&w_all, ui.cwin.l, (int16_t)ui.cwin.y, CON_WIN_W, CON_WIN_H, CON_WIN_R); //弹窗背景黑边 + OLED_WinDrawRBox(&w_all, p_current_ui->cwin.l, (int16_t)p_current_ui->cwin.y, CON_WIN_W, CON_WIN_H, CON_WIN_R); //弹窗背景黑边 OLED_SetPointColor(1); //绘制外框 - OLED_WinDrawRBoxEmpty(&w_all, ui.cwin.l, (int16_t)ui.cwin.y, CON_WIN_W,CON_WIN_H,CON_WIN_R); - OLED_WinDrawStr(&w_all, (OLED_WIDTH - OLED_GetStrWidth((const char*)&(win->text[2]),CON_WIN_FONT_H) )>>1, (int16_t)ui.cwin.y, + OLED_WinDrawRBoxEmpty(&w_all, p_current_ui->cwin.l, (int16_t)p_current_ui->cwin.y, CON_WIN_W,CON_WIN_H,CON_WIN_R); + OLED_WinDrawStr(&w_all, (OLED_WIDTH - OLED_GetStrWidth((const char*)&(win->text[2]),CON_WIN_FONT_H) )>>1, (int16_t)p_current_ui->cwin.y, CON_WIN_FONT_H,(uint8_t*)&(win->text[2]));// 《/2》 - OLED_WinDrawStr(&w_all, ui.cwin.l+15, (int16_t)ui.cwin.y+20,CON_WIN_FONT_H,(uint8_t*)"Yes"); - OLED_WinDrawStr(&w_all, OLED_WIDTH-ui.cwin.l-30, (int16_t)ui.cwin.y+20,CON_WIN_FONT_H,(uint8_t*)"No"); - OLED_WinDrawRBoxEmpty(&w_all, ui.cwin.l, (int16_t)ui.cwin.y+18, CON_WIN_W/2,CON_WIN_BTN_H,CON_WIN_R); //绘制选项框《/2》 - OLED_WinDrawRBoxEmpty(&w_all, ui.cwin.l+CON_WIN_W/2, (int16_t)ui.cwin.y+18, CON_WIN_W/2,CON_WIN_BTN_H,CON_WIN_R); //《/2》 + OLED_WinDrawStr(&w_all, p_current_ui->cwin.l+15, (int16_t)p_current_ui->cwin.y+20,CON_WIN_FONT_H,(uint8_t*)"Yes"); + OLED_WinDrawStr(&w_all, OLED_WIDTH-p_current_ui->cwin.l-30, (int16_t)p_current_ui->cwin.y+20,CON_WIN_FONT_H,(uint8_t*)"No"); + OLED_WinDrawRBoxEmpty(&w_all, p_current_ui->cwin.l, (int16_t)p_current_ui->cwin.y+18, CON_WIN_W/2,CON_WIN_BTN_H,CON_WIN_R); //绘制选项框《/2》 + OLED_WinDrawRBoxEmpty(&w_all, p_current_ui->cwin.l+CON_WIN_W/2, (int16_t)p_current_ui->cwin.y+18, CON_WIN_W/2,CON_WIN_BTN_H,CON_WIN_R); //《/2》 OLED_SetPointColor(2); //反色绘制 if(win->val == True) //选中的话 - OLED_WinDrawRBox(&w_all, ui.cwin.bar, (int16_t)ui.cwin.y+18, CON_WIN_W/2, CON_WIN_BTN_H, CON_WIN_R);//绘制选中背景 《/2》 + OLED_WinDrawRBox(&w_all, p_current_ui->cwin.bar, (int16_t)p_current_ui->cwin.y+18, CON_WIN_W/2, CON_WIN_BTN_H, CON_WIN_R);//绘制选中背景 《/2》 else - OLED_WinDrawRBox(&w_all, ui.cwin.bar+CON_WIN_W/2, (int16_t)ui.cwin.y+18, CON_WIN_W/2, CON_WIN_BTN_H, CON_WIN_R); //《/2》 + OLED_WinDrawRBox(&w_all, p_current_ui->cwin.bar+CON_WIN_W/2, (int16_t)p_current_ui->cwin.y+18, CON_WIN_W/2, CON_WIN_BTN_H, CON_WIN_R); //《/2》 OLED_SetPointColor(1);//改回实色绘制 } static void OLED_ConWinReact(PageAddr bg,Option* win) { - if(ui.cwin.y == ui.cwin.y_trg && ui.cwin.y != CON_WIN_Y_TRG) //弹窗进场动画结束 + if(p_current_ui->cwin.y == p_current_ui->cwin.y_trg && p_current_ui->cwin.y != CON_WIN_Y_TRG) //弹窗进场动画结束 { InputMsg msg = OLED_MsgQueRead(); Page* p = (Page*)bg; @@ -449,14 +603,14 @@ static void OLED_ConWinReact(PageAddr bg,Option* win) case msg_up: case msg_down: //上下键在确认弹窗时用于切换 win->val = !(win->val); - ui.cwin.bar_trg = ui.cwin.l; //触发选项移动动画 + p_current_ui->cwin.bar_trg = p_current_ui->cwin.l; //触发选项移动动画 break; case msg_click: //对于确认弹窗来说,只有按下确认键,才会触发回调 - if((p->cb) != NULL)p->cb(p->page_id, win); + if((p->cb) != NULL)p->cb(p, win); //这儿不用break;因为确认结束,直接退出弹窗 case msg_return: - ui.cwin.y_trg = CON_WIN_Y_TRG; //弹窗退场 - ui.cwin.state = 0; //标志退出弹窗状态 + p_current_ui->cwin.y_trg = CON_WIN_Y_TRG; //弹窗退场 + p_current_ui->cwin.state = 0; //标志退出弹窗状态 break; default: break; @@ -494,65 +648,60 @@ static void OLED_ListDrawText_CheckBox(float start_y ,Option* item) static void OLED_ListPageAnimInit(PageAddr page_addr) { - ListPage * lp = (ListPage *)page_addr; - lp->y = 0; - lp->y_trg = LIST_LINE_H; - lp->box_x = 0; - lp->box_y = 0; - lp->bar_y = 0; -// ui.vwin.state = 0; //刚进入列表时默认关闭弹窗 -// #if UI_CONWIN_ENABLE -// ui.cwin.state = 0; //刚进入列表时默认关闭弹窗 -// #endif + p_current_ui->lp_var.y = 0; + p_current_ui->lp_var.y_trg = LIST_LINE_H; + p_current_ui->lp_var.box_x = 0; + p_current_ui->lp_var.box_y = 0; + p_current_ui->lp_var.bar_y = 0; } static void OLED_ListPageShow(PageAddr page_addr) { ListPage * lp = (ListPage *)page_addr; static float temp = 0; //用于临时存放列表每一项的y坐标 //计算选中框目标值和进度条y值目标 - lp->box_x_trg = OLED_GetStrWidth(lp->option_array[lp->select_item].text,LIST_TEXT_H) + LIST_TEXT_S * 2; - lp->bar_y_trg = (int16_t)(lp->select_item * OLED_HEIGHT/(lp->item_num-1))+1; + p_current_ui->lp_var.box_x_trg = OLED_GetStrWidth(lp->option_array[lp->select_item].text,LIST_TEXT_H) + LIST_TEXT_S * 2; + p_current_ui->lp_var.bar_y_trg = (int16_t)(lp->select_item * OLED_HEIGHT/(lp->item_num-1))+1; //计算动画过渡值 - OLED_Animation(&(lp->y), &(lp->y_trg), ui.upara->ani_param[LIST_ANI]); - OLED_Animation(&(lp->box_x), &(lp->box_x_trg), ui.upara->ani_param[LIST_ANI]); - OLED_Animation(&(lp->box_y), &(lp->box_y_trg), ui.upara->ani_param[LIST_ANI]); - OLED_Animation(&(lp->bar_y), &(lp->bar_y_trg), ui.upara->ani_param[LIST_ANI]); + OLED_Animation(&(p_current_ui->lp_var.y), &(p_current_ui->lp_var.y_trg), p_current_ui->upara->ani_param[LIST_ANI]); + OLED_Animation(&(p_current_ui->lp_var.box_x), &(p_current_ui->lp_var.box_x_trg), p_current_ui->upara->ani_param[LIST_ANI]); + OLED_Animation(&(p_current_ui->lp_var.box_y), &(lp->box_y_trg), p_current_ui->upara->ani_param[LIST_ANI]); + OLED_Animation(&(p_current_ui->lp_var.bar_y), &(p_current_ui->lp_var.bar_y_trg), p_current_ui->upara->ani_param[LIST_ANI]); //绘制进度条 OLED_WinDrawHLine(&w_all,OLED_WIDTH - LIST_BAR_W,0,LIST_BAR_W); OLED_WinDrawHLine(&w_all,OLED_WIDTH - LIST_BAR_W,OLED_HEIGHT-1,LIST_BAR_W); OLED_WinDrawVLine(&w_all,OLED_WIDTH - ((LIST_BAR_W/2)+1),0,OLED_HEIGHT); - OLED_WinDrawRBox(&w_all,OLED_WIDTH - LIST_BAR_W,0,LIST_BAR_W,lp->bar_y,0); + OLED_WinDrawRBox(&w_all,OLED_WIDTH - LIST_BAR_W,0,LIST_BAR_W,p_current_ui->lp_var.bar_y,0); - if(lp->slip_flag && lp->box_y == lp->box_y_trg) lp->slip_flag = False; + if(p_current_ui->lp_var.slip_flag && p_current_ui->lp_var.box_y == lp->box_y_trg) p_current_ui->lp_var.slip_flag = False; //该标志位是为了防止 切换动画导致的box_y移动对过度动画造成影响 - if(!ui.init_finish_flag) //过度动画 + if(!p_current_ui->init_finish_flag) //过度动画 { for (uint8_t i = 0; i < (lp->item_num); i++) { - if(ui.upara->ufd_param[LIST_UFD]) //从头展开 - temp = i*(lp->y) - LIST_LINE_H*(lp->select_item) + (lp->box_y_trg); + if(p_current_ui->upara->ufd_param[LIST_UFD]) //从头展开 + temp = i*(p_current_ui->lp_var.y) - LIST_LINE_H*(lp->select_item) + (lp->box_y_trg); else //选中项展开 - temp = (i - (lp->select_item))*(lp->y) + lp->box_y_trg; + temp = (i - (lp->select_item))*(p_current_ui->lp_var.y) + lp->box_y_trg; OLED_ListDrawText_CheckBox(temp, &(lp->option_array[i])); } - if(lp->y == lp->y_trg) //动画抵达目标位置 + if(p_current_ui->lp_var.y == p_current_ui->lp_var.y_trg) //动画抵达目标位置 { - ui.init_finish_flag = True;//过度动画完成 - lp->y = lp->y_trg = -LIST_LINE_H * (lp->select_item) + (lp->box_y_trg); + p_current_ui->init_finish_flag = True;//过度动画完成 + p_current_ui->lp_var.y = p_current_ui->lp_var.y_trg = -LIST_LINE_H * (lp->select_item) + (lp->box_y_trg); //第一个选项到光标(盒子)所在的距离确定下来 } } else //过度后,一般上下切换选项时的动画,但目标参数不在这儿设置 for (uint8_t i = 0; i < (lp->item_num); i++) { - temp = LIST_LINE_H *i + (lp->y); + temp = LIST_LINE_H *i + (p_current_ui->lp_var.y); OLED_ListDrawText_CheckBox(temp, &(lp->option_array[i])); } //绘制文字选中框,框需要在文字前绘制,否则文字无法显色 OLED_SetPointColor(2);//反色绘制 - OLED_WinDrawRBox(&w_all, 0, lp->box_y, lp->box_x, LIST_LINE_H, LIST_BOX_R); + OLED_WinDrawRBox(&w_all, 0, p_current_ui->lp_var.box_y, p_current_ui->lp_var.box_x, LIST_LINE_H, LIST_BOX_R); OLED_SetPointColor(1);//实色绘制 } @@ -567,22 +716,22 @@ static void OLED_ListPageReact(PageAddr page_addr) switch (msg) { case msg_up: //上一个 - if(ui.init_finish_flag && !(lp->slip_flag)) //初始化动画已完成 + if(p_current_ui->init_finish_flag && !(p_current_ui->lp_var.slip_flag)) //初始化动画已完成 { #if PAGE_WAVE_ENABLE - if(OLED_CheckPageType(lp) == type_wave) wave_tag.change_flag = True;//如果是波形页面的话,标志波形切换 + if(OLED_CheckPageType(lp) == type_wave) p_current_ui->wt_var.change_flag = True;//如果是波形页面的话,标志波形切换 #endif if(lp->select_item == 0) //选中第一个的话 { - if(ui.upara->loop_param[LIST_LOOP]) //同时loop参数开的话 + if(p_current_ui->upara->loop_param[LIST_LOOP]) //同时loop参数开的话 { - lp->slip_flag = True; + p_current_ui->lp_var.slip_flag = True; lp->select_item = lp->item_num - 1; //选中最后一个 if(lp->item_num > lp->line_n) //数目超出一页的最大数目 {//更改box到最底 lp->box_y_trg = OLED_HEIGHT - LIST_LINE_H; //同时更改文字到最底 - lp->y_trg = OLED_HEIGHT - (lp->item_num)*LIST_LINE_H; + p_current_ui->lp_var.y_trg = OLED_HEIGHT - (lp->item_num)*LIST_LINE_H; } else // 没有超出数目则是到最后一个 lp->box_y_trg = (lp->item_num - 1)*LIST_LINE_H; @@ -591,20 +740,20 @@ static void OLED_ListPageReact(PageAddr page_addr) else //没有选中第一个 { lp->select_item -= 1; //选中减1 - if(lp->select_item < -((lp->y_trg) / LIST_LINE_H))//光标盒子到页面顶了???? + if(lp->select_item < -((p_current_ui->lp_var.y_trg) / LIST_LINE_H))//光标盒子到页面顶了???? { if(!(OLED_HEIGHT % LIST_LINE_H)) //上面剩余完整的行 - lp->y_trg += LIST_LINE_H; //文字下移 + p_current_ui->lp_var.y_trg += LIST_LINE_H; //文字下移 else //上面的行不完整(LIST_LINE_H该项用于页面和行高非整除时) { if(lp->box_y_trg == OLED_HEIGHT-LIST_LINE_H*lp->line_n) {//文字往下走一行,且光标盒子置于0处,把上面的非整行去掉 - lp->y_trg += (lp->line_n+1)*LIST_LINE_H - OLED_HEIGHT; + p_current_ui->lp_var.y_trg += (lp->line_n+1)*LIST_LINE_H - OLED_HEIGHT; lp->box_y_trg = 0; } else if(lp->box_y_trg == LIST_LINE_H) lp->box_y_trg = 0; //上面整行直接移动光标盒子 - else lp->y_trg += LIST_LINE_H; //顶页整行,文字直接往下走 + else p_current_ui->lp_var.y_trg += LIST_LINE_H; //顶页整行,文字直接往下走 } } else //光标盒子没到页面顶 @@ -613,38 +762,40 @@ static void OLED_ListPageReact(PageAddr page_addr) } break; case msg_down: //下一个 - if(ui.init_finish_flag && !(lp->slip_flag)) //初始化动作已完成 + if(p_current_ui->init_finish_flag && !(p_current_ui->lp_var.slip_flag)) //初始化动作已完成 { #if PAGE_WAVE_ENABLE - if(OLED_CheckPageType(lp) == type_wave) wave_tag.change_flag = True;//如果是波形页面的话,标志波形切换 + if(OLED_CheckPageType(lp) == type_wave) p_current_ui->wt_var.change_flag = True;//如果是波形页面的话,标志波形切换 #endif if(lp->select_item == (lp->item_num) -1) //到最后一个选项了 { - if(ui.upara->loop_param[LIST_LOOP]) //loop开关开 + if(p_current_ui->upara->loop_param[LIST_LOOP]) //loop开关开 {//全部回到顶部 - lp->slip_flag = True; + p_current_ui->lp_var.slip_flag = True; lp->select_item = 0; - lp->y_trg = 0; + p_current_ui->lp_var.y_trg = 0; lp->box_y_trg = 0; } } else //不是最后一个选项 { lp->select_item += 1; - if((lp->select_item+1) > ((lp->line_n) - (lp->y_trg)/LIST_LINE_H)) + if((lp->select_item+1) > ((lp->line_n) - (p_current_ui->lp_var.y_trg)/LIST_LINE_H)) {//光标到页面底 - if(!(OLED_HEIGHT % LIST_LINE_H)) lp->y_trg -= LIST_LINE_H; + if(!(OLED_HEIGHT % LIST_LINE_H)) p_current_ui->lp_var.y_trg -= LIST_LINE_H; else //非整行的情况 { if(lp->box_y_trg == LIST_LINE_H*(lp->line_n-1)) { - lp->y_trg -= (lp->line_n+1)*LIST_LINE_H - OLED_HEIGHT; + p_current_ui->lp_var.y_trg -= (lp->line_n+1)*LIST_LINE_H - OLED_HEIGHT; + //取出要向下移动的距离,对y_trg来说就是向上移动的距离 lp->box_y_trg = OLED_HEIGHT - LIST_LINE_H; } - else if(lp->box_y_trg == OLED_HEIGHT - LIST_LINE_H*2) + else if(lp->box_y_trg == OLED_HEIGHT - LIST_LINE_H*2) + //这种情况什么时候会出现呢嗯? lp->box_y_trg = OLED_HEIGHT - LIST_LINE_H; else - lp->y_trg -= LIST_LINE_H; + p_current_ui->lp_var.y_trg -= LIST_LINE_H; } } else lp->box_y_trg += LIST_LINE_H; @@ -664,7 +815,7 @@ static void OLED_ListPageReact(PageAddr page_addr) //lp->option_array[lp->select_item].val ^= contorl_flip; //将对应值取反(用step的是否非0控制val是否取反) #if PAGE_RADIO_ENABLE - if(selcet_string[0] == '=')radio_click_flag = True; //标记为1,用于OLED_RadioReact进行轮询判断单选 + if(selcet_string[0] == '=')p_current_ui->rp_var.radio_click_flag = True; //标记为1,用于OLED_RadioReact进行轮询判断单选 #endif } @@ -679,15 +830,15 @@ static void OLED_ListPageReact(PageAddr page_addr) if(selcet_string[0] == '~') {//数值弹窗的话,进入数值弹窗这个动作不触发回调,但弹窗内不论点击什么都会实时触发回调 //当数值弹窗step设为0为只读是,进入数值弹窗前会调用一次回调,以便外界更改val值 - ui.vwin.state = 1; //进入弹窗初始化 + p_current_ui->vwin.state = 1; //进入弹窗初始化 if((lp->option_array[lp->select_item].step == 0) && (lp->page.cb != NULL)) - lp->page.cb(lp->page.page_id, &(lp->option_array[lp->select_item])); + lp->page.cb(&(lp->page), &(lp->option_array[lp->select_item])); } #if UI_CONWIN_ENABLE - else if(selcet_string[0] == '$') ui.cwin.state = 1; //进入确认弹窗初始化 + else if(selcet_string[0] == '$') p_current_ui->cwin.state = 1; //进入确认弹窗初始化 //确认弹窗内只有确认弹窗内的click才会触发回调 #endif - else if(lp->page.cb != NULL)lp->page.cb(lp->page.page_id, &(lp->option_array[lp->select_item])); + else if(lp->page.cb != NULL)lp->page.cb(&(lp->page), &(lp->option_array[lp->select_item])); break; default:break; } @@ -695,14 +846,13 @@ static void OLED_ListPageReact(PageAddr page_addr) void OLED_ListPageInit( ListPage * lp, //列表页面对象 - uint8_t page_id, //为该页面分配一个唯一的id uint8_t item_num, //选项个数,需与title数组大小,icon数组大小一致 Option *option_array, //整个页面的选项数组(数组大小需与item_num一致) CallBackFunc call_back) //回调函数,参数为确认选中项index(1-256)0表示未确认哪个选项 { //缺少选项个数检查,检查, lp->page.page_type = type_list; - OLED_PageInit((PageAddr)lp, page_id, call_back); + OLED_PageInit((PageAddr)lp, call_back); lp->page.ani_init = OLED_ListPageAnimInit; lp->page.show = OLED_ListPageShow; lp->page.react = OLED_ListPageReact;//关联相关处理函数 @@ -722,8 +872,10 @@ void OLED_WavePageAnimInit(PageAddr page_addr) { WavePage * wp = (WavePage *)page_addr; OLED_ListPageAnimInit(wp); - wave_tag.text_bg_r = 0; - wave_tag.text_bg_r_trg = WAVE_TEXT_BG_W; + p_current_ui->wt_var.p_rear = 0; + p_current_ui->wt_var.p_head = 0; //重新进入页面时,会重新开始显示波形 + p_current_ui->wt_var.text_bg_r = 0; + p_current_ui->wt_var.text_bg_r_trg = WAVE_TEXT_BG_W; } void OLED_WavePageShow(PageAddr page_addr) @@ -732,28 +884,33 @@ void OLED_WavePageShow(PageAddr page_addr) int16_t temp; //临时变量用于存放波形的点,暂时显示 String temp_str = NULL; OLED_ListPageShow(wp); - OLED_Animation(&wave_tag.text_bg_r, &wave_tag.text_bg_r_trg, ui.upara->ani_param[TAG_ANI]); - OLED_WinDrawRBoxEmpty(&w_all, WAVE_BOX_L_S, 0 ,WAVE_BOX_W , WAVE_BOX_H,0); OLED_WinDrawRBoxEmpty(&w_all, WAVE_BOX_L_S+1, 1 ,WAVE_BOX_W -2, WAVE_BOX_H-2,0); //数据入队列 - wave_tag.data_que[wave_tag.p_rear] = wp->option_array[wp->select_item].val; //放入数据 - wave_tag.p_rear++; wave_tag.p_rear %= (WAVE_W-1); - if((wave_tag.p_rear)%(WAVE_W-1) == wave_tag.p_head) //队列满了 - wave_tag.p_head++; wave_tag.p_head %= (WAVE_W-1); //环状前进 - wave_tag.p_font = wave_tag.p_head; //获取起始地址 - if(wp->box_y == wp->box_y_trg && wp->y == wp->y_trg)//完成过度动画 + if(wp->option_array[wp->select_item].step == 1) //有数据更新,才将数据入队 + { + p_current_ui->wt_var.p_rear++; p_current_ui->wt_var.p_rear %= (WAVE_W-1); + p_current_ui->wt_var.data_que[p_current_ui->wt_var.p_rear] = wp->option_array[wp->select_item].val; //放入数据 + wp->option_array[wp->select_item].step = 0; //将数据更新的标志位置0 + } + if((p_current_ui->wt_var.p_rear+1)%(WAVE_W-1) == p_current_ui->wt_var.p_head) //队列满了 + { + p_current_ui->wt_var.p_head++; p_current_ui->wt_var.p_head %= (WAVE_W-1); //环状前进 + } + p_current_ui->wt_var.p_font = p_current_ui->wt_var.p_head; //获取起始地址 + if(p_current_ui->lp_var.box_y == wp->box_y_trg && p_current_ui->lp_var.y == p_current_ui->lp_var.y_trg)//完成过度动画 { for (uint8_t i = 1; i < WAVE_W -1; i++) { - if(wave_tag.p_rear != wave_tag.p_font) //队列非空 + if(p_current_ui->wt_var.p_rear != p_current_ui->wt_var.p_font) //队列非空 { - temp = wave_tag.data_que[wave_tag.p_font]; - wave_tag.p_font++;wave_tag.p_font %= (WAVE_W -1); //出队指针前移 + temp = p_current_ui->wt_var.data_que[p_current_ui->wt_var.p_font]; + p_current_ui->wt_var.p_font++;p_current_ui->wt_var.p_font %= (WAVE_W -1); //出队指针前移 //画点或者差值画斜线函数 OLED_WinDrawPoint(&w_all,WAVE_L + i , - WAVE_BOX_H - (temp - wp->option_array[wp->select_item].item_min)*WAVE_BOX_H/(wp->option_array[wp->select_item].item_max - wp->option_array[wp->select_item].item_min)); + WAVE_BOX_H-2 - (temp - wp->option_array[wp->select_item].item_min)*(WAVE_BOX_H-4)/(wp->option_array[wp->select_item].item_max - wp->option_array[wp->select_item].item_min)); + //因为0会占掉一个像素点,所以波形没有完全对称。 } else break; } @@ -763,7 +920,9 @@ void OLED_WavePageShow(PageAddr page_addr) OLED_HEIGHT-28, WAVE_FONT_H, (uint8_t*)temp_str); //绘制选框 OLED_SetPointColor(2); //反色选框 - OLED_WinDrawRBox(&w_all, WAVE_TEXT_BG_L_S, OLED_HEIGHT - WAVE_TEXT_BG_H, wave_tag.text_bg_r, WAVE_TEXT_BG_H, 0); + //注意这个动态宽度在过度动画完成后才执行,且从0到宽度,不是从中间开始的 + OLED_Animation(&p_current_ui->wt_var.text_bg_r, &p_current_ui->wt_var.text_bg_r_trg, p_current_ui->upara->ani_param[TAG_ANI]); + OLED_WinDrawRBox(&w_all, WAVE_TEXT_BG_L_S, OLED_HEIGHT - WAVE_TEXT_BG_H, p_current_ui->wt_var.text_bg_r, WAVE_TEXT_BG_H, 0); OLED_SetPointColor(1); //恢复实色 } } @@ -772,22 +931,23 @@ void OLED_WavePageReact(PageAddr page_addr) { WavePage * wp = (WavePage *)page_addr; OLED_ListPageReact(wp); - if(wave_tag.change_flag) + if(p_current_ui->wt_var.change_flag) { - wave_tag.p_rear = 0; - wave_tag.p_head = 0; //切换选项时,重新开始显示波形 - wave_tag.change_flag = False; + p_current_ui->wt_var.p_rear = 0; + p_current_ui->wt_var.p_head = 0; //切换选项时,重新开始显示波形 + p_current_ui->wt_var.text_bg_r = 0; + p_current_ui->wt_var.text_bg_r_trg = WAVE_TEXT_BG_W; //切换选项时唤醒tag动画 + p_current_ui->wt_var.change_flag = False; } } void OLED_WavePageInit( WavePage * wp, //波形页面对象 - uint8_t page_id, //为该页面分配一个唯一的id uint8_t item_num, //选项个数,需与option_array数组大小,icon数组大小一致 Option *option_array, //整个页面的选项数组(数组大小需与item_num一致) CallBackFunc call_back) //回调函数,参数为 self_id 和 选中项option指针 { - OLED_ListPageInit(wp,page_id,item_num,option_array,call_back); //先初始化为list + OLED_ListPageInit(wp,item_num,option_array,call_back); //先初始化为list wp->page.page_type = type_wave; //指定为波形页面 wp->page.ani_init = OLED_WavePageAnimInit; wp->page.show = OLED_WavePageShow; @@ -798,6 +958,7 @@ void OLED_WavePageInit( void OLED_UIWaveUpdateVal(Option * op, int16_t val) { //这里可以添加断言 + op->step = 1; //wave中的step用于指示是否更新这个波形的数值 op->val = val; } @@ -810,7 +971,7 @@ void OLED_RadioPageReact(PageAddr page_addr) { RadioPage * rp = (RadioPage *)page_addr; OLED_ListPageReact(rp); - if(radio_click_flag) + if(p_current_ui->rp_var.radio_click_flag) { for(uint8_t i = 0; i < rp->item_num; i++) { @@ -820,25 +981,23 @@ void OLED_RadioPageReact(PageAddr page_addr) else rp->option_array[i].val = True; //确保单选 } } - radio_click_flag = False; + p_current_ui->rp_var.radio_click_flag = False; } } void OLED_RadioPageInit( RadioPage * rp, //Radio单选页面对象 - uint8_t page_id, //为该页面分配一个唯一的id uint8_t item_num, //选项个数,option_array 大小一致 Option *option_array, //整个页面的选项数组(数组大小需与item_num一致),需要注意单选项 的 text 需要以“= ”开头,一般标识符则不需要 CallBackFunc call_back) //回调函数,参数为 self_id 和 选中项option指针 { - OLED_ListPageInit(rp, page_id, item_num, option_array, call_back); + OLED_ListPageInit(rp, item_num, option_array, call_back); rp->page.page_type = type_radio; //标记为单选终端页面 rp->page.react = OLED_RadioPageReact; //只有单选的react函数不一样,其他处理函数和list的一样 } #endif - //-----镭射文字界面相关函数 #if PAGE_RADERPIC_ENABLE @@ -847,8 +1006,8 @@ void OLED_RaderPicAnimInit(PageAddr page_addr) RaderPicPage* rpp = (RaderPicPage*)page_addr; if(rpp->cur_pic_index == rpp->pic_num) //所有的图片已经绘制完成,且从pic页面退出重新进入(因为在layIn中调用该函数) rpp->cur_pic_index = 0; //重新开始绘制图片页面的绘制 - rpp->move_x = -1.0; - rpp->move_y = -1.0; + p_current_ui->rrp_var.move_x = -1.0; + p_current_ui->rrp_var.move_y = -1.0; } void OLED_RaderPicShow(PageAddr page_addr) @@ -857,8 +1016,8 @@ void OLED_RaderPicShow(PageAddr page_addr) RaderPic *cur_pic = NULL; Option temp_op; float target = 0; - OLED_Animation(&(rpp->move_x), &target, ui.upara->raderpic_move_rate); - OLED_Animation(&(rpp->move_y), &target, ui.upara->raderpic_move_rate); + OLED_Animation(&(p_current_ui->rrp_var.move_x), &target, p_current_ui->upara->raderpic_move_rate); + OLED_Animation(&(p_current_ui->rrp_var.move_y), &target, p_current_ui->upara->raderpic_move_rate); if(rpp->cur_pic_index < rpp->pic_num) //当前序号在数组大小内的话 { uint8_t pic_finish_flag = 0; @@ -867,17 +1026,17 @@ void OLED_RaderPicShow(PageAddr page_addr) for(uint8_t i = 0; i < rpp->cur_pic_index ; i++) { RaderPic * temp_pic = &(rpp->pic_array[i]); - OLED_WinDrawBMP(&w_all, temp_pic->start_x*(1+rpp->move_x), temp_pic->start_y*(1+rpp->move_y), temp_pic->w, temp_pic->h, temp_pic->pic,1);//实色显示 + OLED_WinDrawBMP(&w_all, temp_pic->start_x*(1+p_current_ui->rrp_var.move_x), temp_pic->start_y*(1+p_current_ui->rrp_var.move_y), temp_pic->w, temp_pic->h, temp_pic->pic,1);//实色显示 } - pic_finish_flag = OLED_WinDrawRaderPic(&w_all,cur_pic->pic, cur_pic->start_x*(1+rpp->move_x), cur_pic->start_y*(1+rpp->move_y), - cur_pic->w,cur_pic->h,cur_pic->rd,ui.upara->raderpic_scan_mode,ui.upara->raderpic_scan_rate); + pic_finish_flag = OLED_WinDrawRaderPic(&w_all,cur_pic->pic, cur_pic->start_x*(1+p_current_ui->rrp_var.move_x), cur_pic->start_y*(1+p_current_ui->rrp_var.move_y), + cur_pic->w,cur_pic->h, &(rpp->pic_end_point), cur_pic->rd,p_current_ui->upara->raderpic_scan_mode,p_current_ui->upara->raderpic_scan_rate); if(pic_finish_flag) //一张图片绘制完成切换下一张 { rpp->cur_pic_index++; //默认自增(1 ~ pic_num) if(rpp->page.cb != NULL) { temp_op.order = rpp->cur_pic_index; - rpp->page.cb(rpp->page.page_id,&temp_op); //传入回调函数第i(1 ~ pic_num)张图像已经绘制完成 + rpp->page.cb(&(rpp->page),&temp_op); //传入回调函数第i(1 ~ pic_num)张图像已经绘制完成 } } } @@ -896,7 +1055,7 @@ void OLED_RaderPicShow(PageAddr page_addr) if(rpp->page.cb != NULL) { temp_op.order = rpp->cur_pic_index; - rpp->page.cb(rpp->page.page_id,&temp_op); //传入回调函数第i(0 ~ pic_num-1)张图像已经绘制完成 + rpp->page.cb(&(rpp->page),&temp_op); //传入回调函数第i(0 ~ pic_num-1)张图像已经绘制完成 } break; default: break; @@ -919,14 +1078,13 @@ void OLED_RaderPicReact(PageAddr page_addr) void OLED_RaderPicPageInit( RaderPicPage* rpp, //镭射页面对象 - uint8_t page_id, //该页面的id uint8_t pic_num, //页面内的图片数量,pic_array的数组大小 RaderPic * pic_array, //镭射图片数组 RaderPicMode mode, //所有图片播放完后的操作模式选择(clear,hold,loop) CallBackFunc cb) //回调函数,在每绘制完一个图片前会调用一次 { rpp->page.page_type = type_rader_pic; - OLED_PageInit((PageAddr)rpp, page_id, cb); + OLED_PageInit((PageAddr)rpp, cb); rpp->pic_num = pic_num; rpp->pic_array = pic_array; rpp->cur_pic_index = 0;//默认第一张显示的序号为数组下标为0的图片 @@ -956,11 +1114,11 @@ static void OLED_DigitalDrawUline(DigitalPage *dp, uint8_t color) { start_x = (OLED_WIDTH-OLED_GetStrWidth(dp->label_array[dp->select_label_index],DIGITAL_Label_SIZE))>>1; end_x = start_x + OLED_GetStrWidth(dp->label_array[dp->select_label_index],DIGITAL_Label_SIZE); - start_y = dp->w_digtal[1].start_y + DIGITAL_Label_SIZE; + start_y = p_current_ui->dp_var.w_digtal[1].start_y + DIGITAL_Label_SIZE; } else if(dp->select_index < Digital_Pos_IndexLabel) //是数字的话 { - start_y = dp->w_digtal[0].start_y + DIGITAL_NUM_SIZE+2; - start_x = 16 + digital_num_xindex[(dp->select_index)*2+1]; //012->135 《*2》 + start_y = p_current_ui->dp_var.w_digtal[0].start_y + DIGITAL_NUM_SIZE+2; + start_x = 16 + p_current_ui->dp_var.digital_num_xindex[(dp->select_index)*2+1]; //012->135 《*2》 end_x = start_x + DIGITAL_NUM_SIZE; //两个字符宽 } if(dp->select_index != Digital_Pos_Complete) @@ -986,11 +1144,11 @@ static void OLED_DigitalDrawUline(DigitalPage *dp, uint8_t color) */ static void OLED_DigitalDirChangey(DigitalPage *dp, DigitalDirect dir) { - dp->num_y = 0; + p_current_ui->dp_var.num_y = 0; switch (dir) { - case Digital_Direct_Increase : dp->num_y_trg = -24; break; - case Digital_Direct_Decrease : dp->num_y_trg = 24; break; + case Digital_Direct_Increase : p_current_ui->dp_var.num_y_trg = -24; break; + case Digital_Direct_Decrease : p_current_ui->dp_var.num_y_trg = 24; break; default:break; } } @@ -1037,16 +1195,16 @@ static void OLED_DigitalSetValAnim(DigitalPage * dp, DigitalPosIndex bit, uint8_ if((val >= dp->option_array[bit].item_min) && (val <= dp->option_array[bit].item_max) && (last_val != val)) //更新的数据符合要求 { dp->option_array[bit].val = val; - dp->dir = dir; + p_current_ui->dp_var.dir = dir; if((val%100)/10 != (last_val%100)/10) //十位发生变化 { - dp->digital_num_pos |= (1<<(bit*2+1)); //012->135 - dp->temp_ripple_index = (bit*2+1); //记下这个十位 + p_current_ui->dp_var.digital_num_pos |= (1<<(bit*2+1)); //012->135 + p_current_ui->dp_var.temp_ripple_index = (bit*2+1); //记下这个十位 } if(val%10 != (last_val%10)) //个位发生变化 { - dp->digital_num_pos |= (1<<(bit*2)); //012->024 - dp->temp_ripple_index = (bit*2); //记下这个个位(个位在十位后,所以最低位会被记录) + p_current_ui->dp_var.digital_num_pos |= (1<<(bit*2)); //012->024 + p_current_ui->dp_var.temp_ripple_index = (bit*2); //记下这个个位(个位在十位后,所以最低位会被记录) } } } @@ -1063,55 +1221,50 @@ static void OLED_DigitalSetValAnim(DigitalPage * dp, DigitalPosIndex bit, uint8_ static void OLED_DigitalDrawLabel(DigitalPage * dp, int16_t y , String label) { int16_t x = (OLED_WIDTH-OLED_GetStrWidth(label,DIGITAL_Label_SIZE))>>1; // 计算起始横坐标 - OLED_WinDrawStr(&(dp->w_digtal[1]), x, y, DIGITAL_Label_SIZE, (uint8_t*)(label)); // 绘制标签 + OLED_WinDrawStr(&(p_current_ui->dp_var.w_digtal[1]), x, y, DIGITAL_Label_SIZE, (uint8_t*)(label)); // 绘制标签 } - -static uint8_t temp_num_pos = 0; //用于在show函数内暂时装载num_pos变量,实现同时运动动画和ripple动画的切换 -static DigitalDirect temp_dir = Digital_Direct_None; //记录下运动方向 -static DigitalDirect temp_label_dir = Digital_Direct_None; //记录下label运动方向,防止数字和label同时需要运动的情况出现 - static void OLED_DigitalShow(PageAddr page_addr) { DigitalPage* dp = (DigitalPage*)page_addr; - if(!ui.init_finish_flag) //绘制过度动画 + if(!p_current_ui->init_finish_flag) //绘制过度动画 { - OLED_Animation(&(dp->rect_y), &(dp->rect_y_trg), ui.upara->ani_param[WIN_ANI]); //使用弹窗的速度 - OLED_Animation(&(dp->label_y), &(dp->label_y_trg), ui.upara->ani_param[WIN_ANI]); //使用弹窗的速度 - OLED_WinDrawRBoxEmpty(&w_all,DIGITAL_RECT_X, dp->rect_y, DIGITAL_RECT_W, DIGITAL_RECT_H, DIGITAL_RECT_R); - dp->w_digtal[0].start_y = dp->rect_y + DIGITAL_NUM_T_S; - OLED_WinDrawStr(&(dp->w_digtal[0]), 0, 0, DIGITAL_NUM_SIZE,(uint8_t*)OLED_DigitalCreateText(dp)); + OLED_Animation(&(p_current_ui->dp_var.rect_y), &(p_current_ui->dp_var.rect_y_trg), p_current_ui->upara->ani_param[WIN_ANI]); //使用弹窗的速度 + OLED_Animation(&(p_current_ui->dp_var.label_y), &(p_current_ui->dp_var.label_y_trg), p_current_ui->upara->ani_param[WIN_ANI]); //使用弹窗的速度 + OLED_WinDrawRBoxEmpty(&w_all,DIGITAL_RECT_X, p_current_ui->dp_var.rect_y, DIGITAL_RECT_W, DIGITAL_RECT_H, DIGITAL_RECT_R); + p_current_ui->dp_var.w_digtal[0].start_y = p_current_ui->dp_var.rect_y + DIGITAL_NUM_T_S; + OLED_WinDrawStr(&(p_current_ui->dp_var.w_digtal[0]), 0, 0, DIGITAL_NUM_SIZE,(uint8_t*)OLED_DigitalCreateText(dp)); //这儿可以将label的移动改为label窗口的移动,再将label绘制在label窗口中 - dp->w_digtal[1].start_y = dp->label_y; //更新label窗口的纵坐标 + p_current_ui->dp_var.w_digtal[1].start_y = p_current_ui->dp_var.label_y; //更新label窗口的纵坐标 OLED_DigitalDrawLabel(dp, 0, dp->label_array[dp->select_label_index]); - if(dp->rect_y == dp->rect_y_trg && dp->label_y == dp->label_y_trg) ui.init_finish_flag = True; + if(p_current_ui->dp_var.rect_y == p_current_ui->dp_var.rect_y_trg && p_current_ui->dp_var.label_y == p_current_ui->dp_var.label_y_trg) p_current_ui->init_finish_flag = True; } else //绘制切换动画 { //绘制不需要移动的框 OLED_WinDrawRBoxEmpty(&w_all,DIGITAL_RECT_X, DIGITAL_RECT_Y, DIGITAL_RECT_W, DIGITAL_RECT_H, DIGITAL_RECT_R); //闪烁 - if(Gap_shine_time <= ((dp->gap_shine_time)>>1)) //恒定为0是显示的内容 + if(p_current_ui->dp_var.Gap_shine_time <= ((dp->gap_shine_time)>>1)) //恒定为0是显示的内容 { - OLED_WinDrawASCII(&w_all, digital_num_xindex[4]+28, dp->w_digtal[0].start_y, DIGITAL_NUM_SIZE, dp->gap_char); - OLED_WinDrawASCII(&w_all, digital_num_xindex[2]+28, dp->w_digtal[0].start_y, DIGITAL_NUM_SIZE, dp->gap_char); + OLED_WinDrawASCII(&w_all, p_current_ui->dp_var.digital_num_xindex[4]+28, p_current_ui->dp_var.w_digtal[0].start_y, DIGITAL_NUM_SIZE, dp->gap_char); + OLED_WinDrawASCII(&w_all, p_current_ui->dp_var.digital_num_xindex[2]+28, p_current_ui->dp_var.w_digtal[0].start_y, DIGITAL_NUM_SIZE, dp->gap_char); } else { - OLED_WinDrawASCII(&w_all, digital_num_xindex[4]+28, dp->w_digtal[0].start_y, DIGITAL_NUM_SIZE, ' '); - OLED_WinDrawASCII(&w_all, digital_num_xindex[2]+28, dp->w_digtal[0].start_y, DIGITAL_NUM_SIZE, ' '); + OLED_WinDrawASCII(&w_all, p_current_ui->dp_var.digital_num_xindex[4]+28, p_current_ui->dp_var.w_digtal[0].start_y, DIGITAL_NUM_SIZE, ' '); + OLED_WinDrawASCII(&w_all, p_current_ui->dp_var.digital_num_xindex[2]+28, p_current_ui->dp_var.w_digtal[0].start_y, DIGITAL_NUM_SIZE, ' '); } - if(Gap_shine_time == dp->gap_shine_time)Gap_shine_time = 0; - else Gap_shine_time++; + if(p_current_ui->dp_var.Gap_shine_time == dp->gap_shine_time)p_current_ui->dp_var.Gap_shine_time = 0; + else p_current_ui->dp_var.Gap_shine_time++; //根据模式横杠闪烁提示 switch(dp->mod) { case Digital_Mode_Edit: - if(Uline_shine_time <= ((dp->uline_shine_time)>>1)) //恒定为0是显示的内容 + if(p_current_ui->dp_var.Uline_shine_time <= ((dp->uline_shine_time)>>1)) //恒定为0是显示的内容 OLED_DigitalDrawUline(dp,0); else OLED_DigitalDrawUline(dp,1); - if(Uline_shine_time == dp->uline_shine_time)Uline_shine_time = 0; - else Uline_shine_time++; + if(p_current_ui->dp_var.Uline_shine_time == dp->uline_shine_time)p_current_ui->dp_var.Uline_shine_time = 0; + else p_current_ui->dp_var.Uline_shine_time++; break; case Digital_Mode_Observe: //未进入编辑模式时,没有横杠 OLED_DigitalDrawUline(dp,0); @@ -1122,113 +1275,113 @@ static void OLED_DigitalShow(PageAddr page_addr) default:break; } //数字上下移动 - if(dp->dir != Digital_Direct_None) + if(p_current_ui->dp_var.dir != Digital_Direct_None) { - if((dp->digital_num_pos & 0x3F) && !(dp->digital_num_pos & 0x40)) + if((p_current_ui->dp_var.digital_num_pos & 0x3F) && !(p_current_ui->dp_var.digital_num_pos & 0x40)) { - temp_dir = dp->dir; //记录数字传入的方向, + p_current_ui->dp_var.temp_dir = p_current_ui->dp_var.dir; //记录数字传入的方向, //ripple模式和一起滚动模式的区别只对数字移动有效(对标签滚动无效) //排除标签是为了防止在数字运动是标签运动重复进入 - if(ui.upara->digital_ripple) //第一次接收到运动消息时, + if(p_current_ui->upara->digital_ripple) //第一次接收到运动消息时, { - OLED_DigitalDirChangey(dp,temp_dir); - temp_num_pos = (dp->digital_num_pos & 0x3F) & (1<temp_ripple_index); - OLED_DigitalSetSingleBit(dp , dp->temp_ripple_index, num_array); //更新第一个需要运动的位的数据 - (dp->temp_ripple_index)++; + OLED_DigitalDirChangey(dp,p_current_ui->dp_var.temp_dir); + p_current_ui->dp_var.temp_num_pos = (p_current_ui->dp_var.digital_num_pos & 0x3F) & (1<dp_var.temp_ripple_index); + OLED_DigitalSetSingleBit(dp , p_current_ui->dp_var.temp_ripple_index, p_current_ui->dp_var.num_array); //更新第一个需要运动的位的数据 + (p_current_ui->dp_var.temp_ripple_index)++; } else //一起滚动的话 { - temp_num_pos = (dp->digital_num_pos & 0x3F); //设置需要滚动的位 - for(uint8_t i = 0; i < 6; i++)OLED_DigitalSetSingleBit(dp ,i , num_array); + p_current_ui->dp_var.temp_num_pos = (p_current_ui->dp_var.digital_num_pos & 0x3F); //设置需要滚动的位 + for(uint8_t i = 0; i < 6; i++)OLED_DigitalSetSingleBit(dp ,i , p_current_ui->dp_var.num_array); //更新选中位的值 - OLED_DigitalDirChangey(dp,temp_dir); + OLED_DigitalDirChangey(dp,p_current_ui->dp_var.temp_dir); } } - else if(dp->digital_num_pos & 0x40) //如果是标签 + else if(p_current_ui->dp_var.digital_num_pos & 0x40) //如果是标签 { - temp_label_dir = dp->dir; + p_current_ui->dp_var.temp_label_dir = p_current_ui->dp_var.dir; } - dp->dir = Digital_Direct_None; //保证只有接收到运动消息的第一次进来 + p_current_ui->dp_var.dir = Digital_Direct_None; //保证只有接收到运动消息的第一次进来 } - if(temp_dir != Digital_Direct_None && (dp->digital_num_pos & 0x3F)) //持续运动//移动的是数字 - OLED_Animation(&(dp->num_y),&(dp->num_y_trg),ui.upara->ani_param[DIGI_ANI]); //从0-24 - if(temp_label_dir != Digital_Direct_None && (dp->digital_num_pos & 0x40)) //移动的是标签 - OLED_Animation(&(dp->label_y),&(dp->label_y_trg),ui.upara->ani_param[DIGI_ANI]); + if(p_current_ui->dp_var.temp_dir != Digital_Direct_None && (p_current_ui->dp_var.digital_num_pos & 0x3F)) //持续运动//移动的是数字 + OLED_Animation(&(p_current_ui->dp_var.num_y),&(p_current_ui->dp_var.num_y_trg),p_current_ui->upara->ani_param[DIGI_ANI]); //从0-24 + if(p_current_ui->dp_var.temp_label_dir != Digital_Direct_None && (p_current_ui->dp_var.digital_num_pos & 0x40)) //移动的是标签 + OLED_Animation(&(p_current_ui->dp_var.label_y),&(p_current_ui->dp_var.label_y_trg),p_current_ui->upara->ani_param[DIGI_ANI]); for(uint8_t i = 0; i < DIGITAL_NUM_INDEX_MAX; i++) //绘制每个数字win的位置 { - if((temp_num_pos & (1<dp_var.temp_num_pos & (1<dp_var.temp_dir == Digital_Direct_Decrease) //选中了数字且收到下的消息 { - OLED_WinDrawASCII(&(dp->w_digtal[0]), digital_num_xindex[i],dp->num_y - DIGITAL_NUM_SIZE,DIGITAL_NUM_SIZE,((num_array[i].num)%10)+'0'); //上一个数字 - OLED_WinDrawASCII(&(dp->w_digtal[0]), digital_num_xindex[i],dp->num_y,DIGITAL_NUM_SIZE,((num_array[i].num+1)%10)+'0'); //这个数字 + OLED_WinDrawASCII(&(p_current_ui->dp_var.w_digtal[0]), p_current_ui->dp_var.digital_num_xindex[i],p_current_ui->dp_var.num_y - DIGITAL_NUM_SIZE,DIGITAL_NUM_SIZE,((p_current_ui->dp_var.num_array[i].num)%10)+'0'); //上一个数字 + OLED_WinDrawASCII(&(p_current_ui->dp_var.w_digtal[0]), p_current_ui->dp_var.digital_num_xindex[i],p_current_ui->dp_var.num_y,DIGITAL_NUM_SIZE,((p_current_ui->dp_var.num_array[i].num+1)%10)+'0'); //这个数字 } - else if((temp_num_pos & (1<dp_var.temp_num_pos & (1<dp_var.temp_dir == Digital_Direct_Increase) //选中数字且收到上的消息 { - OLED_WinDrawASCII(&(dp->w_digtal[0]), digital_num_xindex[i],dp->num_y + DIGITAL_NUM_SIZE,DIGITAL_NUM_SIZE,((num_array[i].num)%10)+'0'); //下一个数字 - OLED_WinDrawASCII(&(dp->w_digtal[0]), digital_num_xindex[i],dp->num_y,DIGITAL_NUM_SIZE,((num_array[i].num-1)%10)+'0'); //这个 + OLED_WinDrawASCII(&(p_current_ui->dp_var.w_digtal[0]), p_current_ui->dp_var.digital_num_xindex[i],p_current_ui->dp_var.num_y + DIGITAL_NUM_SIZE,DIGITAL_NUM_SIZE,((p_current_ui->dp_var.num_array[i].num)%10)+'0'); //下一个数字 + OLED_WinDrawASCII(&(p_current_ui->dp_var.w_digtal[0]), p_current_ui->dp_var.digital_num_xindex[i],p_current_ui->dp_var.num_y,DIGITAL_NUM_SIZE,((p_current_ui->dp_var.num_array[i].num-1)%10)+'0'); //这个 } else //直接绘制这个数字就可以 - { OLED_WinDrawASCII(&(dp->w_digtal[0]), digital_num_xindex[i],0,DIGITAL_NUM_SIZE,(num_array[i].num%10)+'0'); //因为只有单位数字 + { OLED_WinDrawASCII(&(p_current_ui->dp_var.w_digtal[0]), p_current_ui->dp_var.digital_num_xindex[i],0,DIGITAL_NUM_SIZE,(p_current_ui->dp_var.num_array[i].num%10)+'0'); //因为只有单位数字 } } - if(dp->num_y == dp->num_y_trg && (dp->digital_num_pos&0x3F)) //单次字符运动结束时 + if(p_current_ui->dp_var.num_y == p_current_ui->dp_var.num_y_trg && (p_current_ui->dp_var.digital_num_pos&0x3F)) //单次字符运动结束时 { - if(ui.upara->digital_ripple) + if(p_current_ui->upara->digital_ripple) { do{ - temp_num_pos = (dp->digital_num_pos &0x3F) & (1<temp_ripple_index); - if(temp_num_pos) + p_current_ui->dp_var.temp_num_pos = (p_current_ui->dp_var.digital_num_pos &0x3F) & (1<dp_var.temp_ripple_index); + if(p_current_ui->dp_var.temp_num_pos) { - OLED_DigitalDirChangey(dp,temp_dir); //设置运动坐标 - OLED_DigitalSetSingleBit(dp, dp->temp_ripple_index ,num_array);//更新下一位数据 - (dp->temp_ripple_index)++; //准备检测下一位 + OLED_DigitalDirChangey(dp,p_current_ui->dp_var.temp_dir); //设置运动坐标 + OLED_DigitalSetSingleBit(dp, p_current_ui->dp_var.temp_ripple_index ,p_current_ui->dp_var.num_array);//更新下一位数据 + (p_current_ui->dp_var.temp_ripple_index)++; //准备检测下一位 break; } - dp->temp_ripple_index++; //准备检测下一位 - if(dp->temp_ripple_index >= 6)//所有位到扫描完,才完全退出 + p_current_ui->dp_var.temp_ripple_index++; //准备检测下一位 + if(p_current_ui->dp_var.temp_ripple_index >= 6)//所有位到扫描完,才完全退出 { - temp_dir = Digital_Direct_None;dp->digital_num_pos &= 0xC0; - temp_num_pos = 0; //全部数字运动完清零 + p_current_ui->dp_var.temp_dir = Digital_Direct_None;p_current_ui->dp_var.digital_num_pos &= 0xC0; + p_current_ui->dp_var.temp_num_pos = 0; //全部数字运动完清零 break;//所有位检测完了break; } }while(1); //不需要运动继续往下检测 } else - {temp_dir = Digital_Direct_None; dp->digital_num_pos &= 0xC0;} + {p_current_ui->dp_var.temp_dir = Digital_Direct_None; p_current_ui->dp_var.digital_num_pos &= 0xC0;} } //标签上下移动 //绘制移动标签 - if((dp->digital_num_pos&0x40) && temp_label_dir == Digital_Direct_Increase) + if((p_current_ui->dp_var.digital_num_pos&0x40) && p_current_ui->dp_var.temp_label_dir == Digital_Direct_Increase) { - OLED_DigitalDrawLabel(dp, dp->label_y + DIGITAL_Label_SIZE, dp->label_array[dp->select_label_index]); - OLED_DigitalDrawLabel(dp, dp->label_y, dp->label_array[last_or_next_label_index]); + OLED_DigitalDrawLabel(dp, p_current_ui->dp_var.label_y + DIGITAL_Label_SIZE, dp->label_array[dp->select_label_index]); + OLED_DigitalDrawLabel(dp, p_current_ui->dp_var.label_y, dp->label_array[p_current_ui->dp_var.last_or_next_label_index]); } - else if (((dp->digital_num_pos)&0x40) && temp_label_dir == Digital_Direct_Decrease) + else if (((p_current_ui->dp_var.digital_num_pos)&0x40) && p_current_ui->dp_var.temp_label_dir == Digital_Direct_Decrease) { - OLED_DigitalDrawLabel(dp, dp->label_y - DIGITAL_Label_SIZE, dp->label_array[dp->select_label_index]); - OLED_DigitalDrawLabel(dp, dp->label_y, dp->label_array[last_or_next_label_index]); + OLED_DigitalDrawLabel(dp, p_current_ui->dp_var.label_y - DIGITAL_Label_SIZE, dp->label_array[dp->select_label_index]); + OLED_DigitalDrawLabel(dp, p_current_ui->dp_var.label_y, dp->label_array[p_current_ui->dp_var.last_or_next_label_index]); } else OLED_DigitalDrawLabel(dp, 0, dp->label_array[dp->select_label_index]); //运动完成 - if(dp->label_y == dp->label_y_trg && ((dp->digital_num_pos)&0x40)) - { temp_label_dir = Digital_Direct_None; dp->digital_num_pos &= 0x3F;} + if(p_current_ui->dp_var.label_y == p_current_ui->dp_var.label_y_trg && ((p_current_ui->dp_var.digital_num_pos)&0x40)) + { p_current_ui->dp_var.temp_label_dir = Digital_Direct_None; p_current_ui->dp_var.digital_num_pos &= 0x3F;} } } static void OLED_DigitalAnimInit(PageAddr page_addr) { DigitalPage* dp = (DigitalPage*)page_addr; - dp->rect_y = - DIGITAL_RECT_Y - DIGITAL_RECT_H; - dp->rect_y_trg = DIGITAL_RECT_Y ; - dp->label_y = OLED_HEIGHT; - dp->label_y_trg = OLED_HEIGHT- DIGITAL_Label_SIZE-4; - dp->dir = Digital_Direct_None; //默认进入页面没有动作 dp->mod = Digital_Mode_Observe; //默认观察模式 - dp->digital_num_pos = 0; //默认没有选中数字 - dp->temp_ripple_index = 0; //默认没有开始滚动 dp->select_index = Digital_Pos_Complete; //默认光标位置为完成状态(即没有选中任何位) for(uint8_t i = 0; i < 6; i++) - OLED_DigitalSetSingleBit(dp, i, num_array); //设置显示数字 + OLED_DigitalSetSingleBit(dp, i,p_current_ui->dp_var.num_array); //设置显示数字 + p_current_ui->dp_var.rect_y = - DIGITAL_RECT_Y - DIGITAL_RECT_H; + p_current_ui->dp_var.rect_y_trg = DIGITAL_RECT_Y ; + p_current_ui->dp_var.label_y = OLED_HEIGHT; + p_current_ui->dp_var.label_y_trg = OLED_HEIGHT- DIGITAL_Label_SIZE-4; + p_current_ui->dp_var.dir = Digital_Direct_None; //默认进入页面没有动作 + p_current_ui->dp_var.digital_num_pos = 0; //默认没有选中数字 + p_current_ui->dp_var.temp_ripple_index = 0; //默认没有开始滚动 } @@ -1251,7 +1404,7 @@ static void OLED_DigitalSetOptionAndCallback(DigitalPage *dp, Option *op) } // 如果页面回调函数不为空,则调用回调函数并传入页面ID和选项指针 if (dp->page.cb != NULL) - dp->page.cb(dp->page.page_id, op); + dp->page.cb(&(dp->page), op); } @@ -1275,8 +1428,8 @@ static void OLED_DigitalReact(PageAddr page_addr) } else if(msg == msg_return) { - temp_dir = Digital_Direct_None; - temp_num_pos = 0; //退出时将临时变量全部清零,防止动画运行一半退出时,在其他DigitalPage页面造成影响。 + p_current_ui->dp_var.temp_dir = Digital_Direct_None; + p_current_ui->dp_var.temp_num_pos = 0; //退出时将临时变量全部清零,防止动画运行一半退出时,在其他DigitalPage页面造成影响。 OLED_PageReturn((PageAddr)dp); } break; @@ -1335,7 +1488,6 @@ static void OLED_DigitalReact(PageAddr page_addr) void OLED_DigitalPageInit( DigitalPage* dp, //数字显示页面 - uint8_t page_id, //当前页面id Option * option_array, //选项数组,必须包含3个选项,因为要显示3个数字 uint8_t label_array_num, //标签数组的大小 String * label_array, //标签数组,方便标签滚动,数组大小必须和label_array_num一致 @@ -1346,7 +1498,7 @@ void OLED_DigitalPageInit( ) { dp->page.page_type = type_digital; //赋值页面类型 - OLED_PageInit((PageAddr)dp, page_id, cb); + OLED_PageInit((PageAddr)dp, cb); //对方法赋值 dp->page.ani_init = OLED_DigitalAnimInit; dp->page.show = OLED_DigitalShow; @@ -1360,13 +1512,6 @@ void OLED_DigitalPageInit( dp->gap_char = gap_char; dp->gap_shine_time = gap_shine_time; dp->uline_shine_time = uline_shine_time; - //数字控件的横坐标 - dp->w_digtal[0].start_x = 16; //确定数字窗口的x坐标 - dp->w_digtal[0].h = 24; - dp->w_digtal[0].w = 96; //数字窗口的一些参数 - dp->w_digtal[1].start_x = 0; - dp->w_digtal[1].h = 16; - dp->w_digtal[1].w = 128; //标签窗口的一些参数 } @@ -1381,15 +1526,15 @@ void OLED_DigitalPage_UpdateLabelAnimation(DigitalPage * dp, uint8_t label_index { if(label_index == 255) label_index = dp->label_array_num -1; // 如果标签索引为255,则设置为最后一个标签索引 else if(label_index >= dp->label_array_num)label_index = 0; // 如果标签索引大于等于标签数组长度,则设置为第一个标签索引 - if(dp->page.page_id == ui.current_page_id) //只有当前页面是要更新的页面时,才需要更新动画,否则直接更新值就可以 + if(dp == (DigitalPage*)(p_current_ui->current_page)) //只有当前页面是要更新的页面时,才需要更新动画,否则直接更新值就可以 { // 这里需要考虑下,给外界调用需不需要等待运动完成??????if(digital_num_pos == 0) - dp->dir = dir; // 确定方向 - dp->label_y = 0; // 设置标签的初始位置 - dp->digital_num_pos |= 0x40; // 设置数字位置标志位 - if(dir == Digital_Direct_Increase)dp->label_y_trg = - DIGITAL_Label_SIZE; // 如果方向为增加,则设置运动目标值为负数 - else dp->label_y_trg = DIGITAL_Label_SIZE; // 如果方向为减少,则设置运动目标值为正数 - last_or_next_label_index = dp->select_label_index; // 存储上一次的值 + p_current_ui->dp_var.dir = dir; // 确定方向 + p_current_ui->dp_var.label_y = 0; // 设置标签的初始位置 + p_current_ui->dp_var.digital_num_pos |= 0x40; // 设置数字位置标志位 + if(dir == Digital_Direct_Increase)p_current_ui->dp_var.label_y_trg = - DIGITAL_Label_SIZE; // 如果方向为增加,则设置运动目标值为负数 + else p_current_ui->dp_var.label_y_trg = DIGITAL_Label_SIZE; // 如果方向为减少,则设置运动目标值为正数 + p_current_ui->dp_var.last_or_next_label_index = dp->select_label_index; // 存储上一次的值 } dp->select_label_index = label_index; // 更新选中项 } @@ -1408,9 +1553,9 @@ void OLED_DigitalPage_UpdateLabelAnimation(DigitalPage * dp, uint8_t label_index void OLED_DigitalPage_UpdateDigitalNumAnimation(DigitalPage * dp, uint8_t leftval, uint8_t midval, uint8_t rightval, DigitalDirect dir) { uint8_t val_array[3] = {rightval, midval, leftval}; - if(dp->page.page_id == ui.current_page_id)//当当前页面是要更新的页面时,才触发动画更新,否则直接更新数据就可以 + if(dp == (DigitalPage*)(p_current_ui->current_page))//当当前页面是要更新的页面时,才触发动画更新,否则直接更新数据就可以 { - if((dp->digital_num_pos&0x3F) == 0) //数字运动完成就可以更新 + if((p_current_ui->dp_var.digital_num_pos&0x3F) == 0) //数字运动完成就可以更新 //运动结束赋值发生变化,才能从外部更新数据,(是否需要处于obeserve模式由外界自己决定,这样就可以在回调函数中使用这个函数了) { //触发数字的动画(调用时倒着循环调用)(保证能让temp_ripplr_index记录到最低需要滚动的位) @@ -1428,110 +1573,78 @@ void OLED_DigitalPage_UpdateDigitalNumAnimation(DigitalPage * dp, uint8_t leftva #endif - - - //-------UI相关函数 -static void OLED_UIParaInit(void) +//将当前操作的UI对象选择为默认UI对象 +void OLED_SelectDefaultUI(void) { - ui_para.ani_param[TILE_ANI] = 120; // 磁贴动画速度 - ui_para.ani_param[LIST_ANI] = 120; // 列表动画速度 - ui_para.ani_param[WIN_ANI] = 120; // 弹窗动画速度 -// ui_para.ani_param[SPOT_ANI] = 50; // 聚光动画速度 -// ui_para.ani_param[FADE_ANI] = 30; // 消失动画速度 - ui_para.ani_param[TAG_ANI] = 60; // 标签动画速度 - ui_para.ani_param[DIGI_ANI] = 100; // 数字动画滚动速度 - ui_para.ufd_param[TILE_UFD] = True; // 磁贴图标从头展开开关 - ui_para.ufd_param[LIST_UFD] = True; // 菜单列表从头展开开关 - ui_para.loop_param[TILE_LOOP] = True; // 磁贴图标循环模式开关 - ui_para.loop_param[LIST_LOOP] = True; // 菜单列表循环模式开关 - ui_para.valwin_broken = True; //弹窗背景虚化开关 - ui_para.conwin_broken = True; //确认弹窗背景虚化开关 - ui_para.digital_ripple = True; //digital页面波纹递增动画开关 - ui_para.raderpic_scan_mode = False; //镭射文字只扫描亮处 - ui_para.raderpic_scan_rate = 4; //镭射文字扫描速度 - ui_para.raderpic_move_rate = 50; //镭射文字移动速度 + p_current_ui = &default_ui; } - - -void OLED_UiInit(void) +//设置当前正在操作的UI对象 +void OLED_SetCurrentUI(WouoUI *ui) { - ui.init_finish_flag = False; //初始时需要先开启过度动画 - ui.current_page_id = 0; //默认0页面为主页面(开始页面) - ui.state = ui_layer_in; //从没页面进入主页面,所以是lay_in - ui.vwin.l = (OLED_WIDTH - WIN_W)/2;//《/2》 - ui.vwin.u = (OLED_HEIGHT - WIN_H)/2;//弹窗里的默认参数《/2》 - ui.vwin.state = 0 ; //默认弹窗是关闭的 - ui.vwin.anim_init = OLED_ValWinAnimInit; - ui.vwin.show = OLED_ValWinShow; - ui.vwin.react = OLED_ValWinReact; //关联相关的处理函数 -#if UI_CONWIN_ENABLE - ui.cwin.l = (OLED_WIDTH - CON_WIN_W)/2; //不管选框宽度,以字体宽度为准《/2》 - ui.cwin.u = (OLED_HEIGHT - CON_WIN_H)/2; //确认弹窗里的默认参数 - ui.cwin.state = 0 ; //默认弹窗是关闭的 - ui.cwin.anim_init = OLED_ConWinAnimInit; - ui.cwin.show = OLED_ConWinShow; - ui.cwin.react = OLED_ConWinReact; //关联相关的处理函数 -#endif - OLED_UIParaInit(); - ui.upara = &ui_para; //将设置好的参数赋值给ui + p_current_ui = ui; +} +//初始化一个新的UI对象,需要传入这个UI的设置参数 +void OLED_NewUI(WouoUI *ui, UiPara *ui_para) +{ + *ui = default_ui; //将默认UI的值复制到新UI + ui->upara = ui_para; //将参数设置为新的UI的参数 } - static void OLED_UILayerInProc(void) { - if(page_array[ui.current_page_id] != NULL)//检查该页面地址存在 + if(p_current_ui->current_page != NULL)//检查该页面地址存在 { - Page* p = (Page*)(page_array[ui.current_page_id]); //把当前页面转为page读取 - p->ani_init(page_array[ui.current_page_id]); + Page* p = (Page*)(p_current_ui->current_page); //把当前页面转为page读取 + p->ani_init(p_current_ui->current_page); } } static void OLED_UIPageProc(void) //页面处理任务 { - if(page_array[ui.current_page_id] != NULL) //该页面地址存在 + if(p_current_ui->current_page != NULL) //该页面地址存在 { Option *op = NULL; Page * p = NULL; TitlePage * cur_tile = NULL; ListPage * cur_list = NULL; - PageType pt = OLED_CheckPageType(page_array[ui.current_page_id]); + PageType pt = OLED_CheckPageType(p_current_ui->current_page); switch (pt) { case type_title: - cur_tile = (TitlePage *)page_array[ui.current_page_id]; + cur_tile = (TitlePage *)(p_current_ui->current_page); op = &(cur_tile->option_array[cur_tile->select_item]); break; case type_list: - cur_list = (ListPage *)page_array[ui.current_page_id]; + cur_list = (ListPage *)(p_current_ui->current_page); op = &(cur_list->option_array[cur_list->select_item]); break; default:break; } - p = (Page *)(page_array[ui.current_page_id]);//把当前页面转为page读取 - p->show(page_array[ui.current_page_id]); + p = (Page *)(p_current_ui->current_page);//把当前页面转为page读取 + p->show(p_current_ui->current_page); if(pt == type_list || pt == type_title) {//valwin和conwin不会同时出现 #if UI_CONWIN_ENABLE - if(ui.vwin.state == 0 && ui.cwin.state == 0)p->react(page_array[ui.current_page_id]); - OLED_WinFSM(&(ui.cwin), page_array[ui.current_page_id], op); + if(p_current_ui->vwin.state == 0 && p_current_ui->cwin.state == 0)p->react(p_current_ui->current_page); + OLED_WinFSM(&(p_current_ui->cwin), p_current_ui->current_page, op); #else - if(ui.vwin.state == 0)p->react(page_array[ui.current_page_id]); + if(p_current_ui->vwin.state == 0)p->react(p_current_ui->current_page); #endif - OLED_WinFSM(&(ui.vwin), page_array[ui.current_page_id], op); + OLED_WinFSM(&(p_current_ui->vwin), p_current_ui->current_page, op); } - else p->react(page_array[ui.current_page_id]); + else p->react(p_current_ui->current_page); } } void OLED_UIProc(void) //UI总任务(FSM) { OLED_RefreshBuff(); - switch (ui.state) //ui状态机轮询 + switch (p_current_ui->state) //ui状态机轮询 { case ui_layer_in://主要是对页面动画在切换时做一次参数的赋值 OLED_UILayerInProc(); - ui.state = ui_page_proc; + p_current_ui->state = ui_page_proc; break; case ui_page_proc://因为主要的绘制图像都在这儿完成,所以进入前需清空一次buff OLED_ClearBuff(); @@ -1546,19 +1659,23 @@ void OLED_UIProc(void) //UI总任务(FSM) /** * @brief 跳转到指定页面(跳转是会将当前页面id输入,用于关联确认上下级页面关系) * - * @param self_page_id 当前页面ID + * @param self_page 当前页面对象的地址 * @param terminate_page 目标页面地址 */ -void OLED_UIJumpToPage(uint8_t self_page_id,PageAddr terminate_page) +void OLED_UIJumpToPage(PageAddr self_page_addr,PageAddr terminate_page) { // 关联上级页面并跳转页面 if(terminate_page != NULL) { Page * p = (Page*)terminate_page; - p->last_page_id = self_page_id; - ui.current_page_id = p->page_id; - ui.init_finish_flag = False; // 开启过度动画 - ui.state = ui_layer_in; // 开始层级渲染 + p->last_page = self_page_addr; + p_current_ui->current_page = terminate_page; + if(p_current_ui->vwin.state != 0)p_current_ui->vwin.state = 0; //跳转页面时,如果当前页面有弹窗,将其关闭 +#if UI_CONWIN_ENABLE + if(p_current_ui->cwin.state != 0)p_current_ui->cwin.state = 0; //跳转页面时,如果当前页面有弹窗,将其关闭 +#endif + p_current_ui->init_finish_flag = False; // 开启过度动画 + p_current_ui->state = ui_layer_in; // 开始层级渲染 } } @@ -1571,14 +1688,22 @@ void OLED_UIChangeCurrentPage(PageAddr terminate_page) { if(terminate_page != NULL) { - Page * p = (Page*)terminate_page; - ui.current_page_id = p->page_id; // Set the current page ID to the page ID of the specified page. - ui.init_finish_flag = False; // Enable the transition animation. - ui.state = ui_layer_in; // Start rendering the layers. + p_current_ui->current_page = terminate_page;; // Set the current page ID to the page ID of the specified page. + if(p_current_ui->vwin.state != 0)p_current_ui->vwin.state = 0; //跳转页面时,如果当前页面有弹窗,将其关闭 +#if UI_CONWIN_ENABLE + if(p_current_ui->cwin.state != 0)p_current_ui->cwin.state = 0; //跳转页面时,如果当前页面有弹窗,将其关闭 +#endif + p_current_ui->init_finish_flag = False; // Enable the transition animation. + p_current_ui->state = ui_layer_in; // Start rendering the layers. } } -uint8_t OLED_UIGetCurrentPageID(void) +/** + * @brief 得到当前页面的地址 + * + * @param terminate_page The address of the page to change to. + */ +Page* OLED_GetCurrentPage(void) { - return ui.current_page_id; + return (Page*)p_current_ui->current_page; } diff --git a/Csource/src/oled_ui.h b/Csource/src/oled_ui.h index 341ec25..5d422dd 100644 --- a/Csource/src/oled_ui.h +++ b/Csource/src/oled_ui.h @@ -1,6 +1,19 @@ +/* +版本更新的日志记录: +2024年8月29日:<0.1.1> 不再使用全局数组,使用指针代替,可以动态添加不限个数的页面。 +改进方向:[ ] 将底层绘制函数和w_all合并入WouoUI对象,便于多个UI对象的同时使用 + [ ] 将各个参数改为页面百分比,实现多尺寸页面的适配 + [ ] 加入中文显示的支持, +*/ + #ifndef __OLED_UI_H__ #define __OLED_UI_H__ +#ifdef __cplusplus +extern "C" { +#endif + + #include "oled_g.h" #include "oled_conf.h" /*============================================常量定义=========================================*/ @@ -79,9 +92,11 @@ #define DIGITAL_NUM_T_S 8 //数字到外框的边距 #define DIGITAL_NUM_SIZE 24 //数字的尺寸 #define DIGITAL_Label_SIZE 16 //数字的尺寸 -#define DIGITAL_NUM_INDEX_MAX 6 //digital页面共有6个数字 +#define DIGITAL_NUM_INDEX_MAX 6 //digital页面共有6个数字 /*============================================类型声明=========================================*/ +//--------UI对象类型 +typedef struct _WouoUI WouoUI; //--------页面类型枚举 typedef enum { @@ -111,8 +126,9 @@ typedef struct //其实单选列表项,需使用其他项在应用层关联跳转单选终端页面实现(单选列表项必须使用=做字符串开头)。 } Option; //通用选项类,其中item_max,item_min,entity与列表选项(单选/多选/弹窗项)相关,磁贴选项可不管 //选择类界面的回调函数类型定义,参数为确认选中项的指针。 -typedef void (*CallBackFunc)(uint8_t self_page_id,Option* select_item); - +typedef struct _page Page; //页面基类的声明,方便作为回调函数参数 +//更改回调函数直接传入当前页面的页面地址 +typedef void (*CallBackFunc)(const Page* cur_page_addr,Option* select_item); typedef const uint8_t Icon[ICON_BUFFSIZE]; //定义图标类型 //页面地址类型,用于声明全局页面数组存放页面使用 #define PageAddr void* @@ -121,16 +137,15 @@ typedef void (*PageAniInit)(PageAddr); //页面的动画初始化函数 typedef void (*PageShow)(PageAddr); //页面的展示函数 typedef void (*PageReact)(PageAddr); //页面的响应函数 -typedef struct +struct _page { PageType page_type; //页面类型,以便在处理时调用不同函数绘制 - uint8_t page_id; //页面的序号,每个页面唯一一个,用于指示在数组中的位置,方便跳转 - uint8_t last_page_id; //上一个页面的id,用于返回时使用 + PageAddr last_page; //父页面的地址 CallBackFunc cb; //页面的回调函数 PageAniInit ani_init; PageShow show; PageReact react; -} Page; //最基本的页面类型(所有页面类型的基类和结构体的**第一个成员**) +}; //最基本的页面类型(所有页面类型的基类和结构体的**第一个成员**) //----------5种页面类 typedef struct @@ -140,15 +155,6 @@ typedef struct Option *option_array; //选项类型的数组(由于数组大小不确定,使用指针代替) Icon *icon_array ; //图标数组(由于数组大小不确定,使用指针代替) uint8_t select_item; //选中选项 - - float icon_x; //图标的x坐标距选中目标的间距的变量 - float icon_x_trg;//图标的x坐标距选中目标的间距的变量目标 - float icon_y;//图标的y坐标 - float icon_y_trg;//图标的y坐标目标 - float indi_x; //指示器的x坐标 - float indi_x_trg;//指示器的x坐标目标值 - float title_y;//标题的y坐标 - float title_y_trg;//标题的y坐标目标值 } TitlePage; //磁帖页面类型(所有类型页面,类型成员为第一个,方便查看) typedef struct @@ -157,17 +163,8 @@ typedef struct uint8_t item_num ; //页面选项个数,title和icon个数需与此一致 uint8_t select_item; //选中选项 Option *option_array; //选项类型的数组(由于数组大小不确定,使用指针代替) - - uint8_t slip_flag; //切换动画是否完成的标志位 - uint8_t line_n; // = DISP_H / LIST_LINE_H; 屏幕内有多少行选项 - float y; //列表中每个选项的间隔值 - float y_trg; //列表中每个选项间隔的目标值 - float box_x; //选中框x - float box_x_trg; //选中框x的目标值 - float box_y; //选中框y - float box_y_trg; //选中框y的目标值 - float bar_y; //进度条的y值 - float bar_y_trg; //进度条的y目标值 + uint8_t line_n; // = DISP_H / LIST_LINE_H; 屏幕内有多少行选 + float box_y_trg;//选中框y的目标值(这个变量放在每一个页面中,用于推算正真的页面的起始y坐标值) } ListPage; //列表页面类型(所有类型页面,类型成员为第一个,方便查看) #if PAGE_WAVE_ENABLE @@ -192,14 +189,12 @@ typedef struct { Page page; //基类 //镭射界面回调函数,传入已经绘制完成的pic序号 -//为了方便在镭射图片界面,绘制自己想要的其他元素(如文字提示,在模式为Rader_Pic_Mode_Hold是,会不断绘制已完成的图片并不断调用回调函数) +//为了方便在镭射图片界面,绘制自己想要的其他元素(如文字提示,在模式为Rader_Pic_Mode_Hold时,会不断绘制已完成的图片并不断调用回调函数) uint8_t pic_num ; //页面pic个数,pic_array数组大小需与此一致 uint8_t rader_pic_mode:2; //结束之后的操作 RaderPic* pic_array; //镭射图片数组 - uint8_t cur_pic_index; //当前正在绘制完成的pic序号(0~pic_num-1) - float move_x; - float move_y; + uint16_t pic_end_point; //中断是图片扫描的断点标识 } RaderPicPage; //镭射图片页面对象 typedef enum @@ -247,20 +242,9 @@ typedef struct Option * option_array; //选项数组,数组大小必须为3 ,用于显示三个数字 uint8_t label_array_num; // 标签数组的大小 String * label_array; //标签数组,方便标签滚动 - - DigitalPosIndex select_index:4; //选中项的index - uint8_t digital_num_pos; //0表示没有选中位置,1-7bit每一位置1表示该位被选中 - uint8_t temp_ripple_index; //用于在ripple时记录选中位置(选中最低位位置开始,慢慢往上增) - DigitalDirect dir:2; //用于Digital Show和React函数间传递信号 - DigitalMode mod:2; //digital页面的模式 uint8_t select_label_index; //在标签数组中选中的标签的index - window w_digtal[2]; //用限制数字时钟的窗口(1个数字窗口+1个label窗口) 2个窗口 - float rect_y; //移动外框的顶点坐标 - float rect_y_trg; //移动外框的顶点坐标目标 - float label_y; //移动外框的顶点坐标 - float label_y_trg; //移动外框的顶点坐标目标 - float num_y; //移动数字的顶点坐标 - float num_y_trg; //移动数字的顶点坐标目标 + DigitalPosIndex select_index:4; //选中项的index + DigitalMode mod:2; //digital页面的当前模式 } DigitalPage; //时间页面 #endif @@ -286,8 +270,6 @@ enum _ani_kind //动画速度类别(数组中的下标) TILE_ANI = 0x00, //磁贴动画速度 LIST_ANI, //列表动画速度 WIN_ANI, //弹窗动画速度 - // SPOT_ANI, //聚光动画速度 - // FADE_ANI, //消失动画速度 TAG_ANI, //标签动画速度 DIGI_ANI, //数字动画滚动速度 AIN_ALL_NUM, //动画速度参数的数目,用于数组初始化 @@ -326,51 +308,64 @@ typedef struct uint8_t ufd_param[UFD_ALL_NUM]; //展开参数数组 uint8_t loop_param[LOOP_ALL_NUM]; //循环参数数组 } UiPara; //UI参数集合类型 -extern UiPara ui_para; //共外部使用的全局UI参数变量 +extern UiPara g_default_ui_para; //共外部使用的全局UI参数变量 extern window w_all; //这个窗口是ui绘制时的全局窗口,可供外界自由绘制 /*============================================接口函数=========================================*/ -void OLED_TitlePageInit(TitlePage * title_page, uint8_t page_id,uint8_t item_num,Option* option_array,Icon *icon_array,CallBackFunc call_back); -void OLED_ListPageInit(ListPage * lp,uint8_t page_id,uint8_t item_num,Option *option_array,CallBackFunc call_back); +void OLED_TitlePageInit(TitlePage * title_page, uint8_t item_num,Option* option_array,Icon *icon_array,CallBackFunc call_back); +void OLED_ListPageInit(ListPage * lp,uint8_t item_num,Option *option_array,CallBackFunc call_back); //用于向UI传递一个消息Msg(msg_click/msg_up/msg_down/msg_return) void OLED_MsgQueSend(InputMsg msg); -//UI必要的一些参数和变量的初始化 -void OLED_UiInit(void); +//切换当前UI的操作对象为内置的默认UI对象 +void OLED_SelectDefaultUI(void); +//设置当前操作的UI对象 +void OLED_SetCurrentUI(WouoUI *ui); +//生成一个新的UI对象必要的初始化流程 +//(这个还需要改进,只是初始化一个带参数的UI对象没有意义,需要带上对应的画点函数才有意义) +void OLED_NewUI(WouoUI *ui, UiPara *ui_para); //UI运行任务,需要放在主循环中循环调用,而且尽量不要阻塞 void OLED_UIProc(void); /* * 从一个页面跳转到另一个页面,常用于回调函数中调用,并确定页面的上下级关系(这样,在terminate_page页面收到return消息时,会返回self_page_id所代表的页面) -@param self_page_id 是当前页面的id(回调函数中有这个参数) +@param self_page 是当前页面的地址(回调函数中第一个参数强转为通用地址类型PageAddr传入即可) @param terminate_page 要跳转的那个页面的地址(不需要理会是那种类型的页面,直接将页面地址作为参数传入即可) */ -void OLED_UIJumpToPage(uint8_t self_page_id,PageAddr terminate_page); +void OLED_UIJumpToPage(PageAddr self_page,PageAddr terminate_page); /* * 切换当前页面的函数,与Jump函数不同的时,这个函数不会绑定上下级页面关系,terminate_page 页面收到return 消息不会返回当前页面(常用于临时的画面切换) @param terminate_page 要跳转的那个页面的地址(不需要理会是那种类型的页面,直接将页面地址作为参数传入即可) */ void OLED_UIChangeCurrentPage(PageAddr terminate_page); -/*获取当前页面的id*/ -uint8_t OLED_UIGetCurrentPageID(void); +/* +@ attention:得到当前所处页面的指针(地址) +*/ +Page* OLED_GetCurrentPage(void); #if PAGE_WAVE_ENABLE -void OLED_WavePageInit(WavePage * wp, uint8_t page_id, uint8_t item_num, Option *option_array, CallBackFunc call_back); +void OLED_WavePageInit(WavePage * wp, uint8_t item_num, Option *option_array, CallBackFunc call_back); void OLED_UIWaveUpdateVal(Option * op, int16_t val); #endif #if PAGE_RADIO_ENABLE -void OLED_RadioPageInit(RadioPage * rp, uint8_t page_id, uint8_t item_num,Option *option_array,CallBackFunc call_back); +void OLED_RadioPageInit(RadioPage * rp, uint8_t item_num,Option *option_array,CallBackFunc call_back); #endif #if PAGE_RADERPIC_ENABLE -void OLED_RaderPicPageInit(RaderPicPage* rpp,uint8_t page_id,uint8_t pic_num,RaderPic * pic_array,RaderPicMode mode,CallBackFunc cb) ; +void OLED_RaderPicPageInit(RaderPicPage* rpp,uint8_t pic_num,RaderPic * pic_array,RaderPicMode mode,CallBackFunc cb) ; #endif #if PAGE_DIGITAL_ENABLE -void OLED_DigitalPageInit(DigitalPage* dp, uint8_t page_id, Option * option_array, uint8_t label_array_num, String * label_array, char gap_char, uint8_t gap_shine_time, uint8_t uline_shine_time,CallBackFunc cb); +void OLED_DigitalPageInit(DigitalPage* dp, Option * option_array, uint8_t label_array_num, String * label_array, char gap_char, uint8_t gap_shine_time, uint8_t uline_shine_time,CallBackFunc cb); void OLED_DigitalPage_UpdateDigitalNumAnimation(DigitalPage * dp, uint8_t leftval, uint8_t midval, uint8_t rightval, DigitalDirect dir); void OLED_DigitalPage_UpdateLabelAnimation(DigitalPage * dp, uint8_t label_index, DigitalDirect dir); #endif +#ifdef __cplusplus +} +#endif + + + #endif diff --git a/ProjectExamples/PCSimulate/PCSimulate.zip b/ProjectExamples/PCSimulate/PCSimulate.zip index e7c83be..134daef 100644 Binary files a/ProjectExamples/PCSimulate/PCSimulate.zip and b/ProjectExamples/PCSimulate/PCSimulate.zip differ diff --git a/README.md b/README.md index 6b62978..71d88eb 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,12 @@ 在此十分感谢WouoUI作者开源WouoUI的源码🙏🙏,这是[WouoUI的Github链接](https://github.com/RQNG/WouoUI )和[作者的b站链接](https://space.bilibili.com/9182439)。 (推荐大家可以去阅读下WouoUI的源代码(Arduino),写得非常好,逻辑相当清晰)。 +### 版本声明 + +- 由于本项目处于改进的过程中,我将在每一个大版本(如0.1.0,0.2.0等大版中)对硬件代码进行适配;一般的小版本(如0.1.1,0.1.2等小版本中)只会在PCSimulate仿真端进行测试,不会对硬件适配的代码进行更新。 +- 因此,在小版本中,只会更新 CSource文件夹下的文件和ProjectExamples/PCSimulate文件夹下的PC端仿真工程。 +- 每次版本更新时,我会尽量保持接口函数保持不变,必要的接口函数改动也会在这个文件中同步更新,在小版本更新中我也会更新ReadMe文件(因此,如果在这个过程中需要使用旧版本,请将ReadMe文件回退到旧版本中,否则可能有一些接口函数不太一样)。 +- 具体版本更新的说明和未来更新的进度查看最底部的[项目维护](#项目维护) ### 想法由来和一些啰嗦 @@ -31,7 +37,7 @@ WouoUIPage版的想法是源自我自己想将使用WouoUI用到自己设置的 | ------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | 依赖库 | 依赖U8g2库,适用性广,拓展性强 ;但消耗的RAM和FLASH可能会较多(特别是对于使用C语言开发而不是使用Arduino开发的情况) | 自己写的图形层驱动文件,功能比较少只提供必须用到的,纯C语言编写,对内存有限,使用C开发单片机来说比较合适;但由于没有使用U8g2库,适用性、拓展性差。(后面看看自己有没有时间将上面的这部分抽象移植到U8g2图形库上) | | 接口 | 原作者的所有代码都在一个.ino文件中完成,方便查看源码; 但需要读懂一部分源码才能二次开发 | 统一了一部分接口,并做了抽象,二次开发时只需要按接口文档来使用提供的接口函数 | -| 适用性 | 原作者开发了适应多个屏幕尺寸的版本👍(这点我自己觉得可能很难做到) | 因为项目的需要,Page版只有128*64这一个尺寸适配,我也没有做其他屏幕的开发。 | +| 适用性 | 原作者开发了适应多个屏幕尺寸的版本👍(这点我目前有计划但还在开发中) | 因为项目的需要,Page版只有128*64这一个尺寸适配,我也没有做其他屏幕的开发。 | ## 移植说明 @@ -89,7 +95,6 @@ OK ,到这里的话,就算移植结束了(感觉说是复制更为合适, ```c #define UI_CONWIN_ENABLE 1 //是否使能 以"$ " 为开头的选项使用确认弹窗 -#define UI_MAX_PAGE_NUM 32 //页面的最大数量,这个数字需要大于所有页面的page_id #define UI_INPUT_MSG_QUNEE_SIZE 4 //ui内部消息对列的大小(至少需要是2) //页面类型使能宏,使用对应的页面类型,则需要开启该宏,将宏置为1,默认都开启 @@ -150,11 +155,11 @@ OK ,到这里的话,就算移植结束了(感觉说是复制更为合适, - `CallBackFunc` : 回调函数类型,每个页面都需要一个回调函数(如果没有回调函数,在对应初始化函数中置NULL即可)。 - 通常需要定义一个形如`void MainPage_CallBack(uint8_t self_page_id,Option* select_item)`的函数(其中,MainPage_CallBack是由我们定义的回调函数名(地址)),并该函数地址作为参数给对应的页面初始化函数。 + 通常需要定义一个形如`void MainPage_CallBack(const Page* self_page,Option* select_item)`的函数(其中,MainPage_CallBack是由我们定义的回调函数名(地址)),并该函数地址作为参数给对应的页面初始化函数。 > 在页面中的选项被click时,该页面的回调函数会被调用, > - > 传入回调函数的参数`self_page_id` 为当前页面的id(每个页面都有唯一的id,需要在对应页面初始化时传入); + > 传入回调函数的参数`self_page` 为当前页面的地址(以Page*指针的形式传入,可以强转为任何页面类型); > > 传入回调函数的参数`select_item`为当前页面被选中且click的选项(类型为Option),可以通过读取该函数的order得知当前选中的是哪个选项,并在回调函数中进行对应的处理。 @@ -170,9 +175,9 @@ OK ,到这里的话,就算移植结束了(感觉说是复制更为合适, - 接口函数只有一个 - `void OLED_TitlePageInit(TitlePage * title_page, uint8_t page_id,uint8_t item_num,Option* option_array,Icon *icon_array,CallBackFunc call_back);` + `void OLED_TitlePageInit(TitlePage * title_page, uint8_t item_num,Option* option_array,Icon *icon_array,CallBackFunc call_back);` - >- 参数需要有TitlePage 页面对象的指针,唯一的page_id(每个页面必须有一个唯一的id); + >- 参数需要有TitlePage 页面对象的指针; > >- 需要注意的有 :**item_num 表示后面 option_array(选项数组)和 icon_arra(图标数组)的数组大小,三者必须保持一致**; > @@ -196,9 +201,9 @@ OK ,到这里的话,就算移植结束了(感觉说是复制更为合适, - 同样地,接口函数只有一个 - `void OLED_ListPageInit(ListPage * lp,uint8_t page_id,uint8_t item_num,Option *option_array,CallBackFunc call_back);` + `void OLED_ListPageInit(ListPage * lp, uint8_t item_num,Option *option_array,CallBackFunc call_back);` - >- 参数需要有ListPage 页面对象的指针,唯一的page_id(每个页面必须有一个唯一的id); + >- 参数需要有ListPage 页面对象的指针; >- 同样需要注意的是:**item_num 表示后面option_array(选项数组)的数组大小,必须保持一致** >- 同时,**option_array选项数组中text字符串使用前缀表示选项的类型** > - **`"~ "` 前缀表示数值弹窗** @@ -213,11 +218,11 @@ OK ,到这里的话,就算移植结束了(感觉说是复制更为合适, RadioPage演示 -- 其实,**RadioPage页面和ListPage页面是基本一样的,不同的是,对于使用`"= "` 作为text前缀的选项来说,RadioPage页面会将其处理为单选项,即,这个页面内,所有使用 `"= "` 为text前缀的选项只能有一个能被选中,以实现单选的效果。**因为,通常对于这样的选项页面,我们一整个页面内都是这种单选项,所以将其单独作为一个页面类型拿出。 +- 其实,**RadioPage页面和ListPage页面是基本一样的,不同的是,对于使用`"= "` 作为text前缀的选项来说,RadioPage页面会将其处理为单选项,即,这个页面内,所有使用 `"= "` 为text前缀的选项只能有一个能被选中,以实现单选的效果**。因为,通常对于这样的选项页面,我们一整个页面内都是这种单选项,所以将其单独作为一个页面类型拿出。 - 其接口函数与ListPage基本一致:(注意事项也请参考上面😆) - `void OLED_RadioPageInit(RadioPage * rp, uint8_t page_id, uint8_t item_num,Option *option_array,CallBackFunc call_back);` + `void OLED_RadioPageInit(RadioPage * rp, uint8_t item_num,Option *option_array,CallBackFunc call_back);` 唯一一点区别,可能就是第一个参数的类型,需要是RadioPage类型。 @@ -229,9 +234,9 @@ OK ,到这里的话,就算移植结束了(感觉说是复制更为合适, - WavePage页面有两个接口函数 -1. `void OLED_WavePageInit(WavePage * wp, uint8_t page_id, uint8_t item_num, Option *option_array, CallBackFunc call_back);` (照例是初始化函数) +1. `void OLED_WavePageInit(WavePage * wp, uint8_t item_num, Option *option_array, CallBackFunc call_back);` (照例是初始化函数) - >- 参数需要有WavePage 页面对象的指针,唯一的page_id(每个页面必须有一个唯一的id); + >- 参数需要有WavePage 页面对象的指针; >- 同样需要注意的是:**item_num 表示后面option_array(选项数组)的数组大小,必须保持一致** > >- **与其他页面不同的是,WavePage 页面选项text的字符串前缀均没有特殊意义,同时也不建议在WavePage页面使用选项前缀,因为需要显示波形的关系,选项字符串的大小最好不要超过5个字符,因此就不加前缀占用多余的字符了** @@ -259,9 +264,9 @@ OK ,到这里的话,就算移植结束了(感觉说是复制更为合适, - RaderPicPage 类只有一个接口函数(就是初始化函数) - `void OLED_RaderPicPageInit(RaderPicPage* rpp,uint8_t page_id,uint8_t pic_num,RaderPic * pic_array,RaderPicMode mode,CallBackFunc cb);` + `void OLED_RaderPicPageInit(RaderPicPage* rpp,uint8_t pic_num,RaderPic * pic_array,RaderPicMode mode,CallBackFunc cb);` - >- 参数需要有RaderPicPage 页面对象的指针,唯一的page_id(每个页面必须有一个唯一的id); + >- 参数需要有RaderPicPage 页面对象的指针; > >- 需要注意的是,**pic_num是后面pic_array数组的数组大小,必须保持一致** ,同时,这里有一个RaderPicPage页面才会用到的类(结构体类型)RaderPic,详情在下方。 >- 同时,**mode成员为一个枚举类型,用于设置页面图片全部绘制完成后的操作,有两个可取值** @@ -306,9 +311,9 @@ OK ,到这里的话,就算移植结束了(感觉说是复制更为合适, #### DigitalPage 页面相关的接口函数有三个: -- `void OLED_DigitalPageInit(DigitalPage* dp, uint8_t page_id, Option * option_array, uint8_t label_array_num, String * label_array, char gap_char, uint8_t gap_shine_time, uint8_t uline_shine_time,CallBackFunc cb);` +- `void OLED_DigitalPageInit(DigitalPage* dp, Option * option_array, uint8_t label_array_num, String * label_array, char gap_char, uint8_t gap_shine_time, uint8_t uline_shine_time,CallBackFunc cb);` - >- 参数需要有DigitalPage 页面对象的指针,唯一的page_id(每个页面必须有一个唯一的id); + >- 参数需要有DigitalPage 页面对象的指针; > >- 需要注意的参数有: > @@ -375,20 +380,30 @@ DigitalPage页面运行的状态机如下图所示:有兴趣的可以看看 ```c //用于向UI传递一个消息Msg(msg_click/msg_up/msg_down/msg_return) void OLED_MsgQueSend(InputMsg msg); -//UI必要的一些参数和变量的初始化 -void OLED_UiInit(void); +//切换当前UI的操作对象为内置的默认UI对象 +void OLED_SelectDefaultUI(void); +//设置当前操作的UI对象 +void OLED_SetCurrentUI(WouoUI *ui); +//生成一个新的UI对象必要的初始化流程 +//(这个还需要改进,只是初始化一个带参数的UI对象没有意义,需要带上对应的画点函数才有意义) +void OLED_NewUI(WouoUI *ui, UiPara *ui_para); //UI运行任务,需要放在主循环中循环调用,而且尽量不要阻塞 void OLED_UIProc(void); -//从一个页面跳转到另一个页面,常用于回调函数中调用,并确定页面的上下级关系(这样,在terminate_page页面收到return消息时,会返回self_page_id所代表的页面) -//@param self_page_id 是当前页面的id(回调函数中有这个参数) -//@param terminate_page 要跳转的那个页面的地址(不需要理会是那种类型的页面,直接将页面地址作为参数传入即可) -void OLED_UIJumpToPage(uint8_t self_page_id,PageAddr terminate_page); -//切换当前页面的函数,与Jump函数不同的时,这个函数不会绑定上下级页面关系, -//terminate_page 页面收到return 消息不会返回当前页面(常用于临时的画面切换) -//@param terminate_page 要跳转的那个页面的地址(不需要理会是那种类型的页面,直接将页面地址作为参数传入即可) +/* +* 从一个页面跳转到另一个页面,常用于回调函数中调用,并确定页面的上下级关系(这样,在terminate_page页面收到return消息时,会返回self_page_id所代表的页面) +@param self_page 是当前页面的地址(回调函数中第一个参数强转为通用地址类型PageAddr传入即可) +@param terminate_page 要跳转的那个页面的地址(不需要理会是那种类型的页面,直接将页面地址作为参数传入即可) +*/ +void OLED_UIJumpToPage(PageAddr self_page,PageAddr terminate_page); +/* +* 切换当前页面的函数,与Jump函数不同的时,这个函数不会绑定上下级页面关系,terminate_page 页面收到return 消息不会返回当前页面(常用于临时的画面切换) +@param terminate_page 要跳转的那个页面的地址(不需要理会是那种类型的页面,直接将页面地址作为参数传入即可) +*/ void OLED_UIChangeCurrentPage(PageAddr terminate_page); -/*获取当前页面的id*/ -uint8_t OLED_UIGetCurrentPageID(void); +/* +@ attention:得到当前所处页面的指针(地址) +*/ +Page* OLED_GetCurrentPage(void); ``` 需要注意的只有: @@ -454,7 +469,7 @@ WouoUIPage的参数基本上WouoUI原作保持一致,如下:(由于我没有 ### 关于UI层 -- `PageAddr` 页面地址变量,其实是一个 `void*` 类型,为了用于实现 `OLED_UIJumpToPage` 函数和 `OLED_UIChangeCurrentPage` 函数的 "伪多态"。(其实内部所有`AnimInit` 、 `Show` 、 `React` 函数都使用这样的"伪多态") 。 +- `PageAddr` 页面地址变量,其实是一个 `void*` 类型,为了用于实现 `OLED_UIJumpToPage` 函数和 `OLED_UIChangeCurrentPage` 函数的 "伪多态"。(其实内部所有`AnimInit` 、 `Show` 、 `React` 函数都使用这样的**伪多态**) 。 在获取页面地址后,直接强转为 `Page` 类,这是一个所有页面类型都必须包含的结构体成员(且必须是第一个,为了方便转换类型)。`Page` 类中包含了所有页面必须有的一些成员,如下: @@ -466,8 +481,7 @@ WouoUIPage的参数基本上WouoUI原作保持一致,如下:(由于我没有 typedef struct { PageType page_type; //页面类型,以便在处理时调用不同函数绘制 - uint8_t page_id; //页面的序号,每个页面唯一一个,用于指示在数组中的位置,方便跳转 - uint8_t last_page_id; //上一个页面的id,用于返回时使用 + PageAddr last_page; //父页面的地址 CallBackFunc cb; //页面的回调函数 PageAniInit ani_init; PageShow show; @@ -485,11 +499,24 @@ WouoUIPage的参数基本上WouoUI原作保持一致,如下:(由于我没有 ## 项目维护 +### 项目版本更新的说明 +- 0.1.0版 稳定的版本有在两个硬件上移植测试过的版本; +- 0.1.1版 + - 将全局数组去掉,改为指针连接上级页面,支持理论上无限多个页面,不再受数组大小的限制。 + - UI文件中的变量整理归类,使代码体积占用更小(会在下一个大版本中给出具体的代码内存占用数据)。 + - 修复在弹窗时页面跳转的bug。 + +### 项目长期的改进需求 + 目前项目有以下的改进需求,会逐步展开😶。 - [x] ~~PC电脑端的测试环境,方便编写UI进行代码测试。(已完成,在ProjectExamples下有使用例子)~~ - [ ] 添加sleep的运行状态,在没有消息传入时不会一直刷新页面占用CPU。 - - [ ] 适配多种大小的单色屏小屏幕(200*200px以上的大屏幕不在我想支持的范围内,因为对于这类屏幕有更合适的UI),支持文字过长时的自适应滚动。 - [ ] 支持中文,能够以方便的方式设置UI的字体,同时不会产生太大的内存占用(使用这类小屏幕应用的单片机,一般内存不会太大,因此维持这个框架的轻量也是必要的)。 - [ ] 移植底层适配U8g2的版本,顶层接口基本不改变。 + +### 其他 +- 项目使用第一版硬件[Air001的小时钟](https://www.bilibili.com/video/BV1J6421g7H1/) 由于RAM和Flash的限制,在下两个大版本后可能适配(个人精力是在有限,有uu可以帮忙适配更多的硬件那就更好了)。 + +- 第二版的硬件加入了立创的星火计划(目前正在忙里偷闲的进行钟,使用stmf103RCT6芯片,第二版的硬件上WouoPage只是作为一小部分,多合一的USB设备是我努力的重点,到时候可能会讲讲如果使用HAL库实现多合一的USB设备😀)。 \ No newline at end of file