K1Guitar/UI/UI_global.c

1278 lines
47 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "includes.h"
extern uint8_t level;
/* 0902 控件-11/12 左右实心三角x 为图标左缘cy 为垂直中心 */
static void UI_DrawTriLeft(uint16_t x, uint16_t cy)
{
uint16_t y = (cy >= UI0902_TRI_L_H / 2) ? (uint16_t)(cy - UI0902_TRI_L_H / 2) : 0;
LCD_WR_PIC_Trans(x, y, UI0902_TRI_L_W, UI0902_TRI_L_H,
gImage_UI0902_TriLeft_22x22, BLACK);
}
static void UI_DrawTriRight(uint16_t x, uint16_t cy)
{
uint16_t y = (cy >= UI0902_TRI_R_H / 2) ? (uint16_t)(cy - UI0902_TRI_R_H / 2) : 0;
LCD_WR_PIC_Trans(x, y, UI0902_TRI_R_W, UI0902_TRI_R_H,
gImage_UI0902_TriRight_23x22, BLACK);
}
// ==============================================
// <20><><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EBB6A8>
// ==============================================
void (*MenuPage_Idle_Proc)(void);
void (*MenuPage_SongMode_Proc)(void);
void (*MenuPage_ExpertMode_Proc)(void);
void (*MenuPage_FreeMode_Proc)(void);
void (*MenuPage_Setting_Proc)(void);
void (*MenuPage_SystemSetting_Proc)(void);
void (*MenuPage_Mixer_Proc)(void);
void (*MenuPage_Restore_Proc)(void);
// ==============================================
// <20><>ʼ<EFBFBD><CABC><EFBFBD>˵<EFBFBD>UI
// ==============================================
void InitMenuUI(void) {
MenuPage_Idle_Proc = CallUI_Idle; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
MenuPage_SongMode_Proc = CallUI_SongMode; // <20><><EFBFBD><EFBFBD>ģʽ
MenuPage_ExpertMode_Proc = CallUI_ExpertMode; // ר<><D7A8>ģʽ
MenuPage_FreeMode_Proc = CallUI_FreeMode; // <20><><EFBFBD><EFBFBD>ģʽ
MenuPage_Setting_Proc = CallUI_Setting; // <20><><EFBFBD><EFBFBD>
MenuPage_SystemSetting_Proc = CallUI_SystemSetting; // ϵͳ<CFB5><CDB3><EFBFBD><EFBFBD>
MenuPage_Mixer_Proc = CallUI_Mixer; //<2F><><EFBFBD><EFBFBD>̨
MenuPage_Restore_Proc = CallUI_RestoreSelect;
}
// ==============================================
// <20><><EFBFBD><EFBFBD> UI <20><><EFBFBD>ú<EFBFBD><C3BA><EFBFBD>
// ==============================================
void CallUI_Idle(void) {
CurrUIProcress = IdleProcess;
app_log_set_ui_page("Idle");
LOG_I("UI", "page Idle");
}
void CallUI_SongMode(void) {
app_touch_suppress(500);
UI_SongMode_Init();
CurrUIProcress = UI_SongMode_Process;
app_log_set_ui_page("Song");
LOG_I("UI", "page SongMode tab=%u", (unsigned)mGuiData[GUI_TAB_INDEX].Current);
}
void CallUI_ExpertMode(void) {
app_touch_suppress(500);
UI_ExpertMode_Init();
// CurrUIProcress = UI_ExpertMode_Process;
CurrUIProcress = UI_SongMode_Process;
app_log_set_ui_page("Expert");
LOG_I("UI", "page ExpertMode");
}
void CallUI_FreeMode(void) {
app_touch_suppress(500);
UI_FreeMode_Init();
// CurrUIProcress = UI_FreeMode_Process;
CurrUIProcress = UI_SongMode_Process;
app_log_set_ui_page("Free");
LOG_I("UI", "page FreeMode");
}
void CallUI_Setting(void) {
app_touch_suppress(500);
CurrUIProcress = UI_Setting_Process;
UI_Setting_Init();
app_log_set_ui_page("Setting");
LOG_I("UI", "page Setting");
}
void CallUI_Mixer(void) {
app_touch_suppress(500);
CurrUIProcress = UI_Mixer_Process;
UI_Mixer_Init();
app_log_set_ui_page("Mixer");
LOG_I("UI", "page Mixer");
}
void CallUI_SystemSetting(void) {
app_touch_suppress(500);
CurrUIProcress = UI_SystemSet_Process;
UI_SystemSet_Init();
app_log_set_ui_page("SysSet");
LOG_I("UI", "page SystemSetting");
}
void CallUI_RestoreSelect(void) {
CurrUIProcress = UI_Restore_Select_Process;
UI_Restore_Select_Init();
app_log_set_ui_page("Restore");
LOG_I("UI", "page Restore");
}
/* 音师万能→3.bin普通/专业节奏→1.bin、本地曲目→2.bin */
void UI_ApplyToneAddress(void)
{
uint32_t expect = 0;
const char *map_name = "?";
switch (mGuiData[GUI_TAB_INDEX].Current)
{
case 0: /* 万能:和弦走向库 */
ADDRESS = FLASH_ADDR_MODE_UNIVERSAL;
expect = EXTFLASH_BIN3_UNIVERSAL_ADDR;
map_name = "BIN3_UNIVERSAL";
break;
case 1: /* 专业 */
if (mGuiData[GUI_AUTOBAND_SW].Current) {
ADDRESS = FLASH_ADDR_SONG_HAITIAN;
expect = EXTFLASH_BIN2_SONG_HAITIAN_ADDR;
map_name = "BIN2_SONG_HAITIAN";
} else {
ADDRESS = FLASH_ADDR_MODE_EXPERT;
expect = EXTFLASH_BIN1_RHYTHM_ADDR;
map_name = "BIN1_RHYTHM";
}
break;
case 2: /* 普通 */
if (mGuiData[GUI_AUTOBAND_SW].Current) {
ADDRESS = FLASH_ADDR_SONG_HAITIAN;
expect = EXTFLASH_BIN2_SONG_HAITIAN_ADDR;
map_name = "BIN2_SONG_HAITIAN";
} else {
ADDRESS = FLASH_ADDR_MODE_NORMAL;
expect = EXTFLASH_BIN1_RHYTHM_ADDR;
map_name = "BIN1_RHYTHM";
}
break;
default:
ADDRESS = FLASH_ADDR_MODE_UNIVERSAL;
expect = EXTFLASH_BIN3_UNIVERSAL_ADDR;
map_name = "BIN3_UNIVERSAL";
break;
}
LOG_I("tone", "ADDRESS=0x%08X map=%s expect=0x%08X tab=%u sw=%u %s",
(unsigned)ADDRESS, map_name, (unsigned)expect,
(unsigned)mGuiData[GUI_TAB_INDEX].Current,
(unsigned)mGuiData[GUI_AUTOBAND_SW].Current,
(ADDRESS == expect) ? "OK" : "MISMATCH");
}
void UI_ReloadTonePreset(void)
{
UI_ApplyToneAddress();
/* 换库前先停,避免播放中改 relocate 指针 */
AutoBandTop1_Stop();
StartFlag = 0;
/* 万能:和弦走向 */
if (mGuiData[GUI_TAB_INDEX].Current == 0)
{
int ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[ALL_MODE_PARAM].Current);
LOG_I("tone", "load universal idx=%d ret=%d name=%s addr=0x%08X map=BIN3@0x%08X",
ParamGuiData[ALL_MODE_PARAM].Current, ret,
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?",
(unsigned)ADDRESS, (unsigned)EXTFLASH_BIN3_UNIVERSAL_ADDR);
return;
}
/* 普通/专业:本地曲目或节奏类型 */
if (mGuiData[GUI_AUTOBAND_SW].Current)
{
GUI_SWITCH *local = &ParamGuiData[EXPRESS_MODE_PARAM];
local->Max = (LOCAL_SONG_COUNT > 0) ? (uint16_t)(LOCAL_SONG_COUNT - 1) : 0;
if (local->Current > local->Max)
local->Current = local->Max;
int ret = AutoBandTop1_LoadPresetItemFromFlash(local->Current);
if (ret != 0)
LOG_E("tone", "load local song idx=%d failed ret=%d addr=0x%08X map=BIN2@0x%08X",
local->Current, ret, (unsigned)ADDRESS,
(unsigned)EXTFLASH_BIN2_SONG_HAITIAN_ADDR);
else
LOG_I("tone", "local song idx=%d name=%s addr=0x%08X map=BIN2@0x%08X %s",
local->Current,
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?",
(unsigned)ADDRESS,
(unsigned)EXTFLASH_BIN2_SONG_HAITIAN_ADDR,
(ADDRESS == EXTFLASH_BIN2_SONG_HAITIAN_ADDR) ? "OK" : "MISMATCH");
{
int bin_n = AutoBandTop1_GetPresetItemCount();
if (bin_n != LOCAL_SONG_COUNT)
LOG_W("tone", "local song count csv=%d bin=%d", LOCAL_SONG_COUNT, bin_n);
}
return;
}
{
int ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[SONG_MODE_PARAM].Current);
LOG_I("tone", "load rhythm idx=%d ret=%d name=%s addr=0x%08X map=BIN1@0x%08X %s",
ParamGuiData[SONG_MODE_PARAM].Current, ret,
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?",
(unsigned)ADDRESS,
(unsigned)EXTFLASH_BIN1_RHYTHM_ADDR,
(ADDRESS == EXTFLASH_BIN1_RHYTHM_ADDR) ? "OK" : "MISMATCH");
(void)ret;
}
}
static uint8_t s_ui_focus_id = UI_FOCUS_NONE;
static uint8_t UI_NormalizeFocusId(uint8_t widget_id)
{
if (widget_id == GUI_AUTOBAND_SW)
return GUI_MODE_PARAM;
return widget_id;
}
static void UI_RedrawWidget(uint8_t id)
{
if (CurrUIProcress == UI_SongMode_Process)
{
switch (id)
{
case GUI_TRANSPOSE:
label_Tranzpose_ui(&UI_Label[GUI_TRANSPOSE], &mGuiData[GUI_TRANSPOSE]);
break;
case GUI_SPEED:
label_Speed_ui(&UI_Label[GUI_SPEED], &mGuiData[GUI_SPEED]);
break;
case GUI_MODE_PARAM:
label_ModeSelece_ui(&UI_Label[GUI_MODE_PARAM], &mGuiData[GUI_MODE_PARAM]);
break;
case GUI_TIMBRE_SELECT:
label_TimbreSelece_ui(&UI_Label[GUI_TIMBRE_SELECT], &mGuiData[GUI_TIMBRE_SELECT]);
break;
case GUI_PLAY_SECTION:
label_PlaySection_ui(&UI_Label[GUI_PLAY_SECTION], &mGuiData[GUI_PLAY_SECTION]);
break;
default:
break;
}
}
else if (CurrUIProcress == UI_Setting_Process)
{
if (id <= GUI_RESTORE)
Draw_System_Item_List(&SystemSetting[id], &mGuiData_SystemSETTING[id]);
}
}
void UI_ClearFocus(void)
{
s_ui_focus_id = UI_FOCUS_NONE;
}
uint8_t UI_IsFocused(uint8_t widget_id)
{
return (s_ui_focus_id == UI_NormalizeFocusId(widget_id)) ? 1 : 0;
}
void UI_GetFocusGrad(uint8_t widget_id, uint16_t *c_top, uint16_t *c_bot)
{
/* 0902行背景保持深色选中态由 TAB/段落按钮自身高亮,避免整行变蓝 */
(void)widget_id;
*c_top = UI0902_ROW_BG;
*c_bot = UI0902_ROW_BG;
}
uint8_t UI_SetFocus(uint8_t widget_id)
{
uint8_t prev = s_ui_focus_id;
widget_id = UI_NormalizeFocusId(widget_id);
if (prev == widget_id)
return 0;
s_ui_focus_id = widget_id;
if (prev != UI_FOCUS_NONE)
UI_RedrawWidget(prev);
if (widget_id != UI_FOCUS_NONE)
UI_RedrawWidget(widget_id);
return 1;
}
void UI_DrawStatusSepLine(void)
{
/* 与模式选择/各模式主页统一:需求稿分割线 y=361px 厚 */
LCD_FillByColor(0, UI0902_STATUS_SEP_Y, 240,
(uint16_t)(UI0902_STATUS_SEP_Y + UI0902_SEP_LINE_THICK),
UI0902_STATUS_SEP_COLOR);
}
void label_top()
{
LCD_FillByColor(0, 0, 240, UI_STATUS_BAR_H, UI0902_BG_COLOR);
/* 音量条:渐变 + 圆角(见 Draw_Volume_Bar */
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, level, 1, WHITE, GRAY);
Show_BL_Icon(mGuiData[GUI_BL_SW].Current);
Show_Battery_Icon(usb_charging_state);
UI_DrawStatusSepLine();
}
/* 小节选择刷新(占位,实际绘制在 UI_SongMode 内部) */
void Refresh_SectionSelect(uint16_t last_value, const LEBEL_UI *UI, GUI_SWITCH *Group)
{
Draw_Tab_Section_Menu(UI,(TAB_SECTION_INDEX)Group->Current);
}
/* TAB 选择刷新tab 未变时不切页,避免误触/phantom touch 整页重绘闪烁 */
void Refresh_TabSelect_ui(const LEBEL_UI *UI, GUI_SWITCH *Group)
{
static uint8_t s_last_tab = 0xFFU;
uint8_t tab = (uint8_t)Group->Current;
(void)UI;
if (tab == s_last_tab) {
return;
}
s_last_tab = tab;
switch (tab)
{
case 0:
MenuPage_SongMode_Proc();
break;
case 1:
MenuPage_ExpertMode_Proc();
break;
case 2:
MenuPage_FreeMode_Proc();
break;
case 3:
MenuPage_SystemSetting_Proc();
break;
default:
break;
}
}
/* 返回当前 TAB 对应的模式页(设置/调音台页的“返回”用) */
void UI_GotoCurrentModePage(void)
{
switch (mGuiData[GUI_TAB_INDEX].Current)
{
case 0:
MenuPage_SongMode_Proc(); /* Init 内 Reload */
break;
case 1:
MenuPage_ExpertMode_Proc();
break;
case 2:
MenuPage_FreeMode_Proc();
break;
default:
MenuPage_SongMode_Proc();
break;
}
}
/* 蓝牙图标:按系统开关显示;关则清空区域不画图标 */
void Show_BL_Icon(uint8_t value)
{
static int8_t s_bt_pwr = -1;
uint8_t on = value ? 1u : 0u;
/* Fill 终点为开区间,传 W/H 本身;高度须停在分割线之上 */
LCD_FillByColor(UI0902_BT_X, UI0902_BT_Y,
UI0902_BT_X + UI0902_BT_W,
UI0902_BT_Y + UI0902_BT_H, UI0902_BG_COLOR);
if (on)
{
LCD_WR_PIC_Trans(UI0902_BT_X, UI0902_BT_Y, UI0902_BT_W, UI0902_BT_H,
gImage_UI0902_Bluetooth_11x17, BLACK);
}
if (s_bt_pwr != (int8_t)on)
{
s_bt_pwr = (int8_t)on;
BSP_BlueToothPowerEnable(on);
}
UI_DrawStatusSepLine();
}
void Draw_Status_Battery_Icon(uint8_t battery_percent)
{
uint8_t Info[8];
uint16_t fill_w;
uint16_t actual_w;
uint16_t max_w;
uint16_t group_w;
uint16_t clear_x;
uint16_t bat_x;
uint16_t text_x;
uint16_t text_y;
uint16_t fill_x1, fill_y1, fill_x2, fill_y2;
uint8_t adv = UI0902_ASCII_W(UI0902_BATTERY_TEXT_SIZE);
if (battery_percent > 100)
battery_percent = 100;
sprintf((char *)Info, "%d%%", battery_percent);
actual_w = (uint16_t)(strlen((char *)Info) * adv);
/* 图标与百分比紧贴整组右对齐。「100%」变位数时图标左移,不拉开字距 */
max_w = (uint16_t)(4u * adv);
group_w = (uint16_t)(UI0902_BATTERY_W + UI0902_BATTERY_TEXT_GAP + actual_w);
bat_x = (uint16_t)(240 - UI0902_BATTERY_RIGHT_MARGIN - group_w);
text_x = (uint16_t)(bat_x + UI0902_BATTERY_W + UI0902_BATTERY_TEXT_GAP);
text_y = (uint16_t)(UI0902_BATTERY_Y
+ ((int16_t)UI0902_BATTERY_H - (int16_t)UI0902_BATTERY_TEXT_SIZE) / 2);
if ((int16_t)text_y < 0)
text_y = 0;
clear_x = (uint16_t)(240 - UI0902_BATTERY_RIGHT_MARGIN
- UI0902_BATTERY_W - UI0902_BATTERY_TEXT_GAP - max_w);
if (clear_x > 2)
clear_x = (uint16_t)(clear_x - 2);
else
clear_x = 0;
LCD_FillByColor(clear_x, 0, 240, UI0902_STATUS_SEP_Y, UI0902_BG_COLOR);
/* 内腔约 y+2..y+9 / x+3..x+23上下左右各留 1px电量不贴外壳 */
fill_w = (uint16_t)((19UL * battery_percent) / 100);
if (fill_w > 0) {
fill_x1 = (uint16_t)(bat_x + 4);
fill_y1 = (uint16_t)(UI0902_BATTERY_Y + 3);
fill_x2 = (uint16_t)(fill_x1 + fill_w);
fill_y2 = (uint16_t)(fill_y1 + 6);
LCD_FillByColor(fill_x1, fill_y1, fill_x2, fill_y2, WHITE);
}
LCD_WR_PIC_Trans(bat_x, UI0902_BATTERY_Y, UI0902_BATTERY_W, UI0902_BATTERY_H,
gImage_UI0902_BatteryOutline_29x12, BLACK);
LCD_ShowString(text_x, text_y, Info, WHITE, UI0902_BG_COLOR,
UI0902_BATTERY_TEXT_SIZE, 0);
UI_DrawStatusSepLine();
}
void Show_Battery_Icon(uint8_t flag)
{
(void)flag;
Draw_Status_Battery_Icon(percentage);
}
void show_Param(const LEBEL_UI *UI, GUI_SWITCH *Group)
{
char Textstr_new[40] = {0};
char NumBuf[8] = {0};
/* 0902 比例TAB 行高 18 在区块顶,曲目行在其下,正文在行内垂直居中 */
const uint16_t row_y = UI->y + UI0902_TAB_H + 4; /* 曲目行顶 = 130 */
const uint16_t row_h = UI->h - UI0902_TAB_H - 4; /* 31 */
const uint16_t text_y = row_y + (row_h - UI->Text_size) / 2 + 1;
uint8_t idx = Group->Current + 1;
uint16_t c_top, c_bot;
UI_GetFocusGrad(GUI_MODE_PARAM, &c_top, &c_bot);
LCD_FillRoundRectGradient(
UI->x+25, row_y,
UI->x + UI->w-40-(UI->x+25),
row_h,
0,
c_top, c_bot
);
// 拼接序号 1. 2. 3.
sprintf(NumBuf, "%d.", idx);
uint16_t num_w = (uint16_t)(strlen(NumBuf) * UI0902_ASCII_W(UI->Text_size));
if (Group->Id == EXPRESS_MODE_PARAM && Group->Current < LOCAL_SONG_COUNT)
strcpy(Textstr_new, LocalSongNameGbk[Group->Current]);
else
GET_ParamNum_Str(Group->Current, 0, Textstr_new, Group->Id);
uint32_t string_start_x = LCD_ShowMixedString(UI->x+10, UI->x + UI->w, text_y, (uint8_t *)Textstr_new , LCD_ALIGN_CENTER, WHITE, BLACK, UI->Text_size, 1);
//序号X = 中文起点 - 数字宽度 - 5<EFBC8C>?像素
uint16_t num_x = string_start_x - num_w;
// 绘制左侧数字序号
LCD_ShowString(num_x, text_y, (const uint8_t *)NumBuf, UI->Text_fc, UI->Text_bc, UI->Text_size, 1);
}
//void Refresh_Transpose(uint8_t last_data,const LEBEL_UI *UI, GUI_SWITCH * Group)
//{
// LCD_FillRoundRectGradient(
// UI->x+30,
// UI->y + 20,
// 25 + 10+10+5,
// 20,
// 0,
// START_COLOR, END_COLOR
// );
// char Textstr1[20] = {0,};
// GET_Num_Str(Group->Current,0,Textstr1,Group->Id);
//
// LCD_ShowString_AutoAlign_Gradient(
// UI->x, // 坐标<E59D90>?
// UI->x+UI->w,
// UI->y + 17,
// (const uint8_t*)Textstr1,
// UI->Text_Align,
// UI->Text_fc,
// START_COLOR,
// END_COLOR,
// UI->Text_size
// );
//}
/* 稿面文本框:以 cx 为水平中心,宽 box_wY 为框顶。
* 行高有效lh >= font时在 max(lh, box_h) 内垂直居中;否则顶对齐画字。 */
static uint16_t UI_CardTextBoxX1(uint16_t cx, uint16_t box_w, uint16_t content_w)
{
uint16_t w = box_w;
if (content_w > w)
w = content_w;
if (cx < w / 2)
return 0;
return (uint16_t)(cx - w / 2);
}
static uint16_t UI_CardTextBoxX2(uint16_t cx, uint16_t box_w, uint16_t content_w)
{
uint16_t w = box_w;
if (content_w > w)
w = content_w;
return (uint16_t)(cx - w / 2 + w - 1);
}
static uint16_t UI_CardTextDrawY(uint16_t box_y, uint8_t box_h, uint8_t line_h, uint8_t font_h)
{
uint8_t cell = box_h;
if (line_h >= font_h && line_h > cell)
cell = line_h;
if (cell < font_h)
return box_y;
return (uint16_t)(box_y + (cell - font_h) / 2);
}
void Refresh_Transpose(const LEBEL_UI *UI, GUI_SWITCH * Group)
{
uint16_t c_top, c_bot;
uint16_t cx = (UI->Id == GUI_SPEED) ? UI0902_CARD_TEXT_CX_R : UI0902_CARD_TEXT_CX_L;
uint16_t value_y, value_y0, sub_y, x1, x2, content_w, clear_w, clear_h;
char Textstr1[20] = {0,};
const uint8_t *sub_txt = (UI->Id == GUI_SPEED) ? (const uint8_t *)"BPM" : (const uint8_t *)"KEY";
UI_GetFocusGrad(UI->Id, &c_top, &c_bot);
GET_Num_Str(Group->Current,0,Textstr1,Group->Id);
content_w = (uint16_t)(strlen(Textstr1) * UI0902_ASCII_W(UI0902_CARD_VALUE_SIZE));
/* 清区按最大位数移调最多2字符(Db)速度最多3位(260) */
clear_w = (uint16_t)(((UI->Id == GUI_SPEED) ? 3u : 2u) * UI0902_ASCII_W(UI0902_CARD_VALUE_SIZE));
if (content_w > clear_w)
clear_w = content_w;
if (clear_w < UI0902_CARD_VALUE_W)
clear_w = UI0902_CARD_VALUE_W;
value_y0 = UI_CardTextDrawY(UI0902_CARD_VALUE_Y, UI0902_CARD_VALUE_H,
UI0902_CARD_VALUE_LH, UI0902_CARD_VALUE_SIZE);
value_y = (uint16_t)((int16_t)value_y0 + UI0902_CARD_VALUE_OY);
/* 清区高度保证主值完整;不得侵入 KEY/BPM 行 */
clear_h = (uint16_t)(UI0902_CARD_VALUE_H + 1);
if (clear_h < (uint16_t)(UI0902_CARD_VALUE_SIZE + 1))
clear_h = (uint16_t)(UI0902_CARD_VALUE_SIZE + 1);
if (value_y + clear_h > UI0902_CARD_SUB_Y)
clear_h = (uint16_t)(UI0902_CARD_SUB_Y - value_y);
x1 = (uint16_t)(UI_CardTextBoxX1(cx, clear_w, clear_w) + UI0902_CARD_VALUE_OX);
x2 = (uint16_t)(UI_CardTextBoxX2(cx, clear_w, clear_w) + UI0902_CARD_VALUE_OX);
LCD_FillRoundRectGradient(
x1, value_y,
(uint16_t)(x2 - x1 + 1),
clear_h,
0, c_top, c_bot);
x1 = (uint16_t)(UI_CardTextBoxX1(cx, UI0902_CARD_VALUE_W, content_w) + UI0902_CARD_VALUE_OX);
x2 = (uint16_t)(UI_CardTextBoxX2(cx, UI0902_CARD_VALUE_W, content_w) + UI0902_CARD_VALUE_OX);
LCD_ShowString_AutoAlign_Gradient(
x1, x2, value_y,
(const uint8_t*)Textstr1,
LCD_ALIGN_CENTER, UI->Text_fc, c_top, c_bot,
UI0902_CARD_VALUE_SIZE);
/* 主值刷新后必须重画 KEY/BPM避免残影或被清区边缘吃掉 */
sub_y = UI_CardTextDrawY(UI0902_CARD_SUB_Y, UI0902_CARD_SUB_H,
UI0902_CARD_SUB_LH, UI0902_CARD_SUB_SIZE);
x1 = UI_CardTextBoxX1(cx, UI0902_CARD_SUB_W, UI0902_CARD_SUB_W);
x2 = UI_CardTextBoxX2(cx, UI0902_CARD_SUB_W, UI0902_CARD_SUB_W);
LCD_FillRoundRectGradient(
x1, sub_y,
(uint16_t)(x2 - x1 + 1),
UI0902_CARD_SUB_SIZE + 1,
0, c_top, c_bot);
LCD_ShowString_AutoAlign_Gradient(
x1, x2, sub_y, sub_txt,
LCD_ALIGN_CENTER, UI->Text_fc, c_top, c_bot,
UI0902_CARD_SUB_SIZE);
}
void Refresh_StringTimbre(uint8_t last_data,const LEBEL_UI *UI, GUI_SWITCH * Group)
{
(void)last_data;
/* 与 label_TimbreSelece_ui 同一套居中布局;旧版 UI->y+25 在 TIMBRE_H=30 时会画到行外,叠出第二行 */
label_TimbreSelece_ui(UI, Group);
if (Group->Id == GUI_TIMBRE_SELECT)
{
uint8_t AllNoteOff_buff[3] = {0xB0, 0x7B, 0x00};
SendMidiDataToDreamDSP(AllNoteOff_buff, sizeof(AllNoteOff_buff));
}
}
void Refresh_ModeSelect(uint8_t last_data, const LEBEL_UI *UI, GUI_SWITCH *Group)
{
Draw_Tab_Mode_Menu(UI,Group);
}
void Refresh_Mode1Select(uint8_t last_data, LEBEL_UI *UI, GUI_SWITCH *Group)
{
char Textstr1[20] = {0};
char Textstr2[20] = {0};
GUI_SWITCH *pCurData =NULL;
// 重点<EFBC9A>?当前选中的模式2/3/4找到<E689BE>?<3F>应数据结构<E7BB93>?
switch(mGuiData[GUI_TAB_INDEX].Current)
{
case 0: pCurData = &ParamGuiData[ALL_MODE_PARAM]; break; /* 万能:和弦走向 */
case 1: /* 专业 */
case 2: /* 普通 */
if (mGuiData[GUI_AUTOBAND_SW].Current)
pCurData = &ParamGuiData[EXPRESS_MODE_PARAM];
else
pCurData = &ParamGuiData[SONG_MODE_PARAM];
break;
//default: pCurData = &mGuiData[GUI_MODE1_SELECT];
}
// 清除旧数字(清除的是旧值,不是当前值)
GET_ParamNum_Str(last_data, 0, Textstr1, pCurData->Id);
LCD_ClearString_AutoAlign(
UI->x, UI->x + UI->w,
UI->y + 25,
(const uint8_t*)Textstr1,
UI->Text_Align,
UI->Text_fc,
UI->Text_bc,
0, UI->Text_size
);
// 显示当前选中模式的真实数<E5AE9E>?
GET_ParamNum_Str(pCurData->Current, 0, Textstr2, pCurData->Id);
LCD_ShowString_AutoAlign(
UI->x, UI->x + UI->w,
UI->y + 25,
(const uint8_t*)Textstr2,
UI->Text_Align,
UI->Text_fc,
UI->Text_bc,
0, UI->Text_size
);
}
void label_Tranzpose_ui(const LEBEL_UI *UI,GUI_SWITCH * Group)
{
uint8_t Textstr[20] = {0};
uint16_t c_top, c_bot;
uint16_t cx = UI0902_CARD_TEXT_CX_L;
uint16_t label_y, value_y, sub_y, chev_cy;
uint16_t x1, x2, content_w;
UI_GetFocusGrad(UI->Id, &c_top, &c_bot);
LCD_FillRoundRectGradient(
UI->x, UI->y, UI->w, UI->h,
UI0902_RADIUS_CARD, c_top, c_bot);
/* 移调11 / LH13 / 框22×11 / (64,60) */
label_y = UI_CardTextDrawY(UI0902_CARD_LABEL_Y, UI0902_CARD_LABEL_H,
UI0902_CARD_LABEL_LH, UI0902_CARD_LABEL_SIZE);
x1 = UI_CardTextBoxX1(cx, UI0902_CARD_LABEL_W, UI0902_CARD_LABEL_W);
x2 = UI_CardTextBoxX2(cx, UI0902_CARD_LABEL_W, UI0902_CARD_LABEL_W);
LCD_ShowChinese_AutoAlign_Gradient(
x1, x2, label_y, UI->p,
LCD_ALIGN_CENTER, UI->Tab_fc, c_top, c_bot, UI0902_CARD_LABEL_SIZE);
GET_Num_Str(mGuiData[UI->Id].Current, 0, (char*)Textstr, UI->Id);
content_w = (uint16_t)(strlen((char*)Textstr) * UI0902_ASCII_W(UI0902_CARD_VALUE_SIZE));
/* 主值基准位:三角仍按此中线;字母单独右移/上移 */
value_y = UI_CardTextDrawY(UI0902_CARD_VALUE_Y, UI0902_CARD_VALUE_H,
UI0902_CARD_VALUE_LH, UI0902_CARD_VALUE_SIZE);
x1 = UI_CardTextBoxX1(cx, UI0902_CARD_VALUE_W, content_w);
x2 = UI_CardTextBoxX2(cx, UI0902_CARD_VALUE_W, content_w);
/* mode.png三角中心低于主值中线约 3px≈y81 */
chev_cy = (uint16_t)(value_y + UI0902_CARD_VALUE_SIZE / 2 + 3);
UI_DrawTriLeft(UI->x + 5, chev_cy);
UI_DrawTriRight((uint16_t)(UI->x + UI->w - 5 - UI0902_TRI_R_W), chev_cy);
LCD_ShowString_AutoAlign_Gradient(
(uint16_t)(x1 + UI0902_CARD_VALUE_OX),
(uint16_t)(x2 + UI0902_CARD_VALUE_OX),
(uint16_t)((int16_t)value_y + UI0902_CARD_VALUE_OY),
Textstr,
LCD_ALIGN_CENTER, UI->Text_fc, c_top, c_bot, UI0902_CARD_VALUE_SIZE);
/* KEY独立行先清底再画保证不被主值残影叠住 */
sub_y = UI_CardTextDrawY(UI0902_CARD_SUB_Y, UI0902_CARD_SUB_H,
UI0902_CARD_SUB_LH, UI0902_CARD_SUB_SIZE);
x1 = UI_CardTextBoxX1(cx, UI0902_CARD_SUB_W, UI0902_CARD_SUB_W);
x2 = UI_CardTextBoxX2(cx, UI0902_CARD_SUB_W, UI0902_CARD_SUB_W);
LCD_FillRoundRectGradient(
x1, sub_y,
(uint16_t)(x2 - x1 + 1),
UI0902_CARD_SUB_SIZE + 1,
0, c_top, c_bot);
LCD_ShowString_AutoAlign_Gradient(
x1, x2, sub_y, (const uint8_t*)"KEY",
LCD_ALIGN_CENTER, UI->Text_fc, c_top, c_bot, UI0902_CARD_SUB_SIZE);
}
void label_Speed_ui(const LEBEL_UI *UI,GUI_SWITCH * Group)
{
uint8_t Textstr[20] = {0};
uint16_t c_top, c_bot;
uint16_t cx = UI0902_CARD_TEXT_CX_R;
uint16_t label_y, value_y, sub_y;
uint16_t x1, x2, content_w;
int16_t btn_y;
UI_GetFocusGrad(UI->Id, &c_top, &c_bot);
LCD_FillRoundRectGradient(
UI->x, UI->y, UI->w, UI->h,
UI0902_RADIUS_CARD, c_top, c_bot);
label_y = UI_CardTextDrawY(UI0902_CARD_LABEL_Y, UI0902_CARD_LABEL_H,
UI0902_CARD_LABEL_LH, UI0902_CARD_LABEL_SIZE);
x1 = UI_CardTextBoxX1(cx, UI0902_CARD_LABEL_W, UI0902_CARD_LABEL_W);
x2 = UI_CardTextBoxX2(cx, UI0902_CARD_LABEL_W, UI0902_CARD_LABEL_W);
LCD_ShowChinese_AutoAlign_Gradient(
x1, x2, label_y, UI->p,
LCD_ALIGN_CENTER, UI->Tab_fc, c_top, c_bot, UI0902_CARD_LABEL_SIZE);
GET_Num_Str(mGuiData[UI->Id].Current, 0, (char*)Textstr, UI->Id);
content_w = (uint16_t)(strlen((char*)Textstr) * UI0902_ASCII_W(UI0902_CARD_VALUE_SIZE));
value_y = UI_CardTextDrawY(UI0902_CARD_VALUE_Y, UI0902_CARD_VALUE_H,
UI0902_CARD_VALUE_LH, UI0902_CARD_VALUE_SIZE);
x1 = UI_CardTextBoxX1(cx, UI0902_CARD_VALUE_W, content_w);
x2 = UI_CardTextBoxX2(cx, UI0902_CARD_VALUE_W, content_w);
/* ± 低于主值中线与三角同偏移完整绘制KEY 行后画会盖住透明底边 */
btn_y = (int16_t)value_y + ((int16_t)UI0902_CARD_VALUE_SIZE - (int16_t)UI0902_BTN_MINUS_H) / 2 + 3;
if (btn_y < (int16_t)UI->y + 2) btn_y = (int16_t)UI->y + 2;
LCD_WR_PIC_Trans(UI->x + 5, (uint16_t)btn_y,
UI0902_BTN_MINUS_W, UI0902_BTN_MINUS_H,
gImage_UI0902_BtnMinus_23x22, BLACK);
LCD_WR_PIC_Trans(UI->x + UI->w - 5 - UI0902_BTN_PLUS_W, (uint16_t)btn_y,
UI0902_BTN_PLUS_W, UI0902_BTN_PLUS_H,
gImage_UI0902_BtnPlus_23x22, BLACK);
LCD_ShowString_AutoAlign_Gradient(
(uint16_t)(x1 + UI0902_CARD_VALUE_OX),
(uint16_t)(x2 + UI0902_CARD_VALUE_OX),
(uint16_t)((int16_t)value_y + UI0902_CARD_VALUE_OY),
Textstr,
LCD_ALIGN_CENTER, UI->Text_fc, c_top, c_bot, UI0902_CARD_VALUE_SIZE);
sub_y = UI_CardTextDrawY(UI0902_CARD_SUB_Y, UI0902_CARD_SUB_H,
UI0902_CARD_SUB_LH, UI0902_CARD_SUB_SIZE);
x1 = UI_CardTextBoxX1(cx, UI0902_CARD_SUB_W, UI0902_CARD_SUB_W);
x2 = UI_CardTextBoxX2(cx, UI0902_CARD_SUB_W, UI0902_CARD_SUB_W);
LCD_FillRoundRectGradient(
x1, sub_y,
(uint16_t)(x2 - x1 + 1),
UI0902_CARD_SUB_SIZE + 1,
0, c_top, c_bot);
LCD_ShowString_AutoAlign_Gradient(
x1, x2, sub_y, (const uint8_t*)"BPM",
LCD_ALIGN_CENTER, UI->Text_fc, c_top, c_bot, UI0902_CARD_SUB_SIZE);
}
// 万能:和弦走向;普通/专业:节奏类型 | 本地曲目
void label_ModeSelece_ui(const LEBEL_UI *UI,GUI_SWITCH * Group)
{
char *str;
GUI_SWITCH *paramCurData = NULL;
uint16_t c_top, c_bot;
uint8_t tab = (uint8_t)mGuiData[GUI_TAB_INDEX].Current;
UI_GetFocusGrad(GUI_MODE_PARAM, &c_top, &c_bot);
(void)Group;
LCD_FillRoundRectGradient(UI->x, UI->y+UI0902_TAB_H+4, UI->w, UI->h-UI0902_TAB_H-4, UI0902_RADIUS_CARD, c_top, c_bot);
if (tab == 0)
{
/* 万能:无 TAB标题「和弦走向」 */
str = (char*)"\xBA\xCD\xCF\xD2\xD7\xDF\xCF\xF2";
{
uint16_t row_y = (uint16_t)(UI->y + UI0902_TAB_H + 4);
uint16_t lab_y = (row_y > 15) ? (uint16_t)(row_y - 15) : 0;
LCD_FillByColor(UI->x, lab_y, UI->x + UI->w, (uint16_t)(row_y - 1), UI0902_BG_COLOR);
LCD_ShowChinese_AutoAlign(
UI->x, UI->x+UI->w, lab_y,
(uint8_t *)str, UI->Tab_Align, UI->Tab_fc, UI0902_BG_COLOR, 0, UI->Tab_size
);
}
paramCurData = &ParamGuiData[ALL_MODE_PARAM];
}
else
{
/* 普通/专业:节奏类型 | 本地曲目 */
Draw_Tab_Mode_Menu(UI, &mGuiData[GUI_AUTOBAND_SW]);
if (mGuiData[GUI_AUTOBAND_SW].Current)
paramCurData = &ParamGuiData[EXPRESS_MODE_PARAM];
else
paramCurData = &ParamGuiData[SONG_MODE_PARAM];
}
show_Param(&UI_Label[GUI_MODE_PARAM], paramCurData);
{
uint16_t row_cy = UI->y + UI0902_TAB_H + 4 + (UI->h - UI0902_TAB_H - 4) / 2;
UI_DrawTriLeft(UI->x + 5, row_cy);
UI_DrawTriRight((uint16_t)(UI->x + UI->w - 5 - UI0902_TRI_R_W), row_cy);
}
}
void label_TimbreSelece_ui(const LEBEL_UI *UI, GUI_SWITCH * Group)
{
uint8_t Textstr[20] = {0};
char NumBuf[8] = {0};
/* 0902 比例:音色行高 30正文在行内垂直居中 */
uint16_t text_y = UI->y + (UI->h - UI->Text_size) / 2 + 1;
uint8_t idx = mGuiData[UI->Id].Current + 1;
uint16_t c_top, c_bot;
uint16_t chev_cy = UI->y + UI->h / 2;
UI_GetFocusGrad(UI->Id, &c_top, &c_bot);
LCD_FillRoundRectGradient(
UI->x,
UI->y,
UI->w,
UI->h,
UI0902_RADIUS_CARD,
c_top, c_bot
);
LCD_ShowChinese_AutoAlign(
UI->x,
UI->x+UI->w,
UI->y - 15,
UI->p,
UI->Tab_Align,
UI->Tab_fc,
UI0902_BG_COLOR,
1,
UI->Tab_size
);
UI_DrawTriLeft(UI->x + 5, chev_cy);
UI_DrawTriRight((uint16_t)(UI->x + UI->w - 5 - UI0902_TRI_R_W), chev_cy);
LCD_FillRoundRectGradient(
UI->x + 40,
UI->y,
UI->x + UI->w - 40 - UI->x - 40 ,
UI->h,
0,
c_top, c_bot
);
sprintf(NumBuf, "%d.", idx);
uint16_t num_w = (uint16_t)(strlen(NumBuf) * UI0902_ASCII_W(UI->Text_size));
GET_Num_Str(mGuiData[UI->Id].Current, 0, (char*)Textstr, UI->Id);
uint32_t chinese_start_x = LCD_ShowChinese_AutoAlign_Gradient(
UI->x + num_w,
UI->x + UI->w,
text_y,
(const uint8_t*)Textstr,
UI->Text_Align,
UI->Text_fc,
c_top, c_bot,
UI->Text_size
);
uint16_t num_x = chinese_start_x - num_w - 5;
LCD_ShowString_AutoAlign_Gradient(num_x, num_x + num_w, text_y,
(const uint8_t *)NumBuf, LCD_ALIGN_LEFT, UI->Text_fc,
c_top, c_bot, UI->Text_size);
switch(Group->Id)
{
case GUI_TIMBRE_SELECT:
SendProgramChangeMidiEvent(0,Timbre_index[Group->Current]);
break;
default:
break;
}
}
void label_PlaySection_ui(const LEBEL_UI *UI,GUI_SWITCH * Group)
{
/* 0902 比例:标签在按钮上方 15px先画按钮再补标签底避免色块盖住 */
Draw_Tab_Section_Menu(UI,(TAB_SECTION_INDEX)Group->Current);
LCD_FillByColor(UI->x, UI->y - 15, UI->x + UI->w, UI->y - 1, UI0902_BG_COLOR);
LCD_ShowChinese_AutoAlign(
UI->x,
UI->x+UI->w,
UI->y - 14,
UI->p,
UI->Tab_Align,
UI->Tab_fc,
UI0902_BG_COLOR,
1,
UI->Tab_size
);
}
void UI_DrawSubPageHeader(const uint8_t *title_gbk)
{
/* 0904左返回位图调音台控件-1+ 居中标题 + 细分隔线06/07/08 一致) */
LCD_WR_PIC_Trans(UI0902_SUB_BACK_X, UI0902_SUB_BACK_Y,
UI0902_SUB_BACK_W, UI0902_SUB_BACK_H,
gImage_UI0902_TabBack_30x24, BLACK);
LCD_ShowChinese_AutoAlign(0, 240, UI0902_SUB_TITLE_Y, title_gbk,
LCD_ALIGN_CENTER, WHITE, UI0902_BG_COLOR, 0, UI0902_SUB_TITLE_SIZE);
LCD_DrawLine(0, UI0902_SUB_SEP_Y, 239, UI0902_SUB_SEP_Y, UI0902_SEP_LINE_COLOR);
}
void Draw_Bottom_Bar(uint8_t sel, uint8_t first_back)
{
/* 需求稿四键:万能 | 普通 | 专业 | 设置first_back 时设置位仍高亮(返回用触控逻辑) */
const uint8_t *icons[4];
uint8_t ws[4], hs[4];
/* 0904四键中心约 40 / 100 / 160 / 210 */
const uint16_t cx[4] = { 40, 100, 160, 210 };
uint8_t i;
(void)first_back;
/* 从段落钮底边之下清屏,勿切掉按钮底圆角(钮 y=231..264 */
LCD_FillByColor(0, (uint16_t)(UI0902_SECTION_Y + UI0902_SECTION_BTN_H),
240, 320, UI0902_BG_COLOR);
/* mode.png段落钮与底栏之间横线分隔与顶栏同色同厚 */
LCD_FillByColor(0, UI0902_SEP_LINE_Y, 240,
(uint16_t)(UI0902_SEP_LINE_Y + UI0902_SEP_LINE_THICK),
UI0902_SEP_LINE_COLOR);
if (sel == UI0902_NAV_UNIVERSAL) { icons[0] = gImage_Nav_Universal_Sel; ws[0] = 36; hs[0] = 28; }
else { icons[0] = gImage_Nav_Universal_Not; ws[0] = 36; hs[0] = 28; }
if (sel == UI0902_NAV_NORMAL) { icons[1] = gImage_Nav_Normal_Sel; ws[1] = 35; hs[1] = 29; }
else { icons[1] = gImage_Nav_Normal_Not; ws[1] = 35; hs[1] = 28; }
if (sel == UI0902_NAV_EXPERT) { icons[2] = gImage_Nav_Expert_Sel; ws[2] = 35; hs[2] = 27; }
else { icons[2] = gImage_Nav_Expert_Not; ws[2] = 35; hs[2] = 27; }
if (sel == UI0902_NAV_SETTING) { icons[3] = gImage_Nav_Setting_Sel; ws[3] = 18; hs[3] = 28; }
else { icons[3] = gImage_Nav_Setting_Not; ws[3] = 18; hs[3] = 28; }
for (i = 0; i < 4; i++)
{
LCD_WR_PIC_Trans(cx[i] - ws[i] / 2, 283, ws[i], hs[i], icons[i], BLACK);
}
}
void UI_NavBar_Action(uint8_t value)
{
switch (value)
{
case UI0902_NAV_UNIVERSAL:
/* Init 内会设 TAB 并 ReloadTonePreset勿在此前加载会仍用旧 TAB */
MenuPage_SongMode_Proc();
break;
case UI0902_NAV_NORMAL:
MenuPage_FreeMode_Proc();
break;
case UI0902_NAV_EXPERT:
MenuPage_ExpertMode_Proc();
break;
case UI0902_NAV_SETTING:
MenuPage_SystemSetting_Proc(); /* 0902-11 设置入口:调音台/系统设置 */
break;
default:
break;
}
}
void label_Tab_Select_ui(const LEBEL_UI *UI,GUI_SWITCH * Group)
{
uint8_t sel = UI0902_NAV_NONE;
(void)UI;
(void)Group;
/* GUI_TAB_INDEX0万能 1专业 2普通 */
switch (mGuiData[GUI_TAB_INDEX].Current)
{
case 0: sel = UI0902_NAV_UNIVERSAL; break;
case 1: sel = UI0902_NAV_EXPERT; break;
case 2: sel = UI0902_NAV_NORMAL; break;
default: break;
}
Draw_Bottom_Bar(sel, 0);
}
void Draw_Tab_Section_Menu(const LEBEL_UI *UI, TAB_SECTION_INDEX select_tab)
{
const uint16_t tab_w = UI0902_SECTION_BTN_W;
const uint16_t tab_h = UI0902_SECTION_BTN_H;
const uint8_t tab_r = UI0902_RADIUS_BTN;
const uint8_t pitch = UI0902_SECTION_PITCH;
const uint16_t start_x = UI0902_MARGIN_X; /* 0902-0412/69/126/183 */
const uint16_t start_y = UI->y;
/* 0819演奏段落数字与标题同为 13按钮内垂直居中视觉重心 +1 */
const uint16_t text_y = start_y + (tab_h - UI0902_FONT_BODY) / 2 + 1;
const char *nums[4] = {"1", "2", "3", "4"};
uint8_t i;
for (i = 0; i < 4; i++)
{
uint16_t x = start_x + i * pitch;
uint16_t bg = (select_tab == i) ? COLOR_GRAD_MID : UI0902_ROW_BG;
LCD_FillRoundRect(x, start_y, tab_w, tab_h, tab_r, bg);
LCD_ShowString_AutoAlign(
x, (uint16_t)(x + tab_w - 1), text_y,
(const uint8_t*)nums[i],
UI->Text_Align,
WHITE,
bg,
0,
UI0902_FONT_BODY
);
}
}
void GET_ParamNum_Str(int16_t NUM, uint8_t ValidLen, char* Str, uint8_t hasSign)
{
// int16_t Value;
switch(hasSign)
{
case 0:
switch(NUM)
{
case 0: strcpy(Str,"\xBC\xAA\xCB\xFB\xBE\xAD\xB5\xE4\xB7\xD6\xBD\xE2 4-4\0"); break; // 00 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>4-4
case 1: strcpy(Str,"\xBC\xAA\xCB\xFB\xBE\xAD\xB5\xE4\xC9\xA8\xCF\xD2 4-4\0"); break; // 01 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɨ<EFBFBD><C9A8>4-4
case 2: strcpy(Str,"\xB8\xB4\xB9\xC5\xBC\xAA\xCB\xFB\xC1\xF7\xD0\xD0 4-4\0"); break; // 02 <20><><EFBFBD>ż<EFBFBD><C5BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4-4
case 3: strcpy(Str,"\xC1\xF7\xD0\xD0\xD2\xA1\xB9\xF6 4-4\0"); break; // 03 <20><><EFBFBD><EFBFBD>ҡ<EFBFBD><D2A1>4-4
case 4: strcpy(Str,"\xBE\xAD\xB5\xE4\xC7\xE9\xB8\xE8 4-4\0"); break; // 04 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4-4
case 5: strcpy(Str,"\xC1\xB5\xC8\xCB\xC7\xE9\xB8\xE8 2-4\0"); break; // 05 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2-4
case 6: strcpy(Str,"\xCC\xF0\xC3\xDB\xC7\xE9\xB8\xE8 4-4\0"); break; // 06 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4-4
case 7: strcpy(Str,"\xCE\xC2\xC7\xE9 8 \xC5\xC4 4-4\0"); break; // 07 <20><><EFBFBD><EFBFBD>8<EFBFBD><38>4-4
case 8: strcpy(Str,"\xCE\xC2\xC8\xE1 8 \xC5\xC4 4-4\0"); break; // 08 <20><><EFBFBD><EFBFBD>8<EFBFBD><38>4-4
case 9: strcpy(Str,"\xCF\xA6\xD1\xF4\xC1\xF7\xD0\xD0 4-4\0"); break; // 09 Ϧ<><CFA6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4-4
case 10: strcpy(Str,"\xCE\xF7\xB7\xBD\xCA\xEF\xB9\xE2 4-4\0"); break; // 10 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4-4
case 11: strcpy(Str,"\xCE\xC2\xDC\xB0\xC3\xF1\xD2\xA5 4-4\0"); break; // 11 <20><>ܰ<EFBFBD><DCB0>ҥ4-4
case 12: strcpy(Str,"\xD6\xD0\xCB\xD9\xD2\xA1\xB9\xF6 4-4\0"); break; // 12 <20><><EFBFBD><EFBFBD>ҡ<EFBFBD><D2A1>4-4
case 13: strcpy(Str,"\xD6\xD0\xCB\xD9\xC7\xE9\xB8\xE8 4-4\0"); break; // 13 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4-4
case 14: strcpy(Str,"\xCC\xF0\xC3\xC0 8 \xC5\xC4 4-4\0"); break; // 14 <20><><EFBFBD><EFBFBD>8<EFBFBD><38>4-4
case 15: strcpy(Str,"\xC0\xD6\xB6\xD3 8 \xC5\xC4 4-4\0"); break; // 15 <20>ֶ<EFBFBD>8<EFBFBD><38>4-4
case 16: strcpy(Str,"8 \xC5\xC4\xBB\xB3\xBE\xC9 4-4\0"); break; // 16 8<>Ļ<EFBFBD><C4BB><EFBFBD>4-4
case 17: strcpy(Str,"\xCF\xC4\xC8\xD5\xB2\xA8\xC8\xF8 4-4\0"); break; // 17 <20><><EFBFBD>ղ<EFBFBD><D5B2><EFBFBD>4-4
case 18: strcpy(Str,"\xB7\xC5\xBF\xCB\xC2\xC9\xB6\xAF 4-4\0"); break; // 18 <20>ſ<EFBFBD><C5BF>ɶ<EFBFBD>4-4
case 19: strcpy(Str,"\xB4\xF2\xB0\xF1\xD2\xA1\xB9\xF6\xC0\xD6 4-4\0"); break; // 19 <20><><EFBFBD>ҡ<EFBFBD><D2A1><EFBFBD><EFBFBD>4-4
case 20: strcpy(Str,"\xC1\xF7\xD0\xD0\xD6\xD0\xCB\xD9\xB5\xAF\xB3\xAA 4-4\0"); break; // 20 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٵ<EFBFBD><D9B5><EFBFBD>4-4
case 21: strcpy(Str,"\xC8\xF8\xBF\xCB\xCB\xB9 8 \xC5\xC4 4-4\0"); break; // 21 <20><><EFBFBD><EFBFBD>˹8<CBB9><38>4-4
case 22: strcpy(Str,"\xB8\xD6\xC7\xD9\xC2\xC9\xB6\xAF 4-4\0"); break; // 22 <20><><EFBFBD><EFBFBD><EFBFBD>ɶ<EFBFBD>4-4
case 23: strcpy(Str,"\xBF\xE1\xEC\xC5\xD0\xF0\xCA\xC2\xC7\xFA 4-4\0"); break; // 23 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4-4
case 24: strcpy(Str,"\xBF\xEC\xC0\xD6\xC7\xA1\xC7\xA1 4-4\0"); break; // 24 <20><><EFBFBD><EFBFBD>ǡǡ4-4
case 25: strcpy(Str,"16 \xC5\xC4\xC7\xE9\xB8\xE8 4-4\0"); break; // 25 16<31><36><EFBFBD><EFBFBD><EFBFBD>4-4
case 26: strcpy(Str,"\xB1\xEA\xD7\xBC\xD0\xF0\xCA\xC2\xC7\xFA 6-8\0"); break; // 26 <20><>׼<EFBFBD><D7BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>6-8
case 27: strcpy(Str,"\xCC\xA8\xCD\xE5\xC1\xF7\xD0\xD0\xC0\xD6 4-4\0"); break; // 27 ̨<><CCA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4-4
case 28: strcpy(Str,"\xB5\xE7\xD3\xB0\xD0\xF0\xCA\xC2 6-8\0"); break; // 28 <20><>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD>6-8
case 29: strcpy(Str,"\xCA\xA5\xB5\xAE\xD6\xAE\xD2\xB9 3-4\0"); break; // 29 ʥ<><CAA5>֮ҹ3-4
case 30: strcpy(Str,"\xBC\xAA\xCB\xFB\xB3\xAA\xD7\xF7\xD5\xDF 4-4\0"); break; // 30 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4-4
}
return;
break;
case 1: /* EXPRESS_MODE_PARAM本地曲目显示名CSV→LocalSongNames.h */
if (NUM >= 0 && NUM < LOCAL_SONG_COUNT)
strcpy(Str, LocalSongNameGbk[NUM]);
else
sprintf(Str, "%d", NUM);
return;
break;
case 2:
switch(NUM)
{
case 0: memcpy(Str,"1645", 4); break;
case 1: memcpy(Str,"1564", 4); break;
case 2: memcpy(Str,"1364", 4); break;
}
return;
break;
}
}
void GET_Num_Str(int16_t NUM, uint8_t ValidLen, char* Str, uint8_t hasSign)
{
switch(hasSign)
{
case 0:
switch(NUM)
{
case 0: memcpy(Str,"C\0", 2); break;
case 1: memcpy(Str,"Db\0",3); break;
case 2: memcpy(Str,"D\0", 2); break;
case 3: memcpy(Str,"Eb\0",3); break;
case 4: memcpy(Str,"E\0", 2); break;
case 5: memcpy(Str,"F\0", 2); break;
case 6: memcpy(Str,"Gb\0",3); break;
case 7: memcpy(Str,"G\0", 2); break;
case 8: memcpy(Str,"Ab\0",3); break;
case 9: memcpy(Str,"A\0", 2); break;
case 10: memcpy(Str,"Bb\0",3); break;
case 11: memcpy(Str,"B\0", 2); break;
}
return;
break;
case 1:
sprintf(Str, "%d", NUM);
return;
break;
case 3:
switch(NUM)
{
case 0: memcpy(Str,"\xD2\xF4\xC0\xD6\xBB\xE1\xB8\xD6\xCF\xD2\xBC\xAA\xCB\xFB\x00", 15); break; // 01 音乐会钢弦吉<E5BCA6>?
case 1: memcpy(Str,"\xBE\xAD\xB5\xE4\xB8\xD6\xCF\xD2\xBC\xAA\xCB\xFB\x00", 13); break; // 02 经典钢弦吉他
case 2: memcpy(Str,"\xBE\xAD\xB5\xE4\xC7\xE5\xD2\xF4\xBC\xAA\xCB\xFB\x00", 13); break; // 03 经典轻音吉他
case 3: memcpy(Str,"\xB8\xB4\xB9\xC5\xCA\xA7\xD5\xE6\xB5\xE7\xBC\xAA\xCB\xFB\x00",15); break; // 04 复古失真电吉<E794B5>?
case 4: memcpy(Str,"\xB5\xE7\xB1\xB4\xCB\xBE\x00", 7); break; // 05 电贝<E794B5>?
}
return;
break;
case 5:
sprintf(Str, "%d", NUM);
return;
break;
case 6:
sprintf(Str, "%d", NUM);
return;
break;
case 7:
sprintf(Str, "%d", NUM);
return;
break;
}
}
void RefreshSystemSetting(uint8_t last_data,const LEBEL_UI *UI,GUI_SWITCH * Group)
{
Draw_System_Item_List(UI,Group);
}
/* 将自动关机索引应用到运行时计数器手册15/30/45/60/不自动) */
static void ApplyAutoCloseIndex(uint16_t idx)
{
AutoCloseFlag = true;
switch (idx)
{
case 0: AutoCloseTime = 15; mAutoPowerOffCount = (uint16_t)(AutoCloseTime * 60); break;
case 1: AutoCloseTime = 30; mAutoPowerOffCount = (uint16_t)(AutoCloseTime * 60); break;
case 2: AutoCloseTime = 45; mAutoPowerOffCount = (uint16_t)(AutoCloseTime * 60); break;
case 3: AutoCloseTime = 60; mAutoPowerOffCount = (uint16_t)(AutoCloseTime * 60); break;
case 4: AutoCloseTime = 0; AutoCloseFlag = false; break;
default:
AutoCloseTime = 15;
mAutoPowerOffCount = (uint16_t)(AutoCloseTime * 60);
break;
}
}
void RestoreSetting(void)
{
NvmParam_Type *nvm = drv_nvm_param_ptr();
/* 写入出厂静态参数到 RAM并同步 GUI / 推子 */
drv_nvm_load_default_calibration_static_value(nvm, 1);
mGuiData[GUI_PLAY_SECTION].Current = 0;
/* 出厂默认蓝牙开(已由 static_value 写入 NVM/GUI */
mGuiData_SystemSETTING[GUI_BLUETOOTH_SW].Current = 1;
mGuiData[GUI_BL_SW].Current = 1;
nvm->param.BluetoothSW = 1;
BSP_BlueToothPowerEnable(1);
ApplyAutoCloseIndex(mGuiData_SystemSETTING[GUI_AUTOCLOSE].Current);
/* 音色 / 音量 / 混响等到 DSP */
LoadConfig();
AutoBandTop1_ChangeBPM((int)mGuiData[GUI_SPEED].Current);
/* 持久化到内部 Flash */
drv_nvm_save_to_flash();
LOG_I("NVM", "factory restore applied and saved");
}
void Draw_System_Item_List(const LEBEL_UI *UI, GUI_SWITCH *Group)
{
NvmParam_Type * nvm = drv_nvm_param_ptr();
char Info[40];
uint16_t c_top, c_bot;
uint16_t row_w = UI->w ? UI->w : UI0902_SET_ROW_W;
uint8_t label_sz = UI->Tab_size ? UI->Tab_size : UI0902_SET_ROW_FONT;
uint8_t value_sz = UI->Text_size ? UI->Text_size : UI0902_FONT_LABEL;
uint16_t text_y = UI->y + (UI->h - label_sz) / 2;
uint16_t val_x1 = UI->x + 118;
uint16_t val_x2 = UI->x + row_w - 18;
uint16_t chev_cy = UI->y + UI->h / 2;
/* 先清整块外接矩形为页面底色,避免焦点蓝圆角残留四角描边 */
LCD_FillByColor(UI->x, UI->y, (uint16_t)(UI->x + row_w), (uint16_t)(UI->y + UI->h),
UI0902_BG_COLOR);
if (UI_IsFocused(Group->Id))
{
c_top = START_COLOR;
c_bot = END_COLOR;
LCD_FillRoundRectGradient(UI->x, UI->y, row_w, UI->h, UI0902_RADIUS_CARD, c_top, c_bot);
}
else
{
c_top = c_bot = UI0902_ROW_BG;
LCD_FillRoundRect(UI->x, UI->y, row_w, UI->h, UI0902_RADIUS_CARD, UI0902_ROW_BG);
}
/* 行标签:与 0904 正文字号统一 */
LCD_ShowChinese_AutoAlign_Gradient(UI->x + 49, UI->x + row_w, text_y, UI->p,
LCD_ALIGN_LEFT, WHITE, c_top, c_bot, label_sz);
switch(Group->Id)
{
case GUI_VERSION:
/* 0902-07芯片图标系统设置图标-10 */
LCD_WR_PIC_FROM_FLASH_Trans(UI->x+12, UI->y + (UI->h - 19) / 2, 20, 19, UI0902_ICON_SYS_LANG_ADDR);
sprintf (Info, "%d.%d.%d", Version[0], Version[1],Version[2]);
/* 版本框右缘与蓝牙/自动关机右三角右缘val_x2对齐 */
{
const uint16_t ver_box_w = 54;
const uint16_t ver_x1 = (uint16_t)(val_x2 - ver_box_w);
LCD_FillRoundRect(ver_x1, UI->y + (UI->h - 22) / 2, ver_box_w, 22, 4, UI0902_BG_COLOR);
LCD_ShowString_AutoAlign(ver_x1, val_x2,
UI->y + (UI->h - value_sz) / 2,
(const uint8_t*)Info, LCD_ALIGN_CENTER, WHITE, UI0902_BG_COLOR, 0, value_sz);
}
break;
case GUI_BLUETOOTH_SW:
/* 素材:系统设置图标-11白蓝牙符Flash 槽名 RESTORE尺寸 13x21 */
LCD_WR_PIC_FROM_FLASH_Trans(UI->x + 12,
(uint16_t)(UI->y + (UI->h - UI0902_ICON_SYS_RESTORE_H) / 2),
UI0902_ICON_SYS_RESTORE_W, UI0902_ICON_SYS_RESTORE_H,
UI0902_ICON_SYS_RESTORE_ADDR);
UI_DrawTriLeft(val_x1, chev_cy);
if(Group->Current)
LCD_ShowChinese_AutoAlign_Gradient(val_x1 + UI0902_TRI_L_W, val_x2 - UI0902_TRI_R_W, text_y,(const uint8_t*)"\xCA\xC7",LCD_ALIGN_CENTER, WHITE,c_top, c_bot,value_sz);
else
LCD_ShowChinese_AutoAlign_Gradient(val_x1 + UI0902_TRI_L_W, val_x2 - UI0902_TRI_R_W, text_y,(const uint8_t*)"\xB9\xD8",LCD_ALIGN_CENTER, WHITE,c_top, c_bot,value_sz);
UI_DrawTriRight((uint16_t)(val_x2 - UI0902_TRI_R_W), chev_cy);
BSP_BlueToothPowerEnable (Group->Current);
mGuiData[GUI_BL_SW].Current = Group->Current;
nvm->param.BluetoothSW = (uint8_t)(Group->Current ? 1 : 0);
drv_nvm_save_to_flash();
break;
case GUI_AUTOCLOSE:
/* 素材:系统设置图标-12电源符 / ABOUT 槽 18x21 */
LCD_WR_PIC_FROM_FLASH_Trans(UI->x+12, UI->y + (UI->h - 21) / 2, 18, 21, UI0902_ICON_SYS_ABOUT_ADDR);
ApplyAutoCloseIndex(Group->Current);
UI_DrawTriLeft(val_x1, chev_cy);
if(Group->Current != 4)
{
sprintf (Info, "%d",AutoCloseTime);
/* 与蓝牙「关」相同:数值在左右三角之间水平居中;数字相对标签下移 2px */
LCD_ShowString_AutoAlign_Gradient(val_x1 + UI0902_TRI_L_W, val_x2 - UI0902_TRI_R_W,
(uint16_t)(text_y + 2),
(const uint8_t *)Info, LCD_ALIGN_CENTER,
WHITE, c_top, c_bot, value_sz);
}else
{
/* 手册「不自动」;字库无「不」,界面用稿面「关机」 */
LCD_ShowChinese_AutoAlign_Gradient(val_x1 + UI0902_TRI_L_W, val_x2 - UI0902_TRI_R_W, text_y,
(const uint8_t*)"\xB9\xD8\xBB\xFA",
LCD_ALIGN_CENTER, WHITE, c_top, c_bot, value_sz);
}
UI_DrawTriRight((uint16_t)(val_x2 - UI0902_TRI_R_W), chev_cy);
nvm->param.AutoCloseTime = Group->Current;
drv_nvm_save_to_flash();
break;
case GUI_RESTORE:
/* 逆时针箭头:当前在 VERSION 槽(19x18)RESTORE 槽曾误为蓝牙符 */
LCD_WR_PIC_FROM_FLASH_Trans(UI->x + 12,
(uint16_t)(UI->y + (UI->h - UI0902_ICON_SYS_VERSION_H) / 2),
UI0902_ICON_SYS_VERSION_W, UI0902_ICON_SYS_VERSION_H,
UI0902_ICON_SYS_VERSION_ADDR);
/* 右三角与蓝牙/自动关机同一右缘val_x2 */
UI_DrawTriRight((uint16_t)(val_x2 - UI0902_TRI_R_W), chev_cy);
break;
default: break;
}
}