1 #pragma once 2 #include "ColorConvert.h" 3 #include "DrawCommon.h" 4 #include "Common.h" 5 6 namespace CONSTVAL 7 { 8 const COLORREF BACKGROUND_COLOR = GRAY(255); //更改此颜色的值可以修改主窗口背景色 9 const double FULL_SCREEN_ZOOM_FACTOR = 1.5; 10 } 11 12 struct DeviceInfo //播放设备的信息 13 { 14 int index; //设备的索引 15 wstring name; //设备的名称 16 wstring driver; //设备的驱动程序 17 DWORD flags; //设备的状态 18 }; 19 20 21 struct FontStyle 22 { 23 bool bold{ false }; //粗体 24 bool italic{ false }; //斜体 25 bool underline{ false }; //下划线 26 bool strike_out{ false }; //删除线 27 ToIntFontStyle28 int ToInt() 29 { 30 int value = 0; 31 if (bold) 32 value |= 0x01; 33 if (italic) 34 value |= 0x02; 35 if (underline) 36 value |= 0x04; 37 if (strike_out) 38 value |= 0x08; 39 return value; 40 } 41 FromIntFontStyle42 void FromInt(int value) 43 { 44 bold = (value % 2 != 0); 45 italic = ((value >> 1) % 2 != 0); 46 underline = ((value >> 2) % 2 != 0); 47 strike_out = ((value >> 3) % 2 != 0); 48 } 49 }; 50 51 struct FontInfo 52 { 53 wstring name; //字体名称 54 int size; //字体大小 55 FontStyle style; //字体样式 56 }; 57 58 59 struct UIFont 60 { 61 private: 62 CFont font; 63 CFont font_l; 64 65 public: 66 CFont& GetFont(bool large = false) 67 { 68 return (large ? font_l : font); 69 } 70 71 void SetFont(int font_size, LPCTSTR font_name, FontStyle style = FontStyle()) 72 { 73 if (font_size < 5) 74 font_size = 5; 75 76 if (font.m_hObject) 77 font.DeleteObject(); 78 CreateFontSimple(font, font_size, font_name, style); 79 80 if (font_l.m_hObject) 81 font_l.DeleteObject(); 82 CreateFontSimple(font_l, static_cast<int>(font_size * CONSTVAL::FULL_SCREEN_ZOOM_FACTOR), font_name, style); 83 } 84 SetFontUIFont85 void SetFont(FontInfo font_info) 86 { 87 SetFont(font_info.size, font_info.name.c_str(), font_info.style); 88 } 89 90 static void CreateFontSimple(CFont& font, int font_size, LPCTSTR font_name, FontStyle style = FontStyle()) 91 { 92 font.CreateFont( 93 FontSizeToLfHeight(font_size), // nHeight 94 0, // nWidth 95 0, // nEscapement 96 0, // nOrientation 97 (style.bold ? FW_BOLD : FW_NORMAL), // nWeight 98 style.italic, // bItalic 99 style.underline, // bUnderline 100 style.strike_out, // cStrikeOut 101 DEFAULT_CHARSET, // nCharSet 102 OUT_DEFAULT_PRECIS, // nOutPrecision 103 CLIP_DEFAULT_PRECIS, // nClipPrecision 104 DEFAULT_QUALITY, // nQuality 105 DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily 106 font_name); 107 } 108 109 //将字号转成LOGFONT结构中的lfHeight FontSizeToLfHeightUIFont110 static int FontSizeToLfHeight(int font_size) 111 { 112 HDC hDC = ::GetDC(HWND_DESKTOP); 113 int lfHeight = -MulDiv(font_size, GetDeviceCaps(hDC, LOGPIXELSY), 72); 114 ::ReleaseDC(HWND_DESKTOP, hDC); 115 return lfHeight; 116 } 117 118 }; 119 120 struct FontSet 121 { 122 const int FONT_SIZE_MIN{ 8 }; 123 const int FONT_SIZE_MAX{ 16 }; 124 std::map<int, UIFont> fonts; //不同大小的默认字体 125 126 UIFont dlg; // 窗口控件字体 127 UIFont lyric; //歌词字体 128 UIFont lyric_translate; //歌词翻译的字体 129 UIFont cortana; //搜索框字体 130 UIFont cortana_translate; //搜索框翻译字体 131 132 133 void Init(LPCTSTR font_name); 134 135 //获取一个指定大小的字体(目前支持8~16) 136 UIFont& GetFontBySize(int font_size); 137 138 }; 139 140 141 //播放列表中项目的显示格式 142 enum DisplayFormat 143 { 144 DF_FILE_NAME, //文件名 145 DF_TITLE, //标题 146 DF_ARTIST_TITLE, //艺术家 - 标题 147 DF_TITLE_ARTIST //标题 - 艺术家 148 }; 149 150 //最近播放曲目列表显示范围 151 enum RecentPlayedRange 152 { 153 RPR_ALL, //显示全部 154 RPR_TODAY, //今天 155 RPR_THREE_DAYS, //最近三天 156 RPR_WEAK, //最近一个星期 157 RPR_MONTH, //最近一个月 158 RPR_HALF_YEAR, //最近半年 159 RPR_YEAR, //最近一年 160 }; 161 162 163 //选项设置数据 164 165 struct DesktopLyricSettingData //桌面歌词设置 166 { 167 bool lyric_double_line{ false }; 168 FontInfo lyric_font; 169 COLORREF text_color1{}; 170 COLORREF text_color2{}; 171 int text_gradient{}; 172 COLORREF highlight_color1{}; 173 COLORREF highlight_color2{}; 174 int highlight_gradient{}; 175 int opacity{ 100 }; 176 bool lock_desktop_lyric{ false }; 177 bool hide_lyric_window_without_lyric{ false }; //没有歌词时隐藏歌词窗口 178 bool hide_lyric_window_when_paused{ false }; //暂停时隐藏歌词窗口 179 bool lyric_background_penetrate{ false }; 180 bool show_unlock_when_locked{ true }; //桌面歌词锁定时显示解锁图标 181 Alignment lyric_align{ Alignment::AUTO }; //歌词的对齐方式 182 }; 183 184 struct LyricSettingData 185 { 186 bool lyric_karaoke_disp{ true }; //可以是否以卡拉OK样式显示 187 bool lyric_fuzzy_match{ true }; //歌词模糊匹配 188 // bool save_lyric_in_offset{}; //是否将歌词保存在offset标签中,还是保存在每个时间标签中 189 wstring lyric_path; //歌词文件夹的路径 190 bool use_inner_lyric_first{}; //优先使用内嵌歌词 191 bool show_translate{ true }; //歌词是否显示翻译 192 bool donot_show_blank_lines{}; //单行和双行显示模式下不显示空白行 193 bool show_song_info_if_lyric_not_exist{}; //是否在没有歌词时显示歌曲信息 194 195 enum LyricSavePolicy //歌词保存策略 196 { 197 LS_DO_NOT_SAVE, //不保存(手动保存) 198 LS_AUTO_SAVE, //自动保存 199 LS_INQUIRY //询问 200 }; 201 202 LyricSavePolicy lyric_save_policy{}; //歌词自动保存策略 203 204 FontInfo lyric_font; //歌词字体 205 int lyric_line_space{ 2 }; //歌词的行间距 206 Alignment lyric_align{ Alignment::AUTO }; //歌词的对齐方式 207 208 bool cortana_info_enable{}; //是否允许在Cortana的搜索框中显示信息 209 bool cortana_show_lyric{ true }; //是否在Cortana搜索框中显示歌词 210 bool cortana_lyric_double_line{ true }; //是否在Cortana搜索中以双行显示歌词 211 int cortana_color{ 0 }; //Cortana搜索框的背景颜色(0:跟随系统,1:黑色,2:白色) 212 bool cortana_show_album_cover{ true }; //是否在Cortana搜索框显示专辑封面 213 bool cortana_icon_beat{ true }; //Cortana图标随音乐节奏跳动 214 bool cortana_lyric_compatible_mode{ false }; //Cortana搜索框歌词显示使用兼容模式 215 FontInfo cortana_font; //搜索框字体 216 bool cortana_lyric_keep_display{ false }; //搜索框歌词是否在暂停时保持显示 217 bool cortana_show_spectrum{ false }; //是否在搜索框显示频谱 218 bool cortana_opaque{ false }; //搜索框不透明 219 Alignment cortana_lyric_align{ Alignment::AUTO }; //搜索框歌词对齐方式 220 bool show_default_album_icon_in_search_box{ false }; //没有歌词时搜索框显示黑色胶片图标 221 COLORREF cortana_transparent_color{}; 222 223 bool show_desktop_lyric{ false }; //显示桌面歌词 224 DesktopLyricSettingData desktop_lyric_data; 225 }; 226 227 struct ApperanceSettingData 228 { 229 int window_transparency{ 100 }; //窗口透明度 230 ColorTable theme_color; //主题颜色 231 bool theme_color_follow_system{ true }; //主题颜色跟随系统(仅Win8以上支持) 232 bool show_album_cover; //显示专辑封面 233 CDrawCommon::StretchMode album_cover_fit{ CDrawCommon::StretchMode::FILL }; //专辑封面契合度(拉伸模式) 234 bool enable_background{ true }; 235 bool album_cover_as_background{ false }; //将专辑封面作为背景 236 bool show_spectrum{ true }; //显示频谱分析 237 int sprctrum_height{ 100 }; //频谱分析高度比例(%) 238 bool spectrum_low_freq_in_center{ false }; //频谱分析低频部分显示在中间 239 bool use_old_style_specturm{ false }; //使用旧风格的频谱分析显示 240 int background_transparency{ 80 }; //背景的透明度 241 242 bool use_out_image{ true }; //使用外部图片作为专辑封面 243 bool use_inner_image_first{ true }; //优先使用内嵌专辑封面 244 wstring album_cover_path; // 专辑封面存储路径 245 vector<wstring> default_album_name; //默认的专辑封面文件名 246 247 bool background_gauss_blur{ true }; //背景高斯模糊 248 int gauss_blur_radius{ 60 }; //高斯模糊半径*10 249 bool lyric_background{ true }; //歌词界面背景 250 bool dark_mode{ false }; //深色模式 251 252 bool draw_album_high_quality{ false }; //专辑封面图片使用Gdi+高质量绘图 253 int ui_refresh_interval{ 100 }; //界面刷新的时间间隔 254 255 int notify_icon_selected{}; //使用的通知区图标 256 bool notify_icon_auto_adapt{ false }; //通知区图标是否自动适应Win10深浅色模式 257 258 bool button_round_corners{ false }; //按钮是否使用圆角风格 259 260 wstring default_background; //默认的背景图片 261 262 int playlist_width_percent{ 50 }; //主界面播放列表宽度的百分比 263 264 bool use_desktop_background{ false }; //使用桌面壁纸作为背景 265 266 bool always_show_statusbar{ false }; //总是显示状态栏 267 bool show_fps{ true }; //是否在状态栏显示帧率 268 bool show_next_track{ false }; //是否在状态栏显示下一首播放曲目 269 270 bool show_window_frame{ true }; //显示标准窗口边框 271 bool show_minimize_btn_in_titlebar{ true }; //是否在标题栏显示“最小化”按钮 272 bool show_maximize_btn_in_titlebar{ true }; //是否在标题栏显示“最大化”按钮 273 bool show_minimode_btn_in_titlebar{ true }; //是否在标题栏显示“迷你模式”按钮 274 bool show_fullscreen_btn_in_titlebar{ true }; //是否在标题栏显示“全屏模式”按钮 275 bool show_skin_btn_in_titlebar{ false }; //是否在标题栏显示“切换界面”按钮 276 bool show_settings_btn_in_titlebar{ false }; //是否在标题栏显示“设置”按钮 277 bool show_dark_light_btn_in_titlebar{ false }; //是否在标题栏显示“深色模式/浅色模式”按钮 278 int TitleDisplayItem() const; 279 280 //如果为true时,当系统为Windows10/11时,如果使用的是自绘标题栏,则去掉标题栏顶部的白边 281 //(目前还存在一些问题,当窗口得到或失去焦点时,窗口会闪烁) 282 bool remove_titlebar_top_frame{ false }; 283 }; 284 285 struct GeneralSettingData 286 { 287 bool id3v2_first{ false }; //优先获取ID3V2标签 288 bool auto_download_lyric{ false }; //是否自动下载歌词 289 bool auto_download_album_cover{ true }; //是否自动下载专辑封面 290 bool auto_download_only_tag_full{ true }; //仅在歌曲信息完整时自动下载 291 bool save_lyric_to_song_folder{ true }; // 将自动下载的歌词文件保存在歌曲文件夹 292 bool save_album_to_song_folder{ true }; // 将自动下载的封面文件保存在歌曲文件夹 293 bool download_lyric_text_and_translation_in_same_line{ true }; //下载的歌词原文和翻译在同一行 294 bool check_update_when_start{ true }; //是否在程序启动时检查更新 295 int update_source{}; //更新源。0: GitHub; 1: Gitee 296 bool minimize_to_notify_icon{ false }; //是否最小到通知区图标 297 bool global_mouse_wheel_volume_adjustment{ true }; //全局鼠标滚轮音量调节 298 299 wstring language_; // 这个是设置状态(空字符串为跟随系统) 300 bool portable_mode{ false }; //如果为true,则程序所有数据都保存到exe所在目录下,否则保存到Appdata\Romaing目录下 301 }; 302 303 struct PlaySettingData 304 { 305 bool stop_when_error{ true }; //出现错误时停止播放 306 bool auto_play_when_start{ false }; //程序启动时自动播放 307 bool continue_when_switch_playlist{ false };//若当前播放歌曲存在于切换到的播放列表则保持播放状态不变 308 bool show_taskbar_progress{ false }; //在任务栏按钮上显示播放进度 309 bool show_playstate_icon{ true }; //在任务栏按钮上显示播放状态的角标 310 wstring output_device; //播放设备的名称 311 int device_selected{}; 312 bool fade_effect{ true }; //播放淡入淡出效果 313 int fade_time{ 500 }; //淡入淡出时间(毫秒) 314 bool use_media_trans_control{}; //使用系统MediaTransportControls 315 316 bool use_mci{ false }; //是否使用MCI内核 317 /// 是否使用ffmpeg内核 318 bool use_ffmpeg{ false }; 319 /// ffmpeg内核缓存时长(单位:s) 320 int ffmpeg_core_cache_length { 15 }; 321 /// ffmpeg内核最大重试次数 322 int ffmpeg_core_max_retry_count { 3 }; 323 /// ffmpeg内核非本地文件重试间隔时间(单位s) 324 int ffmpeg_core_url_retry_interval { 5 }; 325 /// ffmpeg内核是否启用WASAPI 326 int ffmpeg_core_enable_WASAPI { false }; 327 /// ffmpeg内核是否启用WASAPI独占模式 328 int ffmpeg_core_enable_WASAPI_exclusive_mode { false }; 329 /// ffmpeg内核seek等操作最大等待时间 330 int ffmpeg_core_max_wait_time { 3000 }; 331 332 //MIDI设置 333 wstring sf2_path; //MIDI音色库路径 334 bool midi_use_inner_lyric{ false }; //播放MIDI音乐时显示内嵌歌词 335 }; 336 337 struct GlobalHotKeySettingData 338 { 339 bool hot_key_enable = true; 340 bool global_multimedia_key_enable{ true }; //是否在全局范围内启用多媒体键 341 }; 342 343 enum MediaLibDisplayItem 344 { 345 MLDI_ARTIST = 1, 346 MLDI_ALBUM = (1 << 1), 347 MLDI_GENRE = (1 << 2), 348 MLDI_YEAR = (1 << 3), 349 MLDI_TYPE = (1 << 4), 350 MLDI_BITRATE = (1 << 5), 351 MLDI_RATING = (1 << 6), 352 MLDI_ALL = (1 << 7), 353 MLDI_RECENT = (1 << 8), 354 MLDI_FOLDER_EXPLORE = (1 << 9) 355 }; 356 357 struct MediaLibSettingData 358 { 359 vector<wstring> media_folders; //媒体库文件夹浏览中显示的文件夹 360 vector<wstring> artist_split_ext; // 艺术家分割例外,设置名字本身含有分隔符(/;&、)的艺术家(22/7) 361 bool hide_only_one_classification; //媒体库中将只有一项的分类归到其他类中 362 bool disable_delete_from_disk; //禁用从磁盘删除 363 bool show_tree_tool_tips; //树控件显示鼠标提示 364 bool update_media_lib_when_start_up; //启动时自动更新媒体库 365 bool ignore_too_short_when_update; // 自动更新/刷新媒体库时忽略时长低于阈值的文件(不影响手动加入) 366 int file_too_short_sec; // 音频低时长阈值(清理媒体库功能也使用这个设置) 367 bool remove_file_not_exist_when_update{}; //更新媒体库时移除不存在的音频文件 368 bool disable_drag_sort; //禁止通过拖放排序 369 DisplayFormat display_format{}; //播放列表中项目的显示样式 370 bool insert_begin_of_playlist{ false }; // 向播放列表添加歌曲时插入开头而不是追加到末尾 371 bool show_playlist_tooltip{}; //显示播放列表工具提示 372 bool float_playlist_follow_main_wnd{}; //浮动播放列表跟随主窗口 373 bool playlist_btn_for_float_playlist{ false }; // 指定主界面中进度条右侧的“显示/隐藏播放列表”按钮的功能是否为显示浮动播放列表 374 int playlist_item_height{ 24 }; 375 RecentPlayedRange recent_played_range{}; //最近播放曲目列表的显示范围 376 int display_item{}; //媒体库显示的项目 377 bool write_id3_v2_3{ false }; //写入的ID3V2版本是否为2.3,否则为2.4 378 bool enable_lastfm { false }; ///是否启用Last.fm相关功能 379 int lastfm_least_perdur { 50 }; ///将记录写入缓存要求播放的百分比 380 int lastfm_least_dur { 60 }; ///将记录写入缓存要求播放的秒数 381 bool lastfm_auto_scrobble { true }; ///是否自动上传缓存里的记录 382 int lastfm_auto_scrobble_min { 1 }; ///自动上传缓存里的记录的下限 383 bool lastfm_enable_https { false }; ///是否使用HTTPS与last.fm服务器通信 384 bool lastfm_enable_nowplaying{ true }; ///是否上传当前播放歌曲 385 }; 386 387 struct NonCategorizedSettingData 388 { 389 int volum_step{ 3 }; //点击主界面中的音量调节时一次调整的步长 390 int mouse_volum_step{ 2 }; //通过鼠标滚轮调节音量时的步长 391 int volume_map{ 100 }; //音量映射(例如:如果将此值从100改为60,则当音量设置为最大(100%)时的音量大小为原来的60%) 392 bool show_cover_tip{ true }; //是否显示专辑封面上的鼠标提示 393 //wstring default_back_image_path{}; //没有专辑封面时的默认背景的路径 394 bool no_sf2_warning{ true }; //是否在没有MIDI音色库时弹出提示信息 395 bool show_hide_menu_bar_tip{ true }; //是隐藏菜单栏是否弹出提示信息 396 bool always_on_top{ false }; //是否总是置顶 397 wstring default_osu_img; 398 399 bool float_playlist{ false }; //浮动播放列表(不应该用此变量来判断浮动播放列表是否存在) 400 CSize playlist_size{ 320, 530 }; //浮动播放列表的大小 401 402 int max_album_cover_size{ 800 }; 403 bool show_debug_info{ false }; 404 405 int light_mode_default_transparency{ 80 }; 406 int dark_mode_default_transparency{ 40 }; 407 408 vector<wstring> default_file_type; 409 vector<wstring> user_defined_type_ffmpeg; //FFMPEG内核时用户添加的文件格式扩展名 410 411 enum eLogType 412 { 413 LT_NONE = 0, 414 LT_NORMAL = 1, 415 LT_ERROR = 2 416 }; 417 418 int debug_log{ 0 }; //是否写入日志信息 419 }; 420 421 422 //界面相关的一些选项 423 struct UIData 424 { 425 bool narrow_mode; //窄界面模式 426 bool show_playlist{ true }; 427 bool show_menu_bar{ true }; 428 bool full_screen{ false }; 429 430 int draw_area_width; //绘图区的宽度 431 int draw_area_height; //绘图区的高度 432 CImage default_background; //默认的背景 433 CCriticalSection default_background_sync; 434 435 bool ShowWindowMenuBar() const ;/* { return show_menu_bar && show_window_frame && !full_screen; }*/ 436 bool ShowUiMenuBar() const;/* { return show_menu_bar && !show_window_frame && !full_screen; }*/ 437 }; 438 439 440 struct ImageSet 441 { 442 Gdiplus::Image* default_cover_img{}; 443 Gdiplus::Image* default_cover_not_played_img{}; 444 string default_cover_img_data; 445 string default_cover_not_played_img_data; 446 ~ImageSetImageSet447 ~ImageSet() 448 { 449 SAFE_DELETE(default_cover_img); 450 SAFE_DELETE(default_cover_not_played_img); 451 } 452 }; 453 454 //通过构造函数传递一个bool变量的引用,在构造时将其置为true,析构时置为false 455 class CFlagLocker 456 { 457 public: CFlagLocker(bool & flag)458 CFlagLocker(bool& flag) 459 : m_flag(flag) 460 { 461 m_flag = true; 462 } 463 ~CFlagLocker()464 ~CFlagLocker() 465 { 466 m_flag = false; 467 } 468 469 private: 470 bool& m_flag; 471 }; 472 473 474 struct MediaUpdateThreadPara 475 { 476 int num_added{}; //更新媒体库时新增(包括更新)的音频文件数量 477 int process_percent{}; // 更新媒体库进度% 478 bool thread_exit{}; //如果为true,则线程应该退出 479 bool force; // 为true时无视修改时间强制刷新 480 }; 481