1 #include "stdafx.h" 2 #include "CUIDrawer.h" 3 #include "MusicPlayer2.h" 4 5 6 CUIDrawer::CUIDrawer(UIColors& colors) 7 : m_colors(colors) 8 { 9 } 10 11 12 CUIDrawer::~CUIDrawer() 13 { 14 } 15 16 void CUIDrawer::DrawLryicCommon(CRect rect, Alignment align) 17 { 18 SetDrawArea(rect); 19 20 if (!IsDrawMultiLine(rect.Height())) 21 DrawLyricTextSingleLine(rect, true, align); 22 else 23 DrawLyricTextMultiLine(rect, align); 24 } 25 26 int CUIDrawer::GetLyricTextHeight() const 27 { 28 //计算文本高度 29 if (!m_for_cortana_lyric) 30 m_pDC->SelectObject(&theApp.m_font_set.lyric.GetFont(theApp.m_ui_data.full_screen)); 31 else 32 m_pDC->SelectObject(&theApp.m_font_set.cortana.GetFont()); 33 return m_pDC->GetTextExtent(L"文").cy; //根据当前的字体设置计算文本的高度 34 } 35 36 void CUIDrawer::Create(CDC* pDC, CWnd* pMainWnd) 37 { 38 CDrawCommon::Create(pDC, pMainWnd); 39 } 40 41 bool CUIDrawer::IsDrawMultiLine(int height) const 42 { 43 return height >= static_cast<int>(GetLyricTextHeight() * 3.5); 44 } 45 46 void CUIDrawer::SetForCortanaLyric(bool for_cortana_lyric) 47 { 48 m_for_cortana_lyric = for_cortana_lyric; 49 } 50 51 void CUIDrawer::DrawLyricTextMultiLine(CRect lyric_area, Alignment align) 52 { 53 int line_space{}; 54 if (m_for_cortana_lyric) 55 { 56 line_space = theApp.DPI(4); 57 } 58 else 59 { 60 line_space = theApp.m_lyric_setting_data.lyric_line_space; 61 if (theApp.m_ui_data.full_screen) 62 line_space = static_cast<int>(line_space * CONSTVAL::FULL_SCREEN_ZOOM_FACTOR); 63 } 64 65 int lyric_height = GetLyricTextHeight() + line_space; //文本高度加上行间距 66 int lyric_height2 = lyric_height * 2 + line_space; //包含翻译的歌词高度 67 68 CFont* pOldFont = SetLyricFont(); 69 if (CPlayerUIHelper::IsMidiLyric()) 70 { 71 wstring current_lyric{ CPlayer::GetInstance().GetMidiLyric() }; 72 DrawWindowText(lyric_area, current_lyric.c_str(), m_colors.color_text, Alignment::CENTER, false, true); 73 } 74 else if (CPlayer::GetInstance().m_Lyrics.IsEmpty()) 75 { 76 DrawWindowText(lyric_area, CCommon::LoadText(IDS_NO_LYRIC_INFO), m_colors.color_text_2, Alignment::CENTER); 77 } 78 else 79 { 80 //CRect arect{ lyric_area }; //一行歌词的矩形区域 81 //arect.bottom = arect.top + lyric_height; 82 //vector<CRect> rects(CPlayer::GetInstance().m_Lyrics.GetLyricCount() + 1, arect); 83 //为每一句歌词创建一个矩形,保存在容器里 84 vector<CRect> rects; 85 int lyric_count = CPlayer::GetInstance().m_Lyrics.GetLyricCount() + 1; //获取歌词数量(由于第一行歌词需要显示标题,所以这里要+1) 86 for (int i{}; i < lyric_count; i++) 87 { 88 CRect arect{ lyric_area }; 89 if (!CPlayer::GetInstance().m_Lyrics.GetLyric(i).translate.empty() && theApp.m_lyric_setting_data.show_translate) 90 arect.bottom = arect.top + lyric_height2; 91 else 92 arect.bottom = arect.top + lyric_height; 93 rects.push_back(arect); 94 } 95 int center_pos = (lyric_area.top + lyric_area.bottom) / 2; //歌词区域的中心y坐标 96 Time time{ CPlayer::GetInstance().GetCurrentPosition() }; //当前播放时间 97 int lyric_index = CPlayer::GetInstance().m_Lyrics.GetLyricIndex(time) + 1; //当前歌词的序号(歌词的第一句GetLyricIndex返回的是0,由于显示时第一句歌词要显示标题,所以这里要+1) 98 int progress = CPlayer::GetInstance().m_Lyrics.GetLyricProgress(time); //当前歌词进度(范围为0~1000) 99 int y_progress; //当前歌词在y轴上的进度 100 if (!CPlayer::GetInstance().m_Lyrics.GetLyric(lyric_index).translate.empty() && theApp.m_lyric_setting_data.show_translate) 101 y_progress = progress * lyric_height2 / 1000; 102 else 103 y_progress = progress * lyric_height / 1000; 104 //int start_pos = center_pos - y_progress - (lyric_index + 1)*lyric_height; //第1句歌词的起始y坐标 105 //计算第1句歌词的起始y坐标 106 //由于当前歌词需要显示在歌词区域的中心位置,因此从中心位置开始,减去当前歌词在Y轴上的进度 107 //再依次减去之前每一句歌词的高度,即得到了第一句歌词的起始位置 108 int start_pos; 109 start_pos = center_pos - y_progress; 110 for (int i{ lyric_index - 1 }; i >= 0; i--) 111 { 112 if (theApp.m_lyric_setting_data.show_translate && !CPlayer::GetInstance().m_Lyrics.GetLyric(i).translate.empty()) 113 start_pos -= lyric_height2; 114 else 115 start_pos -= lyric_height; 116 } 117 118 //依次绘制每一句歌词 119 for (size_t i{}; i < rects.size(); i++) 120 { 121 //计算每一句歌词的位置 122 if (i == 0) 123 rects[i].MoveToY(start_pos); 124 else 125 rects[i].MoveToY(rects[i - 1].bottom); 126 //绘制歌词文本 127 if (!(rects[i] & lyric_area).IsRectEmpty()) //只有当一句歌词的矩形区域和歌词区域的矩形有交集时,才绘制歌词 128 { 129 //设置歌词文本和翻译文本的矩形区域 130 CRect rect_text{ rects[i] }; 131 CRect rect_translate; 132 if (!CPlayer::GetInstance().m_Lyrics.GetLyric(i).translate.empty() && theApp.m_lyric_setting_data.show_translate) 133 { 134 rect_text.MoveToY(rect_text.top + line_space); 135 rect_text.bottom = rect_text.top + GetLyricTextHeight(); 136 rect_translate = rect_text; 137 rect_translate.MoveToY(rect_text.bottom + line_space); 138 } 139 140 if (i == lyric_index && progress < 1000) //绘制正在播放的歌词 141 { 142 CLyrics::Lyric lyric = CPlayer::GetInstance().m_Lyrics.GetLyric(i); 143 //这里实现文本从非高亮缓慢变化到高亮效果 144 int last_time_span = time - lyric.time; //当前播放的歌词已持续的时间 145 int fade_percent = last_time_span / 8; //计算颜色高亮变化的百分比,除数越大则持续时间越长,10则为1秒 146 COLORREF text_color = CColorConvert::GetGradientColor(m_colors.color_text_2, m_colors.color_text, fade_percent); 147 //绘制歌词文本 148 SetLyricFont(); 149 if (theApp.m_lyric_setting_data.lyric_karaoke_disp) 150 DrawWindowText(rect_text, lyric.text.c_str(), m_colors.color_text, m_colors.color_text_2, progress, align, true); 151 else 152 DrawWindowText(rect_text, lyric.text.c_str(), text_color, text_color, progress, align, true); 153 //绘制翻译文本 154 if (!lyric.translate.empty() && theApp.m_lyric_setting_data.show_translate) 155 { 156 SetLyricFontTranslated(); 157 DrawWindowText(rect_translate, CPlayer::GetInstance().m_Lyrics.GetLyric(i).translate.c_str(), text_color, text_color, progress, align, true); 158 } 159 } 160 else //绘制非正在播放的歌词 161 { 162 SetLyricFont(); 163 COLORREF text_color; 164 if (i == lyric_index - 1) //绘制上一句歌词(这里实现上一句歌词颜色从高亮缓慢变化到非高亮效果) 165 { 166 CLyrics::Lyric playing_lyric = CPlayer::GetInstance().m_Lyrics.GetLyric(lyric_index); 167 int last_time_span = time - playing_lyric.time; //当前播放的歌词已持续的时间 168 int fade_percent = last_time_span / 20; //计算颜色高亮变化的百分比,当持续时间为2000毫秒时为100%,即颜色缓慢变化的时间为2秒 169 text_color = CColorConvert::GetGradientColor(m_colors.color_text, m_colors.color_text_2, fade_percent); 170 } 171 else 172 { 173 text_color = m_colors.color_text_2; 174 } 175 //绘制歌词文本 176 DrawWindowText(rect_text, CPlayer::GetInstance().m_Lyrics.GetLyric(i).text.c_str(), text_color, align, true); 177 //绘制翻译文本 178 if (!CPlayer::GetInstance().m_Lyrics.GetLyric(i).translate.empty() && theApp.m_lyric_setting_data.show_translate) 179 { 180 SetLyricFontTranslated(); 181 DrawWindowText(rect_translate, CPlayer::GetInstance().m_Lyrics.GetLyric(i).translate.c_str(), text_color, align, true); 182 } 183 } 184 } 185 } 186 } 187 SetFont(pOldFont); 188 } 189 190 void CUIDrawer::DrawLyricTextSingleLine(CRect rect, bool double_line, Alignment align) 191 { 192 CFont* pOldFont = SetLyricFont(); 193 194 if (CPlayerUIHelper::IsMidiLyric()) 195 { 196 wstring current_lyric{ CPlayer::GetInstance().GetMidiLyric() }; 197 DrawWindowText(rect, current_lyric.c_str(), m_colors.color_text, Alignment::CENTER, false, true); 198 } 199 else if (CPlayer::GetInstance().m_Lyrics.IsEmpty()) 200 { 201 DrawWindowText(rect, CCommon::LoadText(IDS_NO_LYRIC_INFO), m_colors.color_text_2, Alignment::CENTER); 202 } 203 else 204 { 205 SetDrawArea(rect); 206 CRect lyric_rect = rect; 207 208 const bool old_mode{ !theApp.m_lyric_setting_data.lyric_karaoke_disp || !theApp.m_lyric_setting_data.donot_show_blank_lines }; 209 const wstring mark{ L"♪♪♪" }; 210 211 auto& now_lyrics{ CPlayer::GetInstance().m_Lyrics }; 212 Time time{ CPlayer::GetInstance().GetCurrentPosition() }; 213 CLyrics::Lyric current_lyric = now_lyrics.GetLyric(time, 0); 214 bool is_lyric_empty{ current_lyric.text.empty() }; 215 int lyric_mode{}; // 0:默认状态 1:有进度符号且正在显示进度符号 2:有进度符号且正在显示歌词 216 int lyric_index = now_lyrics.GetLyricIndex(time); 217 int progress = now_lyrics.GetLyricProgress(time); 218 219 if (old_mode) // 设置为独立显示空行 220 { 221 if (is_lyric_empty) 222 current_lyric.text = CCommon::LoadText(IDS_DEFAULT_LYRIC_TEXT_CORTANA); 223 } 224 else 225 { 226 lyric_index = now_lyrics.GetLyricIndexIgnoreBlank(lyric_index, 0); // 使用忽略空白行后的索引 227 if (is_lyric_empty) // 如果当前time对应歌词为空则试着忽略空白获取歌词 228 current_lyric = now_lyrics.GetLyricIgnoreBlank(lyric_index); 229 if (current_lyric.text.empty()) // 如果忽略空白仍然不能取得歌词说明时间已超过末尾的歌词 230 current_lyric.text = CCommon::LoadText(IDS_DEFAULT_LYRIC_TEXT); 231 else 232 { 233 bool blanktimeok{ now_lyrics.GetBlankTimeBeforeLyric(lyric_index) > LYRIC_BLANK_IGNORE_TIME }; // 判断空白时长是否有必要显示符号 234 if (is_lyric_empty) // 当前time处在空白行中并且正在提前显示下一行歌词 235 { 236 if (blanktimeok) 237 { 238 progress = now_lyrics.GetBlankLyricProgress(lyric_index, time); // 获取合并空白行后的进度 239 lyric_mode = 1; 240 } 241 else 242 progress = 0; 243 } 244 else if (blanktimeok) // 当前time对应非空歌词但是上行歌词为空 245 lyric_mode = 2; 246 } 247 } 248 249 //双行显示歌词 250 if (double_line && (!CPlayer::GetInstance().m_Lyrics.IsTranslated() || !theApp.m_lyric_setting_data.show_translate) && rect.Height() > static_cast<int>(GetLyricTextHeight() * 1.73)) 251 { 252 wstring next_lyric_text; 253 if (old_mode) 254 { 255 next_lyric_text = now_lyrics.GetLyric(time, 1).text; 256 if (next_lyric_text.empty()) 257 next_lyric_text = CCommon::LoadText(IDS_DEFAULT_LYRIC_TEXT); 258 } 259 else 260 { 261 int next_lyric_index{ now_lyrics.GetLyricIndexIgnoreBlank(lyric_index, 1) }; 262 next_lyric_text = now_lyrics.GetLyricIgnoreBlank(next_lyric_index).text; 263 if (next_lyric_text.empty()) 264 next_lyric_text = CCommon::LoadText(IDS_DEFAULT_LYRIC_TEXT); 265 else if (now_lyrics.GetBlankTimeBeforeLyric(next_lyric_index) > LYRIC_BLANK_IGNORE_TIME) 266 next_lyric_text = mark + L" " + next_lyric_text; 267 } 268 //这里实现文本从非高亮缓慢变化到高亮效果 269 int last_time_span = time - current_lyric.time; //当前播放的歌词已持续的时间 270 int fade_percent = last_time_span / 8; //计算颜色高亮变化的百分比,除数越大则持续时间越长,10则为1秒 271 DrawLyricDoubleLine(lyric_rect, mark.c_str(), current_lyric.text.c_str(), next_lyric_text.c_str(), progress, lyric_index, lyric_mode, fade_percent); 272 } 273 else 274 { 275 // 单行歌词在这里显示翻译,同时更新歌词区域为单行有翻译时的位置 276 if (theApp.m_lyric_setting_data.show_translate && !current_lyric.translate.empty() && rect.Height() > static_cast<int>(GetLyricTextHeight() * 1.73)) 277 { 278 lyric_rect.bottom = lyric_rect.top + rect.Height() / 2; 279 CRect translate_rect = lyric_rect; 280 translate_rect.MoveToY(lyric_rect.bottom); 281 282 SetLyricFontTranslated(); 283 DrawWindowText(translate_rect, current_lyric.translate.c_str(), m_colors.color_text, m_colors.color_text, progress, align, true); 284 } 285 // 绘制单行歌词 286 SetLyricFont(); 287 if (lyric_mode == 1) 288 DrawWindowTextForLyric(lyric_rect, mark.c_str(), current_lyric.text.c_str(), m_colors.color_text, theApp.m_lyric_setting_data.lyric_karaoke_disp ? m_colors.color_text_2 : m_colors.color_text, progress, true, align, true); 289 else if (lyric_mode == 2) 290 DrawWindowTextForLyric(lyric_rect, mark.c_str(), current_lyric.text.c_str(), m_colors.color_text, theApp.m_lyric_setting_data.lyric_karaoke_disp ? m_colors.color_text_2 : m_colors.color_text, progress, false, align, true); 291 else 292 DrawWindowText(lyric_rect, current_lyric.text.c_str(), m_colors.color_text, theApp.m_lyric_setting_data.lyric_karaoke_disp ? m_colors.color_text_2 : m_colors.color_text, progress, align, true); 293 } 294 } 295 296 SetFont(pOldFont); 297 } 298 299 void CUIDrawer::DrawSpectrum(CRect rect, SpectrumCol col, bool draw_reflex /*= false*/, bool low_freq_in_center, bool fixed_width) 300 { 301 int cols; //要显示的频谱柱形的数量 302 switch (col) 303 { 304 case CUIDrawer::SC_64: 305 cols = 64; 306 break; 307 case CUIDrawer::SC_32: 308 cols = 32; 309 break; 310 case CUIDrawer::SC_16: 311 cols = 16; 312 break; 313 case CUIDrawer::SC_8: 314 cols = 8; 315 break; 316 default: 317 cols = SPECTRUM_COL; 318 break; 319 } 320 int max_width{ rect.Width() }; 321 if (fixed_width) 322 { 323 if (col == SC_64) 324 { 325 max_width = DPI(280); 326 } 327 } 328 int gap_width{ max_width * (SPECTRUM_COL / cols) / 168 }; //频谱柱形间隙宽度 329 if (theApp.m_ui_data.full_screen && !m_for_cortana_lyric) 330 gap_width *= CONSTVAL::FULL_SCREEN_ZOOM_FACTOR; 331 int width = (max_width - (cols - 1) * gap_width) / (cols - 1); 332 if (gap_width < 1) 333 gap_width = 1; 334 if (width < 1) 335 width = 1; 336 337 if (fixed_width) 338 SetDrawArea(rect); 339 DrawSpectrum(rect, width, gap_width, cols, m_colors.color_spectrum, draw_reflex, low_freq_in_center); 340 } 341 342 void CUIDrawer::DrawSpectrum(CRect rect, int col_width, int gap_width, int cols, COLORREF color, bool draw_reflex /*= false*/, bool low_freq_in_center) 343 { 344 CRect rc_spectrum_top = rect; 345 if (draw_reflex) //如果要绘制倒影,则倒影占总高度的1/3 346 rc_spectrum_top.bottom = rect.top + (rect.Height() * 2 / 3); 347 348 CRect rects[SPECTRUM_COL]; 349 rects[0] = rc_spectrum_top; 350 rects[0].right = rects[0].left + col_width; 351 for (int i{ 1 }; i < cols; i++) 352 { 353 rects[i] = rects[0]; 354 rects[i].left += (i * (col_width + gap_width)); 355 rects[i].right += (i * (col_width + gap_width)); 356 } 357 for (int i{}; i < cols; i++) 358 { 359 int index; 360 if (low_freq_in_center) 361 { 362 if (i < cols / 2) 363 index = (-i + cols / 2) * 2 - 1; 364 else 365 index = (i - cols / 2) * 2; 366 } 367 else 368 { 369 index = i; 370 } 371 if (index >= cols) 372 index = cols; 373 if (index < 0) 374 index = 0; 375 float spetral_data = CPlayer::GetInstance().GetSpectralData()[index * (SPECTRUM_COL / cols)]; 376 float peak_data = CPlayer::GetInstance().GetSpectralPeakData()[index * (SPECTRUM_COL / cols)]; 377 378 CRect rect_tmp{ rects[i] }; 379 int spetral_height = static_cast<int>(spetral_data * rects[0].Height() / 30 * theApp.m_app_setting_data.sprctrum_height / 100); 380 int peak_height = static_cast<int>(peak_data * rects[0].Height() / 30 * theApp.m_app_setting_data.sprctrum_height / 100); 381 if (spetral_height < 0 || CPlayer::GetInstance().IsError()) spetral_height = 0; //如果播放出错,不显示频谱 382 if (peak_height < 0 || CPlayer::GetInstance().IsError()) peak_height = 0; 383 384 int peak_rect_height = max(theApp.DPIRound(1.1), gap_width / 2); //顶端矩形的高度 385 spetral_height += peak_rect_height; //频谱至少和顶端矩形一样高 386 peak_height += peak_rect_height; 387 388 rect_tmp.top = rect_tmp.bottom - spetral_height; 389 if (rect_tmp.top < rects[0].top) rect_tmp.top = rects[0].top; 390 FillRect(rect_tmp, color, true); 391 //绘制倒影 392 if (draw_reflex) 393 { 394 CRect rc_invert = rect_tmp; 395 rc_invert.bottom = rect_tmp.top + rect_tmp.Height() * 2 / 3; 396 rc_invert.MoveToY(rect_tmp.bottom + gap_width); 397 FillAlphaRect(rc_invert, color, 96, true); 398 } 399 400 //绘制顶端 401 CRect rect_peak{ rect_tmp }; 402 rect_peak.bottom = rect_tmp.bottom - peak_height - gap_width; 403 rect_peak.top = rect_peak.bottom - peak_rect_height; 404 FillRect(rect_peak, color, true); 405 ////绘制顶端倒影 406 //CRect rc_peak_invert = rect_peak; 407 //rc_peak_invert.MoveToY(rc_invert.top + peak_height + theApp.DPIRound(1.1)); 408 //FillAlphaRect(rc_peak_invert, color, 96); 409 } 410 411 } 412 413 int CUIDrawer::DPI(int pixel) 414 { 415 if (theApp.m_ui_data.full_screen && !m_for_cortana_lyric) 416 return static_cast<int>(theApp.DPI(pixel * CONSTVAL::FULL_SCREEN_ZOOM_FACTOR)); 417 else 418 return theApp.DPI(pixel); 419 } 420 421 void CUIDrawer::DrawLyricDoubleLine(CRect rect, LPCTSTR beforelyric, LPCTSTR lyric, LPCTSTR next_lyric, int progress, int index, int lyric_mode, int fade_percent) 422 { 423 CFont* pOldFont = SetLyricFont(); 424 static bool swap; 425 static int last_index; 426 if (last_index != index) //如果歌词索引改变,说明歌词切换到了下一句 427 { 428 swap = !swap; 429 } 430 last_index = index; 431 432 CRect up_rect{ rect }, down_rect{ rect }; //上半部分和下半部分歌词的矩形区域 433 up_rect.bottom = up_rect.top + (up_rect.Height() / 2); 434 down_rect.top = down_rect.bottom - (down_rect.Height() / 2); 435 436 //根据下一句歌词的文本计算需要的宽度,从而实现下一行歌词右对齐 437 //GetDC()->SelectObject(&theApp.m_font_set.lyric.GetFont(theApp.m_ui_data.full_screen)); 438 int width; 439 if (!swap) 440 width = GetTextExtent(next_lyric).cx; 441 else if (lyric_mode != 0) 442 { 443 wstring mark_lyric; 444 mark_lyric.append(beforelyric).append(L" ").append(lyric); 445 width = GetTextExtent(mark_lyric.c_str()).cx; 446 } 447 else 448 width = GetTextExtent(lyric).cx; 449 if (width < rect.Width()) 450 down_rect.left = down_rect.right - width; 451 452 COLORREF color1, color2; 453 if (theApp.m_lyric_setting_data.lyric_karaoke_disp) 454 { 455 color1 = m_colors.color_text; 456 color2 = m_colors.color_text_2; 457 } 458 else 459 { 460 color1 = color2 = CColorConvert::GetGradientColor(m_colors.color_text_2, m_colors.color_text, fade_percent); 461 } 462 463 // 绘制当前歌词 464 if (lyric_mode == 1) 465 DrawWindowTextForLyric(swap ? down_rect : up_rect, beforelyric, lyric, color1, color2, progress, true); 466 else if (lyric_mode == 2) 467 DrawWindowTextForLyric(swap ? down_rect : up_rect, beforelyric, lyric, color1, color2, progress, false); 468 else 469 DrawWindowText(swap ? down_rect : up_rect, lyric, color1, color2, progress); 470 //DrawWindowText(swap ? down_rect : up_rect, lyric, color1, color2, progress); 471 472 // 绘制下一句歌词 473 DrawWindowText(swap ? up_rect : down_rect, next_lyric, m_colors.color_text_2); 474 SetFont(pOldFont); 475 } 476 477 CFont* CUIDrawer::SetLyricFont() 478 { 479 if (!m_for_cortana_lyric) 480 return SetFont(&theApp.m_font_set.lyric.GetFont(theApp.m_ui_data.full_screen)); 481 else 482 return SetFont(&theApp.m_font_set.cortana.GetFont()); 483 } 484 485 CFont* CUIDrawer::SetLyricFontTranslated() 486 { 487 if (!m_for_cortana_lyric) 488 return SetFont(&theApp.m_font_set.lyric_translate.GetFont(theApp.m_ui_data.full_screen)); 489 else 490 return SetFont(&theApp.m_font_set.cortana_translate.GetFont()); 491 } 492