1 #include "stdafx.h"
2 #include "CPlayerUIBase.h"
3 #include "MusicPlayerDlg.h"
4 #include "MiniModeUserUi.h"
5 #include "SongInfoHelper.h"
6 #include "UIElement.h"
7 #include "MusicPlayerCmdHelper.h"
8 #include "UIWindowCmdHelper.h"
9
10 bool CPlayerUIBase::m_show_ui_tip_info = false;
11
CPlayerUIBase(UIData & ui_data,CWnd * pMainWnd)12 CPlayerUIBase::CPlayerUIBase(UIData& ui_data, CWnd* pMainWnd)
13 : m_ui_data(ui_data), m_pMainWnd(pMainWnd)
14 {
15
16 }
17
18
~CPlayerUIBase()19 CPlayerUIBase::~CPlayerUIBase()
20 {
21 m_mem_bitmap_static.DeleteObject();
22 }
23
Init(CDC * pDC)24 void CPlayerUIBase::Init(CDC* pDC)
25 {
26 m_pDC = pDC;
27 //m_draw.Create(m_pDC, m_pMainWnd);
28 m_draw.Create(m_pDC, &theApp.m_font_set.dlg.GetFont()); // m_draw的字体直接从m_font_set取得,CWnd->GetFont在不保留多语言窗口资源后不再准确
29
30 m_tool_tip.Create(m_pMainWnd, TTS_ALWAYSTIP);
31 m_tool_tip.SetMaxTipWidth(theApp.DPI(400));
32 //为CToolTipCtrl设置鼠标穿透
33 SetWindowLong(m_tool_tip.GetSafeHwnd(), GWL_EXSTYLE, GetWindowLong(m_tool_tip.GetSafeHwnd(), GWL_EXSTYLE) | WS_EX_TRANSPARENT);
34 m_first_draw = true;
35 }
36
DrawInfo(bool reset)37 void CPlayerUIBase::DrawInfo(bool reset)
38 {
39 PreDrawInfo();
40
41 #if 0
42 //双缓冲绘图
43 {
44 //CDrawDoubleBuffer drawDoubleBuffer(m_pDC, m_draw_rect);
45 CDC memDC;
46 CBitmap memBitmap;
47 CBitmap* pOldBit;
48 memDC.CreateCompatibleDC(NULL);
49 if (m_mem_bitmap_static.GetSafeHandle() == NULL || reset)
50 {
51 memBitmap.CreateCompatibleBitmap(m_pDC, m_draw_rect.Width(), m_draw_rect.Height());
52 pOldBit = memDC.SelectObject(&memBitmap);
53 m_draw.SetDC(&memDC); //将m_draw中的绘图DC设置为缓冲的DC
54 m_draw.SetFont(&theApp.m_font_set.normal.GetFont(theApp.m_ui_data.full_screen));
55 //绘制背景
56 DrawBackground();
57 m_mem_bitmap_static.DeleteObject();
58 //bool b = m_mem_bitmap_static.Attach(CDrawCommon::CopyBitmap(memBitmap));
59 CDrawCommon::CopyBitmap(m_mem_bitmap_static, memBitmap);
60 CDrawCommon::SaveBitmap(memBitmap, L"D:\\Temp\\before.bmp");
61 CDrawCommon::SaveBitmap(m_mem_bitmap_static, L"D:\\Temp\\after.bmp");
62 }
63 else
64 {
65 //memBitmap.Attach(CDrawCommon::CopyBitmap(m_mem_bitmap_static));
66 CDrawCommon::CopyBitmap(memBitmap, m_mem_bitmap_static);
67 pOldBit = memDC.SelectObject(&memBitmap);
68 m_draw.SetDC(&memDC); //将m_draw中的绘图DC设置为缓冲的DC
69 m_draw.SetFont(&theApp.m_font_set.normal.GetFont(theApp.m_ui_data.full_screen));
70 }
71 //绘制界面中其他信息
72 _DrawInfo(reset);
73 ////绘制背景
74 //DrawBackground();
75 m_pDC->BitBlt(m_draw_rect.left, m_draw_rect.top, m_draw_rect.Width(), m_draw_rect.Height(), &memDC, 0, 0, SRCCOPY);
76 memDC.SelectObject(pOldBit);
77 memBitmap.DeleteObject();
78 memDC.DeleteDC();
79 }
80
81 #else
82 //双缓冲绘图
83 {
84 CDrawDoubleBuffer drawDoubleBuffer(m_pDC, m_draw_rect);
85 m_draw.SetDC(drawDoubleBuffer.GetMemDC()); //将m_draw中的绘图DC设置为缓冲的DC
86 m_draw.SetFont(&theApp.m_font_set.GetFontBySize(9).GetFont(theApp.m_ui_data.full_screen));
87
88 //绘制背景
89 DrawBackground();
90
91 //绘制状态栏
92 CRect draw_rect = m_draw_rect;
93 bool draw_status_bar = IsDrawStatusBar();
94 if (draw_status_bar)
95 {
96 CRect rc_status_bar = draw_rect;
97 draw_rect.bottom -= DPI(20);
98 rc_status_bar.top = draw_rect.bottom;
99 DrawStatusBar(rc_status_bar, reset);
100 }
101
102 //如果不显示Windows标准标题栏,则绘制标题栏
103 if (IsDrawTitleBar())
104 {
105 CRect rc_title_bar = draw_rect;
106 rc_title_bar.bottom = rc_title_bar.top + m_layout.titlabar_height;
107 draw_rect.top = rc_title_bar.bottom;
108 DrawTitleBar(rc_title_bar);
109 }
110
111 //绘制菜单栏
112 if (IsDrawMenuBar())
113 {
114 CRect rc_menu_bar = draw_rect;
115 rc_menu_bar.bottom = rc_menu_bar.top + m_layout.menubar_height;
116 draw_rect.top = rc_menu_bar.bottom;
117 DrawUiMenuBar(rc_menu_bar);
118 }
119
120 //绘制界面中其他信息
121 _DrawInfo(draw_rect, reset);
122
123 //绘制提示信息
124 if (m_show_ui_tip_info && !m_ui_tip_info.empty())
125 {
126 UiFontGuard guard(this, 10);
127 //根据文本的长度计算提示信息的矩形区域
128 CSize text_size = m_draw.GetTextExtent(m_ui_tip_info.c_str());
129 int tip_max_width = draw_rect.Width() - EdgeMargin() * 2 - DPI(40);
130 int lines = text_size.cx / tip_max_width + 1;
131 int tip_width = tip_max_width;
132 if (lines == 1)
133 tip_width = text_size.cx;
134 int tip_height = lines * text_size.cy;
135 //仅当界面高度不小于提示信息矩形区域高度时才显示提示信息
136 if (draw_rect.Height() >= tip_height)
137 {
138 CRect tip_rect{ draw_rect };
139 tip_rect.top += (draw_rect.Height() - tip_height) / 2;
140 tip_rect.left += (draw_rect.Width() - tip_width) / 2;
141 tip_rect.bottom = tip_rect.top + tip_height;
142 tip_rect.right = tip_rect.left + tip_width;
143 //画背景
144 CRect back_rect{ tip_rect };
145 back_rect.InflateRect(DPI(20), DPI(20));
146 DrawRectangle(back_rect);
147 //画文字
148 m_draw.DrawWindowText(tip_rect, m_ui_tip_info.c_str(), m_colors.color_text, Alignment::CENTER, true, true);
149 }
150 }
151
152 //如果切换了显示/隐藏状态栏,则需要更新鼠标提示的位置
153 static bool last_draw_status_bar{ false };
154 if (draw_status_bar != last_draw_status_bar)
155 {
156 last_draw_status_bar = draw_status_bar;
157 m_need_update_tooltip_pos = true;
158 }
159
160 //如果标题栏显示按钮发生了改变,则更新鼠标提示的位置
161 static int last_titlebar_btn{};
162 int titlebar_btn{ theApp.m_app_setting_data.TitleDisplayItem() };
163 if (last_titlebar_btn != titlebar_btn)
164 {
165 last_titlebar_btn = titlebar_btn;
166 m_need_update_tooltip_pos = true;
167 }
168 }
169
170 #endif
171
172 if (m_first_draw)
173 {
174 AddToolTips();
175 }
176 else
177 {
178 static int last_width{}, last_height{}, last_ui_index{};
179 //检测到绘图区域变化或界面进行了切换时
180 if (last_width != m_draw_rect.Width() || last_height != m_draw_rect.Height()
181 || (last_ui_index != GetUiIndex() && GetUiIndex() != 0))
182 {
183 //更新工具提示的位置
184 m_need_update_tooltip_pos = true;
185
186 //更新任务栏缩略图区域
187 CRect thumbnail_rect = GetThumbnailClipArea();
188 CMusicPlayerDlg* pMainWindow = CMusicPlayerDlg::GetInstance();
189 if (pMainWindow != nullptr)
190 {
191 pMainWindow->TaskBarSetClipArea(thumbnail_rect);
192 }
193
194 last_width = m_draw_rect.Width();
195 last_height = m_draw_rect.Height();
196 last_ui_index = GetUiIndex();
197 }
198 }
199 m_first_draw = false;
200
201 if (m_need_update_tooltip_pos)
202 {
203 UpdateToolTipPosition();
204 m_need_update_tooltip_pos = false;
205 }
206 }
207
ClearInfo()208 void CPlayerUIBase::ClearInfo()
209 {
210 PreDrawInfo();
211 m_pDC->FillSolidRect(m_draw_rect, CONSTVAL::BACKGROUND_COLOR);
212 }
213
LButtonDown(CPoint point)214 bool CPlayerUIBase::LButtonDown(CPoint point)
215 {
216 for (auto& btn : m_buttons)
217 {
218 if (btn.second.enable && btn.second.rect.PtInRect(point) != FALSE)
219 {
220 btn.second.pressed = true;
221 return true;
222 }
223 }
224 return false;
225 }
226
RButtonUp(CPoint point)227 void CPlayerUIBase::RButtonUp(CPoint point)
228 {
229 if (!m_draw_rect.PtInRect(point))
230 return;
231
232 if (m_buttons[BTN_VOLUME].rect.PtInRect(point) == FALSE)
233 m_show_volume_adj = false;
234
235 CPoint point1; //定义一个用于确定光标位置的位置
236 GetCursorPos(&point1); //获取当前光标的位置,以便使得菜单可以跟随光标,该位置以屏幕左上角点为原点,point则以客户区左上角为原点
237 if (m_buttons[BTN_REPETEMODE].rect.PtInRect(point)) //如果在“循环模式”的矩形区域内点击鼠标右键,则弹出“循环模式”的子菜单
238 {
239 CMenu* pMenu = theApp.m_menu_mgr.GetMenu(MenuMgr::MainPlayCtrlRepeatModeMenu);
240 ASSERT(pMenu != nullptr);
241 if (pMenu != NULL)
242 pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, theApp.m_pMainWnd);
243 return;
244 }
245
246 if (m_buttons[BTN_SHOW_PLAYLIST].rect.PtInRect(point))
247 {
248 CMenu* pMenu = theApp.m_menu_mgr.GetMenu(MenuMgr::MainAreaPlaylistBtnMenu);
249 ASSERT(pMenu != nullptr);
250 if (pMenu != NULL)
251 pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, theApp.m_pMainWnd);
252 return;
253 }
254
255 if (m_buttons[BTN_AB_REPEAT].rect.PtInRect(point))
256 {
257 CMenu* pMenu = theApp.m_menu_mgr.GetMenu(MenuMgr::MainPlayCtrlAbRepeatMenu);
258 ASSERT(pMenu != nullptr);
259 if (pMenu != nullptr)
260 pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, theApp.m_pMainWnd);
261 return;
262 }
263
264 if (m_buttons[BTN_SKIN].rect.PtInRect(point))
265 {
266 CMenu* pMenu = theApp.m_menu_mgr.GetMenu(MenuMgr::MainViewSwitchUiMenu);
267 ASSERT(pMenu != nullptr);
268 if (pMenu != nullptr)
269 pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, theApp.m_pMainWnd);
270 return;
271 }
272
273 for (auto& btn : m_buttons)
274 {
275 //按钮上点击右键不弹出菜单
276 if (btn.first != BTN_COVER && btn.second.rect.PtInRect(point) != FALSE)
277 return;
278 }
279
280 if (m_draw_data.lyric_rect.PtInRect(point)) //如果在歌词区域点击了鼠标右键
281 {
282 theApp.m_menu_mgr.GetMenu(MenuMgr::MainAreaLrcMenu)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, theApp.m_pMainWnd);
283 return;
284 }
285 // 其他区域显示主界面区域右键菜单
286 theApp.m_menu_mgr.GetMenu(MenuMgr::MainAreaMenu)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, theApp.m_pMainWnd);
287 }
288
MouseMove(CPoint point)289 void CPlayerUIBase::MouseMove(CPoint point)
290 {
291 for (auto& btn : m_buttons)
292 {
293 if (btn.second.enable)
294 btn.second.hover = (btn.second.rect.PtInRect(point) != FALSE);
295 }
296
297 m_buttons[BTN_PROGRESS].hover = m_buttons[BTN_PROGRESS].hover && !(m_show_volume_adj && (m_buttons[BTN_VOLUME_UP].rect.PtInRect(point) || m_buttons[BTN_VOLUME_DOWN].rect.PtInRect(point)));
298
299 //鼠标指向进度条时显示定位到几分几秒
300 if (m_buttons[BTN_PROGRESS].hover)
301 {
302 __int64 song_pos;
303 song_pos = static_cast<__int64>(point.x - m_buttons[BTN_PROGRESS].rect.left) * CPlayer::GetInstance().GetSongLength() / m_buttons[BTN_PROGRESS].rect.Width();
304 Time song_pos_time;
305 song_pos_time.fromInt(static_cast<int>(song_pos));
306 static int last_sec{};
307 if (last_sec != song_pos_time.sec) //只有鼠标指向位置对应的秒数变化了才更新鼠标提示
308 {
309 wstring min = std::to_wstring(song_pos_time.min);
310 wstring sec = std::to_wstring(song_pos_time.sec);
311 wstring str = theApp.m_str_table.LoadTextFormat(L"UI_TIP_SEEK_TO_MINUTE_SECOND", { min, sec.size() <= 1 ? L'0' + sec : sec });
312 UpdateMouseToolTip(BTN_PROGRESS, str.c_str());
313 last_sec = song_pos_time.sec;
314 }
315 }
316
317 TRACKMOUSEEVENT tme;
318 tme.cbSize = sizeof(tme);
319 tme.hwndTrack = m_pMainWnd->GetSafeHwnd();
320 tme.dwFlags = TME_LEAVE | TME_HOVER;
321 tme.dwHoverTime = 1;
322 _TrackMouseEvent(&tme);
323 }
324
LButtonUp(CPoint point)325 bool CPlayerUIBase::LButtonUp(CPoint point)
326 {
327 if (!m_show_volume_adj) //如果设有显示音量调整按钮,则点击音量区域就显示音量调整按钮
328 m_show_volume_adj = (m_buttons[BTN_VOLUME].rect.PtInRect(point) != FALSE);
329 else //如果已经显示了音量调整按钮,则点击音量调整时保持音量调整按钮的显示
330 m_show_volume_adj = (m_buttons[BTN_VOLUME_UP].rect.PtInRect(point) || m_buttons[BTN_VOLUME_DOWN].rect.PtInRect(point));
331
332 auto showMenu = [](const CRect& rect, CMenu* pMenu)
333 {
334 CPoint point;
335 point.x = rect.left;
336 point.y = rect.bottom;
337 ClientToScreen(AfxGetMainWnd()->GetSafeHwnd(), &point);
338 if (pMenu)
339 pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd());
340 };
341
342 for (auto& btn : m_buttons)
343 {
344 bool pressed = btn.second.pressed;
345 //if (btn.second.rect.PtInRect(point) != FALSE)
346 //{
347 //btn.second.hover = false;
348 btn.second.pressed = false;
349 //}
350
351 if (pressed && btn.second.rect.PtInRect(point) && btn.second.enable)
352 {
353 switch (btn.first)
354 {
355 case BTN_APP_CLOSE:
356 theApp.m_pMainWnd->SendMessage(WM_CLOSE);
357 return true;
358
359 case BTN_MAXIMIZE:
360 m_buttons[BTN_MAXIMIZE].hover = false;
361 if (theApp.m_pMainWnd->IsZoomed())
362 theApp.m_pMainWnd->SendMessage(WM_SYSCOMMAND, SC_RESTORE);
363 else
364 theApp.m_pMainWnd->SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE);
365 return true;
366
367 case BTN_MINIMIZE:
368 m_buttons[BTN_MINIMIZE].hover = false;
369 theApp.m_pMainWnd->SendMessage(WM_SYSCOMMAND, SC_MINIMIZE);
370 return true;
371
372 case BTN_REPETEMODE:
373 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_REPEAT_MODE);
374 return true;
375
376 case BTN_VOLUME:
377 break;
378
379 case BTN_TRANSLATE:
380 theApp.m_lyric_setting_data.show_translate = !theApp.m_lyric_setting_data.show_translate;
381 return true;
382
383 case BTN_SKIN:
384 case BTN_SKIN_TITLEBAR:
385 {
386 m_buttons[BTN_SKIN].hover = false;
387 m_buttons[BTN_SKIN_TITLEBAR].hover = false;
388 //theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_SWITCH_UI);
389 CPoint point1;
390 GetCursorPos(&point1);
391 CMenu* pMenu = theApp.m_menu_mgr.GetMenu(MenuMgr::MainViewSwitchUiMenu);
392 ASSERT(pMenu != nullptr);
393 if (pMenu != nullptr)
394 pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, theApp.m_pMainWnd);
395 return true;
396 }
397
398 case BTN_EQ:
399 m_buttons[BTN_EQ].hover = false;
400 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_EQUALIZER);
401 return true;
402
403 case BTN_SETTING: case BTN_SETTING_TITLEBAR:
404 m_buttons[BTN_SETTING].hover = false;
405 m_buttons[BTN_SETTING_TITLEBAR].hover = false;
406 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_OPTION_SETTINGS);
407 return true;
408
409 case BTN_MINI: case BTN_MINI_TITLEBAR:
410 m_buttons[BTN_MINI].hover = false;
411 m_buttons[BTN_MINI_TITLEBAR].hover = false;
412 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_MINI_MODE);
413 return true;
414
415 case BTN_INFO:
416 m_buttons[BTN_INFO].hover = false;
417 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_SONG_INFO);
418 return true;
419
420 case BTN_LRYIC:
421 theApp.m_lyric_setting_data.show_desktop_lyric = !theApp.m_lyric_setting_data.show_desktop_lyric;
422 return true;
423
424 case BTN_AB_REPEAT:
425 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_AB_REPEAT);
426 return true;
427
428 case BTN_STOP:
429 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_STOP);
430 return true;
431
432 case BTN_PREVIOUS:
433 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_PREVIOUS);
434 return true;
435 case BTN_PLAY_PAUSE:
436 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_PLAY_PAUSE);
437 return true;
438
439 case BTN_NEXT:
440 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_NEXT);
441 return true;
442
443 case BTN_SHOW_PLAYLIST:
444 m_buttons[BTN_SHOW_PLAYLIST].hover = false;
445 if (theApp.m_media_lib_setting_data.playlist_btn_for_float_playlist)
446 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_FLOAT_PLAYLIST);
447 else
448 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_SHOW_PLAYLIST);
449 return true;
450
451 case BTN_MEDIA_LIB:
452 m_buttons[BTN_MEDIA_LIB].hover = false;
453 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_MEDIA_LIB);
454 return true;
455
456 case BTN_FAVOURITE:
457 m_buttons[BTN_FAVOURITE].hover = false;
458 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_ADD_REMOVE_FROM_FAVOURITE);
459 return true;
460
461 case BTN_DARK_LIGHT:
462 m_buttons[BTN_DARK_LIGHT].hover = false;
463 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_DARK_MODE);
464 return true;
465
466 case BTN_DARK_LIGHT_TITLE_BAR:
467 m_buttons[BTN_DARK_LIGHT_TITLE_BAR].hover = false;
468 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_DARK_MODE);
469 return true;
470
471 case BTN_LOCATE_TO_CURRENT:
472 m_buttons[BTN_LOCATE_TO_CURRENT].hover = false;
473 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_LOCATE_TO_CURRENT);
474 return true;
475
476 case BTN_VOLUME_UP:
477 if (m_show_volume_adj)
478 {
479 CPlayer::GetInstance().MusicControl(Command::VOLUME_ADJ, theApp.m_nc_setting_data.volum_step);
480 return true;
481 }
482 break;
483
484 case BTN_VOLUME_DOWN:
485 if (m_show_volume_adj)
486 {
487 CPlayer::GetInstance().MusicControl(Command::VOLUME_ADJ, -theApp.m_nc_setting_data.volum_step);
488 return true;
489 }
490 break;
491
492 case BTN_PROGRESS:
493 {
494 int ckick_pos = point.x - m_buttons[BTN_PROGRESS].rect.left;
495 double progress = static_cast<double>(ckick_pos) / m_buttons[BTN_PROGRESS].rect.Width();
496 if (CPlayer::GetInstance().GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000)))
497 {
498 CPlayer::GetInstance().SeekTo(progress);
499 CPlayer::GetInstance().GetPlayStatusMutex().unlock();
500 }
501 }
502 return true;
503
504 case BTN_FIND:
505 m_buttons[BTN_FIND].hover = false;
506 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_FIND);
507 return true;
508
509 case BTN_FULL_SCREEN_TITLEBAR:
510 m_buttons[BTN_FULL_SCREEN_TITLEBAR].hover = false;
511 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_FULL_SCREEN);
512 return true;
513
514 case BTN_FULL_SCREEN:
515 m_buttons[BTN_FULL_SCREEN].hover = false;
516 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_FULL_SCREEN);
517 return true;
518
519 case BTN_MENU_TITLEBAR:
520 {
521 CPoint point(m_buttons[BTN_MENU_TITLEBAR].rect.left, m_buttons[BTN_MENU_TITLEBAR].rect.bottom);
522 theApp.m_pMainWnd->SendMessage(WM_MAIN_MENU_POPEDUP, (WPARAM)&point);
523 return true;
524 }
525
526 case BTN_MENU:
527 {
528 CPoint point(m_buttons[BTN_MENU].rect.left, m_buttons[BTN_MENU].rect.bottom);
529 theApp.m_pMainWnd->SendMessage(WM_MAIN_MENU_POPEDUP, (WPARAM)&point);
530 return true;
531 }
532
533 case BTN_ADD_TO_PLAYLIST:
534 {
535 CPoint point1;
536 GetCursorPos(&point1);
537 CMenu* add_to_menu = theApp.m_menu_mgr.GetMenu(MenuMgr::AddToPlaylistMenu);
538 ASSERT(add_to_menu != nullptr);
539 if (add_to_menu != nullptr)
540 {
541 add_to_menu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, theApp.m_pMainWnd);
542 }
543 return true;
544 }
545
546 case BTN_SWITCH_DISPLAY:
547 SwitchStackElement();
548 return true;
549
550 case BTN_OPEN_FOLDER:
551 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_FILE_OPEN_FOLDER);
552 return true;
553
554 case BTN_NEW_PLAYLIST:
555 {
556 CMusicPlayerCmdHelper helper;
557 helper.OnNewPlaylist();
558 return true;
559 }
560 case BTN_PLAY_MY_FAVOURITE:
561 {
562 CMusicPlayerCmdHelper helper;
563 helper.OnPlayMyFavourite();
564 return true;
565 }
566 case BTN_MEDIALIB_FOLDER_SORT:
567 {
568 CRect btn_rect(m_buttons[BTN_MEDIALIB_FOLDER_SORT].rect);
569 CPoint point(btn_rect.left, btn_rect.bottom);
570 ClientToScreen(theApp.m_pMainWnd->GetSafeHwnd(), &point);
571 CMenu* add_to_menu = theApp.m_menu_mgr.GetMenu(MenuMgr::LibFolderSortMenu);
572 ASSERT(add_to_menu != nullptr);
573 if (add_to_menu != nullptr)
574 {
575 CUIWindowCmdHelper helper(nullptr);
576 helper.SetMenuState(add_to_menu);
577 UINT command = add_to_menu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, point.x, point.y, theApp.m_pMainWnd);
578 helper.OnUiCommand(command);
579 }
580 return true;
581 }
582 case BTN_MEDIALIB_PLAYLIST_SORT:
583 {
584 CRect btn_rect(m_buttons[BTN_MEDIALIB_PLAYLIST_SORT].rect);
585 CPoint point(btn_rect.left, btn_rect.bottom);
586 ClientToScreen(theApp.m_pMainWnd->GetSafeHwnd(), &point);
587 CMenu* add_to_menu = theApp.m_menu_mgr.GetMenu(MenuMgr::LibPlaylistSortMenu);
588 ASSERT(add_to_menu != nullptr);
589 if (add_to_menu != nullptr)
590 {
591 CUIWindowCmdHelper helper(nullptr);
592 helper.SetMenuState(add_to_menu);
593 UINT command = add_to_menu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, point.x, point.y, theApp.m_pMainWnd);
594 helper.OnUiCommand(command);
595 }
596 return true;
597 }
598 case BTN_KARAOKE:
599 theApp.m_lyric_setting_data.lyric_karaoke_disp = !theApp.m_lyric_setting_data.lyric_karaoke_disp;
600 return true;
601
602 //菜单
603 case MENU_FILE:
604 showMenu(btn.second.rect, theApp.m_menu_mgr.GetMenu(MenuMgr::MainFileMenu));
605 return true;
606 case MENU_PLAY_CONTROL:
607 showMenu(btn.second.rect, theApp.m_menu_mgr.GetMenu(MenuMgr::MainPlayCtrlMenu));
608 return true;
609 case MENU_PLAYLIST:
610 showMenu(btn.second.rect, theApp.m_menu_mgr.GetMenu(MenuMgr::MainPlaylistMenu));
611 return true;
612 case MENU_LYRICS:
613 showMenu(btn.second.rect, theApp.m_menu_mgr.GetMenu(MenuMgr::MainLyricMenu));
614 return true;
615 case MENU_VIEW:
616 showMenu(btn.second.rect, theApp.m_menu_mgr.GetMenu(MenuMgr::MainViewMenu));
617 return true;
618 case MENU_TOOLS:
619 showMenu(btn.second.rect, theApp.m_menu_mgr.GetMenu(MenuMgr::MainToolMenu));
620 return true;
621 case MENU_HELP:
622 showMenu(btn.second.rect, theApp.m_menu_mgr.GetMenu(MenuMgr::MainHelpMenu));
623 return true;
624 default:
625 break;
626 }
627 }
628 }
629 return false;
630 }
631
632
RButtonDown(CPoint point)633 void CPlayerUIBase::RButtonDown(CPoint point)
634 {
635 }
636
MouseWheel(int delta,CPoint point)637 bool CPlayerUIBase::MouseWheel(int delta, CPoint point)
638 {
639 return false;
640 }
641
DoubleClick(CPoint point)642 bool CPlayerUIBase::DoubleClick(CPoint point)
643 {
644 return false;
645 }
646
GetThumbnailClipArea()647 CRect CPlayerUIBase::GetThumbnailClipArea()
648 {
649 //获取菜单栏的高度
650 int menu_bar_height = 0;
651 if (m_ui_data.ShowWindowMenuBar() && theApp.m_app_setting_data.show_window_frame)
652 {
653 menu_bar_height = CCommon::GetMenuBarHeight(theApp.m_pMainWnd->GetSafeHwnd());
654 if (menu_bar_height == 0)
655 menu_bar_height = theApp.DPI(20);
656 else
657 menu_bar_height += theApp.DPI(1);
658 }
659
660 CRect thumbnail_rect = DrawAreaToClient(m_draw_data.thumbnail_rect, m_draw_rect);
661 thumbnail_rect.MoveToY(thumbnail_rect.top + menu_bar_height);
662 return thumbnail_rect;
663 }
664
UpdateRepeatModeToolTip()665 void CPlayerUIBase::UpdateRepeatModeToolTip()
666 {
667 SetRepeatModeToolTipText();
668 UpdateMouseToolTip(BTN_REPETEMODE, m_repeat_mode_tip.c_str());
669 }
670
UpdateSongInfoToolTip()671 void CPlayerUIBase::UpdateSongInfoToolTip()
672 {
673 SetSongInfoToolTipText();
674 UpdateMouseToolTip(BTN_INFO, m_info_tip.c_str());
675
676 SetCoverToolTipText();
677 UpdateMouseToolTip(BTN_COVER, m_cover_tip.c_str());
678 }
679
UpdatePlayPauseButtonTip()680 void CPlayerUIBase::UpdatePlayPauseButtonTip()
681 {
682 if (CPlayer::GetInstance().IsPlaying() && !CPlayer::GetInstance().IsError())
683 UpdateMouseToolTip(BTN_PLAY_PAUSE, theApp.m_str_table.LoadText(L"UI_TIP_BTN_PAUSE").c_str());
684 else
685 UpdateMouseToolTip(BTN_PLAY_PAUSE, theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAY").c_str());
686 }
687
UpdateFullScreenTip()688 void CPlayerUIBase::UpdateFullScreenTip()
689 {
690 if (m_ui_data.full_screen)
691 {
692 wstring tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_FULL_SCREEN_EXIT") + GetCmdShortcutKeyForTooltips(ID_FULL_SCREEN).GetString();
693 UpdateMouseToolTip(BTN_FULL_SCREEN_TITLEBAR, tip_str.c_str());
694 UpdateMouseToolTip(BTN_FULL_SCREEN, tip_str.c_str());
695 }
696 else
697 {
698 wstring tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_FULL_SCREEN") + GetCmdShortcutKeyForTooltips(ID_FULL_SCREEN).GetString();
699 UpdateMouseToolTip(BTN_FULL_SCREEN_TITLEBAR, tip_str.c_str());
700 UpdateMouseToolTip(BTN_FULL_SCREEN, tip_str.c_str());
701 }
702 }
703
UpdateTitlebarBtnToolTip()704 void CPlayerUIBase::UpdateTitlebarBtnToolTip()
705 {
706 if (theApp.m_pMainWnd->IsZoomed())
707 UpdateMouseToolTip(BTN_MAXIMIZE, theApp.m_str_table.LoadText(L"UI_TIP_BTN_RESTORE").c_str());
708 else
709 UpdateMouseToolTip(BTN_MAXIMIZE, theApp.m_str_table.LoadText(L"UI_TIP_BTN_MAXIMIZE").c_str());
710 }
711
SetCursor()712 bool CPlayerUIBase::SetCursor()
713 {
714 if (m_buttons[BTN_PROGRESS].hover)
715 {
716 ::SetCursor(::LoadCursor(NULL, IDC_HAND));
717 return true;
718 }
719 return false;
720 }
721
MouseLeave()722 void CPlayerUIBase::MouseLeave()
723 {
724 for (auto& btn : m_buttons)
725 {
726 btn.second.hover = false;
727 btn.second.pressed = false;
728 }
729 }
730
ClearBtnRect()731 void CPlayerUIBase::ClearBtnRect()
732 {
733 for (auto& btn : m_buttons)
734 {
735 btn.second.rect = CRect();
736 }
737 }
738
GetUiSize() const739 CPlayerUIBase::UiSize CPlayerUIBase::GetUiSize() const
740 {
741 bool ui_big = (!m_ui_data.narrow_mode && !m_ui_data.show_playlist) || m_draw_rect.Width() > DPI(600);
742 if (IsDrawNarrowMode())
743 return UiSize::SMALL;
744 else if (ui_big)
745 return UiSize::BIG;
746 else
747 return UiSize::NARROW;
748
749 }
750
GetBtnIconType(BtnKey key)751 IconMgr::IconType CPlayerUIBase::GetBtnIconType(BtnKey key)
752 {
753 switch (key)
754 {
755 case BTN_REPETEMODE:
756 switch (CPlayer::GetInstance().GetRepeatMode())
757 {
758 case RepeatMode::RM_PLAY_ORDER:
759 return IconMgr::IconType::IT_Play_Order;
760 case RepeatMode::RM_LOOP_PLAYLIST:
761 return IconMgr::IconType::IT_Loop_Playlist;
762 case RepeatMode::RM_LOOP_TRACK:
763 return IconMgr::IconType::IT_Loop_Track;
764 case RepeatMode::RM_PLAY_SHUFFLE:
765 return IconMgr::IconType::IT_Play_Shuffle;
766 case RepeatMode::RM_PLAY_RANDOM:
767 return IconMgr::IconType::IT_Play_Random;
768 case RepeatMode::RM_PLAY_TRACK:
769 return IconMgr::IconType::IT_Play_Track;
770 default:
771 return IconMgr::IconType::IT_NO_ICON;
772 }
773 case BTN_VOLUME:
774 if (CPlayer::GetInstance().GetVolume() <= 0)
775 return IconMgr::IconType::IT_Volume0;
776 else if (CPlayer::GetInstance().GetVolume() >= 66)
777 return IconMgr::IconType::IT_Volume3;
778 else if (CPlayer::GetInstance().GetVolume() >= 33)
779 return IconMgr::IconType::IT_Volume2;
780 else
781 return IconMgr::IconType::IT_Volume1;
782 case BTN_SKIN:
783 case BTN_SKIN_TITLEBAR:
784 return IconMgr::IconType::IT_Skin;
785 case BTN_EQ:
786 return IconMgr::IconType::IT_Equalizer;
787 case BTN_SETTING:
788 case BTN_SETTING_TITLEBAR:
789 return IconMgr::IconType::IT_Setting;
790 case BTN_MINI:
791 case BTN_MINI_TITLEBAR:
792 if (IsMiniMode())
793 return IconMgr::IconType::IT_Mini_Off;
794 else
795 return IconMgr::IconType::IT_Mini_On;
796 case BTN_INFO:
797 return IconMgr::IconType::IT_Info;
798 case BTN_FIND:
799 return IconMgr::IconType::IT_Find;
800 case BTN_STOP:
801 return IconMgr::IconType::IT_Stop;
802 case BTN_PREVIOUS:
803 return IconMgr::IconType::IT_Previous;
804 case BTN_PLAY_PAUSE:
805 if (CPlayer::GetInstance().IsPlaying())
806 return IconMgr::IconType::IT_Pause;
807 else
808 return IconMgr::IconType::IT_Play;
809 case BTN_NEXT:
810 return IconMgr::IconType::IT_Next;
811 case BTN_SHOW_PLAYLIST:
812 return IconMgr::IconType::IT_Playlist;
813 case BTN_MEDIA_LIB:
814 return IconMgr::IconType::IT_Media_Lib;
815 case BTN_FULL_SCREEN:
816 case BTN_FULL_SCREEN_TITLEBAR:
817 if (m_ui_data.full_screen)
818 return IconMgr::IconType::IT_Full_Screen_Off;
819 else
820 return IconMgr::IconType::IT_Full_Screen_On;
821 case BTN_MENU:
822 case BTN_MENU_TITLEBAR:
823 return IconMgr::IconType::IT_Menu;
824 case BTN_FAVOURITE:
825 if (CPlayer::GetInstance().IsFavourite())
826 return IconMgr::IconType::IT_Favorite_Off;
827 else
828 return IconMgr::IconType::IT_Favorite_On;
829 case BTN_MINIMIZE:
830 return IconMgr::IconType::IT_Minimize;
831 case BTN_MAXIMIZE:
832 if (theApp.m_pMainWnd->IsZoomed())
833 return IconMgr::IconType::IT_Maxmize_Off;
834 else
835 return IconMgr::IconType::IT_Maxmize_On;
836 case BTN_CLOSE:
837 case BTN_APP_CLOSE:
838 return IconMgr::IconType::IT_Close;
839 case BTN_ADD_TO_PLAYLIST:
840 return IconMgr::IconType::IT_Add;
841 case BTN_SWITCH_DISPLAY:
842 return IconMgr::IconType::IT_Switch_Display;
843 case BTN_DARK_LIGHT: case BTN_DARK_LIGHT_TITLE_BAR: // 之前是一个IconRes的深浅色,现拆分为两个图标类型,将来如果换图标主题要轻松一些
844 if (theApp.m_app_setting_data.dark_mode)
845 return IconMgr::IconType::IT_Dark_Mode_Off;
846 else
847 return IconMgr::IconType::IT_Dark_Mode_On;
848 case BTN_LOCATE_TO_CURRENT:
849 return IconMgr::IconType::IT_Locate;
850 case MENU_FILE:
851 return IconMgr::IconType::IT_Folder;
852 case MENU_PLAY_CONTROL:
853 return IconMgr::IconType::IT_Play;
854 case MENU_PLAYLIST:
855 return IconMgr::IconType::IT_Playlist;
856 case MENU_LYRICS:
857 return IconMgr::IconType::IT_Lyric;
858 case MENU_VIEW:
859 return IconMgr::IconType::IT_Playlist_Dock;
860 case MENU_TOOLS:
861 return IconMgr::IconType::IT_Setting;
862 case MENU_HELP:
863 return IconMgr::IconType::IT_Help;
864 case BTN_OPEN_FOLDER:
865 return IconMgr::IconType::IT_NewFolder;
866 case BTN_NEW_PLAYLIST:
867 return IconMgr::IconType::IT_Add;
868 case BTN_PLAY_MY_FAVOURITE:
869 return IconMgr::IconType::IT_Play;
870 case BTN_MEDIALIB_FOLDER_SORT: case BTN_MEDIALIB_PLAYLIST_SORT:
871 return IconMgr::IconType::IT_Sort_Mode;
872 case BTN_KARAOKE:
873 return IconMgr::IconType::IT_Karaoke;
874 default:
875 ASSERT(FALSE);
876 return IconMgr::IconType::IT_NO_ICON;
877 }
878 }
879
GetButtonText(BtnKey key_type)880 std::wstring CPlayerUIBase::GetButtonText(BtnKey key_type)
881 {
882 switch (key_type)
883 {
884 case BTN_REPETEMODE:
885 switch (CPlayer::GetInstance().GetRepeatMode())
886 {
887 case RM_PLAY_ORDER: return theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_ORDER");
888 case RM_PLAY_SHUFFLE: return theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_SHUFFLE");
889 case RM_PLAY_RANDOM: return theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_RANDOM");
890 case RM_LOOP_PLAYLIST: return theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_PLAYLIST");
891 case RM_LOOP_TRACK: return theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_TRACK");
892 case RM_PLAY_TRACK: return theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_ONCE");
893 }
894 break;
895 case BTN_SKIN: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_SWITCH_UI");
896 case BTN_EQ: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_SOUND_EFFECT_SETTING");
897 case BTN_SETTING: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_OPTION_SETTING");
898 case BTN_MINI: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_MINIMODE");
899 case BTN_INFO: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_PROPERTY");
900 case BTN_FIND: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_FIND_SONGS");
901 case BTN_STOP: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_STOP");
902 case BTN_PREVIOUS: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_STOP");
903 case BTN_PLAY_PAUSE: return theApp.m_str_table.LoadText(CPlayer::GetInstance().IsPlaying() ? L"UI_TIP_BTN_PAUSE" : L"UI_TIP_BTN_PLAY");
904 case BTN_NEXT: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_NEXT");
905 case BTN_SHOW_PLAYLIST: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAYLIST_SHOW_HIDE");
906 case BTN_MEDIA_LIB: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_MEDIA_LIB");
907 case BTN_FULL_SCREEN: return theApp.m_str_table.LoadText(m_ui_data.full_screen ? L"UI_TIP_BTN_FULL_SCREEN_EXIT" : L"UI_TIP_BTN_FULL_SCREEN");
908 case BTN_MENU: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_MAIN_MENU");
909 case BTN_FAVOURITE: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_FAVOURITE");
910 case BTN_ADD_TO_PLAYLIST: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_ADD_TO_PLAYLIST");
911 case BTN_SWITCH_DISPLAY: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_SWITCH_DISPLAY");
912 case BTN_DARK_LIGHT: case BTN_DARK_LIGHT_TITLE_BAR: return theApp.m_str_table.LoadText(theApp.m_app_setting_data.dark_mode ? L"UI_TIP_BTN_DARK_LIGHT_TO_LIGHT_MODE" : L"UI_TIP_BTN_DARK_LIGHT_TO_DARK_MODE");
913 case BTN_LOCATE_TO_CURRENT:return theApp.m_str_table.LoadText(L"UI_TIP_BTN_LOCATE_TO_CURRENT");
914 case BTN_OPEN_FOLDER: return theApp.m_str_table.LoadText(L"UI_TXT_BTN_OPEN_FOLDER");
915 case BTN_NEW_PLAYLIST: return theApp.m_str_table.LoadText(L"UI_TXT_BTN_NEW_PLAYLIST");
916 case BTN_PLAY_MY_FAVOURITE: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAY");
917 case BTN_MEDIALIB_FOLDER_SORT: case BTN_MEDIALIB_PLAYLIST_SORT: return theApp.m_str_table.LoadText(L"TXT_LIB_PLAYLIST_SORT");
918 }
919
920 return std::wstring();
921 }
922
PreDrawInfo()923 void CPlayerUIBase::PreDrawInfo()
924 {
925 //设置颜色
926 m_colors = CPlayerUIHelper::GetUIColors(theApp.m_app_setting_data.theme_color, theApp.m_app_setting_data.dark_mode, IsDrawBackgroundAlpha());
927
928 //设置绘制的矩形区域
929 SetDrawRect();
930
931 //检测到界面布局发生了变化时
932 static UiSize last_ui_size{};
933 if (last_ui_size != GetUiSize())
934 {
935 ClearBtnRect();
936 UiSizeChanged();
937 last_ui_size = GetUiSize();
938 }
939 }
940
SetDrawRect()941 void CPlayerUIBase::SetDrawRect()
942 {
943 m_draw_rect = CRect(0, 0, m_ui_data.draw_area_width, m_ui_data.draw_area_height);
944 }
945
DrawBackground()946 void CPlayerUIBase::DrawBackground()
947 {
948 CRect draw_rect = m_draw_rect;
949 draw_rect.MoveToXY(0, 0);
950
951 //绘制背景
952 if (theApp.m_app_setting_data.enable_background)
953 {
954 if (CPlayer::GetInstance().AlbumCoverExist() && theApp.m_app_setting_data.album_cover_as_background)
955 {
956 CImage& back_image{ theApp.m_app_setting_data.background_gauss_blur ? CPlayer::GetInstance().GetAlbumCoverBlur() : CPlayer::GetInstance().GetAlbumCover() };
957 m_draw.DrawBitmap(back_image, CPoint(0, 0), m_draw_rect.Size(), CDrawCommon::StretchMode::FILL);
958 }
959 else
960 {
961 CSingleLock sync(&m_ui_data.default_background_sync, TRUE);
962 //MemDC.FillSolidRect(0, 0, m_draw_rect.Width(), m_draw_rect.Height(), GetSysColor(COLOR_BTNFACE)); //给缓冲DC的绘图区域填充对话框的背景颜色
963 m_draw.DrawBitmap(m_ui_data.default_background, CPoint(0, 0), m_draw_rect.Size(), CDrawCommon::StretchMode::FILL);
964 }
965 }
966
967 //填充背景颜色
968 if (IsDrawBackgroundAlpha())
969 m_draw.FillAlphaRect(draw_rect, m_colors.color_back, ALPHA_CHG(theApp.m_app_setting_data.background_transparency));
970 else
971 m_draw.FillRect(draw_rect, m_colors.color_back);
972 }
973
DrawSongInfo(CRect rect,int font_size,bool reset)974 void CPlayerUIBase::DrawSongInfo(CRect rect, int font_size, bool reset)
975 {
976 //设置字体
977 UiFontGuard set_font(this, font_size);
978
979 //绘制播放状态
980 CRect rc_tmp{ rect };
981 if (!theApp.m_app_setting_data.always_show_statusbar)
982 {
983 CString play_state_str = CPlayer::GetInstance().GetPlayingState().c_str();
984 //m_draw.GetDC()->SelectObject(&theApp.m_font_set.dlg.GetFont());
985 rc_tmp.right = rc_tmp.left + m_draw.GetTextExtent(play_state_str).cx + DPI(4);
986 m_draw.DrawWindowText(rc_tmp, play_state_str, m_colors.color_text_lable);
987 }
988 else //如果总是显示状态栏,由于状态栏中已经有播放状态了,因此这里不显示播放状态
989 {
990 rc_tmp.right = rc_tmp.left;
991 }
992
993 //绘制歌曲序号
994 rc_tmp.MoveToX(rc_tmp.right);
995 wchar_t buff[128];
996 swprintf_s(buff, sizeof(buff) / 2, L"%.3d", CPlayer::GetInstance().GetIndex() + 1);
997 int index_width = m_draw.GetTextExtent(buff).cx;
998 rc_tmp.right = rc_tmp.left + index_width + DPI(4);
999 m_draw.DrawWindowText(rc_tmp, buff, m_colors.color_text_2);
1000
1001 //绘制标识
1002 wstring tag_str;
1003 if (CPlayer::GetInstance().GetCurrentSongInfo().is_cue)
1004 tag_str = L"cue";
1005 else if (CPlayer::GetInstance().IsMidi())
1006 tag_str = L"midi";
1007 else if (CPlayer::GetInstance().IsOsuFile())
1008 tag_str = L"osu!";
1009 int available_width = rect.right - rc_tmp.right;
1010 if (available_width >= DPI(50) && !tag_str.empty())
1011 {
1012 int width = m_draw.GetTextExtent(tag_str.c_str()).cx + DPI(4);
1013 rc_tmp.MoveToX(rc_tmp.right);
1014 rc_tmp.right = rc_tmp.left + width;
1015 DrawPlayTag(rc_tmp, tag_str.c_str());
1016 }
1017
1018 //绘制播放速度
1019 if (std::fabs(CPlayer::GetInstance().GetSpeed() - 1) > 1e-3)
1020 {
1021 wchar_t buff[64];
1022 swprintf_s(buff, L"%.2f", CPlayer::GetInstance().GetSpeed());
1023 tag_str = buff;
1024 if (!tag_str.empty() && tag_str.back() == L'0')
1025 tag_str.pop_back();
1026 tag_str.push_back(L'X');
1027 available_width = rect.right - rc_tmp.right;
1028 if (available_width >= DPI(50))
1029 {
1030 int width = m_draw.GetTextExtent(tag_str.c_str()).cx + DPI(4);
1031 rc_tmp.MoveToX(rc_tmp.right + DPI(2));
1032 rc_tmp.right = rc_tmp.left + width;
1033 DrawPlayTag(rc_tmp, tag_str.c_str());
1034 }
1035 }
1036
1037 // 绘制播放变调
1038 if (CPlayer::GetInstance().GetPitch() != 0)
1039 {
1040 wchar_t buff[64];
1041 int pitch = CPlayer::GetInstance().GetPitch();
1042 wchar_t sign = pitch > 0 ? L'+' : L'-';
1043 swprintf_s(buff, L"K%c%d", sign, std::abs(pitch));
1044 tag_str = buff;
1045 available_width = rect.right - rc_tmp.right;
1046 if (available_width >= DPI(50))
1047 {
1048 int width = m_draw.GetTextExtent(tag_str.c_str()).cx + DPI(4);
1049 rc_tmp.MoveToX(rc_tmp.right + DPI(2));
1050 rc_tmp.right = rc_tmp.left + width;
1051 DrawPlayTag(rc_tmp, tag_str.c_str());
1052 }
1053 }
1054
1055 //绘制文件名
1056 rc_tmp.MoveToX(rc_tmp.right + (tag_str.empty() ? 0 : DPI(4)));
1057 rc_tmp.right = rect.right;
1058 if (rc_tmp.Width() >= DPI(4))
1059 {
1060 static CDrawCommon::ScrollInfo scroll_info1;
1061 m_draw.DrawScrollText(rc_tmp, CPlayer::GetInstance().GetDisplayName().c_str(), m_colors.color_text, GetScrollTextPixel(), false, scroll_info1, reset);
1062 }
1063 }
1064
DrawControlBarBtn(CRect rect,BtnKey btn_type)1065 void CPlayerUIBase::DrawControlBarBtn(CRect rect, BtnKey btn_type)
1066 {
1067 rect.DeflateRect(DPI(2), DPI(2));
1068 DrawUIButton(rect, btn_type);
1069 }
1070
DrawPlayTag(CRect rect,LPCTSTR str_text)1071 void CPlayerUIBase::DrawPlayTag(CRect rect, LPCTSTR str_text)
1072 {
1073 DrawAreaGuard guard(&m_draw, rect);
1074 CRect rc_border = rect;
1075 rc_border.top += DPI(2);
1076 rc_border.bottom -= DPI(1);
1077 m_draw.DrawRectOutLine(rc_border, m_colors.color_text, DPI(1), false);
1078 m_draw.DrawWindowText(rect, str_text, m_colors.color_text, Alignment::CENTER);
1079 }
1080
DrawRectangle(const CRect & rect,bool no_corner_radius,bool theme_color,ColorMode color_mode)1081 void CPlayerUIBase::DrawRectangle(const CRect& rect, bool no_corner_radius, bool theme_color, ColorMode color_mode)
1082 {
1083 bool draw_background{ IsDrawBackgroundAlpha() };
1084 //绘制背景
1085 BYTE alpha;
1086 if (!draw_background)
1087 alpha = 255;
1088 else if (theApp.m_app_setting_data.dark_mode)
1089 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
1090 else
1091 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency);
1092
1093 COLORREF fill_color{};
1094 if (color_mode == RCM_DARK)
1095 {
1096 fill_color = CColorConvert::m_gray_color.dark3;
1097 if (draw_background)
1098 alpha = 108;
1099 }
1100 else if (color_mode == RCM_LIGHT)
1101 {
1102 if (theme_color)
1103 fill_color = theApp.m_app_setting_data.theme_color.light3;
1104 else
1105 fill_color = CColorConvert::m_gray_color.light4;
1106 }
1107 else
1108 {
1109 if (theme_color)
1110 {
1111 fill_color = m_colors.color_control_bar_back;
1112 }
1113 else
1114 {
1115 if (theApp.m_app_setting_data.dark_mode)
1116 fill_color = CColorConvert::m_gray_color.dark3;
1117 else
1118 fill_color = CColorConvert::m_gray_color.light4;
1119 }
1120 }
1121
1122 if (!theApp.m_app_setting_data.button_round_corners || no_corner_radius)
1123 m_draw.FillAlphaRect(rect, fill_color, alpha);
1124 else
1125 {
1126 m_draw.DrawRoundRect(rect, fill_color, CalculateRoundRectRadius(rect), alpha);
1127 }
1128 }
1129
DrawToolBar(CRect rect,bool draw_translate_button)1130 void CPlayerUIBase::DrawToolBar(CRect rect, bool draw_translate_button)
1131 {
1132 DrawRectangle(rect);
1133 DrawToolBarWithoutBackground(rect, draw_translate_button);
1134 }
1135
DrawToolBarWithoutBackground(CRect rect,bool draw_translate_button)1136 void CPlayerUIBase::DrawToolBarWithoutBackground(CRect rect, bool draw_translate_button)
1137 {
1138 CRect rc_tmp = rect;
1139
1140 //绘制循环模式
1141 rc_tmp.right = rect.left + rect.Height();
1142 DrawControlBarBtn(rc_tmp, BTN_REPETEMODE);
1143
1144 //绘制设置按钮
1145 rc_tmp.MoveToX(rc_tmp.right);
1146 DrawControlBarBtn(rc_tmp, BTN_SETTING);
1147
1148 //绘制均衡器按钮
1149 rc_tmp.MoveToX(rc_tmp.right);
1150 DrawControlBarBtn(rc_tmp, BTN_EQ);
1151
1152 //绘制切换界面按钮
1153 rc_tmp.MoveToX(rc_tmp.right);
1154 DrawControlBarBtn(rc_tmp, BTN_SKIN);
1155
1156 //绘制迷你模式按钮
1157 if (rect.Width() >= DPI(174))
1158 {
1159 rc_tmp.MoveToX(rc_tmp.right);
1160 //m_buttons[BTN_MINI].enable = !theApp.m_ui_data.full_screen;
1161 DrawControlBarBtn(rc_tmp, BTN_MINI);
1162 }
1163 else
1164 {
1165 m_buttons[BTN_MINI].rect = CRect();
1166 }
1167
1168 //绘制曲目信息按钮
1169 if (rect.Width() >= DPI(198))
1170 {
1171 rc_tmp.MoveToX(rc_tmp.right);
1172 DrawControlBarBtn(rc_tmp, BTN_INFO);
1173 }
1174 else
1175 {
1176 m_buttons[BTN_INFO].rect = CRect();
1177 }
1178
1179 //绘制查找按钮
1180 if (rect.Width() >= DPI(222))
1181 {
1182 rc_tmp.MoveToX(rc_tmp.right);
1183 DrawControlBarBtn(rc_tmp, BTN_FIND);
1184 }
1185 else
1186 {
1187 m_buttons[BTN_FIND].rect = CRect();
1188 }
1189
1190 //绘制深色/浅色按钮
1191 if (rect.Width() >= DPI(294))
1192 {
1193 rc_tmp.MoveToX(rc_tmp.right);
1194 DrawControlBarBtn(rc_tmp, BTN_DARK_LIGHT);
1195 }
1196 else
1197 {
1198 m_buttons[BTN_DARK_LIGHT].rect = CRect();
1199 }
1200
1201 //绘制AB重复按钮
1202 if (rect.Width() >= DPI(318))
1203 {
1204 rc_tmp.MoveToX(rc_tmp.right);
1205 CRect rc_btn = rc_tmp;
1206 rc_btn.DeflateRect(DPI(2), DPI(2));
1207 DrawABRepeatButton(rc_btn);
1208 }
1209 else
1210 {
1211 m_buttons[BTN_AB_REPEAT].rect = CRect();
1212 }
1213
1214 //绘制翻译按钮
1215 if (draw_translate_button && rect.Width() >= DPI(246))
1216 {
1217 rc_tmp.MoveToX(rc_tmp.right);
1218 CRect translate_rect = rc_tmp;
1219 translate_rect.DeflateRect(DPI(2), DPI(2));
1220 DrawTranslateButton(translate_rect);
1221 }
1222 else
1223 {
1224 m_buttons[BTN_TRANSLATE].rect = CRect();
1225 }
1226
1227 //绘制桌面歌词按钮
1228 if (rect.Width() >= DPI(270))
1229 {
1230 rc_tmp.MoveToX(rc_tmp.right);
1231 CRect desktop_lyric_rect = rc_tmp;
1232 desktop_lyric_rect.DeflateRect(DPI(2), DPI(2));
1233 DrawDesktopLyricButton(desktop_lyric_rect);
1234 }
1235 else
1236 {
1237 m_buttons[BTN_LRYIC].rect = CRect();
1238 }
1239
1240 rc_tmp.left = rc_tmp.right = rect.right;
1241
1242 //显示<<<<
1243 if (rect.Width() >= DPI(368))
1244 {
1245 rc_tmp.right = rc_tmp.left;
1246 rc_tmp.left = rc_tmp.right - DPI(44);
1247 DrawBeatIndicator(rc_tmp);
1248 }
1249
1250
1251 //显示音量
1252 rc_tmp.right = rc_tmp.left;
1253 rc_tmp.left = rc_tmp.right - DPI(56) - Margin();
1254 DrawVolumeButton(rc_tmp);
1255 }
1256
DrawBeatIndicator(CRect rect)1257 void CPlayerUIBase::DrawBeatIndicator(CRect rect)
1258 {
1259 int progress;
1260 Time time{ CPlayer::GetInstance().GetCurrentPosition() };
1261 if (CPlayer::GetInstance().IsMidi())
1262 {
1263 ////progress = (CPlayer::GetInstance().GetMidiInfo().midi_position % 16 + 1) *1000 / 16;
1264 //if (CPlayer::GetInstance().GetMidiInfo().tempo == 0)
1265 // progress = 0;
1266 //else
1267 // progress = (time.toInt() * 1000 / CPlayer::GetInstance().GetMidiInfo().tempo % 4 + 1) * 250;
1268 progress = (CPlayer::GetInstance().GetMidiInfo().midi_position % 4 + 1) * 250;
1269 if (progress == 1000)
1270 progress = 999;
1271 }
1272 else
1273 {
1274 progress = (time.sec % 4 * 1000 + time.msec) / 4;
1275 }
1276 m_draw.DrawWindowText(rect, _T("<<<<"), m_colors.color_text, m_colors.color_text_2, progress);
1277 }
1278
DrawAreaToClient(CRect rect,CRect draw_area)1279 CRect CPlayerUIBase::DrawAreaToClient(CRect rect, CRect draw_area)
1280 {
1281 //rect.MoveToXY(rect.left + draw_area.left, rect.top + draw_area.top);
1282 return rect;
1283 }
1284
ClientAreaToDraw(CRect rect,CRect draw_area)1285 CRect CPlayerUIBase::ClientAreaToDraw(CRect rect, CRect draw_area)
1286 {
1287 //rect.MoveToXY(rect.left - draw_area.left, rect.top - draw_area.top);
1288 return rect;
1289 }
1290
DrawUIButton(const CRect & rect,BtnKey key_type,bool big_icon,bool show_text,int font_size,bool checked)1291 void CPlayerUIBase::DrawUIButton(const CRect& rect, BtnKey key_type, bool big_icon, bool show_text, int font_size, bool checked)
1292 {
1293 auto& btn = m_buttons[key_type];
1294 std::wstring text;
1295 if (show_text)
1296 {
1297 text = GetButtonText(key_type);
1298 }
1299 DrawUIButton(rect, btn, GetBtnIconType(key_type), big_icon, text, font_size, checked);
1300 }
1301
DrawUIButton(const CRect & rect,UIButton & btn,IconMgr::IconType icon_type,bool big_icon,const std::wstring & text,int font_size,bool checked)1302 void CPlayerUIBase::DrawUIButton(const CRect& rect, UIButton& btn, IconMgr::IconType icon_type, bool big_icon, const std::wstring& text, int font_size, bool checked)
1303 {
1304 btn.rect = DrawAreaToClient(rect, m_draw_rect);
1305
1306 CRect rc_tmp = rect;
1307 if (btn.pressed && btn.enable)
1308 rc_tmp.MoveToXY(rect.left + theApp.DPI(1), rect.top + theApp.DPI(1));
1309
1310 //rc_tmp.DeflateRect(DPI(2), DPI(2));
1311 //m_draw.SetDrawArea(rc_tmp);
1312
1313 //绘制的是否为关闭按钮(关闭按钮需要特别处理)
1314 bool is_close_btn = (&btn == &m_buttons[BTN_CLOSE] || &btn == &m_buttons[BTN_APP_CLOSE]);
1315
1316 //绘制背景
1317 if (btn.enable && (btn.pressed || btn.hover || checked))
1318 {
1319 BYTE alpha;
1320 if (!is_close_btn && IsDrawBackgroundAlpha())
1321 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
1322 else
1323 alpha = 255;
1324 COLORREF back_color{};
1325 if (is_close_btn)
1326 {
1327 if (btn.pressed)
1328 back_color = RGB(173, 17, 29);
1329 else
1330 back_color = RGB(232, 17, 35);
1331 }
1332 else
1333 {
1334 if (btn.pressed)
1335 back_color = m_colors.color_button_pressed;
1336 else if (btn.hover)
1337 back_color = m_colors.color_button_hover;
1338 else if (checked)
1339 back_color = m_colors.color_button_back;
1340 }
1341 if (!theApp.m_app_setting_data.button_round_corners)
1342 m_draw.FillAlphaRect(rc_tmp, back_color, alpha, true);
1343 else
1344 m_draw.DrawRoundRect(rc_tmp, back_color, CalculateRoundRectRadius(rc_tmp), alpha);
1345 }
1346
1347 CRect rect_icon{ rc_tmp };
1348 if (!text.empty())
1349 rect_icon.right = rect_icon.left + rect_icon.Height(); //如果要显示文本,则图标显示矩形左侧的正方形区域
1350
1351 IconMgr::IconStyle icon_style = (is_close_btn && (btn.pressed || btn.hover)) ? IconMgr::IconStyle::IS_OutlinedLight : IconMgr::IconStyle::IS_Auto;
1352 IconMgr::IconSize icon_size = big_icon ? IconMgr::IconSize::IS_DPI_20 : IconMgr::IconSize::IS_DPI_16;
1353 DrawUiIcon(rect_icon, icon_type, icon_style, icon_size);
1354
1355 //绘制文本
1356 if (!text.empty())
1357 {
1358 UiFontGuard set_font(this, font_size);
1359
1360 CRect rect_text{ rc_tmp };
1361 rect_text.left = rect_icon.right;
1362 int right_space = (rc_tmp.Height() - DPI(16)) / 2;
1363 rect_text.right -= right_space;
1364 m_draw.DrawWindowText(rect_text, text.c_str(), m_colors.color_text, Alignment::LEFT, true);
1365
1366 }
1367 }
1368
DrawTextButton(CRect rect,BtnKey btn_type,LPCTSTR text,bool checked)1369 void CPlayerUIBase::DrawTextButton(CRect rect, BtnKey btn_type, LPCTSTR text, bool checked)
1370 {
1371 auto& btn = m_buttons[btn_type];
1372 if (btn.enable)
1373 {
1374 if (btn.pressed)
1375 rect.MoveToXY(rect.left + theApp.DPI(1), rect.top + theApp.DPI(1));
1376
1377 //绘制的是否为关闭按钮(关闭按钮需要特别处理)
1378 bool is_close_btn = (&btn == &m_buttons[BTN_CLOSE] || &btn == &m_buttons[BTN_APP_CLOSE]);
1379
1380 BYTE alpha;
1381 if (!is_close_btn && IsDrawBackgroundAlpha())
1382 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
1383 else
1384 alpha = 255;
1385 if (btn.pressed || btn.hover || checked)
1386 {
1387 COLORREF background_color{};
1388 if (is_close_btn)
1389 {
1390 if (btn.pressed)
1391 {
1392 background_color = RGB(173, 17, 29);
1393 }
1394 else if (btn.hover)
1395 {
1396 background_color = RGB(232, 17, 35);
1397 }
1398 }
1399 else
1400 {
1401 if (btn.pressed)
1402 {
1403 background_color = m_colors.color_button_pressed;
1404 }
1405 else if (btn.hover)
1406 {
1407 background_color = m_colors.color_button_hover;
1408 }
1409 else if (checked)
1410 {
1411 background_color = m_colors.color_button_back;
1412 }
1413 }
1414
1415 if (!theApp.m_app_setting_data.button_round_corners)
1416 {
1417 m_draw.FillAlphaRect(rect, background_color, alpha);
1418 }
1419 else
1420 {
1421 m_draw.DrawRoundRect(rect, background_color, CalculateRoundRectRadius(rect), alpha);
1422 }
1423 }
1424 COLORREF front_color{ m_colors.color_text };
1425 if (is_close_btn && (btn.hover || btn.pressed))
1426 front_color = RGB(255, 255, 255);
1427 m_draw.DrawWindowText(rect, text, front_color, Alignment::CENTER);
1428 }
1429 else
1430 {
1431 m_draw.DrawWindowText(rect, text, GRAY(200), Alignment::CENTER);
1432 }
1433 btn.rect = DrawAreaToClient(rect, m_draw_rect);
1434 }
1435
AddMouseToolTip(BtnKey btn,LPCTSTR str)1436 void CPlayerUIBase::AddMouseToolTip(BtnKey btn, LPCTSTR str)
1437 {
1438 m_tool_tip.AddTool(m_pMainWnd, str, m_buttons[btn].rect, btn + GetToolTipIdOffset());
1439 }
1440
UpdateMouseToolTip(BtnKey btn,LPCTSTR str)1441 void CPlayerUIBase::UpdateMouseToolTip(BtnKey btn, LPCTSTR str)
1442 {
1443 m_tool_tip.UpdateTipText(str, m_pMainWnd, btn + GetToolTipIdOffset());
1444 }
1445
UpdateMouseToolTipPosition(int btn,CRect rect)1446 void CPlayerUIBase::UpdateMouseToolTipPosition(int btn, CRect rect)
1447 {
1448 m_tool_tip.SetToolRect(m_pMainWnd, btn + GetToolTipIdOffset(), rect);
1449 }
1450
UpdateVolumeToolTip()1451 void CPlayerUIBase::UpdateVolumeToolTip()
1452 {
1453 m_tool_tip.UpdateTipText(GetVolumeTooltipString(), m_pMainWnd, BTN_VOLUME + GetToolTipIdOffset());
1454 }
1455
UpdatePlaylistBtnToolTip()1456 void CPlayerUIBase::UpdatePlaylistBtnToolTip()
1457 {
1458 wstring tool_tip = theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAYLIST_SHOW_HIDE");
1459 if (theApp.m_media_lib_setting_data.playlist_btn_for_float_playlist)
1460 tool_tip += GetCmdShortcutKeyForTooltips(ID_FLOAT_PLAYLIST).GetString();
1461 else
1462 tool_tip += GetCmdShortcutKeyForTooltips(ID_SHOW_PLAYLIST).GetString();
1463 UpdateMouseToolTip(BTN_SHOW_PLAYLIST, tool_tip.c_str());
1464 }
1465
UpdateDarkLightModeBtnToolTip()1466 void CPlayerUIBase::UpdateDarkLightModeBtnToolTip()
1467 {
1468 wstring tip_str;
1469 if (theApp.m_app_setting_data.dark_mode)
1470 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_DARK_LIGHT_TO_LIGHT_MODE");
1471 else
1472 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_DARK_LIGHT_TO_DARK_MODE");
1473 tip_str += GetCmdShortcutKeyForTooltips(ID_DARK_MODE).GetString();
1474 UpdateMouseToolTip(BTN_DARK_LIGHT, tip_str.c_str());
1475 UpdateMouseToolTip(BTN_DARK_LIGHT_TITLE_BAR, tip_str.c_str());
1476 }
1477
UpdateToolTipPositionLater()1478 void CPlayerUIBase::UpdateToolTipPositionLater()
1479 {
1480 m_need_update_tooltip_pos = true;
1481 }
1482
UpdateToolTipPosition()1483 void CPlayerUIBase::UpdateToolTipPosition()
1484 {
1485 for (const auto& btn : m_buttons)
1486 {
1487 m_tool_tip.SetToolRect(m_pMainWnd, btn.first + GetToolTipIdOffset(), btn.second.rect);
1488 }
1489 }
1490
ShowUiTipInfo(const std::wstring & info)1491 void CPlayerUIBase::ShowUiTipInfo(const std::wstring& info)
1492 {
1493 m_show_ui_tip_info = true;
1494 m_ui_tip_info = info;
1495 KillTimer(theApp.m_pMainWnd->GetSafeHwnd(), UI_TIP_INFO_TIMER_ID);
1496
1497 //设置一个定时器,5秒后m_show_ui_tip_info变为false
1498 SetTimer(theApp.m_pMainWnd->GetSafeHwnd(), UI_TIP_INFO_TIMER_ID, 5000, [](HWND Arg1, UINT Arg2, UINT_PTR Arg3, DWORD Arg4) {
1499 KillTimer(theApp.m_pMainWnd->GetSafeHwnd(), UI_TIP_INFO_TIMER_ID);
1500 m_show_ui_tip_info = false;
1501 });
1502 }
1503
SetRepeatModeToolTipText()1504 void CPlayerUIBase::SetRepeatModeToolTipText()
1505 {
1506 wstring mode_str;
1507 auto repeat_mode = CPlayer::GetInstance().GetRepeatMode();
1508 switch (repeat_mode)
1509 {
1510 case RM_PLAY_ORDER: mode_str = theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_ORDER"); break;
1511 case RM_PLAY_SHUFFLE: mode_str = theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_SHUFFLE"); break;
1512 case RM_PLAY_RANDOM: mode_str = theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_RANDOM"); break;
1513 case RM_LOOP_PLAYLIST: mode_str = theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_PLAYLIST"); break;
1514 case RM_LOOP_TRACK: mode_str = theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_TRACK"); break;
1515 case RM_PLAY_TRACK: mode_str = theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_ONCE"); break;
1516 default: mode_str = L"<repeat mode error>";
1517 }
1518 m_repeat_mode_tip = theApp.m_str_table.LoadText(L"UI_TIP_REPEAT_MODE") + L" (M): " + mode_str;
1519 }
1520
SetSongInfoToolTipText()1521 void CPlayerUIBase::SetSongInfoToolTipText()
1522 {
1523 const SongInfo& songInfo = CPlayer::GetInstance().GetCurrentSongInfo();
1524
1525 m_info_tip = theApp.m_str_table.LoadText(L"UI_TIP_BTN_PROPERTY") + GetCmdShortcutKeyForTooltips(ID_SONG_INFO).GetString() + L"\r\n";
1526 m_info_tip += theApp.m_str_table.LoadText(L"TXT_TITLE") + L": " + songInfo.GetTitle() + L"\r\n";
1527 m_info_tip += theApp.m_str_table.LoadText(L"TXT_ARTIST") + L": " + songInfo.GetArtist() + L"\r\n";
1528 m_info_tip += theApp.m_str_table.LoadText(L"TXT_ALBUM") + L": " + songInfo.GetAlbum();
1529 }
1530
SetCoverToolTipText()1531 void CPlayerUIBase::SetCoverToolTipText()
1532 {
1533 if (theApp.m_nc_setting_data.show_cover_tip && theApp.m_app_setting_data.show_album_cover && CPlayer::GetInstance().AlbumCoverExist())
1534 {
1535 if (CPlayer::GetInstance().IsInnerCover())
1536 m_cover_tip = theApp.m_str_table.LoadTextFormat(L"UI_TIP_COVER_INNER", { CPlayer::GetInstance().GetAlbumCoverType() });
1537 else
1538 m_cover_tip = theApp.m_str_table.LoadTextFormat(L"UI_TIP_COVER_OUT", { CPlayer::GetInstance().GetAlbumCoverPath() });
1539 }
1540 else
1541 m_cover_tip.clear();
1542 }
1543
Margin() const1544 int CPlayerUIBase::Margin() const
1545 {
1546 int margin = m_layout.margin;
1547 if (m_ui_data.full_screen && IsDrawLargeIcon())
1548 margin = static_cast<int>(margin * CONSTVAL::FULL_SCREEN_ZOOM_FACTOR * 1.5);
1549
1550 return margin;
1551 }
1552
EdgeMargin(bool x) const1553 int CPlayerUIBase::EdgeMargin(bool x) const
1554 {
1555 /*全屏时界面外侧边距的计算
1556 边距 = 屏幕像素值 x 屏幕宽度的英寸值 / 常数
1557 此计算方法可以确保边距占屏幕宽度的比例与屏幕宽度的英寸值成正比,即界面看起来越空旷,外侧边距就越大
1558 最后取以上值和theApp.DPI(40)两者中较大的值。
1559 */
1560 if (m_ui_data.full_screen && IsDrawLargeIcon())
1561 {
1562 int draw_size = (x ? m_draw_rect.Width() : m_draw_rect.Height());
1563 int margin = draw_size * draw_size / theApp.GetDPI() / 300;
1564 return max(theApp.DPI(40), margin);
1565 }
1566 else
1567 return m_layout.margin;
1568 }
1569
WidthThreshold() const1570 int CPlayerUIBase::WidthThreshold() const
1571 {
1572 int width = m_layout.width_threshold;
1573 if (m_ui_data.full_screen)
1574 width = static_cast<int>(width * CONSTVAL::FULL_SCREEN_ZOOM_FACTOR);
1575
1576 return width;
1577 }
1578
DrawAreaHeight() const1579 int CPlayerUIBase::DrawAreaHeight() const
1580 {
1581 int info_height = m_layout.info_height;
1582 if (m_ui_data.full_screen)
1583 info_height = static_cast<int>(info_height * CONSTVAL::FULL_SCREEN_ZOOM_FACTOR) + 2 * EdgeMargin();
1584 else if (!theApp.m_app_setting_data.show_window_frame)
1585 info_height += m_layout.titlabar_height;
1586
1587 return info_height;
1588 }
1589
TopRightButtonsWidth() const1590 int CPlayerUIBase::TopRightButtonsWidth() const
1591 {
1592 return m_top_right_buttons_width;
1593 }
1594
PointInControlArea(CPoint point) const1595 bool CPlayerUIBase::PointInControlArea(CPoint point) const
1596 {
1597 bool point_in_control = false;
1598 for (const auto& btn : m_buttons)
1599 {
1600 if (btn.first != BTN_COVER)
1601 point_in_control |= (btn.second.rect.PtInRect(point) != FALSE);
1602 }
1603 return point_in_control;
1604 }
1605
PointInTitlebarArea(CPoint point) const1606 bool CPlayerUIBase::PointInTitlebarArea(CPoint point) const
1607 {
1608 if (!IsDrawTitleBar())
1609 return false;
1610
1611 CRect rect_titlebar = m_draw_rect;
1612 rect_titlebar.bottom = rect_titlebar.top + m_layout.titlabar_height;
1613 return (rect_titlebar.PtInRect(point) != FALSE);
1614 }
1615
PointInAppIconArea(CPoint point) const1616 bool CPlayerUIBase::PointInAppIconArea(CPoint point) const
1617 {
1618 if (!IsDrawTitleBar())
1619 return false;
1620
1621 CRect rect_app_icon{};
1622 rect_app_icon.right = rect_app_icon.bottom = m_layout.titlabar_height;
1623 return (rect_app_icon.PtInRect(point) != FALSE);
1624 }
1625
PointInMenubarArea(CPoint point) const1626 bool CPlayerUIBase::PointInMenubarArea(CPoint point) const
1627 {
1628 if (!IsDrawMenuBar())
1629 return false;
1630
1631 CRect rect_menubar = m_draw_rect;
1632 rect_menubar.top = m_draw_rect.top + m_layout.titlabar_height;
1633 rect_menubar.bottom = rect_menubar.top + m_layout.menubar_height;
1634 return (rect_menubar.PtInRect(point) != FALSE);
1635
1636 }
1637
IsDrawBackgroundAlpha() const1638 bool CPlayerUIBase::IsDrawBackgroundAlpha() const
1639 {
1640 return theApp.m_app_setting_data.enable_background && (CPlayer::GetInstance().AlbumCoverExist() || !m_ui_data.default_background.IsNull());
1641 }
1642
IsDrawStatusBar() const1643 bool CPlayerUIBase::IsDrawStatusBar() const
1644 {
1645 return CPlayerUIHelper::IsDrawStatusBar();
1646 }
1647
IsDrawTitleBar() const1648 bool CPlayerUIBase::IsDrawTitleBar() const
1649 {
1650 return !theApp.m_app_setting_data.show_window_frame && !m_ui_data.full_screen;
1651 }
1652
IsDrawMenuBar() const1653 bool CPlayerUIBase::IsDrawMenuBar() const
1654 {
1655 return m_ui_data.ShowUiMenuBar();
1656 }
1657
GetDisplayFormatString()1658 wstring CPlayerUIBase::GetDisplayFormatString()
1659 {
1660 wstring result;
1661 int chans = CPlayer::GetInstance().GetChannels();
1662 int freq = CPlayer::GetInstance().GetFreq();
1663 wstring chans_str = CSongInfoHelper::GetChannelsString(static_cast<BYTE>(chans));
1664 wchar_t buff[64];
1665 if (!CPlayer::GetInstance().IsMidi())
1666 swprintf_s(buff, L"%s %.1fkHz %dkbps %s", CPlayer::GetInstance().GetCurrentFileType().c_str(), freq / 1000.0f, CPlayer::GetInstance().GetCurrentSongInfo().bitrate, chans_str.c_str());
1667 else
1668 swprintf_s(buff, L"%s %.1fkHz %s", CPlayer::GetInstance().GetCurrentFileType().c_str(), freq / 1000.0f, chans_str.c_str());
1669 result = buff;
1670 if (CPlayer::GetInstance().IsMidi())
1671 {
1672 const MidiInfo& midi_info{ CPlayer::GetInstance().GetMidiInfo() };
1673 swprintf_s(buff, L" %dbpm (%d/%d)", midi_info.speed, midi_info.midi_position, midi_info.midi_length);
1674 result += buff;
1675 }
1676 return result;
1677
1678 }
1679
GetVolumeTooltipString()1680 CString CPlayerUIBase::GetVolumeTooltipString()
1681 {
1682 static const wstring& mute_str = theApp.m_str_table.LoadText(L"UI_TXT_VOLUME_MUTE");
1683 static const wstring& volume_adjust = theApp.m_str_table.LoadText(L"UI_TIP_VOLUME_MOUSE_WHEEL_ADJUST");
1684 wstring tooltip;
1685 if (CPlayer::GetInstance().GetVolume() <= 0)
1686 tooltip = theApp.m_str_table.LoadTextFormat(L"UI_TXT_VOLUME", { mute_str, L"" });
1687 else
1688 tooltip = theApp.m_str_table.LoadTextFormat(L"UI_TXT_VOLUME", { CPlayer::GetInstance().GetVolume(), L"%" });
1689 tooltip += L"\r\n" + volume_adjust;
1690 return CString(tooltip.c_str());
1691 }
1692
DPI(int pixel) const1693 int CPlayerUIBase::DPI(int pixel) const
1694 {
1695 if (m_ui_data.full_screen && IsDrawLargeIcon())
1696 return static_cast<int>(theApp.DPI(pixel) * CONSTVAL::FULL_SCREEN_ZOOM_FACTOR);
1697 else
1698 return theApp.DPI(pixel);
1699 }
1700
DPI(double pixel) const1701 int CPlayerUIBase::DPI(double pixel) const
1702 {
1703 if (m_ui_data.full_screen && IsDrawLargeIcon())
1704 return static_cast<int>(theApp.DPI(pixel) * CONSTVAL::FULL_SCREEN_ZOOM_FACTOR);
1705 else
1706 return theApp.DPI(pixel);
1707 }
1708
DPIDouble(double pixel)1709 double CPlayerUIBase::DPIDouble(double pixel)
1710 {
1711 double rtn_val = static_cast<double>(theApp.GetDPI()) * pixel / 96;
1712 if (m_ui_data.full_screen && IsDrawLargeIcon())
1713 rtn_val *= CONSTVAL::FULL_SCREEN_ZOOM_FACTOR;
1714 return rtn_val;
1715 }
1716
GetScrollTextPixel(bool slower)1717 double CPlayerUIBase::GetScrollTextPixel(bool slower)
1718 {
1719 //界面刷新频率越高,即界面刷新时间间隔越小,则每次滚动的像素值就要越小
1720 double pixel{};
1721 if (slower)
1722 pixel = static_cast<double>(theApp.m_app_setting_data.ui_refresh_interval) * 0.01 + 0.2;
1723 else
1724 pixel = static_cast<double>(theApp.m_app_setting_data.ui_refresh_interval) * 0.0125 + 0.2;
1725 pixel = DPIDouble(pixel);
1726 if (pixel < 0.1)
1727 pixel = 0.1;
1728 if (pixel > 0.5 && pixel < 1)
1729 pixel = 1;
1730 return pixel;
1731 }
1732
CalculateRoundRectRadius(const CRect & rect)1733 int CPlayerUIBase::CalculateRoundRectRadius(const CRect& rect)
1734 {
1735 int radius{ min(rect.Width(), rect.Height()) / 6 };
1736 if (radius < DPI(3))
1737 radius = DPI(3);
1738 if (radius > DPI(8))
1739 radius = DPI(8);
1740 return radius;
1741 }
1742
IsDrawLargeIcon() const1743 bool CPlayerUIBase::IsDrawLargeIcon() const
1744 {
1745 return theApp.m_ui_data.full_screen;
1746 }
1747
IsMiniMode() const1748 bool CPlayerUIBase::IsMiniMode() const
1749 {
1750 return dynamic_cast<const CMiniModeUserUi*>(this) != nullptr;
1751 }
1752
IsDrawNarrowMode() const1753 bool CPlayerUIBase::IsDrawNarrowMode() const
1754 {
1755 if (!m_ui_data.show_playlist)
1756 return false;
1757 else
1758 return m_ui_data.narrow_mode;
1759 }
1760
DrawVolumnAdjBtn()1761 void CPlayerUIBase::DrawVolumnAdjBtn()
1762 {
1763 if (m_show_volume_adj)
1764 {
1765 CRect& volume_down_rect = m_buttons[BTN_VOLUME_DOWN].rect;
1766 CRect& volume_up_rect = m_buttons[BTN_VOLUME_UP].rect;
1767
1768 //判断音量调整按钮是否会超出界面之外,如果是,则将其移动至界面内
1769 int x_offset{}, y_offset{}; //移动的x和y偏移量
1770 CRect rect_text; //音量文本的区域
1771 CString volume_str{};
1772 if (!m_show_volume_text)
1773 {
1774 //如果不显示音量文本,则在音量调整按钮旁边显示音量。在这里计算文本的位置
1775 rect_text = m_buttons[BTN_VOLUME_UP].rect;
1776 if (CPlayer::GetInstance().GetVolume() <= 0)
1777 volume_str = theApp.m_str_table.LoadText(L"UI_TXT_VOLUME_MUTE").c_str();
1778 else
1779 volume_str.Format(_T("%d%%"), CPlayer::GetInstance().GetVolume());
1780 int width{ m_draw.GetTextExtent(volume_str).cx };
1781 rect_text.left = rect_text.right + DPI(2);
1782 rect_text.right = rect_text.left + width;
1783
1784 if (rect_text.right > m_draw_rect.right)
1785 x_offset = m_draw_rect.right - rect_text.right;
1786 if (rect_text.bottom > m_draw_rect.bottom)
1787 y_offset = m_draw_rect.bottom - rect_text.bottom;
1788 }
1789 else
1790 {
1791 if (volume_up_rect.right > m_draw_rect.right)
1792 x_offset = m_draw_rect.right - volume_up_rect.right;
1793 if (volume_up_rect.bottom > m_draw_rect.bottom)
1794 y_offset = m_draw_rect.bottom - volume_up_rect.bottom;
1795 }
1796
1797 if (x_offset != 0)
1798 {
1799 volume_up_rect.MoveToX(volume_up_rect.left + x_offset);
1800 volume_down_rect.MoveToX(volume_down_rect.left + x_offset);
1801 rect_text.MoveToX(rect_text.left + x_offset);
1802 }
1803 if (y_offset != 0)
1804 {
1805 volume_up_rect.MoveToY(volume_up_rect.top + y_offset);
1806 volume_down_rect.MoveToY(volume_down_rect.top + y_offset);
1807 rect_text.MoveToY(rect_text.top + y_offset);
1808 }
1809
1810 BYTE alpha;
1811 if (IsDrawBackgroundAlpha())
1812 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency);
1813 else
1814 alpha = 255;
1815
1816 COLORREF btn_up_back_color, btn_down_back_color;
1817
1818 if (m_buttons[BTN_VOLUME_UP].pressed && m_buttons[BTN_VOLUME_UP].hover)
1819 btn_up_back_color = m_colors.color_button_pressed;
1820 else if (m_buttons[BTN_VOLUME_UP].hover)
1821 btn_up_back_color = m_colors.color_button_hover;
1822 else
1823 btn_up_back_color = m_colors.color_text_2;
1824
1825 if (m_buttons[BTN_VOLUME_DOWN].pressed && m_buttons[BTN_VOLUME_DOWN].hover)
1826 btn_down_back_color = m_colors.color_button_pressed;
1827 else if (m_buttons[BTN_VOLUME_DOWN].hover)
1828 btn_down_back_color = m_colors.color_button_hover;
1829 else
1830 btn_down_back_color = m_colors.color_text_2;
1831
1832 if (!theApp.m_app_setting_data.button_round_corners)
1833 {
1834 m_draw.FillAlphaRect(volume_up_rect, btn_up_back_color, alpha);
1835 m_draw.FillAlphaRect(volume_down_rect, btn_down_back_color, alpha);
1836 }
1837 else
1838 {
1839 CRect rc_buttons{ volume_up_rect | volume_down_rect };
1840 DrawAreaGuard guard(&m_draw, rc_buttons);
1841 m_draw.DrawRoundRect(rc_buttons, m_colors.color_text_2, CalculateRoundRectRadius(rc_buttons), alpha);
1842 if (m_buttons[BTN_VOLUME_UP].pressed || m_buttons[BTN_VOLUME_UP].hover)
1843 m_draw.DrawRoundRect(volume_up_rect, btn_up_back_color, CalculateRoundRectRadius(volume_up_rect), alpha);
1844 if (m_buttons[BTN_VOLUME_DOWN].pressed || m_buttons[BTN_VOLUME_DOWN].hover)
1845 m_draw.DrawRoundRect(volume_down_rect, btn_down_back_color, CalculateRoundRectRadius(volume_down_rect), alpha);
1846 }
1847
1848 if (m_buttons[BTN_VOLUME_DOWN].pressed)
1849 volume_down_rect.MoveToXY(volume_down_rect.left + theApp.DPI(1), volume_down_rect.top + theApp.DPI(1));
1850 if (m_buttons[BTN_VOLUME_UP].pressed)
1851 volume_up_rect.MoveToXY(volume_up_rect.left + theApp.DPI(1), volume_up_rect.top + theApp.DPI(1));
1852
1853 m_draw.DrawWindowText(volume_down_rect, L"-", ColorTable::WHITE, Alignment::CENTER);
1854 m_draw.DrawWindowText(volume_up_rect, L"+", ColorTable::WHITE, Alignment::CENTER);
1855
1856 //如果不显示音量文本且显示了音量调整按钮,则在按钮旁边显示音量
1857 if (!m_show_volume_text)
1858 {
1859 m_draw.DrawWindowText(rect_text, volume_str, m_colors.color_text);
1860 }
1861 }
1862 else
1863 {
1864 m_buttons[BTN_VOLUME_UP].rect = CRect();
1865 m_buttons[BTN_VOLUME_DOWN].rect = CRect();
1866 }
1867 }
1868
DrawControlBar(CRect rect,bool draw_switch_display_btn)1869 void CPlayerUIBase::DrawControlBar(CRect rect, bool draw_switch_display_btn)
1870 {
1871 bool progress_on_top = rect.Width() < m_progress_on_top_threshold;
1872 const int progress_height = DPI(4);
1873 CRect progress_rect;
1874 if (progress_on_top)
1875 {
1876 progress_rect = rect;
1877 int progressbar_height = rect.Height() / 3;
1878 progress_rect.bottom = progress_rect.top + progressbar_height;
1879 DrawProgressBar(progress_rect);
1880 rect.top = progress_rect.bottom;
1881 }
1882
1883 //绘制播放控制按钮
1884 const int btn_width = DPI(36);
1885 const int btn_height = min(rect.Height(), btn_width);
1886
1887 CRect rc_btn{ CPoint(rect.left, rect.top + (rect.Height() - btn_height) / 2), CSize(btn_width, btn_height) };
1888 DrawUIButton(rc_btn, BTN_STOP, true);
1889
1890 rc_btn.MoveToX(rc_btn.right);
1891 DrawUIButton(rc_btn, BTN_PREVIOUS, true);
1892
1893 rc_btn.MoveToX(rc_btn.right);
1894 DrawUIButton(rc_btn, BTN_PLAY_PAUSE, true);
1895
1896 rc_btn.MoveToX(rc_btn.right);
1897 DrawUIButton(rc_btn, BTN_NEXT, true);
1898
1899 int progressbar_left = rc_btn.right + Margin();
1900
1901 //绘制右侧按钮
1902 const int btn_side = DPI(24);
1903 rc_btn.right = rect.right;
1904 rc_btn.left = rc_btn.right - btn_side;
1905 rc_btn.top = rect.top + (rect.Height() - btn_side) / 2;
1906 rc_btn.bottom = rc_btn.top + btn_side;
1907 DrawControlBarBtn(rc_btn, BTN_SHOW_PLAYLIST);
1908
1909 rc_btn.MoveToX(rc_btn.left - btn_side);
1910 m_buttons[BTN_MEDIA_LIB].enable = !CPlayer::GetInstance().m_loading;
1911 DrawControlBarBtn(rc_btn, BTN_MEDIA_LIB);
1912
1913 if (draw_switch_display_btn)
1914 {
1915 rc_btn.MoveToX(rc_btn.left - btn_side);
1916 DrawControlBarBtn(rc_btn, BTN_SWITCH_DISPLAY);
1917 }
1918
1919 rc_btn.MoveToX(rc_btn.left - btn_side);
1920 DrawControlBarBtn(rc_btn, BTN_ADD_TO_PLAYLIST);
1921
1922 rc_btn.MoveToX(rc_btn.left - btn_side);
1923 DrawControlBarBtn(rc_btn, BTN_FAVOURITE);
1924
1925 if (!progress_on_top)
1926 {
1927 progress_rect = rect;
1928 progress_rect.left = progressbar_left;
1929 progress_rect.right = rc_btn.left - Margin();
1930 DrawProgressBar(progress_rect);
1931 }
1932 }
1933
DrawProgressBar(CRect rect,bool play_time_both_side)1934 void CPlayerUIBase::DrawProgressBar(CRect rect, bool play_time_both_side)
1935 {
1936 //绘制播放时间
1937 bool draw_progress_time{ rect.Width() > DPI(110) };
1938 CRect progress_rect{ rect };
1939 if (draw_progress_time)
1940 {
1941 UiFontGuard set_font(this, 8);
1942 if (play_time_both_side)
1943 {
1944 CRect rc_time_left{ rect }, rc_time_right{ rect };
1945 std::wstring str_cur_time = Time(CPlayer::GetInstance().GetCurrentPosition()).toString(false);
1946 std::wstring str_song_length = Time(CPlayer::GetInstance().GetSongLength()).toString(false);
1947 int left_width = m_draw.GetTextExtent(str_cur_time.c_str()).cx;
1948 int right_width = m_draw.GetTextExtent(str_song_length.c_str()).cx;
1949 rc_time_left.right = rc_time_left.left + left_width;
1950 rc_time_right.left = rc_time_right.right - right_width;
1951 m_draw.DrawWindowText(rc_time_left, str_cur_time.c_str(), m_colors.color_text);
1952 m_draw.DrawWindowText(rc_time_right, str_song_length.c_str(), m_colors.color_text);
1953 progress_rect.left += (left_width + Margin());
1954 progress_rect.right -= (right_width + Margin());
1955 }
1956 else
1957 {
1958 CRect rc_time = rect;
1959 wstring strTime = CPlayer::GetInstance().GetTimeString();
1960
1961 CSize strSize = m_draw.GetTextExtent(strTime.c_str());
1962 rc_time.left = rc_time.right - strSize.cx;
1963 //rc_time.InflateRect(0, DPI(2));
1964 rc_time.top -= DPI(1);
1965 m_draw.DrawWindowText(rc_time, strTime.c_str(), m_colors.color_text);
1966 progress_rect.right = rc_time.left - Margin();
1967 }
1968 }
1969
1970 //绘制进度条
1971 DrawProgess(progress_rect);
1972 }
1973
DrawProgess(CRect rect)1974 void CPlayerUIBase::DrawProgess(CRect rect)
1975 {
1976 //进度条的高度
1977 int progress_height = min(DPI(4), rect.Height());
1978 rect.top = rect.top + (rect.Height() - progress_height) / 2;
1979 rect.bottom = rect.top + progress_height;
1980
1981 if (IsDrawBackgroundAlpha())
1982 m_draw.FillAlphaRect(rect, m_colors.color_spectrum_back, ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3);
1983 else
1984 m_draw.FillRect(rect, m_colors.color_spectrum_back);
1985
1986 m_buttons[BTN_PROGRESS].rect = DrawAreaToClient(rect, m_draw_rect);
1987 m_buttons[BTN_PROGRESS].rect.InflateRect(0, DPI(3));
1988
1989 double progress = static_cast<double>(CPlayer::GetInstance().GetCurrentPosition()) / CPlayer::GetInstance().GetSongLength();
1990 if (progress > 1)
1991 progress = 1;
1992 double progress_width_double{ progress * rect.Width() };
1993 int progress_width{ static_cast<int>(progress_width_double) };
1994 CRect played_rect = rect;
1995 played_rect.right = played_rect.left + progress_width;
1996 if (played_rect.right > played_rect.left)
1997 m_draw.FillRect(played_rect, m_colors.color_spectrum);
1998 //绘制进度条最右侧一像素
1999 //进度条最右侧一像素根据当前进度计算出透明度,以使得进度条的变化更加平滑
2000 BYTE alpha{ static_cast<BYTE>((progress_width_double - progress_width) * 256) };
2001 played_rect.left = played_rect.right;
2002 played_rect.right = played_rect.left + 1;
2003 m_draw.FillAlphaRect(played_rect, m_colors.color_spectrum, alpha);
2004
2005 //绘制AB重复的标记
2006 auto ab_repeat_mode = CPlayer::GetInstance().GetABRepeatMode();
2007 if (ab_repeat_mode == CPlayer::AM_A_SELECTED || ab_repeat_mode == CPlayer::AM_AB_REPEAT)
2008 {
2009 CFont* pOldFont = m_draw.GetFont();
2010 //设置字体
2011 m_draw.SetFont(&theApp.m_font_set.GetFontBySize(8).GetFont(theApp.m_ui_data.full_screen)); //AB重复使用小一号字体,即播放时间的字体
2012
2013 double a_point_progres = static_cast<double>(CPlayer::GetInstance().GetARepeatPosition().toInt()) / CPlayer::GetInstance().GetSongLength();
2014 double b_point_progres = static_cast<double>(CPlayer::GetInstance().GetBRepeatPosition().toInt()) / CPlayer::GetInstance().GetSongLength();
2015 CRect rect_draw = rect;
2016 rect_draw.bottom += DPI(12);
2017 DrawAreaGuard guard(&m_draw, rect_draw);
2018 CPoint point1, point2;
2019 //绘制A点标记
2020 point1.x = point2.x = rect.left + static_cast<int>(a_point_progres * rect.Width());
2021 point1.y = rect.top - DPI(2);
2022 point2.y = rect.bottom + DPI(2);
2023 m_draw.DrawLine(point1, point2, m_colors.color_text, DPI(1), false);
2024 CRect rect_text;
2025 rect_text.top = point2.y;
2026 rect_text.left = point1.x - DPI(8);
2027 rect_text.right = point1.x + DPI(8);
2028 rect_text.bottom = rect_text.top + DPI(12);
2029 m_draw.DrawWindowText(rect_text, _T("A"), m_colors.color_text, Alignment::CENTER, true);
2030 //绘制B点标记
2031 if (ab_repeat_mode == CPlayer::AM_AB_REPEAT)
2032 {
2033 point1.x = point2.x = rect.left + static_cast<int>(b_point_progres * rect.Width());
2034 m_draw.DrawLine(point1, point2, m_colors.color_text, DPI(1), false);
2035 rect_text.MoveToX(point1.x - DPI(8));
2036 m_draw.DrawWindowText(rect_text, _T("B"), m_colors.color_text, Alignment::CENTER, true);
2037 }
2038 //恢复字体
2039 m_draw.SetFont(pOldFont);
2040 }
2041 }
2042
DrawTranslateButton(CRect rect)2043 void CPlayerUIBase::DrawTranslateButton(CRect rect)
2044 {
2045 static const wstring& btn_str = theApp.m_str_table.LoadText(L"UI_TXT_BTN_TRANSLATE");
2046 m_buttons[BTN_TRANSLATE].enable = !CPlayer::GetInstance().m_Lyrics.IsEmpty();
2047 DrawTextButton(rect, BTN_TRANSLATE, btn_str.c_str(), theApp.m_lyric_setting_data.show_translate);
2048 }
2049
DrawDesktopLyricButton(CRect rect)2050 void CPlayerUIBase::DrawDesktopLyricButton(CRect rect)
2051 {
2052 static const wstring& btn_str = theApp.m_str_table.LoadText(L"UI_TXT_BTN_DESKTOP_LYRIC");
2053 DrawTextButton(rect, BTN_LRYIC, btn_str.c_str(), theApp.m_lyric_setting_data.show_desktop_lyric);
2054 }
2055
DrawKaraokeButton(CRect rect)2056 void CPlayerUIBase::DrawKaraokeButton(CRect rect)
2057 {
2058 m_buttons[BTN_KARAOKE].enable = !CPlayer::GetInstance().m_Lyrics.IsEmpty();
2059 //如果是卡拉OK样式显示歌词,则按钮显示为选中状态
2060 DrawUIButton(rect, BTN_KARAOKE, false, false, 9, theApp.m_lyric_setting_data.lyric_karaoke_disp);
2061 }
2062
DrawTopRightIcons()2063 void CPlayerUIBase::DrawTopRightIcons()
2064 {
2065 if (!theApp.m_app_setting_data.show_window_frame && !m_ui_data.full_screen)
2066 return;
2067
2068 const int icon_size = DPI(28);
2069 CRect rect_btn;
2070 rect_btn.right = m_draw_rect.right - EdgeMargin(true);
2071 rect_btn.top = EdgeMargin(false);
2072 rect_btn.bottom = rect_btn.top + icon_size;
2073 rect_btn.left = rect_btn.right - icon_size;
2074 int icon_num{};
2075 //绘制“全屏”图标(全屏模式下总是显示“退出全屏”图标)
2076 if (theApp.m_app_setting_data.show_fullscreen_btn_in_titlebar || m_ui_data.full_screen)
2077 {
2078 DrawUIButton(rect_btn, BTN_FULL_SCREEN_TITLEBAR);
2079 icon_num++;
2080 }
2081 else
2082 {
2083 m_buttons[BTN_FULL_SCREEN_TITLEBAR].rect.SetRectEmpty();
2084 rect_btn.MoveToX(rect_btn.left + icon_size + DPI(4)); //右侧第一个图标不显示,则将按钮的位置向右移动一个图标的位置
2085 }
2086
2087 //迷你模式图标
2088 if (theApp.m_app_setting_data.show_minimode_btn_in_titlebar)
2089 {
2090 rect_btn.MoveToX(rect_btn.left - icon_size - DPI(4));
2091 DrawUIButton(rect_btn, BTN_MINI_TITLEBAR);
2092 icon_num++;
2093 }
2094 else
2095 {
2096 m_buttons[BTN_MINI_TITLEBAR].rect.SetRectEmpty();
2097 }
2098 //“深色模式/浅色模式”按钮
2099 if (theApp.m_app_setting_data.show_dark_light_btn_in_titlebar)
2100 {
2101 rect_btn.MoveToX(rect_btn.left - icon_size - DPI(4));
2102 DrawUIButton(rect_btn, BTN_DARK_LIGHT_TITLE_BAR);
2103 icon_num++;
2104 }
2105 else
2106 {
2107 m_buttons[BTN_DARK_LIGHT_TITLE_BAR].rect.SetRectEmpty();
2108 }
2109
2110 //切换界面图标
2111 if (theApp.m_app_setting_data.show_skin_btn_in_titlebar)
2112 {
2113 rect_btn.MoveToX(rect_btn.left - icon_size - DPI(4));
2114 DrawUIButton(rect_btn, BTN_SKIN_TITLEBAR);
2115 icon_num++;
2116 }
2117 else
2118 {
2119 m_buttons[BTN_SKIN_TITLEBAR].rect.SetRectEmpty();
2120 }
2121 //设置图标
2122 if (theApp.m_app_setting_data.show_settings_btn_in_titlebar)
2123 {
2124 rect_btn.MoveToX(rect_btn.left - icon_size - DPI(4));
2125 DrawUIButton(rect_btn, BTN_SETTING_TITLEBAR);
2126 icon_num++;
2127 }
2128 else
2129 {
2130 m_buttons[BTN_SETTING_TITLEBAR].rect.SetRectEmpty();
2131 }
2132 //绘制“主菜单”图标
2133 if (!m_ui_data.show_menu_bar || m_ui_data.full_screen)
2134 {
2135 rect_btn.MoveToX(rect_btn.left - icon_size - DPI(4));
2136 DrawUIButton(rect_btn, BTN_MENU_TITLEBAR);
2137 icon_num++;
2138 }
2139 else
2140 {
2141 m_buttons[BTN_MENU_TITLEBAR].rect.SetRectEmpty();
2142 }
2143 m_top_right_buttons_width = icon_num * (icon_size + DPI(4));
2144 }
2145
DrawCurrentTime()2146 void CPlayerUIBase::DrawCurrentTime()
2147 {
2148 wchar_t buff[64];
2149 CRect rc_tmp;
2150 SYSTEMTIME curTime;
2151 GetLocalTime(&curTime);
2152 std::swprintf(buff, 64, L"%d:%.2d", curTime.wHour, curTime.wMinute);
2153 CSize size = m_draw.GetTextExtent(buff);
2154 rc_tmp.top = theApp.DPI(4);
2155 rc_tmp.right = m_draw_rect.right - theApp.DPI(4);
2156 rc_tmp.bottom = rc_tmp.top + size.cy;
2157 rc_tmp.left = rc_tmp.right - size.cx;
2158 m_draw.SetFont(&theApp.m_font_set.GetFontBySize(8).GetFont(m_ui_data.full_screen));
2159 m_draw.DrawWindowText(rc_tmp, buff, m_colors.color_text);
2160 m_draw.SetFont(&theApp.m_font_set.GetFontBySize(9).GetFont(theApp.m_ui_data.full_screen));
2161 }
2162
DrawStatusBar(CRect rect,bool reset)2163 void CPlayerUIBase::DrawStatusBar(CRect rect, bool reset)
2164 {
2165 bool draw_background{ IsDrawBackgroundAlpha() };
2166 //绘制背景
2167 BYTE alpha;
2168 if (theApp.m_app_setting_data.dark_mode)
2169 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) / 2;
2170 else
2171 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
2172
2173 if (draw_background)
2174 m_draw.FillAlphaRect(rect, m_colors.color_control_bar_back, alpha);
2175 else
2176 m_draw.FillRect(rect, m_colors.color_control_bar_back);
2177
2178 //显示帧率
2179 if (theApp.m_app_setting_data.show_fps)
2180 {
2181 CRect rc_fps{ rect };
2182 rc_fps.left = rc_fps.right - DPI(36);
2183 CFont* pOldFont = m_draw.SetFont(&theApp.m_font_set.GetFontBySize(8).GetFont(theApp.m_ui_data.full_screen));
2184 CString str_info;
2185 str_info.Format(_T("%dFPS"), theApp.m_fps);
2186 m_draw.DrawWindowText(rc_fps, str_info, m_colors.color_text);
2187 m_draw.SetFont(pOldFont);
2188
2189 rect.right = rc_fps.left;
2190 }
2191
2192 rect.DeflateRect(DPI(4), 0);
2193
2194 //显示播放列表载入状态
2195 if (CPlayer::GetInstance().m_loading)
2196 {
2197 int progress_percent = CPlayer::GetInstance().m_thread_info.process_percent;
2198 //绘制进度右侧的进度百分比
2199 CRect rc_percent{ rect };
2200 rc_percent.left = rc_percent.right - DPI(24);
2201 CFont* pOldFont = m_draw.SetFont(&theApp.m_font_set.GetFontBySize(8).GetFont(theApp.m_ui_data.full_screen));
2202 CString str_info;
2203 str_info.Format(_T("%d%%"), progress_percent);
2204 m_draw.DrawWindowText(rc_percent, str_info, m_colors.color_text);
2205 m_draw.SetFont(pOldFont);
2206
2207 rect.right = rc_percent.left - DPI(4);
2208 CRect rc_tmp{ rect };
2209 //绘制进度条(进度条里面包含10格)
2210 int bar_width = DPI(4); //每一格的宽度
2211 int progress_width = (bar_width + DPI(2)) * 10 + DPI(2) * 2;
2212 rc_tmp.left = rect.right - progress_width;
2213 CRect rc_progress{ rc_tmp };
2214 rc_progress.DeflateRect(0, DPI(4));
2215 DrawAreaGuard guard(&m_draw, rc_progress);
2216 m_draw.DrawRectOutLine(rc_progress, m_colors.color_text, DPI(1), false);
2217 int bar_cnt = progress_percent / 10 + 1; //格子数
2218 int last_bar_percent = progress_percent % 10;
2219 CRect rc_bar{ rc_progress };
2220 rc_bar.DeflateRect(DPI(2), DPI(2));
2221 rc_bar.right = rc_bar.left + bar_width;
2222 int start_x_pos = rc_bar.left;
2223 for (int i = 0; i < bar_cnt; i++)
2224 {
2225 rc_bar.MoveToX(start_x_pos + i * (bar_width + DPI(2)));
2226 if (i != bar_cnt - 1)
2227 {
2228 m_draw.FillRect(rc_bar, m_colors.color_text, true);
2229 }
2230 else
2231 {
2232 BYTE alpha = ALPHA_CHG(last_bar_percent * 10);
2233 m_draw.FillAlphaRect(rc_bar, m_colors.color_text, alpha, true);
2234 }
2235 }
2236
2237 //绘制文字
2238 rc_tmp.right = rc_tmp.left - DPI(4);
2239 rc_tmp.left = rect.left;
2240 static CDrawCommon::ScrollInfo scroll_info0;
2241 wstring info = theApp.m_str_table.LoadTextFormat(L"UI_TXT_PLAYLIST_INIT_INFO", { CPlayer::GetInstance().GetSongNum() });
2242 m_draw.DrawScrollText(rc_tmp, info.c_str(), m_colors.color_text, GetScrollTextPixel(), false, scroll_info0, reset);
2243 }
2244 //显示AB重复状态
2245 else if (CPlayer::GetInstance().GetABRepeatMode() != CPlayer::AM_NONE)
2246 {
2247 wstring info;
2248 if (CPlayer::GetInstance().GetABRepeatMode() == CPlayer::AM_A_SELECTED)
2249 info = theApp.m_str_table.LoadTextFormat(L"UI_TXT_AB_REPEAT_A_SELECTED", { CPlayer::GetInstance().GetARepeatPosition().toString(false) });
2250 else if (CPlayer::GetInstance().GetABRepeatMode() == CPlayer::AM_AB_REPEAT)
2251 info = theApp.m_str_table.LoadTextFormat(L"UI_TXT_AB_REPEAT_ON", { CPlayer::GetInstance().GetARepeatPosition().toString(false), CPlayer::GetInstance().GetBRepeatPosition().toString(false) });
2252 m_draw.DrawWindowText(rect, info.c_str(), m_colors.color_text);
2253 }
2254 //显示媒体库更新状态
2255 else if (theApp.IsMeidaLibUpdating() && theApp.m_media_update_para.num_added > 0)
2256 {
2257 wstring info = theApp.m_str_table.LoadTextFormat(L"UI_TXT_MEDIA_LIB_UPDATING_INFO",
2258 { theApp.m_media_update_para.num_added, theApp.m_media_update_para.process_percent });
2259 static CDrawCommon::ScrollInfo scroll_info2;
2260 m_draw.DrawScrollText(rect, info.c_str(), m_colors.color_text, GetScrollTextPixel(), false, scroll_info2, reset);
2261 }
2262 else
2263 {
2264 //显示播放信息
2265 wstring str_info;
2266 if (CPlayer::GetInstance().IsError())
2267 str_info = CPlayer::GetInstance().GetErrorInfo();
2268 else
2269 str_info = CPlayer::GetInstance().GetPlayingState();
2270 int text_width = m_draw.GetTextExtent(str_info.c_str()).cx;
2271 CRect rect_play{ rect };
2272 rect_play.right = rect_play.left + text_width + DPI(8);
2273 m_draw.DrawWindowText(rect_play, str_info.c_str(), m_colors.color_text);
2274
2275 //显示下一个播放曲目
2276 if (theApp.m_app_setting_data.show_next_track)
2277 {
2278 static wstring str_next_track_label = theApp.m_str_table.LoadText(L"UI_TXT_NEXT_TRACK");
2279 CRect rect_next_track{ rect };
2280 rect_next_track.left = rect_play.right;
2281 rect_next_track.right = rect_next_track.left + m_draw.GetTextExtent(str_next_track_label.c_str()).cx;
2282 m_draw.DrawWindowText(rect_next_track, str_next_track_label.c_str(), m_colors.color_text);
2283
2284 rect_next_track.left = rect_next_track.right;
2285 rect_next_track.right = rect.right;
2286 wstring str_next_song;
2287 SongInfo next_song = CPlayer::GetInstance().GetNextTrack();
2288 if (next_song.IsEmpty())
2289 {
2290 if (CPlayer::GetInstance().GetRepeatMode() == RM_PLAY_RANDOM || CPlayer::GetInstance().GetRepeatMode() == RM_PLAY_SHUFFLE)
2291 str_next_song += theApp.m_str_table.LoadText(L"UI_TXT_NEXT_TRACK_RANDOM");
2292 else
2293 str_next_song += theApp.m_str_table.LoadText(L"UI_TXT_NEXT_TRACK_NONE");
2294 }
2295 else
2296 {
2297 str_next_song += CSongInfoHelper::GetDisplayStr(next_song, theApp.m_media_lib_setting_data.display_format);
2298 }
2299 static CDrawCommon::ScrollInfo scroll_info3;
2300 m_draw.DrawScrollText(rect_next_track, str_next_song.c_str(), m_colors.color_text_lable, GetScrollTextPixel(), false, scroll_info3, reset);
2301
2302 }
2303 }
2304 }
2305
DrawTitleBar(CRect rect)2306 void CPlayerUIBase::DrawTitleBar(CRect rect)
2307 {
2308 //填充标题栏背景
2309 bool draw_background{ IsDrawBackgroundAlpha() };
2310 //绘制背景
2311 BYTE alpha;
2312 if (theApp.m_app_setting_data.dark_mode)
2313 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) / 2;
2314 else
2315 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
2316
2317 if (draw_background)
2318 m_draw.FillAlphaRect(rect, m_colors.color_control_bar_back, alpha);
2319 else
2320 m_draw.FillRect(rect, m_colors.color_control_bar_back);
2321
2322 //绘制应用图标
2323 CRect rect_temp = rect;
2324 rect_temp.right = rect_temp.left + m_layout.titlabar_height;
2325 DrawUiIcon(rect_temp, IconMgr::IconType::IT_App);
2326
2327 //绘制右侧图标
2328 rect_temp = rect;
2329 rect_temp.left = rect_temp.right - theApp.DPI(30);
2330 //关闭图标
2331 DrawUIButton(rect_temp, BTN_APP_CLOSE);
2332 //最大化/还原图标
2333 if (theApp.m_app_setting_data.show_maximize_btn_in_titlebar)
2334 {
2335 rect_temp.MoveToX(rect_temp.left - rect_temp.Width());
2336 DrawUIButton(rect_temp, BTN_MAXIMIZE);
2337 }
2338 else
2339 {
2340 m_buttons[BTN_MAXIMIZE].rect = CRect();
2341 }
2342 //最小化图标
2343 if (theApp.m_app_setting_data.show_minimize_btn_in_titlebar)
2344 {
2345 rect_temp.MoveToX(rect_temp.left - rect_temp.Width());
2346 DrawUIButton(rect_temp, BTN_MINIMIZE);
2347 }
2348 else
2349 {
2350 m_buttons[BTN_MINIMIZE].rect = CRect();
2351 }
2352 //全屏模式图标
2353 if (theApp.m_app_setting_data.show_fullscreen_btn_in_titlebar)
2354 {
2355 rect_temp.MoveToX(rect_temp.left - rect_temp.Width());
2356 DrawUIButton(rect_temp, BTN_FULL_SCREEN_TITLEBAR);
2357 }
2358 else
2359 {
2360 m_buttons[BTN_FULL_SCREEN_TITLEBAR].rect = CRect();
2361 }
2362 //迷你模式图标
2363 if (theApp.m_app_setting_data.show_minimode_btn_in_titlebar)
2364 {
2365 rect_temp.MoveToX(rect_temp.left - rect_temp.Width());
2366 DrawUIButton(rect_temp, BTN_MINI_TITLEBAR);
2367 }
2368 else
2369 {
2370 m_buttons[BTN_MINI_TITLEBAR].rect = CRect();
2371 }
2372 //“深色模式/浅色模式”按钮
2373 if (theApp.m_app_setting_data.show_dark_light_btn_in_titlebar)
2374 {
2375 rect_temp.MoveToX(rect_temp.left - rect_temp.Width());
2376 DrawUIButton(rect_temp, BTN_DARK_LIGHT_TITLE_BAR);
2377 }
2378 else
2379 {
2380 m_buttons[BTN_DARK_LIGHT_TITLE_BAR].rect = CRect();
2381 }
2382 //切换界面图标
2383 if (theApp.m_app_setting_data.show_skin_btn_in_titlebar)
2384 {
2385 rect_temp.MoveToX(rect_temp.left - rect_temp.Width());
2386 DrawUIButton(rect_temp, BTN_SKIN_TITLEBAR);
2387 }
2388 else
2389 {
2390 m_buttons[BTN_SKIN_TITLEBAR].rect = CRect();
2391 }
2392 //设置图标
2393 if (theApp.m_app_setting_data.show_settings_btn_in_titlebar)
2394 {
2395 rect_temp.MoveToX(rect_temp.left - rect_temp.Width());
2396 DrawUIButton(rect_temp, BTN_SETTING_TITLEBAR);
2397 }
2398 else
2399 {
2400 m_buttons[BTN_SETTING_TITLEBAR].rect = CRect();
2401 }
2402 //主菜单图标
2403 if (!m_ui_data.ShowUiMenuBar())
2404 {
2405 rect_temp.MoveToX(rect_temp.left - rect_temp.Width());
2406 DrawUIButton(rect_temp, BTN_MENU_TITLEBAR);
2407 }
2408 else
2409 {
2410 m_buttons[BTN_MENU_TITLEBAR].rect = CRect();
2411 }
2412
2413 //绘制标题栏文本
2414 rect_temp.right = rect_temp.left;
2415 rect_temp.left = m_layout.titlabar_height;
2416 static CDrawCommon::ScrollInfo scroll_info{};
2417 m_draw.DrawScrollText(rect_temp, theApp.m_window_title.c_str(), m_colors.color_text, GetScrollTextPixel(), false, scroll_info);
2418 //m_draw.DrawWindowText(rect_temp, title.GetString(), m_colors.color_text);
2419 }
2420
GetToolTipIdOffset()2421 int CPlayerUIBase::GetToolTipIdOffset()
2422 {
2423 return GetUiIndex() * PlayerUiConstVal::BTN_MAX_NUM;
2424 }
2425
GetCmdShortcutKeyForTooltips(UINT id)2426 CString CPlayerUIBase::GetCmdShortcutKeyForTooltips(UINT id)
2427 {
2428 std::wstring shortcut_key{ theApp.m_accelerator_res.GetShortcutDescriptionById(id) };
2429 if (!shortcut_key.empty())
2430 {
2431 CString shortcut_key_tip;
2432 shortcut_key_tip.Format(_T(" (%s)"), shortcut_key.c_str());
2433 return shortcut_key_tip;
2434 }
2435 return CString();
2436 }
2437
GetVolumeRect() const2438 CRect CPlayerUIBase::GetVolumeRect() const
2439 {
2440 auto iter = m_buttons.find(BTN_VOLUME);
2441 if (iter != m_buttons.end())
2442 return iter->second.rect;
2443 return CRect();
2444 }
2445
ReplaceUiStringRes(wstring & str)2446 void CPlayerUIBase::ReplaceUiStringRes(wstring& str)
2447 {
2448 size_t index{};
2449 while ((index = str.find(L"%(", index)) != wstring::npos)
2450 {
2451 size_t right_bracket_index = str.find(L')', index + 2);
2452 if (right_bracket_index == wstring::npos)
2453 break;
2454 wstring key_str{ str.begin() + index + 2 , str.begin() + right_bracket_index };
2455 const wstring& value_str = theApp.m_str_table.LoadText(key_str);
2456 if (value_str == StrTable::error_str) // LoadText内部已记录错误日志
2457 break;
2458 str.replace(index, right_bracket_index + 1, value_str);
2459 index = right_bracket_index + 1;
2460 }
2461 }
2462
DrawAlbumCover(CRect rect)2463 void CPlayerUIBase::DrawAlbumCover(CRect rect)
2464 {
2465 DrawAreaGuard guard(&m_draw, rect);
2466 if (theApp.m_app_setting_data.show_album_cover && CPlayer::GetInstance().AlbumCoverExist())
2467 {
2468 if (theApp.m_app_setting_data.draw_album_high_quality)
2469 m_draw.DrawImage(CPlayer::GetInstance().GetAlbumCover(), rect.TopLeft(), rect.Size(), theApp.m_app_setting_data.album_cover_fit);
2470 else
2471 m_draw.DrawBitmap(CPlayer::GetInstance().GetAlbumCover(), rect.TopLeft(), rect.Size(), theApp.m_app_setting_data.album_cover_fit);
2472 }
2473 else
2474 {
2475 CRect rc_temp = rect;
2476 int cover_margin = static_cast<int>(rect.Width() * 0.08);
2477 rc_temp.DeflateRect(cover_margin, cover_margin);
2478 if (theApp.m_app_setting_data.draw_album_high_quality)
2479 {
2480 Gdiplus::Image* image{ CPlayer::GetInstance().IsPlaying() ? theApp.m_image_set.default_cover_img : theApp.m_image_set.default_cover_not_played_img };
2481 m_draw.DrawImage(image, rc_temp.TopLeft(), rc_temp.Size(), CDrawCommon::StretchMode::FIT);
2482 }
2483 else
2484 {
2485 int cover_side = min(rc_temp.Width(), rc_temp.Height());
2486 int x = rc_temp.left + (rc_temp.Width() - cover_side) / 2;
2487 int y = rc_temp.top + (rc_temp.Height() - cover_side) / 2;
2488
2489 IconMgr::IconType icon_type = IconMgr::IconType::IT_Default_Cover_Stopped;
2490 if (CPlayer::GetInstance().IsPlaying())
2491 icon_type = IconMgr::IconType::IT_Default_Cover_Playing;
2492 HICON hIcon = theApp.m_icon_mgr.GetHICON(icon_type, IconMgr::IconStyle::IS_Color, IconMgr::IconSize::IS_ORG_512);
2493
2494 m_draw.DrawIcon(hIcon, CPoint(x, y), CSize(cover_side, cover_side));
2495 }
2496 }
2497 }
2498
DrawAlbumCoverWithInfo(CRect rect)2499 void CPlayerUIBase::DrawAlbumCoverWithInfo(CRect rect)
2500 {
2501 const int info_height{ DPI(60) }; //歌曲信息区域的高度
2502 if (IsDrawBackgroundAlpha())
2503 {
2504 DrawAlbumCover(rect);
2505 }
2506 else //如果不绘制透明背景,则将专辑封面显示在歌曲信息区域的上方
2507 {
2508 CRect rect_temp{ rect };
2509 rect_temp.bottom -= info_height;
2510 DrawAlbumCover(rect_temp);
2511 }
2512
2513 //绘制信息信息
2514 CRect rect_info{ rect };
2515 rect_info.top = rect_info.bottom - info_height;
2516 if (rect_info.top < m_draw_rect.top)
2517 rect_info.top = m_draw_rect.top;
2518
2519 COLORREF text_color;
2520 COLORREF back_color;
2521 BYTE alpha;
2522 //if (theApp.m_app_setting_data.dark_mode)
2523 //{
2524 // text_color = theApp.m_app_setting_data.theme_color.dark2;
2525 // back_color = ColorTable::WHITE;
2526 // alpha = 204;
2527 //}
2528 //else
2529 //{
2530 text_color = ColorTable::WHITE;
2531 back_color = GRAY(64);
2532 alpha = 108;
2533 //}
2534
2535 if (IsDrawBackgroundAlpha())
2536 m_draw.FillAlphaRect(rect_info, back_color, alpha /** 3 / 4*/);
2537 else
2538 m_draw.FillRect(rect_info, back_color);
2539
2540 rect_info.DeflateRect(DPI(24), DPI(8));
2541 //绘制艺术家
2542 CRect rect_artist{ rect_info };
2543 rect_artist.bottom = rect_artist.top + DPI(16);
2544 static CDrawCommon::ScrollInfo scroll_info_artist;
2545 m_draw.DrawScrollText(rect_artist, CPlayer::GetInstance().GetCurrentSongInfo().GetArtist().c_str(), text_color, GetScrollTextPixel(true), false, scroll_info_artist);
2546 //绘制歌曲标题
2547 CRect rect_title{ rect_info };
2548 rect_title.top = rect_artist.bottom;
2549 wstring str_title;
2550 if (CPlayer::GetInstance().GetCurrentSongInfo().IsTitleEmpty()) //如果标题为空,则显示文件名
2551 str_title = CPlayer::GetInstance().GetCurrentSongInfo().GetFileName();
2552 else
2553 str_title = CPlayer::GetInstance().GetCurrentSongInfo().GetTitle();
2554 CFont* pOldFont = m_draw.SetFont(&theApp.m_font_set.GetFontBySize(12).GetFont(theApp.m_ui_data.full_screen));
2555 static CDrawCommon::ScrollInfo scroll_info_title;
2556 m_draw.DrawScrollText(rect_title, str_title.c_str(), text_color, GetScrollTextPixel(true), false, scroll_info_title);
2557 m_draw.SetFont(pOldFont);
2558
2559 }
2560
DrawVolumeButton(CRect rect,bool adj_btn_top,bool show_text)2561 void CPlayerUIBase::DrawVolumeButton(CRect rect, bool adj_btn_top, bool show_text)
2562 {
2563 m_show_volume_text = show_text;
2564
2565 auto& btn{ m_buttons[BTN_VOLUME] };
2566 if (btn.pressed)
2567 rect.MoveToXY(rect.left + theApp.DPI(1), rect.top + theApp.DPI(1));
2568
2569 DrawAreaGuard guard(&m_draw, rect);
2570 //绘制背景
2571 //if (btn.pressed || btn.hover)
2572 //{
2573 // CRect rect_back{ rect };
2574 // rect_back.DeflateRect(DPI(2), DPI(2));
2575 // BYTE alpha;
2576 // if (IsDrawBackgroundAlpha())
2577 // alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
2578 // else
2579 // alpha = 255;
2580 // COLORREF back_color{};
2581 // if (btn.pressed)
2582 // back_color = m_colors.color_button_pressed;
2583 // else
2584 // back_color = m_colors.color_button_hover;
2585 // if (!theApp.m_app_setting_data.button_round_corners)
2586 // m_draw.FillAlphaRect(rect_back, back_color, alpha);
2587 // else
2588 // m_draw.DrawRoundRect(rect_back, back_color, theApp.DPI(3), alpha);
2589 //}
2590
2591 //绘制图标
2592 CRect rect_icon{ rect };
2593 rect_icon.right = rect_icon.left + rect_icon.Height();
2594 DrawUiIcon(rect_icon, GetBtnIconType(BTN_VOLUME));
2595
2596 //绘制文本
2597 if (show_text && rect_icon.right < rect.right)
2598 {
2599 CRect rect_text{ rect };
2600 rect_text.left = rect_icon.right;
2601 CString str;
2602 if (CPlayer::GetInstance().GetVolume() <= 0)
2603 str = theApp.m_str_table.LoadText(L"UI_TXT_VOLUME_MUTE").c_str();
2604 else
2605 str.Format(_T("%d%%"), CPlayer::GetInstance().GetVolume());
2606 if (m_buttons[BTN_VOLUME].hover) //鼠标指向音量区域时,以另外一种颜色显示
2607 m_draw.DrawWindowText(rect_text, str, m_colors.color_text_heighlight);
2608 else
2609 m_draw.DrawWindowText(rect_text, str, m_colors.color_text);
2610 }
2611 //设置音量调整按钮的位置
2612 CRect rc_tmp = rect;
2613 rc_tmp.bottom = rc_tmp.top + DPI(24);
2614 m_buttons[BTN_VOLUME].rect = DrawAreaToClient(rc_tmp, m_draw_rect);
2615 m_buttons[BTN_VOLUME].rect.DeflateRect(0, DPI(4));
2616 m_buttons[BTN_VOLUME_DOWN].rect = m_buttons[BTN_VOLUME].rect;
2617 m_buttons[BTN_VOLUME_DOWN].rect.bottom += DPI(4);
2618 if (adj_btn_top)
2619 {
2620 m_buttons[BTN_VOLUME_DOWN].rect.MoveToY(m_buttons[BTN_VOLUME].rect.top - m_buttons[BTN_VOLUME_DOWN].rect.Height());
2621 }
2622 else
2623 {
2624 m_buttons[BTN_VOLUME_DOWN].rect.MoveToY(m_buttons[BTN_VOLUME].rect.bottom);
2625 }
2626 m_buttons[BTN_VOLUME_DOWN].rect.right = m_buttons[BTN_VOLUME].rect.left + DPI(27); //设置单个音量调整按钮的宽度
2627 m_buttons[BTN_VOLUME_UP].rect = m_buttons[BTN_VOLUME_DOWN].rect;
2628 m_buttons[BTN_VOLUME_UP].rect.MoveToX(m_buttons[BTN_VOLUME_DOWN].rect.right);
2629 }
2630
DrawABRepeatButton(CRect rect)2631 void CPlayerUIBase::DrawABRepeatButton(CRect rect)
2632 {
2633 CString info;
2634 CPlayer::ABRepeatMode ab_repeat_mode = CPlayer::GetInstance().GetABRepeatMode();
2635 if (ab_repeat_mode == CPlayer::AM_A_SELECTED)
2636 info = _T("A-");
2637 else
2638 info = _T("A-B");
2639 CFont* pOldFont = m_draw.GetFont();
2640 m_draw.SetFont(&theApp.m_font_set.GetFontBySize(8).GetFont(theApp.m_ui_data.full_screen)); //AB重复使用小一号字体,即播放时间的字体
2641 m_buttons[BTN_AB_REPEAT].enable = (!CPlayer::GetInstance().IsError() && !CPlayer::GetInstance().IsPlaylistEmpty());
2642 DrawTextButton(rect, BTN_AB_REPEAT, info, ab_repeat_mode != CPlayer::AM_NONE);
2643 m_draw.SetFont(pOldFont);
2644 }
2645
DrawLyrics(CRect rect,CFont * lyric_font,CFont * lyric_tr_font,bool with_background,bool show_song_info)2646 void CPlayerUIBase::DrawLyrics(CRect rect, CFont* lyric_font, CFont* lyric_tr_font, bool with_background, bool show_song_info)
2647 {
2648 if (rect.Height() < DPI(4))
2649 return;
2650
2651 //填充歌词区域背景
2652 if (with_background && theApp.m_app_setting_data.lyric_background)
2653 {
2654 BYTE alpha = 255;
2655 if (IsDrawBackgroundAlpha())
2656 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 3 / 5;
2657 if (theApp.m_app_setting_data.button_round_corners)
2658 {
2659 DrawAreaGuard guard(&m_draw, rect);
2660 m_draw.DrawRoundRect(rect, m_colors.color_lyric_back, CalculateRoundRectRadius(rect), alpha);
2661 }
2662 else
2663 {
2664 m_draw.FillAlphaRect(rect, m_colors.color_lyric_back, alpha);
2665 }
2666 }
2667 //设置歌词文字区域
2668 int margin = Margin();
2669 rect.DeflateRect(margin, margin);
2670
2671 //绘制歌词文本
2672 m_draw.SetLyricFont(lyric_font, lyric_tr_font);
2673 m_draw.DrawLryicCommon(rect, theApp.m_lyric_setting_data.lyric_align, show_song_info);
2674 }
2675
DrawList(CRect rect,UiElement::ListElement * list_element,int item_height)2676 void CPlayerUIBase::DrawList(CRect rect, UiElement::ListElement* list_element, int item_height)
2677 {
2678 if (rect.IsRectEmpty())
2679 return;
2680
2681 DrawAreaGuard guard(&m_draw, rect);
2682
2683 if (list_element->GetRowCount() <= 0)
2684 {
2685 wstring info = list_element->GetEmptyString();
2686 if (!info.empty())
2687 m_draw.DrawWindowText(rect, info.c_str(), m_colors.color_text);
2688 }
2689 else
2690 {
2691 const int SCROLLBAR_WIDTH{ DPI(10) }; //滚动条的宽度
2692 const int SCROLLBAR_WIDTH_NARROW{ DPI(6) }; //鼠标未指向滚动条时的宽度
2693 const int MIN_SCROLLBAR_LENGTH{ DPI(16) }; //滚动条的最小长度
2694 BYTE background_alpha;
2695 if (!IsDrawBackgroundAlpha())
2696 background_alpha = 255;
2697 else if (theApp.m_app_setting_data.dark_mode)
2698 background_alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) / 2;
2699 else
2700 background_alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
2701
2702 //设置字体
2703 UiFontGuard set_font(this, list_element->font_size);
2704
2705 //displayed_row_index为显示的行号,for循环中的i为实际的行号
2706 int displayed_row_index{};
2707 for (int i{}; i < list_element->GetRowCount(); i++)
2708 {
2709 if (i < 0 || i >= static_cast<int>(list_element->item_rects.size()))
2710 break;
2711 //跳过不显示的行
2712 if (!list_element->IsRowDisplayed(i))
2713 continue;
2714 CRect rect_item{ list_element->item_rects[displayed_row_index] };
2715 rect_item.right -= SCROLLBAR_WIDTH; //留出一定距离用于绘制滚动条
2716 //如果绘制的行在播放列表区域之外,则不绘制该行
2717 if (!(rect_item & rect).IsRectEmpty())
2718 {
2719 COLORREF back_color{};
2720 //选中项目的背景
2721 if (list_element->IsItemSelected(i))
2722 {
2723 back_color = m_colors.color_button_back;
2724 }
2725 //偶数行的背景
2726 else if (displayed_row_index % 2 == 0)
2727 {
2728 back_color = m_colors.color_control_bar_back;
2729 }
2730 //绘制背景
2731 if (back_color != 0)
2732 {
2733 if (theApp.m_app_setting_data.button_round_corners)
2734 m_draw.DrawRoundRect(rect_item, back_color, DPI(4), background_alpha);
2735 else
2736 m_draw.FillAlphaRect(rect_item, back_color, background_alpha, true);
2737 }
2738
2739 //绘制正在播放指示
2740 if (i == list_element->GetHighlightRow())
2741 {
2742 CRect rect_cur_indicator{ rect_item };
2743 rect_cur_indicator.right = rect_cur_indicator.left + DPI(4);
2744 int indicator_hight = item_height * 6 / 10;
2745 rect_cur_indicator.top += (item_height - indicator_hight) / 2;
2746 rect_cur_indicator.bottom = rect_cur_indicator.top + indicator_hight;
2747 if (theApp.m_app_setting_data.button_round_corners)
2748 m_draw.DrawRoundRect(rect_cur_indicator, m_colors.color_text_heighlight, DPI(2));
2749 else
2750 m_draw.FillRect(rect_cur_indicator, m_colors.color_text_heighlight, true);
2751 }
2752
2753 int col_x = rect_item.left + DPI(4);
2754
2755 int indent_space{}; //缩进距离
2756 UiElement::TreeElement* tree_element = dynamic_cast<UiElement::TreeElement*>(list_element);
2757 //如果是树控件
2758 if (tree_element != nullptr)
2759 {
2760 const int indent_per_level = DPI(10); //每一级缩进距离
2761 indent_space = indent_per_level * tree_element->GetItemLevel(i); //缩进距离
2762 //再留出一定距离用于绘制折叠标志
2763 const int collapse_width = DPI(16);
2764 //如果当前行可折叠,绘制折叠标志
2765 if (tree_element->IsCollapsable(i))
2766 {
2767 //计算折叠标志区域
2768 CRect rect_collapsd{ rect_item };
2769 rect_collapsd.left = col_x + indent_space;
2770 rect_collapsd.right = rect_collapsd.left + collapse_width;
2771 //保存折叠标志矩形区域
2772 if (tree_element != nullptr)
2773 tree_element->collapsd_rects[i] = rect_collapsd;
2774 //将折叠标志区域改为正方形
2775 rect_collapsd.top += (rect_collapsd.Height() - collapse_width) / 2;
2776 rect_collapsd.bottom = rect_collapsd.top + collapse_width;
2777 //如果鼠标指向,则绘制背景
2778 if (tree_element->collaps_indicator_hover_row == i)
2779 {
2780 BYTE alpha;
2781 if (IsDrawBackgroundAlpha())
2782 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
2783 else
2784 alpha = 255;
2785 if (!theApp.m_app_setting_data.button_round_corners)
2786 m_draw.FillAlphaRect(rect_collapsd, m_colors.color_button_hover, alpha, true);
2787 else
2788 m_draw.DrawRoundRect(rect_collapsd, m_colors.color_button_hover, CalculateRoundRectRadius(rect_collapsd), alpha);
2789 }
2790 //绘制折叠标志
2791 DrawUiIcon(rect_collapsd, (tree_element->IsCollapsed(i) ? IconMgr::IT_TreeCollapsed : IconMgr::IT_TreeExpanded));
2792 }
2793 indent_space += collapse_width;
2794 }
2795
2796 //绘制图标
2797 if (list_element->HasIcon())
2798 {
2799 CRect rect_icon{ rect_item };
2800 rect_icon.left = col_x;
2801 rect_icon.right = rect_icon.left + DPI(20);
2802 col_x = rect_icon.right;
2803 rect_icon.MoveToX(rect_icon.left + indent_space);
2804 DrawUiIcon(rect_icon, list_element->GetIcon(i));
2805 }
2806
2807 //绘制列
2808 int total_width = rect_item.right - col_x; //所有列的总宽度
2809 for (int j{}; j < list_element->GetColumnCount(); j++)
2810 {
2811 CRect rect_cell{ rect_item };
2812 rect_cell.left = col_x;
2813 rect_cell.right = rect_cell.left + list_element->GetColumnWidth(j, total_width);
2814 std::wstring display_name{ list_element->GetItemText(i, j) };
2815 rect_cell.left += DPI(4); //绘制文字时左侧留出4个像素
2816
2817 //第1列缩进
2818 if (j == 0)
2819 {
2820 rect_cell.left += indent_space;
2821 }
2822
2823 DrawAreaGuard guard(&m_draw, rect & rect_cell);
2824
2825 CRect rect_text{ rect_cell };
2826 //绘制鼠标指向时的按钮
2827 if (list_element->GetHoverButtonCount() > 0 && list_element->GetHoverButtonColumn() == j && rect_cell.PtInRect(list_element->mouse_pos))
2828 {
2829 const int btn_size{ DPI(24) };
2830 int buttons_width = btn_size * list_element->GetHoverButtonCount() + DPI(4); //按钮区域的宽度
2831 if (rect_cell.Width() > buttons_width + DPI(40)) //如果单元格宽度太小则不绘制按钮(至少给文本留出40像素)
2832 {
2833 rect_text.right -= buttons_width;
2834
2835 for (int k{}; k < list_element->GetHoverButtonCount(); k++)
2836 {
2837 //计算按钮矩形区域
2838 CRect rect_btn{ rect_cell };
2839 rect_btn.left = rect_text.right + DPI(2) + btn_size * k;
2840 rect_btn.right = rect_btn.left + btn_size;
2841 rect_btn.top = rect_cell.top + (rect_cell.Height() - btn_size) / 2;
2842 rect_btn.bottom = rect_btn.top + btn_size;
2843 //保存按钮矩形区域
2844 list_element->GetHoverButtonState(k).rect = rect_btn;
2845 //开始绘制按钮
2846 DrawUIButton(rect_btn, list_element->GetHoverButtonState(k), list_element->GetHoverButtonIcon(k, i));
2847 }
2848 }
2849 }
2850 //绘制鼠标未指向时的图标
2851 if (list_element->GetUnHoverIconCount(i) > 0 && list_element->GetHoverButtonColumn() == j && !rect_cell.PtInRect(list_element->mouse_pos))
2852 {
2853 const int btn_size{ DPI(24) };
2854 int icons_width = btn_size * list_element->GetUnHoverIconCount(i) + DPI(4); //按钮区域的宽度
2855 if (rect_cell.Width() > icons_width + DPI(40)) //如果单元格宽度太小则不绘制图标(至少给文本留出40像素)
2856 {
2857 rect_text.right -= icons_width;
2858 for (int k{}; k < list_element->GetUnHoverIconCount(i); k++)
2859 {
2860 //计算按钮矩形区域
2861 CRect rect_icon{ rect_cell };
2862 rect_icon.left = rect_text.right + DPI(2) + btn_size * k;
2863 rect_icon.right = rect_icon.left + btn_size;
2864 rect_icon.top = rect_cell.top + (rect_cell.Height() - btn_size) / 2;
2865 rect_icon.bottom = rect_icon.top + btn_size;
2866 //绘制图标
2867 DrawUiIcon(rect_icon, list_element->GetUnHoverIcon(k, i));
2868 }
2869 }
2870 }
2871
2872 //绘制文本
2873 {
2874 DrawAreaGuard guard(&m_draw, rect & rect_text);
2875 if (!list_element->IsMultipleSelected() && i == list_element->GetItemSelected() && j == list_element->GetColumnScrollTextWhenSelected())
2876 m_draw.DrawScrollText(rect_text, display_name.c_str(), m_colors.color_text, GetScrollTextPixel(), false, list_element->selected_item_scroll_info, false, true);
2877 else
2878 m_draw.DrawWindowText(rect_text, display_name.c_str(), m_colors.color_text, Alignment::LEFT, true);
2879 }
2880 col_x = rect_cell.right;
2881 }
2882 }
2883 displayed_row_index++;
2884 }
2885
2886 //绘制滚动条
2887 DrawAreaGuard guard(&m_draw, rect);
2888 list_element->scrollbar_rect = rect;
2889 list_element->scrollbar_rect.left = list_element->scrollbar_rect.right - SCROLLBAR_WIDTH;
2890 if (list_element->hover || list_element->mouse_pressed || list_element->scrollbar_handle_pressed)
2891 {
2892 CRect scrollbar_rect = list_element->scrollbar_rect;
2893 if (!list_element->scrollbar_hover && !list_element->scrollbar_handle_pressed) //如果鼠标没有指向也没有拖动滚动条,滚动条以更小的宽度显示
2894 {
2895 scrollbar_rect.left = scrollbar_rect.left + (scrollbar_rect.Width() - SCROLLBAR_WIDTH_NARROW) / 2;
2896 scrollbar_rect.right = scrollbar_rect.left + SCROLLBAR_WIDTH_NARROW;
2897 }
2898
2899 auto drawRect = [&](CRect _rect, COLORREF color, BYTE _alpha) {
2900 if (theApp.m_app_setting_data.button_round_corners)
2901 m_draw.DrawRoundRect(_rect, color, DPI(4), _alpha);
2902 else
2903 m_draw.FillAlphaRect(_rect, color, _alpha, true);
2904
2905 };
2906
2907 //开始绘制滚动条
2908 if (list_element->GetDisplayRowCount() > 1 && item_height * list_element->GetDisplayRowCount() > rect.Height())
2909 {
2910 //填充滚动条背景
2911 if (list_element->scrollbar_hover || list_element->scrollbar_handle_pressed)
2912 drawRect(scrollbar_rect, m_colors.color_control_bar_back, background_alpha);
2913
2914 //画滚动条把手
2915 //计算滚动条的长度
2916 int scroll_handle_length{ rect.Height() * rect.Height() / (item_height * list_element->GetDisplayRowCount()) };
2917 list_element->scroll_handle_length_comp = 0;
2918 if (scroll_handle_length < MIN_SCROLLBAR_LENGTH)
2919 {
2920 list_element->scroll_handle_length_comp = MIN_SCROLLBAR_LENGTH - scroll_handle_length;
2921 scroll_handle_length = MIN_SCROLLBAR_LENGTH;
2922 }
2923 //根据播放列表偏移量计算滚动条的位置
2924 int scroll_pos{ (rect.Height() - list_element->scroll_handle_length_comp) * list_element->playlist_offset / (item_height * list_element->GetDisplayRowCount()) };
2925 list_element->scrollbar_handle_rect = scrollbar_rect;
2926 list_element->scrollbar_handle_rect.top = scrollbar_rect.top + scroll_pos;
2927 list_element->scrollbar_handle_rect.bottom = list_element->scrollbar_handle_rect.top + scroll_handle_length;
2928 //限制滚动条把手的位置
2929 if (list_element->scrollbar_handle_rect.top < list_element->scrollbar_rect.top)
2930 list_element->scrollbar_handle_rect.MoveToY(list_element->scrollbar_rect.top);
2931 if (list_element->scrollbar_handle_rect.bottom > list_element->scrollbar_rect.bottom)
2932 list_element->scrollbar_handle_rect.MoveToY(list_element->scrollbar_rect.bottom - list_element->scrollbar_handle_rect.Height());
2933 //滚动条把手的颜色
2934 COLORREF scrollbar_handle_color{ m_colors.color_scrollbar_handle };
2935 if (list_element->scrollbar_handle_pressed)
2936 scrollbar_handle_color = m_colors.color_button_pressed;
2937 else if (list_element->scrollbar_hover)
2938 scrollbar_handle_color = m_colors.color_button_hover;
2939 //滚动条把手的不透明度
2940 BYTE scrollbar_handle_alpha{ 255 };
2941 if (IsDrawBackgroundAlpha())
2942 scrollbar_handle_alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency);
2943 //绘制滚动条把手
2944 drawRect(list_element->scrollbar_handle_rect, scrollbar_handle_color, scrollbar_handle_alpha);
2945 }
2946 }
2947 }
2948 }
2949
DrawCurrentPlaylistIndicator(CRect rect,UiElement::PlaylistIndicator * playlist_indicator)2950 void CPlayerUIBase::DrawCurrentPlaylistIndicator(CRect rect, UiElement::PlaylistIndicator* playlist_indicator)
2951 {
2952 // 此m_list_cache为UI线程缓存当前列表,只有at(0)是有效的
2953 ASSERT(playlist_indicator->m_list_cache.size() == 1);
2954 const ListItem& list_item = playlist_indicator->m_list_cache.at(0);
2955
2956 IconMgr::IconType icon_type = list_item.GetTypeIcon();
2957 wstring str = list_item.GetTypeDisplayName();
2958 //绘制图标
2959 CRect rect_icon{ rect };
2960 rect_icon.right = rect_icon.left + DPI(26);
2961 DrawUiIcon(rect_icon, icon_type);
2962 //设置字体
2963 UiFontGuard set_font(this, playlist_indicator->font_size);
2964 //绘制文本
2965 CRect rect_text{ rect };
2966 rect_text.left = rect_icon.right;
2967 rect_text.right = rect_text.left + m_draw.GetTextExtent(str.c_str()).cx;
2968 m_draw.DrawWindowText(rect_text, str.c_str(), m_colors.color_text, Alignment::LEFT, true);
2969 //绘制菜单按钮
2970 CRect menu_btn_rect{ rect };
2971 menu_btn_rect.left = rect.right - DPI(26);
2972 const int icon_size{ (std::min)(DPI(24), rect.Height()) };
2973 CRect menu_btn_icon_rect = CDrawCommon::CalculateCenterIconRect(menu_btn_rect, icon_size);
2974 DrawUIButton(menu_btn_icon_rect, playlist_indicator->btn_menu, IconMgr::IconType::IT_Menu);
2975 //绘制当前播放列表名称
2976 CRect rect_name{ rect };
2977 rect_name.left = rect_text.right + DPI(8);
2978 rect_name.right = menu_btn_rect.left - DPI(4);
2979 BYTE alpha{ 255 };
2980 if (IsDrawBackgroundAlpha())
2981 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) / 2;
2982 if (theApp.m_app_setting_data.button_round_corners)
2983 m_draw.DrawRoundRect(rect_name, m_colors.color_control_bar_back, DPI(4), alpha);
2984 else
2985 m_draw.FillAlphaRect(rect_name, m_colors.color_control_bar_back, alpha);
2986 playlist_indicator->rect_name = rect_name;
2987 rect_name.left += DPI(6);
2988 rect_name.right -= DPI(30);
2989 static CDrawCommon::ScrollInfo name_scroll_info;
2990 m_draw.DrawScrollText(rect_name, list_item.GetDisplayName().c_str(), m_colors.color_text_heighlight, GetScrollTextPixel(), false, name_scroll_info);
2991 //绘制下拉按钮
2992 CRect rect_drop_down{ rect };
2993 rect_drop_down.left = rect_name.right + DPI(2);
2994 rect_drop_down.right = menu_btn_rect.left - DPI(6);
2995 CRect rect_drop_down_btn = CDrawCommon::CalculateCenterIconRect(rect_drop_down, icon_size);
2996 DrawUIButton(rect_drop_down_btn, playlist_indicator->btn_drop_down, IconMgr::IconType::IT_Triangle_Down);
2997 }
2998
DrawStackIndicator(UIButton indicator,int num,int index)2999 void CPlayerUIBase::DrawStackIndicator(UIButton indicator, int num, int index)
3000 {
3001 //绘制背景
3002 if (indicator.pressed || indicator.hover)
3003 {
3004 BYTE alpha;
3005 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
3006 COLORREF back_color{};
3007 if (indicator.pressed)
3008 back_color = m_colors.color_button_pressed;
3009 else
3010 back_color = m_colors.color_button_hover;
3011 //if (!theApp.m_app_setting_data.button_round_corners)
3012 // m_draw.FillAlphaRect(indicator.rect, back_color, alpha);
3013 //else
3014 m_draw.DrawRoundRect(indicator.rect, back_color, indicator.rect.Height() / 2, alpha);
3015 }
3016
3017 //绘制圆
3018 int start_x = indicator.rect.left;
3019 start_x += (indicator.rect.Width() - num * DPI(12)) / 2;
3020 for (int i = 0; i < num; i++)
3021 {
3022 CRect rect_dot{ indicator.rect };
3023 rect_dot.left = start_x + i * DPI(12);
3024 rect_dot.right = rect_dot.left + DPI(12);
3025 int dot_size{ DPI(5) };
3026 rect_dot.left += (rect_dot.Width() - dot_size) / 2;
3027 rect_dot.top += (rect_dot.Height() - dot_size) / 2;
3028 rect_dot.right = rect_dot.left + dot_size;
3029 rect_dot.bottom = rect_dot.top + dot_size;
3030 COLORREF dot_color{};
3031 BYTE alpha{ 255 };
3032 if (i == index)
3033 {
3034 dot_color = m_colors.color_text;
3035 }
3036 else
3037 {
3038 dot_color = m_colors.color_stack_indicator;
3039 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
3040 }
3041 m_draw.DrawEllipse(rect_dot, dot_color, alpha);
3042 }
3043 }
3044
DrawUiMenuBar(CRect rect)3045 void CPlayerUIBase::DrawUiMenuBar(CRect rect)
3046 {
3047 //m_draw.DrawWindowText(rect, L"menu bar", m_colors.color_text);
3048
3049 //绘制背景
3050 bool draw_background{ IsDrawBackgroundAlpha() };
3051 BYTE alpha;
3052 if (theApp.m_app_setting_data.dark_mode)
3053 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) / 2;
3054 else
3055 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
3056
3057 if (draw_background)
3058 m_draw.FillAlphaRect(rect, m_colors.color_control_bar_back, alpha);
3059 else
3060 m_draw.FillRect(rect, m_colors.color_control_bar_back);
3061
3062 CRect rc_item{ rect };
3063 rc_item.bottom = rc_item.top + DPI(20);
3064 rc_item.left += DPI(4);
3065 auto drawMenuItem = [&](BtnKey key, LPCTSTR menu_str)
3066 {
3067 UIButton& btn{ m_buttons[key] };
3068 btn.rect = rc_item;
3069 btn.rect.right = btn.rect.left + btn.rect.Height() + m_draw.GetTextExtent(menu_str).cx + DPI(6);
3070
3071 CRect rc_cur_item{ btn.rect };
3072 if (btn.pressed && btn.enable)
3073 rc_cur_item.OffsetRect(theApp.DPI(1), theApp.DPI(1));
3074
3075 //绘制背景
3076 if (btn.pressed || btn.hover)
3077 {
3078 BYTE alpha;
3079 if (draw_background)
3080 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
3081 else
3082 alpha = 255;
3083 COLORREF back_color{};
3084 if (btn.pressed)
3085 back_color = m_colors.color_button_pressed;
3086 else
3087 back_color = m_colors.color_button_hover;
3088
3089 if (!theApp.m_app_setting_data.button_round_corners)
3090 m_draw.FillAlphaRect(rc_cur_item, back_color, alpha);
3091 else
3092 m_draw.DrawRoundRect(rc_cur_item, back_color, CalculateRoundRectRadius(rect), alpha);
3093 }
3094
3095 //绘制图标
3096 CRect rc_icon{ rc_cur_item };
3097 rc_icon.left += DPI(2);
3098 rc_icon.right = rc_icon.left + rc_icon.Height();
3099 HICON hIcon = theApp.m_icon_mgr.GetHICON(GetBtnIconType(key),
3100 theApp.m_app_setting_data.dark_mode ? IconMgr::IconStyle::IS_OutlinedLight : IconMgr::IconStyle::IS_OutlinedDark,
3101 IsDrawLargeIcon() ? IconMgr::IconSize::IS_DPI_16_Full_Screen : IconMgr::IconSize::IS_DPI_16);
3102 m_draw.DrawIcon(hIcon, rc_icon, DPI(16));
3103
3104 //绘制文本
3105 CRect rc_text{ rc_cur_item };
3106 rc_text.left = rc_icon.right;
3107 rc_text.right = btn.rect.right;
3108 m_draw.DrawWindowText(rc_text, menu_str, m_colors.color_text);
3109
3110 //下一个矩形的位置
3111 rc_item.left = rc_text.right + DPI(2);
3112 };
3113 // 自绘的菜单栏不支持助记键,显示的字符串与系统菜单栏不同,所以这里的字符串使用LoadText而不是LoadMenuText
3114 static const wstring& menu_name_file = theApp.m_str_table.LoadText(L"UI_TXT_MENU_FILE");
3115 static const wstring& menu_name_play_control = theApp.m_str_table.LoadText(L"UI_TXT_MENU_PLAY_CONTROL");
3116 static const wstring& menu_name_playlist = theApp.m_str_table.LoadText(L"UI_TXT_MENU_PLAYLIST");
3117 static const wstring& menu_name_lyrics = theApp.m_str_table.LoadText(L"UI_TXT_MENU_LYRICS");
3118 static const wstring& menu_name_view = theApp.m_str_table.LoadText(L"UI_TXT_MENU_VIEW");
3119 static const wstring& menu_name_tools = theApp.m_str_table.LoadText(L"UI_TXT_MENU_TOOLS");
3120 static const wstring& menu_name_help = theApp.m_str_table.LoadText(L"UI_TXT_MENU_HELP");
3121 drawMenuItem(MENU_FILE, menu_name_file.c_str()); //文件
3122 drawMenuItem(MENU_PLAY_CONTROL, menu_name_play_control.c_str()); //播放控制
3123 drawMenuItem(MENU_PLAYLIST, menu_name_playlist.c_str()); //播放列表
3124 drawMenuItem(MENU_LYRICS, menu_name_lyrics.c_str()); //歌词
3125 drawMenuItem(MENU_VIEW, menu_name_view.c_str()); //视图
3126 drawMenuItem(MENU_TOOLS, menu_name_tools.c_str()); //工具
3127 drawMenuItem(MENU_HELP, menu_name_help.c_str()); //帮助
3128 }
3129
DrawNavigationBar(CRect rect,UiElement::NavigationBar * tab_element)3130 void CPlayerUIBase::DrawNavigationBar(CRect rect, UiElement::NavigationBar* tab_element)
3131 {
3132 DrawAreaGuard guard(&m_draw, rect);
3133 bool draw_icon{ tab_element->icon_type == UiElement::NavigationBar::ICON_AND_TEXT || tab_element->icon_type == UiElement::NavigationBar::ICON_ONLY };
3134 bool draw_text{ tab_element->icon_type == UiElement::NavigationBar::ICON_AND_TEXT || tab_element->icon_type == UiElement::NavigationBar::TEXT_ONLY };
3135 int x_pos{ rect.left };
3136 int y_pos{ rect.top };
3137 int index{};
3138 tab_element->item_rects.resize(tab_element->tab_list.size());
3139 tab_element->labels.resize(tab_element->tab_list.size());
3140 for (const std::string& item_str : tab_element->tab_list)
3141 {
3142 IconMgr::IconType icon;
3143 std::wstring& item_text{ tab_element->labels[index]};
3144 if (item_str == "album_cover")
3145 {
3146 if (draw_icon) icon = IconMgr::IT_Album_Cover;
3147 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"UI_TXT_ALBUM_COVER");
3148 }
3149 else if (item_str == "spectrum")
3150 {
3151 if (draw_icon) icon = IconMgr::IT_Reverb;
3152 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"UI_TXT_SPECTRUM");
3153 }
3154 else if (item_str == "lyrics")
3155 {
3156 if (draw_icon) icon = IconMgr::IT_Lyric;
3157 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"UI_TXT_LYRICS");
3158 }
3159 else if (item_str == "now_playing")
3160 {
3161 if (draw_icon) icon = IconMgr::IT_NowPlaying;
3162 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"UI_TXT_PLAYSTATUS_PLAYING");
3163 }
3164 else if (item_str == "play_queue")
3165 {
3166 if (draw_icon) icon = IconMgr::IT_Play_In_Playlist;
3167 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"UI_TXT_PLAY_QUEUE");
3168 }
3169 else if (item_str == "recently_played")
3170 {
3171 if (draw_icon) icon = IconMgr::IT_History;
3172 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_RECENT_PLAYED");
3173 }
3174 else if (item_str == "folder")
3175 {
3176 if (draw_icon) icon = IconMgr::IT_Folder;
3177 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_FOLDER");
3178 }
3179 else if (item_str == "playlist")
3180 {
3181 if (draw_icon) icon = IconMgr::IT_Playlist;
3182 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_PLAYLIST");
3183 }
3184 else if (item_str == "artist")
3185 {
3186 if (draw_icon) icon = IconMgr::IT_Artist;
3187 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_ARTIST");
3188 }
3189 else if (item_str == "album")
3190 {
3191 if (draw_icon) icon = IconMgr::IT_Album;
3192 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_ALBUM");
3193 }
3194 else if (item_str == "genre")
3195 {
3196 if (draw_icon) icon = IconMgr::IT_Genre;
3197 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_GENRE");
3198 }
3199 else if (item_str == "year")
3200 {
3201 if (draw_icon) icon = IconMgr::IT_Year;
3202 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_YEAR");
3203 }
3204 else if (item_str == "file_type")
3205 {
3206 if (draw_icon) icon = IconMgr::IT_File_Relate;
3207 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_FILE_TYPE");
3208 }
3209 else if (item_str == "bitrate")
3210 {
3211 if (draw_icon) icon = IconMgr::IT_Bitrate;
3212 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_BITRATE");
3213 }
3214 else if (item_str == "rating")
3215 {
3216 if (draw_icon) icon = IconMgr::IT_Star;
3217 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_RATING");
3218 }
3219 else if (item_str == "media_lib")
3220 {
3221 if (draw_icon) icon = IconMgr::IT_Media_Lib;
3222 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_MEDIA_LIB");
3223 }
3224 else if (item_str == "my_favourite")
3225 {
3226 if (draw_icon) icon = IconMgr::IT_Favorite_On;
3227 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_MY_FAVOURITE");
3228 }
3229 else if (item_str == "all_tracks")
3230 {
3231 if (draw_icon) icon = IconMgr::IT_Media_Lib;
3232 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_ALL_TRACKS");
3233 }
3234 else if (item_str == "folder_explore")
3235 {
3236 if (draw_icon) icon = IconMgr::IT_Folder_Explore;
3237 if (item_text.empty()) item_text = theApp.m_str_table.LoadText(L"TXT_FOLDER_EXPLORE");
3238 }
3239 else
3240 {
3241 continue;
3242 }
3243
3244 //计算矩形区域
3245 int icon_width{};
3246 int text_width{};
3247 if (draw_icon)
3248 {
3249 int item_height{ tab_element->orientation == UiElement::NavigationBar::Horizontal ? rect.Height() : DPI(tab_element->item_height) };
3250 icon_width = (std::max)(DPI(24), item_height - DPI(4));
3251 }
3252 if (draw_text)
3253 text_width = m_draw.GetTextExtent(item_text.c_str()).cx;
3254 CRect item_rect{ rect };
3255 if (tab_element->orientation == UiElement::NavigationBar::Horizontal)
3256 {
3257 item_rect.left = x_pos;
3258 item_rect.right = item_rect.left + icon_width + text_width + DPI(4);
3259 if (tab_element->icon_type == UiElement::NavigationBar::TEXT_ONLY)
3260 item_rect.right += DPI(4);
3261 else if (tab_element->icon_type == UiElement::NavigationBar::ICON_AND_TEXT && tab_element->item_height > 20)
3262 item_rect.right += DPI(tab_element->item_height - 20) / 2; //基于高度值增加一些右侧的边距
3263 }
3264 else
3265 {
3266 item_rect.top = y_pos;
3267 item_rect.bottom = item_rect.top + DPI(tab_element->item_height);
3268 }
3269 tab_element->item_rects[index] = item_rect;
3270
3271 if ((rect & item_rect).IsRectEmpty())
3272 continue;
3273
3274 //绘制背景
3275 if (tab_element->hover_index == index)
3276 {
3277 DrawAreaGuard guard(&m_draw, rect);
3278 BYTE alpha;
3279 if (IsDrawBackgroundAlpha())
3280 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
3281 else
3282 alpha = 255;
3283 if (!theApp.m_app_setting_data.button_round_corners)
3284 m_draw.FillAlphaRect(item_rect, m_colors.color_button_hover, alpha, true);
3285 else
3286 m_draw.DrawRoundRect(item_rect, m_colors.color_button_hover, CalculateRoundRectRadius(item_rect), alpha);
3287 }
3288
3289 //绘制图标
3290 CRect icon_rect{ item_rect };
3291 if (draw_icon)
3292 {
3293 DrawAreaGuard guard(&m_draw, rect);
3294 if (tab_element->icon_type != UiElement::NavigationBar::ICON_ONLY)
3295 {
3296 icon_rect.right = icon_rect.left + icon_width;
3297 if (tab_element->orientation == UiElement::NavigationBar::Vertical)
3298 icon_rect.MoveToX(icon_rect.left + DPI(4));
3299 }
3300 //使用跳动的频谱代替正在播放图标
3301 if (item_str == "now_playing" && CPlayer::GetInstance().GetPlayingState2() != PS_STOPED && !CPlayer::GetInstance().IsMciCore())
3302 {
3303 DrawMiniSpectrum(icon_rect);
3304 }
3305 else
3306 {
3307 DrawUiIcon(icon_rect, icon);
3308 }
3309 }
3310 else
3311 {
3312 icon_rect.right = icon_rect.left;
3313 }
3314
3315 //绘制文本
3316 if (draw_text)
3317 {
3318 DrawAreaGuard guard(&m_draw, rect);
3319 CRect text_rect{ item_rect };
3320 if (tab_element->icon_type != UiElement::NavigationBar::TEXT_ONLY)
3321 {
3322 text_rect.left = icon_rect.right;
3323 }
3324 else
3325 {
3326 text_rect.MoveToX(text_rect.left + DPI(4));
3327 if (tab_element->orientation == UiElement::NavigationBar::Vertical)
3328 text_rect.left += DPI(8);
3329 }
3330 CFont* old_font{}; //原先的字体
3331 bool big_font{ m_ui_data.full_screen && IsDrawLargeIcon() };
3332 old_font = m_draw.SetFont(&theApp.m_font_set.GetFontBySize(tab_element->font_size).GetFont(big_font));
3333 m_draw.DrawWindowText(text_rect, item_text.c_str(), m_colors.color_text, Alignment::LEFT, true);
3334 m_draw.SetFont(old_font);
3335 }
3336
3337 //绘制选中指示
3338 if (tab_element->SelectedIndex() == index)
3339 {
3340 DrawAreaGuard guard(&m_draw, rect);
3341 CRect selected_indicator_rect{ item_rect };
3342 //水平排列时选中指示在底部
3343 if (tab_element->orientation == UiElement::NavigationBar::Horizontal)
3344 {
3345 selected_indicator_rect.left += DPI(4);
3346 selected_indicator_rect.right -= DPI(4);
3347 selected_indicator_rect.top = selected_indicator_rect.bottom - DPI(4);
3348 }
3349 //垂直排列时选中指示在左侧
3350 else
3351 {
3352 selected_indicator_rect.top += DPI(4);
3353 selected_indicator_rect.bottom -= DPI(4);
3354 selected_indicator_rect.right = selected_indicator_rect.left + DPI(4);
3355 }
3356 if (theApp.m_app_setting_data.button_round_corners)
3357 m_draw.DrawRoundRect(selected_indicator_rect, m_colors.color_text_heighlight, DPI(2));
3358 else
3359 m_draw.FillRect(selected_indicator_rect, m_colors.color_text_heighlight, true);
3360
3361 }
3362
3363 if (tab_element->orientation == UiElement::NavigationBar::Horizontal)
3364 x_pos = item_rect.right + DPI(tab_element->item_space);
3365 else
3366 y_pos = item_rect.bottom + DPI(tab_element->item_space);
3367 index++;
3368 }
3369 }
3370
DrawMiniSpectrum(CRect rect)3371 void CPlayerUIBase::DrawMiniSpectrum(CRect rect)
3372 {
3373 COLORREF icon_color{ theApp.m_app_setting_data.dark_mode ? RGB(255, 255, 255) : RGB(110, 110, 110) };
3374 CSize size_icon = IconMgr::GetIconSize(IsDrawLargeIcon() ? IconMgr::IS_DPI_16_Full_Screen : IconMgr::IS_DPI_16);
3375 CPoint pos_icon{ rect.left + (rect.Width() - size_icon.cx) / 2 , rect.top + (rect.Height() - size_icon.cy) / 2 };
3376 CRect draw_icon_rect(pos_icon, size_icon);
3377 draw_icon_rect.bottom -= DPI(2);
3378 const int spectrum_unit_width = DPI(4); //柱形+间隙的宽度
3379 int col_width = DPI(2); //柱形的宽度
3380 int gap_width = spectrum_unit_width - col_width; //间隙的宽度
3381 m_draw.DrawSpectrum(CRect(pos_icon, size_icon), col_width, gap_width, 4, icon_color, false, false, Alignment::CENTER, false, 180);
3382 }
3383
DrawSearchBox(CRect rect,UiElement::SearchBox * search_box)3384 void CPlayerUIBase::DrawSearchBox(CRect rect, UiElement::SearchBox* search_box)
3385 {
3386 //绘制背景
3387 COLORREF back_color;
3388 if (search_box->hover)
3389 back_color = m_colors.color_button_hover;
3390 else
3391 back_color = m_colors.color_control_bar_back;
3392 bool draw_background{ IsDrawBackgroundAlpha() };
3393 BYTE alpha;
3394 if (!draw_background)
3395 alpha = 255;
3396 else if (theApp.m_app_setting_data.dark_mode || search_box->hover)
3397 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency) * 2 / 3;
3398 else
3399 alpha = ALPHA_CHG(theApp.m_app_setting_data.background_transparency);
3400 if (!theApp.m_app_setting_data.button_round_corners)
3401 m_draw.FillAlphaRect(rect, back_color, alpha);
3402 else
3403 m_draw.DrawRoundRect(rect, back_color, CalculateRoundRectRadius(rect), alpha);
3404 //绘制文本
3405 CRect rect_text{ rect };
3406 rect_text.left += DPI(4);
3407 rect_text.right -= rect.Height();
3408 std::wstring text = search_box->key_word;
3409 COLORREF text_color = m_colors.color_text;
3410 if (text.empty())
3411 {
3412 text = theApp.m_str_table.LoadText(L"TXT_SEARCH_PROMPT");
3413 text_color = m_colors.color_text_heighlight;
3414 }
3415 m_draw.DrawWindowText(rect_text, text.c_str(), text_color, Alignment::LEFT, true);
3416 //绘制图标
3417 search_box->icon_rect = rect;;
3418 search_box->icon_rect.left = rect_text.right;
3419 if (search_box->key_word.empty())
3420 {
3421 DrawUiIcon(search_box->icon_rect, IconMgr::IT_Find);
3422 }
3423 else
3424 {
3425 CRect btn_rect{ search_box->icon_rect };
3426 btn_rect.DeflateRect(DPI(2), DPI(2));
3427 DrawUIButton(btn_rect, search_box->clear_btn, IconMgr::IT_Close);
3428 }
3429 }
3430
DrawUiIcon(const CRect & rect,IconMgr::IconType icon_type,IconMgr::IconStyle icon_style,IconMgr::IconSize icon_size)3431 void CPlayerUIBase::DrawUiIcon(const CRect& rect, IconMgr::IconType icon_type, IconMgr::IconStyle icon_style, IconMgr::IconSize icon_size)
3432 {
3433 // style为IS_Auto时根据深色模式设置向IconMgr要求深色/浅色图标,没有对应风格图标时IconMgr会自行fallback
3434 if (icon_style == IconMgr::IconStyle::IS_Auto)
3435 icon_style = theApp.m_app_setting_data.dark_mode ? IconMgr::IconStyle::IS_OutlinedLight : IconMgr::IconStyle::IS_OutlinedDark;
3436 // 要求大图标时在icon_size基础上再进行放大(×全屏缩放系数)
3437 if (IsDrawLargeIcon() && icon_size == IconMgr::IconSize::IS_DPI_16)
3438 icon_size = IconMgr::IconSize::IS_DPI_16_Full_Screen;
3439 if (IsDrawLargeIcon() && icon_size == IconMgr::IconSize::IS_DPI_20)
3440 icon_size = IconMgr::IconSize::IS_DPI_20_Full_Screen;
3441 if (IsDrawLargeIcon() && icon_size == IconMgr::IconSize::IS_DPI_32)
3442 icon_size = IconMgr::IconSize::IS_DPI_32_Full_Screen;
3443 // 使图标在矩形中居中
3444 CSize size_icon = IconMgr::GetIconSize(icon_size);
3445 CPoint pos_icon{ rect.left + (rect.Width() - size_icon.cx) / 2 , rect.top + (rect.Height() - size_icon.cy) / 2 };
3446 // 绘制图标
3447 HICON hIcon = theApp.m_icon_mgr.GetHICON(icon_type, icon_style, icon_size);
3448 m_draw.DrawIcon(hIcon, pos_icon, size_icon);
3449 }
3450
3451 //void CPlayerUIBase::AddMouseToolTip(BtnKey btn, LPCTSTR str)
3452 //{
3453 // m_tool_tip->AddTool(theApp.m_pMainWnd, str, m_buttons[btn].rect, btn + 1);
3454 //}
3455 //
3456 //void CPlayerUIBase::UpdateMouseToolTip(BtnKey btn, LPCTSTR str)
3457 //{
3458 // m_tool_tip->UpdateTipText(str, theApp.m_pMainWnd, btn + 1);
3459 //}
3460
AddToolTips()3461 void CPlayerUIBase::AddToolTips()
3462 {
3463 bool is_mini_mode{ IsMiniMode() };
3464 wstring tip_str;
3465 // 翻译
3466 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_TRANSLATION");
3467 AddMouseToolTip(BTN_TRANSLATE, tip_str.c_str());
3468 // 音量
3469 AddMouseToolTip(BTN_VOLUME, GetVolumeTooltipString());
3470 // 切换界面
3471 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_SWITCH_UI");
3472 if (!is_mini_mode) tip_str += GetCmdShortcutKeyForTooltips(ID_SWITCH_UI);
3473 AddMouseToolTip(BTN_SKIN, tip_str.c_str());
3474 AddMouseToolTip(BTN_SKIN_TITLEBAR, tip_str.c_str());
3475 // 音效
3476 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_SOUND_EFFECT_SETTING");
3477 tip_str += GetCmdShortcutKeyForTooltips(ID_EQUALIZER);
3478 AddMouseToolTip(BTN_EQ, tip_str.c_str());
3479 // 设置
3480 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_OPTION_SETTING");
3481 tip_str += GetCmdShortcutKeyForTooltips(ID_OPTION_SETTINGS);
3482 AddMouseToolTip(BTN_SETTING, tip_str.c_str());
3483 AddMouseToolTip(BTN_SETTING_TITLEBAR, tip_str.c_str());
3484 // MINI模式
3485 if (is_mini_mode)
3486 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_MINIMODE_RTN");
3487 else
3488 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_MINIMODE");
3489 tip_str += GetCmdShortcutKeyForTooltips(ID_MINI_MODE);
3490 AddMouseToolTip(BTN_MINI, tip_str.c_str());
3491 AddMouseToolTip(BTN_MINI_TITLEBAR, tip_str.c_str());
3492 // 曲目信息(属性)
3493 AddMouseToolTip(BTN_INFO, m_info_tip.c_str());
3494 UpdateSongInfoToolTip();
3495 // 停止
3496 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_STOP");
3497 AddMouseToolTip(BTN_STOP, tip_str.c_str());
3498 // 上一曲
3499 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_PREVIOUS");
3500 AddMouseToolTip(BTN_PREVIOUS, tip_str.c_str());
3501 // 播放/暂停
3502 if (CPlayer::GetInstance().IsPlaying())
3503 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_PAUSE");
3504 else
3505 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAY");
3506 AddMouseToolTip(BTN_PLAY_PAUSE, tip_str.c_str());
3507 // 下一曲
3508 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_NEXT");
3509 AddMouseToolTip(BTN_NEXT, tip_str.c_str());
3510 // 进度条
3511 tip_str = theApp.m_str_table.LoadTextFormat(L"UI_TIP_SEEK_TO_MINUTE_SECOND", { L"0", L"00" });
3512 AddMouseToolTip(BTN_PROGRESS, tip_str.c_str());
3513 // 显示/隐藏播放列表
3514 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAYLIST_SHOW_HIDE");
3515 if (!is_mini_mode)
3516 {
3517 if (theApp.m_media_lib_setting_data.playlist_btn_for_float_playlist)
3518 tip_str += GetCmdShortcutKeyForTooltips(ID_FLOAT_PLAYLIST);
3519 else
3520 tip_str += GetCmdShortcutKeyForTooltips(ID_SHOW_PLAYLIST);
3521 }
3522 AddMouseToolTip(BTN_SHOW_PLAYLIST, tip_str.c_str());
3523 // 媒体库
3524 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_MEDIA_LIB");
3525 tip_str += GetCmdShortcutKeyForTooltips(ID_MEDIA_LIB);
3526 AddMouseToolTip(BTN_MEDIA_LIB, tip_str.c_str());
3527 // 查找歌曲
3528 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_FIND_SONGS");
3529 tip_str += GetCmdShortcutKeyForTooltips(ID_FIND);
3530 AddMouseToolTip(BTN_FIND, tip_str.c_str());
3531 // 封面
3532 AddMouseToolTip(BTN_COVER, m_cover_tip.c_str());
3533 // 全屏
3534 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_FULL_SCREEN");
3535 tip_str += GetCmdShortcutKeyForTooltips(ID_FULL_SCREEN);
3536 AddMouseToolTip(BTN_FULL_SCREEN_TITLEBAR, tip_str.c_str());
3537 AddMouseToolTip(BTN_FULL_SCREEN, tip_str.c_str());
3538 // 主菜单
3539 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_MAIN_MENU");
3540 AddMouseToolTip(BTN_MENU_TITLEBAR, tip_str.c_str());
3541 AddMouseToolTip(BTN_MENU, tip_str.c_str());
3542 // “我喜欢的音乐”
3543 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_FAVOURITE");
3544 AddMouseToolTip(BTN_FAVOURITE, tip_str.c_str());
3545 // 桌面歌词
3546 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_DESKTOP_LYRIC");
3547 AddMouseToolTip(BTN_LRYIC, tip_str.c_str());
3548 // AB重复
3549 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_AB_REPEAT");
3550 tip_str += GetCmdShortcutKeyForTooltips(ID_AB_REPEAT);
3551 AddMouseToolTip(BTN_AB_REPEAT, tip_str.c_str());
3552 // 关闭
3553 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_CLOSE");
3554 AddMouseToolTip(BTN_APP_CLOSE, tip_str.c_str());
3555 AddMouseToolTip(BTN_CLOSE, tip_str.c_str());
3556 // 最小化
3557 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_MINIMIZE");
3558 AddMouseToolTip(BTN_MINIMIZE, tip_str.c_str());
3559 // 最大化
3560 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_MAXIMIZE");
3561 AddMouseToolTip(BTN_MAXIMIZE, tip_str.c_str());
3562 // 添加到播放列表
3563 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_ADD_TO_PLAYLIST");
3564 AddMouseToolTip(BTN_ADD_TO_PLAYLIST, tip_str.c_str());
3565 // 切换界面
3566 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_SWITCH_DISPLAY");
3567 AddMouseToolTip(BTN_SWITCH_DISPLAY, tip_str.c_str());
3568 // 深色/浅色模式
3569 if (theApp.m_app_setting_data.dark_mode)
3570 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_DARK_LIGHT_TO_LIGHT_MODE");
3571 else
3572 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_DARK_LIGHT_TO_DARK_MODE");
3573 tip_str += GetCmdShortcutKeyForTooltips(ID_DARK_MODE);
3574 AddMouseToolTip(BTN_DARK_LIGHT, tip_str.c_str());
3575 AddMouseToolTip(BTN_DARK_LIGHT_TITLE_BAR, tip_str.c_str());
3576 // 播放列表定位到当前播放
3577 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_LOCATE_TO_CURRENT");
3578 tip_str += GetCmdShortcutKeyForTooltips(ID_LOCATE_TO_CURRENT);
3579 AddMouseToolTip(BTN_LOCATE_TO_CURRENT, tip_str.c_str());
3580 // 播放列表
3581 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAYLIST_MENU");
3582 AddMouseToolTip(static_cast<CPlayerUIBase::BtnKey>(UiElement::TooltipIndex::PLAYLIST_MENU_BTN), tip_str.c_str());
3583 // 播放列表下拉菜单按钮
3584 tip_str = theApp.m_str_table.LoadText(L"UI_TIP_BTN_RECENT_FOLDER_OR_PLAYLIST");
3585 AddMouseToolTip(static_cast<CPlayerUIBase::BtnKey>(UiElement::TooltipIndex::PLAYLIST_DROP_DOWN_BTN), tip_str.c_str());
3586 // 循环模式
3587 AddMouseToolTip(BTN_REPETEMODE, m_repeat_mode_tip.c_str());
3588 UpdateRepeatModeToolTip();
3589 // 播放列表工具提示
3590 AddMouseToolTip(static_cast<CPlayerUIBase::BtnKey>(UiElement::TooltipIndex::PLAYLIST), L"");
3591 // tabElement工具提示
3592 AddMouseToolTip(static_cast<CPlayerUIBase::BtnKey>(UiElement::TooltipIndex::TAB_ELEMENT), L"");
3593 // "播放“我喜欢的音乐”"
3594 AddMouseToolTip(BTN_PLAY_MY_FAVOURITE, theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAY_MY_FAVOURITE").c_str());
3595 //歌词卡拉OK样式显示
3596 AddMouseToolTip(BTN_KARAOKE, theApp.m_str_table.LoadText(L"UI_TIP_BTN_KARAOKE").c_str());
3597 //搜索框清除按钮
3598 AddMouseToolTip(static_cast<CPlayerUIBase::BtnKey>(UiElement::TooltipIndex::SEARCHBOX_CLEAR_BTN), theApp.m_str_table.LoadText(L"TIP_SEARCH_EDIT_CLEAN").c_str());
3599 }
3600