xref: /MusicPlayer2/MusicPlayer2/CPlayerUIBase.cpp (revision fc77c71b2623add2756a54b7bf5cd93b7619bbd0)
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