xref: /MusicPlayer2/MusicPlayer2/UIElement.h (revision fc77c71b2623add2756a54b7bf5cd93b7619bbd0)
1 #pragma once
2 #include "CPlayerUIBase.h"
3 #include "ListCache.h"
4 
5 class CUiSearchBox;
6 
7 //定义界面元素
8 namespace UiElement
9 {
10     //所有界面元素的基类
11     class Element
12     {
13     public:
14         struct Value        //一个布局的数值
15         {
16             Value(bool _is_vertical, Element* _owner);
17             void FromString(const std::string str);
18             int GetValue(CRect parent_rect) const;   // 获取实际显示的数值
19             bool IsValid() const;           // 返回true说明设置过数值
20         private:
21             int value{ 0 };                 // 如果is_percentate为true则值为百分比,否则为实际值
22             bool valid{ false };            // 如果还没有设置过数值,则为false
23             bool is_percentage{ false };    // 数值是否为百分比
24             bool is_vertical{ false };      // 数值是否为垂直方向的
25             Element* owner;
26         };
27         Value margin_left{ false, this };
28         Value margin_right{ false, this };
29         Value margin_top{ true, this };
30         Value margin_bottom{ true, this };
31         Value x{ false, this };
32         Value y{ true, this };
33         Value width{ false, this };
34         Value height{ true, this };
35         Value max_width{ false, this };
36         Value max_height{ true, this };
37         Value min_width{ false, this };
38         Value min_height{ true, this };
39         Value hide_width{ false, this };
40         Value hide_height{ true, this };
41         int proportion{ 0 };
42 
43         Element* pParent{};     //父元素
44         std::vector<std::shared_ptr<Element>> childLst; //子元素列表
45         std::string name;
46 
47         virtual void Draw();   //绘制此元素
48         virtual bool IsEnable(CRect parent_rect) const;
49         virtual int GetMaxWidth(CRect parent_rect) const;
50         virtual int GetWidth(CRect parent_rect) const;
51         virtual int GetHeight(CRect parent_rect) const;
52         virtual bool IsWidthValid() const;
53         virtual bool IsHeightValid() const;
54         CRect GetRect() const;      //获取此元素在界面中的矩形区域
55         void SetRect(CRect _rect);
56         virtual void ClearRect();
57         Element* RootElement();       //获取根节点
58         //遍历所有界面元素
59         //visible_only为true时,遇到stackElement时,只遍历stackElement下面可见的子节点
60         void IterateAllElements(std::function<bool(UiElement::Element*)> func, bool visible_only = false);
61         void SetUi(CPlayerUIBase* _ui);
62         void AddChild(std::shared_ptr<Element> child);
63 
64         //鼠标消息虚函数。
65         //即使鼠标的位置不在当前元素的矩形区域内,函数仍然会响应,因此在重写这些虚函数时需要先使用rect.PtInRect(point)判断鼠标位置是否在矩形区域内。
LButtonUp(CPoint point)66         virtual void LButtonUp(CPoint point) {}
LButtonDown(CPoint point)67         virtual void LButtonDown(CPoint point) {}
MouseMove(CPoint point)68         virtual void MouseMove(CPoint point) {}
RButtunUp(CPoint point)69         virtual bool RButtunUp(CPoint point) { return false; }
RButtonDown(CPoint point)70         virtual void RButtonDown(CPoint point) {}
MouseWheel(int delta,CPoint point)71         virtual bool MouseWheel(int delta, CPoint point) { return false; }
DoubleClick(CPoint point)72         virtual bool DoubleClick(CPoint point) { return false; }
MouseLeave()73         virtual void MouseLeave() {}
74 
75     protected:
76         CRect ParentRect() const;
77         virtual void CalculateRect();           //计算此元素在界面中的矩形区域
78         static void IterateElements(UiElement::Element* parent_element, std::function<bool(UiElement::Element*)> func, bool visible_only = false);
79 
80         CRect rect;     //用于保存计算得到的元素的矩形区域
81         CPlayerUIBase* ui{};
82     };
83 
84     namespace TooltipIndex
85     {
86         const int PLAYLIST = 900;
87         const int TAB_ELEMENT = 901;
88         const int PLAYLIST_DROP_DOWN_BTN = 902;
89         const int PLAYLIST_MENU_BTN = 903;
90         const int SEARCHBOX_CLEAR_BTN = 904;
91     }
92 
93     //布局
94     class Layout : public Element
95     {
96     public:
97         enum Type
98         {
99             Vertical,
100             Horizontal,
101         };
102         Type type;
103         void CalculateChildrenRect();      //计算布局中所有子元素的位置
104         virtual void Draw() override;
105     };
106 
107     //包含多个元素的堆叠元素,同时只能显示一个元素
108     class StackElement : public Element
109     {
110     public:
111         void SetCurrentElement(int index);
112         void SwitchDisplay(bool previous = false);
113         virtual void Draw() override;
114         bool click_to_switch{};     //鼠标点击时切换
115         bool hover_to_switch{};     //鼠标指向时切换
116         bool scroll_to_switch{};	//鼠标滚轮切换
117         bool show_indicator{};
118         int indicator_offset{};
119         bool mouse_hover{};
120         IPlayerUI::UIButton indicator{};        //指示器
121         int GetCurIndex() const;
122 
123     protected:
124         std::shared_ptr<Element> CurrentElement();
125         std::shared_ptr<Element> GetElement(int index);
126 
127         int cur_index{};
128     };
129 
130     //半透明的矩形
131     class Rectangle : public Element
132     {
133     public:
134         bool no_corner_radius{};
135         bool theme_color{ true };
136         CPlayerUIBase::ColorMode color_mode{ CPlayerUIBase::RCM_AUTO };
137         virtual void Draw() override;
138     };
139 
140     //按钮
141     class Button : public Element
142     {
143     public:
144         CPlayerUIBase::BtnKey key;      //按钮的类型
145         bool big_icon{};                //如果为false,则图标尺寸为16x16,否则为20x20
146         bool show_text{};               //是否在图标右侧显示文本
147         int font_size{ 9 };             //字体大小,仅在show_text为true时有效
148         virtual void Draw() override;
149         void FromString(const std::string& key_type);
150         virtual int GetMaxWidth(CRect parent_rect) const override;
151         virtual void ClearRect() override;
152     };
153 
154     //文本
155     class Text : public Element
156     {
157     public:
158         std::wstring text;
159         Alignment align{};    //对齐方式
160         enum Style       //文本的样式
161         {
162             Static,     //静止的文本
163             Scroll,     //滚动的文本
164             Scroll2     //另一种滚动的文本(只朝一个方向滚动)
165         };
166         Style style;
167 
168         enum Type       //文本的类型
169         {
170             UserDefine, //用户指定(text的值)
171             Title,      //歌曲标题
172             Artist,     //歌曲艺术家
173             Album,      //歌曲唱片集
174             ArtistTitle,    //艺术家 - 标题
175             ArtistAlbum,    //艺术家 - 唱片集
176             Format,     //歌曲格式
177             PlayTime,   //播放时间
178             PlayTimeAndVolume   //显示为播放时间,如果正在调整音量,则显示当前音量,一段时间后恢复
179         };
180 
181         Type type;
182         int font_size{ 9 };
183         bool width_follow_text{};
184         CPlayerUIBase::ColorMode color_mode{ CPlayerUIBase::RCM_AUTO };
185         bool show_volume{};     //当type为PlayTimeAndVolume时有效,如果为true,则显示为音量
186 
187         virtual void Draw() override;
188         virtual int GetMaxWidth(CRect parent_rect) const override;
189         std::wstring GetText() const;
190 
191     private:
192         mutable CDrawCommon::ScrollInfo scroll_info;
193     };
194 
195     //专辑封面
196     class AlbumCover : public Element
197     {
198     public:
199         bool square{};
200         bool show_info{};
201         virtual void Draw() override;
202         virtual void CalculateRect() override;
203     };
204 
205     //频谱分析
206     class Spectrum : public Element
207     {
208     public:
209         bool draw_reflex{};     //是否绘制倒影
210         bool fixed_width{};     //每个柱形是否使用相同的宽度
211         Alignment align{ Alignment::LEFT };     //对齐方式
212         CUIDrawer::SpectrumCol type{ CUIDrawer::SC_64 };     //频谱分析的类型
213         virtual void Draw() override;
214         virtual bool IsEnable(CRect parent_rect) const override;
215     };
216 
217     //曲目信息(包含播放状态、文件名、歌曲标识、速度)
218     class TrackInfo : public Element
219     {
220     public:
221         int font_size{ 9 };
222         virtual void Draw() override;
223     };
224 
225     //工具栏
226     class Toolbar : public Element
227     {
228     public:
229         bool show_translate_btn{};      //是否在工具栏上显示“显示歌词翻译”按钮
230         virtual void Draw() override;
231     };
232 
233     //进度条
234     class ProgressBar : public Element
235     {
236     public:
237         bool show_play_time{};
238         bool play_time_both_side{};
239         virtual void Draw() override;
240     };
241 
242     //歌词
243     class Lyrics : public Element
244     {
245     public:
246         bool no_background = false;         // 总是不使用歌词背景
247         bool use_default_font = false;      // 固定使用默认字体
248         int font_size{ 9 };                 // 使用默认字体时的字号
249         bool show_song_info = false;        //没有歌词时总是显示歌曲信息
250         virtual void Draw() override;
251         virtual void ClearRect() override;
252     protected:
253         bool IsParentRectangle() const;     //判断父元素中是否有矩形元素
254     };
255 
256     //音量
257     class Volume : public Element
258     {
259     public:
260         bool show_text{ true };     //是否在音量图标旁边显示文本
261         bool adj_btn_on_top{ false };   //音量调节按钮是否显示在音量图标的上方
262         virtual void Draw() override;
263     };
264 
265     //节拍指示
266     class BeatIndicator : public Element
267     {
268     public:
269         virtual void Draw() override;
270     };
271 
272     //列表元素
273     class ListElement : public Element
274     {
275     public:
276         friend class CPlayerUIBase;
277 
278         virtual void Draw() override;
279         virtual void LButtonUp(CPoint point) override;
280         virtual void LButtonDown(CPoint point) override;
281         virtual void MouseMove(CPoint point) override;
282         virtual bool RButtunUp(CPoint point) override;
283         void ShowContextMenu(CMenu* menu, CWnd* cmd_reciver);
284         virtual void RButtonDown(CPoint point) override;
285         virtual bool MouseWheel(int delta, CPoint point) override;
286         virtual void MouseLeave() override;
287         virtual bool DoubleClick(CPoint point) override;
288         virtual void ClearRect() override;
289 
290         void EnsureItemVisible(int index);  //确保指定项在播放列表中可见
291         void EnsureHighlightItemVisible();  //确保高亮行可见
292         void RestrictOffset();             //将播放列表偏移量限制在正确的范围
293         void CalculateItemRects();         //计算播放列表中每一项的矩形区域,保存在playlist_info.item_rects中
294         int ItemHeight() const;
295         void SetItemSelected(int index);    //设置单个项目选中
296         int GetItemSelected() const;        //获取单个项目选中
297         void SetItemsSelected(const vector<int>& indexes);  //设置多个项目选中
298         void GetItemsSelected(vector<int>& indexes) const;  //获取多个项目选中
299         bool IsItemSelected(int index) const;   //判断指定行是否选中
300         bool IsMultipleSelected() const;        //是否选中了超过1个项目
301 
302         void SelectAll();                   //全选(仅IsMultipleSelectionEnable返回true时支持)
303         void SelectNone();                  //取消所有选择
304         void SelectReversed();              //反向选择(仅IsMultipleSelectionEnable返回true时支持)
305 
306         virtual std::wstring GetItemText(int row, int col) = 0;
307         virtual int GetRowCount() = 0;
308         virtual int GetColumnCount() = 0;
309         virtual int GetColumnWidth(int col, int total_width) = 0;
GetIcon(int row)310         virtual IconMgr::IconType GetIcon(int row) { return IconMgr::IT_NO_ICON; }
HasIcon()311         virtual bool HasIcon() { return false; }
GetEmptyString()312         virtual std::wstring GetEmptyString() { return std::wstring(); }    //列表为空时显示的文本
GetHighlightRow()313         virtual int GetHighlightRow() { return -1; }
GetColumnScrollTextWhenSelected()314         virtual int GetColumnScrollTextWhenSelected() { return -1; }    //获取选中时需要滚动显示的列
ShowTooltip()315         virtual bool ShowTooltip() { return false; }
GetToolTipText(int row)316         virtual std::wstring GetToolTipText(int row) { return std::wstring(); }
GetToolTipIndex()317         virtual int GetToolTipIndex() const { return 0; }
GetContextMenu(bool item_selected)318         virtual CMenu* GetContextMenu(bool item_selected) { return nullptr; }
GetCmdRecivedWnd()319         virtual CWnd* GetCmdRecivedWnd() { return nullptr; }        //获取右键菜单命令的接收窗口,如果返回空指针,则在CUIWindowCmdHelper中响应
OnDoubleClicked()320         virtual void OnDoubleClicked() {};
OnClicked()321         virtual void OnClicked() {};
GetHoverButtonCount()322         virtual int GetHoverButtonCount() { return 0; }     //获取鼠标指向一行时要显示的按钮数量
GetHoverButtonColumn()323         virtual int GetHoverButtonColumn() { return 0; }    //获取鼠标指向时要显示的按钮所在列
GetHoverButtonIcon(int index,int row)324         virtual IconMgr::IconType GetHoverButtonIcon(int index, int row) { return IconMgr::IT_NO_ICON; } //获取鼠标指向一行时按钮的图标
GetHoverButtonTooltip(int index,int row)325         virtual std::wstring GetHoverButtonTooltip(int index, int row) { return std::wstring(); }     //获取鼠标指向一行时按钮的鼠标提示
OnHoverButtonClicked(int btn_index,int row)326         virtual void OnHoverButtonClicked(int btn_index, int row) {}    //响应鼠标指向时按钮点击
327         IPlayerUI::UIButton& GetHoverButtonState(int btn_index);        //获取储存鼠标指向时按钮信息的结构体
GetUnHoverIconCount(int row)328         virtual int GetUnHoverIconCount(int row) { return 0; }          //获取鼠标未指向的行要显示的图标数量(列为GetHoverButtonColumn返回的列)
GetUnHoverIcon(int index,int row)329         virtual IconMgr::IconType GetUnHoverIcon(int index, int row) { return IconMgr::IT_NO_ICON; }   //获取鼠标未指向的行要显示的图标
330 
IsMultipleSelectionEnable()331         virtual bool IsMultipleSelectionEnable() { return false; }      //是否允许多选
332         virtual void OnRowCountChanged();       //当列表行数发生变化时响应此函数
333 
334         virtual void QuickSearch(const std::wstring& key_word);         //根据关键执行快速搜索(筛选出匹配的项)
335         virtual bool IsItemMatchKeyWord(int row, const std::wstring& key_word);     //判断指定行是否匹配关键字(用于快速搜索功能,默认匹配每一列中的文本,只要有一列的文本匹配就返回true,派生类可重写此函数)
336 
337         int GetDisplayRowCount();       //获取要显示的行数。(处于搜索状态时返回搜索结果数量,正常状态下同GetRowCount)
338         bool IsRowDisplayed(int row);   //判断一行是否显示。(仅处于搜索状态时不匹配的行会返回false)
339 
SetRelatedSearchBox(SearchBox * search_box)340         void SetRelatedSearchBox(SearchBox* search_box) { related_search_box = search_box; }
341 
342         int item_height{ 28 };
343         int font_size{ 9 };
344 
345     private:
346         void DisplayRowToAbsoluteRow(int& row); //将显示的行号转换为绝对行号
347         void AbsoluteRowToDisplayRow(int& row); //将绝对行号转换为显示的行号
348         int GetDisplayedIndexByPoint(CPoint point);
349 
350     protected:
351         int GetListIndexByPoint(CPoint point);
352 
353     protected:
354         bool mouse_pressed{ };          //鼠标左键是否按下
355         bool hover{};                   //指标指向播放列表区域
356         CPoint mouse_pos;               //鼠标指向的区域
357         CPoint mouse_pressed_pos;       //鼠标按下时的位置
358         int mouse_pressed_offset{};     //鼠标按下时播放列表的位移
359         int playlist_offset{};          //当前播放列表滚动的位移
360         std::set<int> items_selected; //选中的序号
361         CDrawCommon::ScrollInfo selected_item_scroll_info;  //绘制选中项滚动文本的结构体
362         std::vector<CRect> item_rects;  //播放列表中每个项目的矩形区域
363         CRect scrollbar_rect{};         //滚动条的位置
364         CRect scrollbar_handle_rect;    //滚动条把手的位置
365         bool scrollbar_hover{};         //鼠标指向滚动条
366         bool scrollbar_handle_pressed{};    //滚动条把手被按下
367         int scroll_handle_length_comp{};    //计算滚动条把手长度时的补偿量
368         std::map<int, IPlayerUI::UIButton> hover_buttons;   //鼠标指向时的按钮
369         int last_row_count{};
370     private:
371         std::vector<int> search_result; //保存搜索结果的序号
372         bool searched{};                //是否处于搜索状态
373         SearchBox* related_search_box{};    //关联的键框
374     };
375 
376 
377     //播放列表
378     class Playlist : public ListElement
379     {
380     public:
381         enum Column
382         {
383             COL_INDEX,
384             COL_TRACK,
385             COL_TIME,
386             COL_MAX
387         };
388 
389         //鼠标指向一行时显示的按钮
390         enum BtnKey
391         {
392             BTN_PLAY,
393             BTN_ADD,
394             BTN_FAVOURITE,
395             BTN_MAX
396         };
397 
398         // 通过 ListElement 继承
399         std::wstring GetItemText(int row, int col) override;
400         int GetRowCount() override;
401         int GetColumnCount() override;
402         virtual int GetColumnWidth(int col, int total_width) override;
403         virtual std::wstring GetEmptyString() override;
404         virtual int GetHighlightRow() override;
405         virtual int GetColumnScrollTextWhenSelected() override;
406         virtual bool ShowTooltip() override;
407         virtual std::wstring GetToolTipText(int row) override;
408         virtual int GetToolTipIndex() const override;
409         virtual CMenu* GetContextMenu(bool item_selected) override;
410         virtual CWnd* GetCmdRecivedWnd() override;
411         virtual void OnDoubleClicked() override;
412         virtual void OnClicked() override;
413         virtual int GetHoverButtonCount() override;
414         virtual int GetHoverButtonColumn() override;
415         virtual IconMgr::IconType GetHoverButtonIcon(int index, int row) override;
416         virtual std::wstring GetHoverButtonTooltip(int index, int row) override;
417         virtual void OnHoverButtonClicked(int btn_index, int row) override;
418         virtual int GetUnHoverIconCount(int row) override;
419         virtual IconMgr::IconType GetUnHoverIcon(int index, int row) override;
420 
IsMultipleSelectionEnable()421         virtual bool IsMultipleSelectionEnable() override { return true; }
422         virtual void OnRowCountChanged() override;
423 
424         virtual bool IsItemMatchKeyWord(int row, const std::wstring& key_word);
425 
426     private:
427         int last_highlight_row{ -1 };
428     };
429 
430     //最近播放
431     class RecentPlayedList : public ListElement
432     {
433     public:
434         enum Column
435         {
436             COL_NAME,
437             COL_COUNT,
438             COL_MAX
439         };
440         static CListCache m_list_cache;     // 为RecentPlayedList的绘制缓存最近播放的ListItem,Draw之前调用reload
441         virtual void Draw() override;
442 
443         // 通过 ListElement 继承
444         std::wstring GetItemText(int row, int col) override;
445         int GetRowCount() override;
446         int GetColumnCount() override;
447         int GetColumnWidth(int col, int total_width) override;
448         virtual int GetColumnScrollTextWhenSelected() override;
449         virtual IconMgr::IconType GetIcon(int row) override;
450         virtual bool HasIcon() override;
451         virtual void OnDoubleClicked() override;
452         virtual CMenu* GetContextMenu(bool item_selected) override;
453         virtual int GetHoverButtonCount() override;
454         virtual int GetHoverButtonColumn() override;
455         virtual IconMgr::IconType GetHoverButtonIcon(int index, int row) override;
456         virtual std::wstring GetHoverButtonTooltip(int index, int row) override;
457         virtual void OnHoverButtonClicked(int btn_index, int row) override;
458     };
459 
460     //媒体库项目列表
461     class MediaLibItemList : public ListElement
462     {
463     public:
464         CMediaClassifier::ClassificationType type{};
465 
466         enum Column
467         {
468             COL_NAME,
469             COL_COUNT,
470             COL_MAX
471         };
472 
473         //鼠标指向一行时显示的按钮
474         enum BtnKey
475         {
476             BTN_PLAY,
477             BTN_ADD,
478             BTN_MAX
479         };
480 
481         // 通过 ListElement 继承
482         std::wstring GetItemText(int row, int col) override;
483         int GetRowCount() override;
484         int GetColumnCount() override;
485         int GetColumnWidth(int col, int total_width) override;
486         virtual std::wstring GetEmptyString() override;
487         virtual int GetHighlightRow() override;
488         virtual int GetColumnScrollTextWhenSelected() override;
489         virtual CMenu* GetContextMenu(bool item_selected) override;
490         virtual void OnDoubleClicked() override;
491         virtual int GetHoverButtonCount() override;
492         virtual int GetHoverButtonColumn() override;
493         virtual IconMgr::IconType GetHoverButtonIcon(int index, int row) override;
494         virtual std::wstring GetHoverButtonTooltip(int index, int row) override;
495         virtual void OnHoverButtonClicked(int btn_index, int row) override;
496     private:
497         int last_highlight_row{ -1 };
498     };
499 
500     //当前播放列表指示
501     class PlaylistIndicator : public Element
502     {
503     public:
504         static CListCache m_list_cache;     // 为PlaylistIndicator的绘制缓存当前播放的ListItem,Draw之前调用reload
505         virtual void Draw() override;
506         virtual void LButtonUp(CPoint point) override;
507         virtual void LButtonDown(CPoint point) override;
508         virtual void MouseMove(CPoint point) override;
509         virtual void MouseLeave() override;
510         virtual void ClearRect() override;
511 
512         int font_size{ 9 };
513 
514         IPlayerUI::UIButton btn_drop_down;
515         IPlayerUI::UIButton btn_menu;
516         CRect rect_name;
517     };
518 
519     class ClassicalControlBar : public Element
520     {
521     public:
522         ClassicalControlBar();
523         virtual void Draw() override;
524 
525     public:
526         bool show_switch_display_btn{};
527     };
528 
529     //导航栏
530     class NavigationBar : public Element
531     {
532     public:
533         virtual void Draw() override;
534         virtual void LButtonUp(CPoint point) override;
535         virtual void MouseMove(CPoint point) override;
536         virtual bool RButtunUp(CPoint point) override;
537         virtual void MouseLeave() override;
538 
539         enum IconType
540         {
541             ICON_AND_TEXT,
542             ICON_ONLY,
543             TEXT_ONLY
544         };
545 
546         enum Orientation
547         {
548             Horizontal,
549             Vertical,
550         };
551 
552         IconType icon_type{};
553         Orientation orientation{ Horizontal };
554         int item_space{};
555         int item_height{ 28 };
556         int font_size{ 9 };
557         std::vector<std::string> tab_list;
558         std::vector<CRect> item_rects;
559         std::vector<std::wstring> labels;
560         int SelectedIndex();
561         int hover_index{ -1 };
562     private:
563         void FindStackElement();        //查找StackElement
564         bool find_stack_element{};      //如果已经查找过StackElement,则为true
565         StackElement* stack_element{};
566         int selected_index{};
567         int last_hover_index{ -1 };
568     };
569 
570     //媒体库的文件夹列表
571     class MediaLibFolder : public ListElement
572     {
573     public:
574         static CListCache m_list_cache;
575         virtual void Draw() override;
576 
577         enum Column
578         {
579             COL_NAME,
580             COL_COUNT,
581             COL_MAX
582         };
583 
584         //鼠标指向一行时显示的按钮
585         enum BtnKey
586         {
587             BTN_PLAY,
588             BTN_ADD,
589             BTN_MAX
590         };
591 
592         // 通过 ListElement 继承
593         std::wstring GetItemText(int row, int col) override;
594         int GetRowCount() override;
595         int GetColumnCount() override;
596         int GetColumnWidth(int col, int total_width) override;
597         virtual int GetHighlightRow() override;
598         virtual int GetColumnScrollTextWhenSelected() override;
599         virtual CMenu* GetContextMenu(bool item_selected) override;
600         virtual void OnDoubleClicked() override;
601         virtual int GetHoverButtonCount() override;
602         virtual int GetHoverButtonColumn() override;
603         virtual IconMgr::IconType GetHoverButtonIcon(int index, int row) override;
604         virtual std::wstring GetHoverButtonTooltip(int index, int row) override;
605         virtual void OnHoverButtonClicked(int btn_index, int row) override;
606     };
607 
608     //媒体库的播放列表列表
609     class MediaLibPlaylist : public ListElement
610     {
611     public:
612         static CListCache m_list_cache;
613         virtual void Draw() override;
614         enum Column
615         {
616             COL_NAME,
617             COL_COUNT,
618             COL_MAX
619         };
620 
621         // 通过 ListElement 继承
622         std::wstring GetItemText(int row, int col) override;
623         int GetRowCount() override;
624         int GetColumnCount() override;
625         int GetColumnWidth(int col, int total_width) override;
626         virtual int GetHighlightRow() override;
627         virtual int GetColumnScrollTextWhenSelected() override;
628         virtual CMenu* GetContextMenu(bool item_selected) override;
629         virtual void OnDoubleClicked() override;
630         virtual int GetHoverButtonCount() override;
631         virtual int GetHoverButtonColumn() override;
632         virtual IconMgr::IconType GetHoverButtonIcon(int index, int row) override;
633         virtual std::wstring GetHoverButtonTooltip(int index, int row) override;
634         virtual void OnHoverButtonClicked(int btn_index, int row) override;
635     };
636 
637     //我喜欢的音乐列表
638     class MyFavouriteList : public ListElement
639     {
640     public:
641         enum Column
642         {
643             COL_INDEX,
644             COL_TRACK,
645             COL_TIME,
646             COL_MAX
647         };
648 
649         //鼠标指向一行时显示的按钮
650         enum BtnKey
651         {
652             BTN_PLAY,
653             BTN_ADD,
654             BTN_MAX
655         };
656 
657         // 通过 ListElement 继承
658         std::wstring GetItemText(int row, int col) override;
659         int GetRowCount() override;
660         int GetColumnCount() override;
661         int GetColumnWidth(int col, int total_width) override;
662         virtual int GetHighlightRow() override;
663         virtual int GetColumnScrollTextWhenSelected() override;
664         virtual CMenu* GetContextMenu(bool item_selected) override;
665         virtual void OnDoubleClicked() override;
666         virtual std::wstring GetEmptyString() override;
667         virtual int GetHoverButtonCount() override;
668         virtual int GetHoverButtonColumn() override;
669         virtual IconMgr::IconType GetHoverButtonIcon(int index, int row) override;
670         virtual std::wstring GetHoverButtonTooltip(int index, int row) override;
671         virtual void OnHoverButtonClicked(int btn_index, int row) override;
672         virtual bool IsMultipleSelectionEnable() override;
673     };
674 
675     //所有曲目列表
676     class AllTracksList : public ListElement
677     {
678     public:
679         enum Column
680         {
681             COL_INDEX,
682             COL_TRACK,
683             COL_TIME,
684             COL_MAX
685         };
686 
687         //鼠标指向一行时显示的按钮
688         enum BtnKey
689         {
690             BTN_PLAY,
691             BTN_ADD,
692             BTN_FAVOURITE,
693             BTN_MAX
694         };
695 
696         // 通过 ListElement 继承
697         std::wstring GetItemText(int row, int col) override;
698         int GetRowCount() override;
699         int GetColumnCount() override;
700         int GetColumnWidth(int col, int total_width) override;
701         virtual int GetHighlightRow() override;
702         virtual int GetColumnScrollTextWhenSelected() override;
703         virtual CMenu* GetContextMenu(bool item_selected) override;
704         virtual void OnDoubleClicked() override;
705         virtual std::wstring GetEmptyString() override;
706         virtual int GetHoverButtonCount() override;
707         virtual int GetHoverButtonColumn() override;
708         virtual IconMgr::IconType GetHoverButtonIcon(int index, int row) override;
709         virtual std::wstring GetHoverButtonTooltip(int index, int row) override;
710         virtual void OnHoverButtonClicked(int btn_index, int row) override;
711         virtual int GetUnHoverIconCount(int row) override;
712         virtual IconMgr::IconType GetUnHoverIcon(int index, int row) override;
713         virtual bool IsMultipleSelectionEnable() override;
714 
715     private:
716         int last_highlight_row{ -1 };
717     };
718 
719     //迷你频谱
720     class MiniSpectrum : public Element
721     {
722     public:
723         virtual void Draw() override;
724     };
725 
726     //占位符
727     class PlaceHolder : public Element
728     {
729     public:
730         virtual int GetWidth(CRect parent_rect) const override;
731         virtual int GetHeight(CRect parent_rect) const override;
732         virtual bool IsWidthValid() const override;
733 
734         bool show_when_use_system_titlebar{};   //仅当开启“使用系统标准标题栏”时才显示
735 
736     private:
737         bool IsHide() const;
738     };
739 
740     //树控件
741     //派生类只需要继承GetRootNodes函数返回树的数据即可
742     class TreeElement : public ListElement
743     {
744     public:
745         //树的一个节点
746         struct Node
747         {
748             std::map<int, std::wstring> texts;   //一行的文本,key是列号,value是文本
749             std::vector<std::shared_ptr<Node>> child_list;     //子节点列表
750             Node* parent{};     //父节点
751             bool collapsed{};   //是否折叠
752 
753             void AddChild(std::shared_ptr<Node> child);
754             int GetLevel() const;       //获取节点的级别,如果节点没有父节点,则级别为0
755 
756             //按顺序遍历子节点
757             //func:遍历节点时的回调函数,如果要结束遍历,则返回true,否则返回false
758             //ignore_invisible:忽略被折叠的节点
759             void IterateNodeInOrder(std::function<bool(Node*)> func, bool ignore_invisible);
760         };
761 
762         virtual std::vector<std::shared_ptr<Node>>& GetRootNodes() = 0;   //获取顶级节点
763 
764         int GetItemLevel(int row);          //获取该行的级别(级别每加1,第一列会缩进一定距离)
765         bool IsCollapsable(int row);        //该行是否可以折叠(如果为true,则显示折叠图标)
766         bool IsCollapsed(int row);          //该行是否折叠
767 
768         // 通过 Element 继承
769         virtual void LButtonUp(CPoint point) override;
770         virtual void MouseMove(CPoint point) override;
771         virtual void MouseLeave() override;
772         virtual bool DoubleClick(CPoint point) override;
773 
774         // 通过 ListElement 继承
775         std::wstring GetItemText(int row, int col) override;
776         int GetRowCount() override;
777         //树控件不使用基类ListElement的搜索逻辑
778         virtual void QuickSearch(const std::wstring& key_word) override;
779         virtual void OnRowCountChanged() override;
780 
781         std::map<int, CRect> collapsd_rects;     //折叠标志的矩形区域(key是行)
782         int collaps_indicator_hover_row{ -1 };    //鼠标指向的折叠标志的行号
783 
784     protected:
785         int GetNodeIndex(const Node* node);     //查找一个节点的序号(如果节点被折叠或不存在则返回-1)
786         Node* GetNodeByIndex(int index);    //根据一个节点的序号查找节点(忽略被折叠的节点)
787         bool IsNodeMathcKeyWord(const Node* node, const std::wstring& key_word);  //判断一个节点是否匹配关键字
788         bool IsNodeDisplayed(const Node* node);
789         void IterateDisplayedNodeInOrder(std::function<bool(Node*)> func);      //遍历所有可见的节点
790         std::set<const Node*> tree_search_result; //保存搜索结果
791         bool tree_searched{};               //是否处于搜索状态
792     };
793 
794     class TestTree : public TreeElement
795     {
796     public:
797         TestTree();
798         static std::shared_ptr<Node> CreateNode(std::wstring name, std::shared_ptr<Node> parent);
799 
GetIcon(int row)800         virtual IconMgr::IconType GetIcon(int row) { return IconMgr::IT_Folder; }
HasIcon()801         virtual bool HasIcon() { return true; }
802         virtual int GetColumnCount() override;
803         virtual int GetColumnWidth(int col, int total_width) override;
804         virtual std::vector<std::shared_ptr<Node>>& GetRootNodes() override;
805 
806     private:
807         std::vector<std::shared_ptr<Node>> root_nodes;
808     };
809 
810     //媒体库中的文件夹浏览
811     class FolderExploreTree : public TreeElement
812     {
813     public:
814         enum Column
815         {
816             COL_NAME,
817             COL_COUNT,
818             COL_MAX
819         };
820 
821         //鼠标指向一行时显示的按钮
822         enum BtnKey
823         {
824             BTN_PLAY,
825             BTN_ADD,
826             BTN_MAX
827         };
828 
829         static std::shared_ptr<Node> CreateNode(std::wstring name, int song_num, std::shared_ptr<Node> parent);
830         static std::wstring GetNodePath(Node* node);       //获取一个节点的路径
831         std::wstring GetSelectedPath();             //获取选中节点的路径
832 
GetIcon(int row)833         virtual IconMgr::IconType GetIcon(int row) { return IconMgr::IT_Folder; }
HasIcon()834         virtual bool HasIcon() { return true; }
835         virtual int GetColumnCount() override;
836         virtual int GetColumnWidth(int col, int total_width) override;
837         virtual int GetColumnScrollTextWhenSelected() override;
838         virtual CMenu* GetContextMenu(bool item_selected) override;
839         virtual void OnDoubleClicked() override;
840         virtual std::wstring GetEmptyString() override;
841         virtual int GetHoverButtonCount() override;
842         virtual int GetHoverButtonColumn() override;
843         virtual IconMgr::IconType GetHoverButtonIcon(int index, int row) override;
844         virtual std::wstring GetHoverButtonTooltip(int index, int row) override;
845         virtual void OnHoverButtonClicked(int btn_index, int row) override;
846         virtual bool IsMultipleSelectionEnable() override;
847 
848         virtual std::vector<std::shared_ptr<Node>>& GetRootNodes() override;
849     };
850 
851     //搜索框
852     class SearchBox : public Element
853     {
854     public:
855         SearchBox();
856         ~SearchBox();
857         void InitSearchBoxControl(CWnd* pWnd);  //初始化搜索框控件。pWnd:父窗口
858         void OnKeyWordsChanged();
859         void Clear();
GetListElement()860         ListElement* GetListElement() { return list_element; }
861 
862         virtual void Draw() override;
863         virtual void MouseMove(CPoint point) override;
864         virtual void MouseLeave() override;
865         virtual void LButtonUp(CPoint point) override;
866         virtual void LButtonDown(CPoint point) override;
867 
868         bool hover{};       //如果鼠标指向搜索框,则为true
869         std::wstring key_word;  //搜索框中的文本
870         CUiSearchBox* search_box_ctrl{};    //搜索框控件
871         CRect icon_rect;    //图标的区域
872         CPlayerUIBase::UIButton clear_btn;      //清除按钮
873 
874     private:
875         void FindListElement();         //查找ListElement
876         bool find_list_element{};       //如果已经查找过ListElement,则为true
877         ListElement* list_element{};    //关联的ListElement
878     };
879 }
880 
881 /////////////////////////////////////////////////////////////////////////////////////////
882 class CElementFactory
883 {
884 public:
885     std::shared_ptr<UiElement::Element> CreateElement(const std::string& name, CPlayerUIBase* ui);
886 };
887