1 #pragma once 2 #include "MusicPlayer2.h" 3 #include "IPlayerUI.h" 4 #include "CPlayerUIHelper.h" 5 #include "CUIDrawer.h" 6 #include "IconMgr.h" 7 8 #define WM_MAIN_MENU_POPEDUP (WM_USER+117) //显示弹出式主菜单的消息,wPara为表示菜单显示位置的CPoint的指针 9 10 namespace UiElement 11 { 12 class Element; 13 class Rectangle; 14 class Button; 15 class Text; 16 class AlbumCover; 17 class Spectrum; 18 class TrackInfo; 19 class Toolbar; 20 class ProgressBar; 21 class Lyrics; 22 class Volume; 23 class BeatIndicator; 24 class StackElement; 25 class ListElement; 26 class Playlist; 27 class PlaylistIndicator; 28 class ClassicalControlBar; 29 class MediaLibItemList; 30 class MediaLibPlaylist; 31 class MediaLibFolder; 32 class RecentPlayedList; 33 class NavigationBar; 34 class MyFavouriteList; 35 class AllTracksList; 36 class MiniSpectrum; 37 class FolderExploreTree; 38 class SearchBox; 39 } 40 41 struct SLayoutData 42 { 43 const int margin = theApp.DPI(4); //边缘的余量 44 const int width_threshold = theApp.DPI(600); //界面从普通界面模式切换到窄界面模式时界面宽度的阈值 45 const int info_height = theApp.DPI(216); //窄界面模式时显示信息区域的高度 46 const int path_edit_height = theApp.DPI(24); //当前路径Edit控件的高度 47 const int search_edit_height = theApp.DPI(26); //歌曲搜索框Edit控件区域的高度 48 const CSize spectral_size{ theApp.DPI(120), theApp.DPI(90) }; //频谱分析区域的大小 49 const int toolbar_height = theApp.DPI(24); //播放列表工具栏的高度 50 const int titlabar_height = theApp.DPI(28); //标题栏的高度 51 const int menubar_height = theApp.DPI(24); //菜单栏的高度 52 }; 53 54 namespace PlayerUiConstVal 55 { 56 const int BTN_MAX_NUM = 1000; 57 } 58 59 class CPlayerUIBase : public IPlayerUI 60 { 61 public: 62 CPlayerUIBase(UIData& ui_data, CWnd* pMainWnd); 63 ~CPlayerUIBase(); 64 GetToolTipCtrl()65 virtual CToolTipCtrl& GetToolTipCtrl() override { return m_tool_tip; } 66 67 friend class UiElement::Element; 68 friend class UiElement::Rectangle; 69 friend class UiElement::Button; 70 friend class UiElement::Text; 71 friend class UiElement::AlbumCover; 72 friend class UiElement::Spectrum; 73 friend class UiElement::TrackInfo; 74 friend class UiElement::Toolbar; 75 friend class UiElement::ProgressBar; 76 friend class UiElement::Lyrics; 77 friend class UiElement::Volume; 78 friend class UiElement::BeatIndicator; 79 friend class UiElement::StackElement; 80 friend class UiElement::ListElement; 81 friend class UiElement::Playlist; 82 friend class UiElement::PlaylistIndicator; 83 friend class UiElement::ClassicalControlBar; 84 friend class UiElement::MediaLibItemList; 85 friend class UiElement::MediaLibPlaylist; 86 friend class UiElement::MediaLibFolder; 87 friend class UiElement::RecentPlayedList; 88 friend class UiElement::NavigationBar; 89 friend class UiElement::MyFavouriteList; 90 friend class UiElement::AllTracksList; 91 friend class UiElement::MiniSpectrum; 92 friend class UiElement::FolderExploreTree; 93 friend class UiElement::SearchBox; 94 95 friend class UiFontGuard; 96 97 public: 98 void Init(CDC* pDC) override; 99 virtual void DrawInfo(bool reset = false) override final; 100 virtual void ClearInfo() override; 101 102 virtual bool LButtonDown(CPoint point) override; 103 virtual void RButtonUp(CPoint point) override; 104 virtual void MouseMove(CPoint point) override; 105 virtual bool LButtonUp(CPoint point) override; 106 virtual void RButtonDown(CPoint point) override; 107 virtual bool MouseWheel(int delta, CPoint point) override; 108 virtual bool DoubleClick(CPoint point) override; 109 110 virtual CRect GetThumbnailClipArea() override; 111 void UpdateRepeatModeToolTip(); 112 void UpdateSongInfoToolTip(); 113 void UpdatePlayPauseButtonTip() override; 114 virtual void UpdateFullScreenTip() override; 115 void UpdateTitlebarBtnToolTip(); //更新标题栏上的最大化/还原按钮的鼠标提示 116 virtual void UpdateVolumeToolTip(); 117 void UpdatePlaylistBtnToolTip(); 118 void UpdateDarkLightModeBtnToolTip(); 119 void UpdateToolTipPositionLater(); 120 121 virtual bool SetCursor() override; 122 virtual void MouseLeave() override; 123 124 void ClearBtnRect(); 125 126 int Margin() const; 127 int EdgeMargin(bool x = true) const; 128 int WidthThreshold() const; 129 int DrawAreaHeight() const; //窄界面模式下显示播放列表时绘图区的高度 130 int TopRightButtonsWidth() const; 131 132 virtual bool PointInControlArea(CPoint point) const; //判断一个点的位置是否在控件区域 133 bool PointInTitlebarArea(CPoint point) const; 134 bool PointInAppIconArea(CPoint point) const; 135 bool PointInMenubarArea(CPoint point) const; 136 137 //获取界面的名称 GetUIName()138 virtual wstring GetUIName() { return wstring(); } 139 140 enum class UiSize 141 { 142 BIG, 143 NARROW, 144 SMALL 145 }; 146 147 UiSize GetUiSize() const; 148 UiSizeChanged()149 virtual void UiSizeChanged() {} 150 151 static CString GetCmdShortcutKeyForTooltips(UINT id); //获取用于显示在鼠标提示中的键盘快捷键 152 153 CRect GetVolumeRect() const; //获取音量图标的矩形区域 154 155 protected: 156 // 将字符串形如“%(KEY_STR)”格式的字符替换成当前<language>.ini中对应id的字符串 157 static void ReplaceUiStringRes(wstring& str); 158 159 public: 160 enum BtnKey //标识按钮的类型 161 { 162 BTN_REPETEMODE, //“循环模式”按钮 163 BTN_VOLUME, //音量按钮 164 BTN_VOLUME_UP, 165 BTN_VOLUME_DOWN, 166 BTN_TRANSLATE, //歌词翻译按钮 167 BTN_SKIN, //切换界面按钮 168 BTN_SKIN_TITLEBAR, //标题栏上的切换界面按钮 169 BTN_EQ, //音效设定按钮 170 BTN_SETTING, //设置按钮 171 BTN_SETTING_TITLEBAR, //标题栏上的设置按钮 172 BTN_MINI, //迷你模式按钮 173 BTN_MINI_TITLEBAR, //标题栏上的迷你模式按钮 174 BTN_INFO, //曲目信息按钮 175 BTN_FIND, //查找歌曲按钮 176 BTN_LRYIC, //桌面歌词按钮 177 BTN_AB_REPEAT, //AB重复按钮 178 BTN_STOP, //停止 179 BTN_PREVIOUS, //上一曲 180 BTN_PLAY_PAUSE, //播放/暂停 181 BTN_NEXT, //下一曲 182 BTN_SHOW_PLAYLIST, //显示/隐藏播放列表 183 BTN_MEDIA_LIB, //媒体库 184 BTN_PROGRESS, //进度条 185 BTN_COVER, //专辑封面 186 BTN_FULL_SCREEN_TITLEBAR, //标题栏上的全屏显示按钮 187 BTN_FULL_SCREEN, //全屏显示按钮 188 BTN_MENU_TITLEBAR, //标题栏上的主菜单按钮 189 BTN_MENU, //主菜单按钮 190 BTN_FAVOURITE, //“我喜欢”按钮 191 BTN_CLOSE, //关闭按钮(迷你模式) 192 BTN_MINIMIZE, //最小化按钮 193 BTN_MAXIMIZE, //最大化按钮 194 BTN_APP_CLOSE, //关闭按钮 195 BTN_ADD_TO_PLAYLIST, //添加到播放列表按钮 196 BTN_SWITCH_DISPLAY, //切换界面中的stackElement 197 BTN_DARK_LIGHT, //切换深色/浅色模式 198 BTN_DARK_LIGHT_TITLE_BAR, //标题栏中的切换深色/浅色模式 199 BTN_LOCATE_TO_CURRENT, //播放列表定位到当前播放 200 BTN_OPEN_FOLDER, //打开文件夹 201 BTN_NEW_PLAYLIST, //新建播放列表 202 BTN_PLAY_MY_FAVOURITE, //播放“我喜欢的音乐” 203 BTN_MEDIALIB_FOLDER_SORT, //媒体库“文件夹”排序方式 204 BTN_MEDIALIB_PLAYLIST_SORT, //媒体库“播放列表”排序方式 205 BTN_KARAOKE, //歌词卡拉OK模式显示 206 207 //菜单栏 208 MENU_FILE, 209 MENU_PLAY_CONTROL, 210 MENU_PLAYLIST, 211 MENU_LYRICS, 212 MENU_VIEW, 213 MENU_TOOLS, 214 MENU_HELP, 215 216 BTN_INVALID, //无效的按钮 217 }; 218 219 enum ColorMode 220 { 221 RCM_AUTO, 222 RCM_DARK, 223 RCM_LIGHT 224 }; 225 226 // 获取参数按钮当前应当使用的图标类型 227 // 将BtnKey枚举和当前状态组合映射为IconMgr::IconType枚举 228 IconMgr::IconType GetBtnIconType(BtnKey key); 229 230 //获取按钮的文本 231 std::wstring GetButtonText(BtnKey key_type); 232 233 protected: 234 struct DrawData 235 { 236 //CRect cover_rect; 237 CRect lyric_rect; 238 CRect thumbnail_rect; 239 }; 240 241 protected: 242 virtual void _DrawInfo(CRect draw_rect, bool reset = false) = 0; 243 virtual void PreDrawInfo(); 244 void SetDrawRect(); 245 void DrawBackground(); 246 void DrawSongInfo(CRect rect, int font_size = 9, bool reset = false); 247 void DrawRectangle(const CRect& rect, bool no_corner_radius = false, bool theme_color = true, ColorMode color_mode = RCM_AUTO); //绘制矩形。如果no_corner_radius为true,则总是绘制直角矩形,忽略“使用圆角风格按钮”的设置;theme_color:是否使用主题彦颜色 248 void DrawToolBar(CRect rect, bool draw_translate_button); 249 void DrawToolBarWithoutBackground(CRect rect, bool draw_translate_button); 250 void DrawBeatIndicator(CRect rect); 251 void DrawVolumnAdjBtn(); 252 void DrawControlBar(CRect rect, bool draw_switch_display_btn = false); 253 void DrawProgressBar(CRect rect, bool play_time_both_side = false); //绘制进度条(包含时间)。play_time_both_side如果为true,则播放时间显示的进度条的两侧,否则显示在进度条的右侧 254 void DrawProgess(CRect rect); //绘制进度条 255 void DrawTranslateButton(CRect rect); 256 void DrawDesktopLyricButton(CRect rect); 257 void DrawKaraokeButton(CRect rect); 258 void DrawTopRightIcons(); //绘制右上角的图标 259 void DrawCurrentTime(); //在右上角绘制当前系统时间 260 void DrawAlbumCover(CRect rect); //绘制专辑封面 261 void DrawAlbumCoverWithInfo(CRect rect); //绘制专辑封面,并在上面绘制歌曲的标题和艺术家 262 void DrawVolumeButton(CRect rect, bool adj_btn_top = false, bool show_text = true); //adj_btn_top:点击后弹出的音量调整按钮是否在上方;show_text:是否显示文本 263 void DrawABRepeatButton(CRect rect); 264 void DrawLyrics(CRect rect, CFont* lyric_font, CFont* lyric_tr_font, bool with_background, bool show_song_info = false); //绘制歌词 rect:歌曲区域;with_background是否绘制背景;show_song_info:是否总是在没有歌词时显示歌曲信息 265 void DrawList(CRect rect, UiElement::ListElement* list_element, int item_height); //绘制播放列表 266 void DrawCurrentPlaylistIndicator(CRect rect, UiElement::PlaylistIndicator* playlist_indicator); //绘制当前播放列表指示 267 /** 268 * @brief 绘制stackElement的指示器 269 * @param UIButton indicator 指示器信息 270 * @param int num 指示器中元素的数量 271 * @param int index 指示器当前索引 272 */ 273 void DrawStackIndicator(UIButton indicator, int num, int index); 274 void DrawUiMenuBar(CRect rect); 275 void DrawNavigationBar(CRect rect, UiElement::NavigationBar* tab_element); 276 void DrawMiniSpectrum(CRect rect); //绘制图标大小的迷你频谱 277 void DrawSearchBox(CRect rect, UiElement::SearchBox* search_box); 278 279 // 实际绘制一个图标 280 void DrawUiIcon(const CRect& rect, IconMgr::IconType icon_type, IconMgr::IconStyle icon_style = IconMgr::IconStyle::IS_Auto, IconMgr::IconSize icon_size = IconMgr::IconSize::IS_DPI_16); 281 // 绘制一个UI按钮 (使用GetBtnIconType取得的图标) 282 void DrawUIButton(const CRect& rect, BtnKey key_type, bool big_icon = false, bool show_text = false, int font_size = 9, bool checked = false); 283 void DrawUIButton(const CRect& rect, UIButton& btn, IconMgr::IconType icon_type, bool big_icon = false, const std::wstring& text = std::wstring(), int font_size = 9, bool checked = false); 284 // 绘制一个工具条按钮(将rect四面缩小 DPI(2) 后调用DrawUIButton) 285 void DrawControlBarBtn(CRect rect, BtnKey btn_type); 286 // 绘制一个UI按钮,以text文本作为图标 287 void DrawTextButton(CRect rect, BtnKey btn_type, LPCTSTR text, bool checked = false); 288 289 virtual void AddMouseToolTip(BtnKey btn, LPCTSTR str); //为一个按钮添加鼠标提示 290 virtual void UpdateMouseToolTip(BtnKey btn, LPCTSTR str); UpdateMouseToolTip(int btn,LPCTSTR str)291 virtual void UpdateMouseToolTip(int btn, LPCTSTR str) override { UpdateMouseToolTip(static_cast<BtnKey>(btn), str); } 292 virtual void UpdateMouseToolTipPosition(int btn, CRect rect); 293 294 virtual void UpdateToolTipPosition() override; 295 296 virtual void AddToolTips(); //为每一个按钮添加鼠标提示(由于按钮的矩形区域只有在第一次绘图之后才能确定,所以此函数必须在第一次绘图之后调用) 297 298 //当绘图区域的原点不是窗口的原点的时候需要使用这两个函数在绘图区域坐标和窗口坐标中转换 299 //现在这两个函数已弃用 300 static CRect DrawAreaToClient(CRect rect, CRect draw_area); 301 static CRect ClientAreaToDraw(CRect rect, CRect draw_area); 302 303 bool IsDrawNarrowMode() const; //是否使用窄界面模式绘图 304 bool IsDrawBackgroundAlpha() const; //是否需要绘制透明背景 305 virtual bool IsDrawStatusBar() const; //是否需要绘制状态栏 306 virtual bool IsDrawTitleBar() const; //是否需要绘制标题栏 307 virtual bool IsDrawMenuBar() const; //是否需要绘制菜单栏 308 309 static wstring GetDisplayFormatString(); //获取显示格式的字符串 310 CString GetVolumeTooltipString(); //获取音量鼠标提示字符串 311 312 int DPI(int pixel) const; 313 int DPI(double pixel) const; 314 double DPIDouble(double pixel); 315 double GetScrollTextPixel(bool slower = false); //计算滚动文本一次滚动的像素值,如果slower为true,则滚动得稍微慢一点 316 int CalculateRoundRectRadius(const CRect& rect); //计算绘制圆角矩形的半径 317 318 virtual bool IsDrawLargeIcon() const; //是否绘制大图标 319 SwitchStackElement()320 virtual void SwitchStackElement() {} 321 322 bool IsMiniMode() const; 323 324 public: GetUiIndex()325 virtual int GetUiIndex() { return 1; } //UI的序号,用于区分每个界面,不会为0 326 327 void ShowUiTipInfo(const std::wstring& info); //在界面的中央显示一个提示信息,几秒钟后自动消失 328 329 private: 330 void SetRepeatModeToolTipText(); 331 void SetSongInfoToolTipText(); 332 void SetCoverToolTipText(); 333 void DrawPlayTag(CRect rect, LPCTSTR str_text); 334 335 void DrawStatusBar(CRect rect, bool reset = false); 336 void DrawTitleBar(CRect rect); 337 338 int GetToolTipIdOffset(); 339 340 protected: 341 CWnd* m_pMainWnd = nullptr; 342 CDC* m_pDC; 343 UIColors m_colors; 344 CUIDrawer m_draw{ m_colors }; //用于绘制文本的对象 345 SLayoutData m_layout; 346 //CFont m_font_time; 347 DrawData m_draw_data; 348 349 350 CToolTipCtrl m_tool_tip; 351 352 wstring m_repeat_mode_tip; 353 wstring m_info_tip; 354 wstring m_cover_tip; 355 356 UIData& m_ui_data; 357 358 //UI 数据 359 CRect m_draw_rect; //绘图区域 360 bool m_show_volume_adj{ false }; //显示音量调整按钮 361 bool m_show_volume_text{}; //是否显示音量文本 362 363 std::map<BtnKey, UIButton> m_buttons; 364 365 const int m_progress_on_top_threshold = theApp.DPI(350); //当控制条的宽度小于此值,将进度条显示在播放控制按钮的上方 366 367 bool m_first_draw{ true }; 368 369 private: 370 CBitmap m_mem_bitmap_static; 371 372 bool m_need_update_tooltip_pos{ false }; //是否需要更新鼠标提示 373 374 enum { UI_TIP_INFO_TIMER_ID = 1728 }; 375 376 static bool m_show_ui_tip_info; 377 wstring m_ui_tip_info; 378 int m_top_right_buttons_width{}; 379 }; 380 381 //用于在UI中设置字体。 382 //在需要设置字体时,创建此类的一个局部对象,它会在构造时设置字体,并在析构时恢复原来的字体 383 class UiFontGuard 384 { 385 public: UiFontGuard(CPlayerUIBase * _ui,int font_size)386 UiFontGuard(CPlayerUIBase* _ui, int font_size) 387 : ui(_ui) 388 { 389 if (ui != nullptr) 390 { 391 bool big_font{ ui->m_ui_data.full_screen && ui->IsDrawLargeIcon() }; 392 //设置字体 393 old_font = ui->m_draw.SetFont(&theApp.m_font_set.GetFontBySize(font_size).GetFont(big_font)); 394 } 395 } ~UiFontGuard()396 ~UiFontGuard() 397 { 398 if (ui != nullptr) 399 { 400 //恢复原来的字体 401 if (old_font != nullptr) 402 ui->m_draw.SetFont(old_font); 403 } 404 } 405 406 private: 407 CFont* old_font{}; 408 CPlayerUIBase* ui{}; 409 }; 410