xref: /MusicPlayer2/MusicPlayer2/UIElement.cpp (revision fc77c71b2623add2756a54b7bf5cd93b7619bbd0)
1 #include "stdafx.h"
2 #include "UIElement.h"
3 #include "MusicPlayer2.h"
4 #include "MusicPlayerDlg.h"
5 #include "SongInfoHelper.h"
6 #include "UiMediaLibItemMgr.h"
7 #include "UserUi.h"
8 #include "MusicPlayerCmdHelper.h"
9 #include "UIWindowCmdHelper.h"
10 #include "CRecentList.h"
11 #include <stack>
12 #include "UiSearchBox.h"
13 
14 ///////////////////////////////////////////////////////////////////////////////
15 //查找一个关联的节点
16 //element:被查找的节点
17 //返回值:查找结果
18 template<class T>
FindRelatedElement(UiElement::Element * element)19 static T* FindRelatedElement(UiElement::Element* element)
20 {
21     UiElement::Element* parent = element->pParent;
22     T* rtn_element = nullptr;
23     while (parent != nullptr)
24     {
25         //依次查找所有父节点下面的指定类型节点
26         for (const auto& ele : parent->childLst)
27         {
28             T* _element = dynamic_cast<T*>(ele.get());
29             if (_element != nullptr)
30             {
31                 rtn_element = _element;
32                 return rtn_element;
33             }
34         }
35         parent = parent->pParent;
36     }
37 
38     //如果没有找到,则查找整个界面第一个指定类型节点
39     if (rtn_element == nullptr)
40     {
41         UiElement::Element* root = element->RootElement();
42         if (root != nullptr)
43         {
44             root->IterateAllElements([&](UiElement::Element* ele)->bool {
45                 T* _element = dynamic_cast<T*>(ele);
46                 if (_element != nullptr)
47                 {
48                     rtn_element = _element;
49                     return true;
50                 }
51                 return false;
52             });
53             if (rtn_element != nullptr)
54                 return rtn_element;
55         }
56     }
57     return nullptr;
58 }
59 
60 ///////////////////////////////////////////////////////////////////////////////
61 ///////////////////////////////////////////////////////////////////////////////
Value(bool _is_vertical,Element * _owner)62 UiElement::Element::Value::Value(bool _is_vertical, Element* _owner)
63     : is_vertical(_is_vertical), owner(_owner)
64 {
65 }
66 
FromString(const std::string str)67 void UiElement::Element::Value::FromString(const std::string str)
68 {
69     size_t index = str.find('%');
70     if (index != std::wstring::npos)   //如果包含百分号
71     {
72         is_percentage = true;
73         value = atoi(str.substr(0, index).c_str());
74     }
75     else
76     {
77         is_percentage = false;
78         value = atoi(str.c_str());
79     }
80     valid = true;
81 }
82 
GetValue(CRect parent_rect) const83 int UiElement::Element::Value::GetValue(CRect parent_rect) const
84 {
85     if (is_percentage)      //如果是百分比,根据父元素的大小计算
86     {
87         if (is_vertical)
88             return parent_rect.Height() * value / 100;
89         else
90             return parent_rect.Width() * value / 100;
91     }
92     else                    //不是百分比,进行根据当前DPI对数值放大
93     {
94         return owner->ui->DPI(value);
95     }
96 }
97 
IsValid() const98 bool UiElement::Element::Value::IsValid() const
99 {
100     return valid;
101 }
102 
Draw()103 void UiElement::Element::Draw()
104 {
105     for (const auto& item : childLst)
106     {
107         if (item != nullptr && item->IsEnable(GetRect()))
108             item->Draw();
109     }
110 }
111 
IsEnable(CRect parent_rect) const112 bool UiElement::Element::IsEnable(CRect parent_rect) const
113 {
114     if (hide_width.IsValid() && hide_width.GetValue(parent_rect) > parent_rect.Width())
115         return false;
116     if (hide_height.IsValid() && hide_height.GetValue(parent_rect) > parent_rect.Height())
117         return false;
118     return true;
119 }
120 
GetMaxWidth(CRect parent_rect) const121 int UiElement::Element::GetMaxWidth(CRect parent_rect) const
122 {
123     if (max_width.IsValid())
124         return max_width.GetValue(parent_rect);
125     return INT_MAX;
126 }
127 
GetWidth(CRect parent_rect) const128 int UiElement::Element::GetWidth(CRect parent_rect) const
129 {
130     int w{ width.GetValue(parent_rect) };
131     w = min(GetMaxWidth(parent_rect), w);
132     if (min_width.IsValid())
133         w = max(min_width.GetValue(parent_rect), w);
134     return w;
135 }
136 
GetHeight(CRect parent_rect) const137 int UiElement::Element::GetHeight(CRect parent_rect) const
138 {
139     int h{ height.GetValue(parent_rect) };
140     if (max_height.IsValid())
141         h = min(max_height.GetValue(parent_rect), h);
142     if (min_height.IsValid())
143         h = max(min_height.GetValue(parent_rect), h);
144     return h;
145 }
146 
IsWidthValid() const147 bool UiElement::Element::IsWidthValid() const
148 {
149     return width.IsValid();
150 }
151 
IsHeightValid() const152 bool UiElement::Element::IsHeightValid() const
153 {
154     return height.IsValid();
155 }
156 
GetRect() const157 CRect UiElement::Element::GetRect() const
158 {
159     return rect;
160 }
161 
SetRect(CRect _rect)162 void UiElement::Element::SetRect(CRect _rect)
163 {
164     rect = _rect;
165 }
166 
ClearRect()167 void UiElement::Element::ClearRect()
168 {
169     rect = CRect();
170 }
171 
RootElement()172 UiElement::Element* UiElement::Element::RootElement()
173 {
174     Element* ele{ this };
175     while (ele != nullptr && ele->pParent != nullptr)
176     {
177         ele = ele->pParent;
178     }
179     return ele;
180 }
181 
ParentRect() const182 CRect UiElement::Element::ParentRect() const
183 {
184     if (pParent == nullptr)
185     {
186         return rect;
187     }
188     else
189     {
190         pParent->CalculateRect();
191         return pParent->GetRect();
192     }
193 }
194 
CalculateRect()195 void UiElement::Element::CalculateRect()
196 {
197     if (pParent == nullptr)     //根节点的矩形不需要计算
198         return;
199 
200     //判断父元素是否为布局元素
201     Layout* layout = dynamic_cast<Layout*>(pParent);
202     if (layout != nullptr)
203     {
204         //如果父元素为布局元素,则由布局元素计算子元素的矩形区域
205         return;
206     }
207     //父元素不是布局元素
208     else
209     {
210         //父元素的矩形区域
211         const CRect rect_parent{ ParentRect() };
212         const CRect rect_root{ RootElement()->GetRect() };
213         rect = rect_parent;
214         if (x.IsValid())
215             rect.left = x.GetValue(rect_parent) + rect_root.left;
216         if (y.IsValid())
217             rect.top = y.GetValue(rect_parent) + rect_root.top;
218 
219         if (margin_left.IsValid())
220             rect.left = rect_parent.left + margin_left.GetValue(rect_parent);
221         if (margin_top.IsValid())
222             rect.top = rect_parent.top + margin_top.GetValue(rect_parent);
223         if (margin_right.IsValid())
224             rect.right = rect_parent.right - margin_right.GetValue(rect_parent);
225         if (margin_bottom.IsValid())
226             rect.bottom = rect_parent.bottom - margin_bottom.GetValue(rect_parent);
227 
228         if (IsWidthValid())
229         {
230             if (!x.IsValid() && !margin_left.IsValid() && margin_right.IsValid())
231                 rect.left = rect.right - width.GetValue(rect_parent);
232             else
233                 rect.right = rect.left + width.GetValue(rect_parent);
234         }
235         if (IsHeightValid())
236         {
237             if (!y.IsValid() && !margin_top.IsValid() && margin_bottom.IsValid())
238                 rect.top = rect.bottom - height.GetValue(rect_parent);
239             else
240                 rect.bottom = rect.top + height.GetValue(rect_parent);
241         }
242     }
243 }
244 
245 
IterateElements(UiElement::Element * parent_element,std::function<bool (UiElement::Element *)> func,bool visible_only)246 void UiElement::Element::IterateElements(UiElement::Element* parent_element, std::function<bool(UiElement::Element*)> func, bool visible_only)
247 {
248     if (parent_element != nullptr)
249     {
250         if (func(parent_element))
251             return;
252         for (const auto& ele : parent_element->childLst)
253         {
254             if (visible_only)
255             {
256                 StackElement* stack_element = dynamic_cast<UiElement::StackElement*>(ele.get());
257                 if (stack_element != nullptr)
258                 {
259                     func(stack_element);
260                     int cur_index = stack_element->GetCurIndex();
261                     if (cur_index >= 0 && cur_index < static_cast<int>(stack_element->childLst.size()))
262                     {
263                         IterateElements(stack_element->childLst[cur_index].get(), func, visible_only);
264                     }
265                 }
266                 else
267                 {
268                     IterateElements(ele.get(), func, visible_only);
269                 }
270             }
271             else
272             {
273                 IterateElements(ele.get(), func, visible_only);
274             }
275         }
276     }
277 }
278 
IterateAllElements(std::function<bool (UiElement::Element *)> func,bool visible_only)279 void UiElement::Element::IterateAllElements(std::function<bool(UiElement::Element*)> func, bool visible_only)
280 {
281     IterateElements(this, func, visible_only);
282 }
283 
SetUi(CPlayerUIBase * _ui)284 void UiElement::Element::SetUi(CPlayerUIBase* _ui)
285 {
286     ui = _ui;
287 }
288 
AddChild(std::shared_ptr<Element> child)289 void UiElement::Element::AddChild(std::shared_ptr<Element> child)
290 {
291     child->pParent = this;
292     childLst.push_back(child);
293 }
294 
295 
296 ///////////////////////////////////////////////////////////////////////////////
297 ///////////////////////////////////////////////////////////////////////////////
CalculateChildrenRect()298 void UiElement::Layout::CalculateChildrenRect()
299 {
300     //水平布局
301     if (type == Horizontal)
302     {
303         vector<int> size_list;          // 已确定子元素尺寸记录(不含边距),未确定项为INT_MIN
304         int total_size{};               // 所有已指定元素的宽度(非浮动宽度)与已确定的总边距
305         int item_fixed_size_num{};      // 有固定宽度的元素的个数
306 
307         // 第一次遍历,获取固定不变的尺寸数据
308         for (const auto& child : childLst)
309         {
310             if (!child->IsEnable(GetRect()))            // 设置为不显示时按尺寸为0的固定尺寸元素处理,并忽略此元素边距
311             {
312                 size_list.push_back(0);
313                 item_fixed_size_num++;
314             }
315             else
316             {
317                 if (child->IsWidthValid() && child->proportion < 1)    // proportion设定时忽略width
318                 {
319                     int width{ child->GetWidth(GetRect()) };
320                     total_size += width;
321                     size_list.push_back(width);
322                     item_fixed_size_num++;
323                 }
324                 else
325                 {
326                     size_list.push_back(INT_MIN); // 这个子元素尺寸未定
327                 }
328                 if (child->margin_left.IsValid())
329                     total_size += child->margin_left.GetValue(GetRect());
330                 if (child->margin_right.IsValid())
331                     total_size += child->margin_right.GetValue(GetRect());
332             }
333         }
334 
335         int left_space{};                // 全部具有固定尺寸时首子元素与开始边缘的间距
336         bool all_ok{};
337         while (!all_ok)
338         {
339             //如果每个元素都有固定的尺寸,则让这些元素在布局中居中
340             if (childLst.size() == item_fixed_size_num)
341             {
342                 left_space = (GetRect().Width() - total_size) / 2;
343                 if (left_space < 0)      // 空间不足时优先显示容器前端元素
344                     left_space = 0;
345                 all_ok = true;
346             }
347             else
348             {
349                 // 此时size_list中为INT_MIN的子元素应按比例处理
350                 int proportion{};                           // 各未固定子元素比例系数和
351                 for (size_t i{}; i < childLst.size(); ++i)  // 计算比例系数和
352                 {
353                     if (size_list[i] == INT_MIN)
354                         proportion += max(childLst[i]->proportion, 1);  // 均未设置时按1处理
355                 }
356                 // 逐个检查是否符合最值
357                 bool ok{ true };
358                 for (size_t i{}; i < childLst.size(); ++i)
359                 {
360                     if (size_list[i] == INT_MIN)
361                     {
362                         auto& child{ childLst[i] };
363                         int size{ (GetRect().Width() - total_size) * max(child->proportion, 1) / proportion };
364                         int max_size{ child->GetMaxWidth(GetRect()) };
365                         int min_size{ child->min_width.IsValid() ? child->min_width.GetValue(GetRect()) : 0 };
366                         if (size < min_size || max_size < min_size)    // 比例与最值冲突时按最值处理并将此元素标记为固定尺寸元素,由于文本收缩的引入最大值可能比预期小故给与最小值更高的优先级
367                         {
368                             size_list[i] = min_size;
369                             total_size += min_size;
370                             item_fixed_size_num++;
371                             ok = false;
372                             break;
373                         }
374                         else if (size > max_size)
375                         {
376                             size_list[i] = max_size;
377                             total_size += max_size;
378                             item_fixed_size_num++;
379                             ok = false;
380                             break;
381                         }
382                     }
383                 }
384                 if (!ok)        // ok为false说明增加了一个固定元素,重新计算比例
385                 {
386                     continue;
387                 }
388                 else            // ok为true说明当前比例可满足最值要求,下面正式进行比例应用
389                 {
390                     for (size_t i{}; i < childLst.size(); ++i)
391                     {
392                         if (size_list[i] == INT_MIN)
393                         {
394                             auto& child{ childLst[i] };
395                             int size{ (GetRect().Width() - total_size) * max(child->proportion, 1) / proportion };
396                             size_list[i] = max(size, 0);
397                         }
398                     }
399                     left_space = 0;
400                     all_ok = true;
401                 }
402             }
403         }
404         ASSERT(find(size_list.begin(), size_list.end(), INT_MIN) == size_list.end());
405 
406         //计算每个子元素的矩形区域
407         int w{};
408         bool first_child{ true };
409         for (size_t i{}; i < childLst.size(); i++)
410         {
411             auto& child{ childLst[i] };
412             CRect child_rect{};
413             if (child->IsHeightValid())
414             {
415                 int child_height = child->GetHeight(GetRect());
416                 int max_height = GetRect().Height() - child->margin_top.GetValue(GetRect()) - child->margin_bottom.GetValue(GetRect());
417                 if (child_height > max_height)
418                     child_height = max_height;
419                 child_rect.top = GetRect().top + (GetRect().Height() - child_height) / 2;
420                 child_rect.bottom = child_rect.top + child->GetHeight(GetRect());
421             }
422             else
423             {
424                 child_rect.top = GetRect().top + child->margin_top.GetValue(GetRect());
425                 child_rect.bottom = GetRect().bottom - child->margin_bottom.GetValue(GetRect());
426             }
427             if (child->IsEnable(GetRect()))
428             {
429                 if (first_child)
430                 {
431                     child_rect.left = GetRect().left + child->margin_left.GetValue(GetRect()) + left_space;
432                     first_child = false;
433                 }
434                 else
435                 {
436                     child_rect.left = w + child->margin_left.GetValue(GetRect());
437                 }
438                 child_rect.right = child_rect.left + size_list[i];
439                 w = child_rect.right + child->margin_right.GetValue(GetRect());
440             }
441             else
442             {
443                 child_rect.left = w;
444                 child_rect.right = w;
445             }
446             child->SetRect(child_rect);
447         }
448     }
449     //垂直布局
450     else
451     {
452         vector<int> size_list;          // 已确定子元素尺寸记录(不含边距),未确定项为INT_MIN
453         int total_size{};               // 所有已指定元素的高度(非浮动高度)与已确定的总边距
454         int item_fixed_size_num{};      // 有固定高度的元素的个数
455 
456         // 第一次遍历,获取固定不变的尺寸数据
457         for (const auto& child : childLst)
458         {
459             if (!child->IsEnable(GetRect()))            // 设置为不显示时按尺寸为0的固定尺寸元素处理
460             {
461                 size_list.push_back(0);
462                 item_fixed_size_num++;
463             }
464             else
465             {
466                 if (child->IsHeightValid() && child->proportion < 1)       // proportion设定时忽略height
467                 {
468                     int height{ child->GetHeight(GetRect()) };
469                     total_size += height;
470                     size_list.push_back(height);
471                     item_fixed_size_num++;
472                 }
473                 else
474                 {
475                     size_list.push_back(INT_MIN); // 这个子元素尺寸未定
476                 }
477                 if (child->margin_top.IsValid())
478                     total_size += child->margin_top.GetValue(GetRect());
479                 if (child->margin_bottom.IsValid())
480                     total_size += child->margin_bottom.GetValue(GetRect());
481             }
482         }
483 
484         int top_space{};                // 全部具有固定尺寸时首子元素与开始边缘的间距
485         bool all_ok{};
486         while (!all_ok)
487         {
488             //如果每个元素都有固定的尺寸,则让这些元素在布局中居中
489             if (childLst.size() == item_fixed_size_num)
490             {
491                 top_space = (GetRect().Height() - total_size) / 2;
492                 if (top_space < 0)      // 空间不足时优先显示容器前端元素
493                     top_space = 0;
494                 all_ok = true;
495             }
496             else
497             {
498                 // 此时size_list中为INT_MIN的子元素应按比例处理
499                 int proportion{};                           // 各未固定子元素比例系数和
500                 for (size_t i{}; i < childLst.size(); ++i)  // 计算比例系数和
501                 {
502                     if (size_list[i] == INT_MIN)
503                         proportion += max(childLst[i]->proportion, 1);  // 均未设置时按1处理
504                 }
505                 // 逐个检查是否符合最值
506                 bool ok{ true };
507                 for (size_t i{}; i < childLst.size(); ++i)
508                 {
509                     if (size_list[i] == INT_MIN)
510                     {
511                         auto& child{ childLst[i] };
512                         int size{ (GetRect().Height() - total_size) * max(child->proportion, 1) / proportion };
513                         int max_size{ child->max_height.IsValid() ? child->max_height.GetValue(GetRect()) : INT_MAX };
514                         int min_size{ child->min_height.IsValid() ? child->min_height.GetValue(GetRect()) : 0 };
515                         if (size < min_size || max_size < min_size)                // 比例与最值冲突时按最值处理并将此元素标记为固定尺寸元素
516                         {
517                             size_list[i] = min_size;
518                             total_size += min_size;
519                             item_fixed_size_num++;
520                             ok = false;
521                             break;
522                         }
523                         else if (size > max_size)
524                         {
525                             size_list[i] = max_size;
526                             total_size += max_size;
527                             item_fixed_size_num++;
528                             ok = false;
529                             break;
530                         }
531                     }
532                 }
533                 if (!ok)        // ok为false说明增加了一个固定元素,重新计算比例
534                 {
535                     continue;
536                 }
537                 else            // ok为true说明当前比例可满足最值要求,下面正式进行比例应用
538                 {
539                     for (size_t i{}; i < childLst.size(); ++i)
540                     {
541                         if (size_list[i] == INT_MIN)
542                         {
543                             auto& child{ childLst[i] };
544                             int size{ (GetRect().Height() - total_size) * max(child->proportion, 1) / proportion };
545                             size_list[i] = max(size, 0);
546                         }
547                     }
548                     top_space = 0;
549                     all_ok = true;
550                 }
551             }
552         }
553         ASSERT(find(size_list.begin(), size_list.end(), INT_MIN) == size_list.end());
554 
555         // 计算每个子元素的矩形区域
556         int h{};
557         bool first_child{ true };
558         for (size_t i{}; i < childLst.size(); i++)
559         {
560             auto& child{ childLst[i] };
561             CRect child_rect{};
562             if (child->IsWidthValid())
563             {
564                 int child_width = child->GetWidth(GetRect());
565                 int max_width = GetRect().Width() - child->margin_left.GetValue(GetRect()) - child->margin_right.GetValue(GetRect());
566                 if (child_width > max_width)
567                     child_width = max_width;
568                 child_rect.left = GetRect().left + (GetRect().Width() - child_width) / 2;
569                 child_rect.right = child_rect.left + child->GetWidth(GetRect());
570             }
571             else
572             {
573                 child_rect.left = GetRect().left + child->margin_left.GetValue(GetRect());
574                 child_rect.right = GetRect().right - child->margin_right.GetValue(GetRect());
575             }
576             if (child->IsEnable(GetRect()))
577             {
578                 if (first_child)
579                 {
580                     child_rect.top = GetRect().top + child->margin_top.GetValue(GetRect()) + top_space;
581                     first_child = false;
582                 }
583                 else
584                 {
585                     child_rect.top = h + child->margin_top.GetValue(GetRect());
586                 }
587                 child_rect.bottom = child_rect.top + size_list[i];
588                 h = child_rect.bottom + child->margin_bottom.GetValue(GetRect());
589             }
590             else
591             {
592                 child_rect.top = h;
593                 child_rect.bottom = h;
594             }
595             child->SetRect(child_rect);
596         }
597     }
598 }
599 
600 
Draw()601 void UiElement::Layout::Draw()
602 {
603     CalculateRect();
604     CalculateChildrenRect();
605     Element::Draw();
606 }
607 
608 
SetCurrentElement(int index)609 void UiElement::StackElement::SetCurrentElement(int index)
610 {
611     if (index >= 0 && index < static_cast<int>(childLst.size()))
612         cur_index = index;
613     else
614         index = 0;
615 }
616 
SwitchDisplay(bool previous)617 void UiElement::StackElement::SwitchDisplay(bool previous)
618 {
619     if (previous)
620     {
621         cur_index--;
622         if (cur_index < 0)
623             cur_index = static_cast<int>(childLst.size()) - 1;
624     }
625     else
626     {
627         cur_index++;
628         if (cur_index >= static_cast<int>(childLst.size()))
629             cur_index = 0;
630     }
631 }
632 
Draw()633 void UiElement::StackElement::Draw()
634 {
635     auto cur_element{ CurrentElement() };
636 
637     //清空不显示的子元素的矩形区域
638     for (size_t i{}; i < childLst.size(); i++)
639     {
640         if (cur_element != childLst[i])
641         {
642             childLst[i]->IterateAllElements([&](UiElement::Element* element) ->bool {
643                 if (element != nullptr)
644                     element->ClearRect();
645                 return false;
646             });
647         }
648     }
649 
650     if (cur_element != nullptr)
651         cur_element->Draw();
652     //只绘制一个子元素
653     //不调用基类的Draw方法。
654 
655     //绘制指示器
656     if (show_indicator)
657     {
658         //计算指示器的位置
659         int indicator_width = ui->DPI(12) * childLst.size();
660         indicator.rect.top = GetRect().bottom + ui->DPI(2) + ui->DPI(indicator_offset);
661         indicator.rect.bottom = indicator.rect.top + ui->DPI(12);
662         indicator.rect.left = GetRect().left + (GetRect().Width() - indicator_width) / 2;
663         indicator.rect.right = indicator.rect.left + indicator_width;
664         indicator.rect.InflateRect(ui->DPI(2), ui->DPI(2));
665         //绘制指示器
666         ui->DrawStackIndicator(indicator, childLst.size(), cur_index);
667     }
668 }
669 
GetCurIndex() const670 int UiElement::StackElement::GetCurIndex() const
671 {
672     return cur_index;
673 }
674 
CurrentElement()675 std::shared_ptr<UiElement::Element> UiElement::StackElement::CurrentElement()
676 {
677     if (hover_to_switch && mouse_hover)
678     {
679         int next_index = cur_index + 1;
680         if (next_index < 0 || next_index >= static_cast<int>(childLst.size()))
681             next_index = 0;
682         return GetElement(next_index);
683     }
684     else
685     {
686         return GetElement(cur_index);
687     }
688 }
689 
GetElement(int index)690 std::shared_ptr<UiElement::Element> UiElement::StackElement::GetElement(int index)
691 {
692     if (childLst.empty())
693         return nullptr;
694     else if (index >= 0 && index < static_cast<int>(childLst.size()))
695         return childLst[index];
696     else
697         return childLst[0];
698 }
699 
700 
Draw()701 void UiElement::Rectangle::Draw()
702 {
703     CalculateRect();
704     ui->DrawRectangle(rect, no_corner_radius, theme_color, color_mode);
705     Element::Draw();
706 }
707 
Draw()708 void UiElement::Button::Draw()
709 {
710     CalculateRect();
711     switch (key)
712     {
713     case CPlayerUIBase::BTN_TRANSLATE:
714         ui->DrawTranslateButton(rect);
715         break;
716     case CPlayerUIBase::BTN_LRYIC:
717         ui->DrawDesktopLyricButton(rect);
718         break;
719     case CPlayerUIBase::BTN_AB_REPEAT:
720         ui->DrawABRepeatButton(rect);
721         break;
722     case CPlayerUIBase::BTN_KARAOKE:
723         ui->DrawKaraokeButton(rect);
724         break;
725     default:
726         ui->DrawUIButton(rect, key, big_icon, show_text, font_size);
727         break;
728     }
729     Element::Draw();
730 }
731 
FromString(const std::string & key_type)732 void UiElement::Button::FromString(const std::string& key_type)
733 {
734     if (key_type == "menu")
735         key = CPlayerUIBase::BTN_MENU;
736     else if (key_type == "miniMode")
737         key = CPlayerUIBase::BTN_MINI;
738     else if (key_type == "miniModeClose")
739         key = CPlayerUIBase::BTN_CLOSE;
740     else if (key_type == "fullScreen")
741         key = CPlayerUIBase::BTN_FULL_SCREEN;
742     else if (key_type == "repeatMode")
743         key = CPlayerUIBase::BTN_REPETEMODE;
744     else if (key_type == "settings")
745         key = CPlayerUIBase::BTN_SETTING;
746     else if (key_type == "equalizer")
747         key = CPlayerUIBase::BTN_EQ;
748     else if (key_type == "skin")
749         key = CPlayerUIBase::BTN_SKIN;
750     else if (key_type == "info")
751         key = CPlayerUIBase::BTN_INFO;
752     else if (key_type == "find")
753         key = CPlayerUIBase::BTN_FIND;
754     else if (key_type == "abRepeat")
755         key = CPlayerUIBase::BTN_AB_REPEAT;
756     else if (key_type == "desktopLyric")
757         key = CPlayerUIBase::BTN_LRYIC;
758     else if (key_type == "lyricTranslate")
759         key = CPlayerUIBase::BTN_TRANSLATE;
760     else if (key_type == "stop")
761         key = CPlayerUIBase::BTN_STOP;
762     else if (key_type == "previous")
763         key = CPlayerUIBase::BTN_PREVIOUS;
764     else if (key_type == "next")
765         key = CPlayerUIBase::BTN_NEXT;
766     else if (key_type == "playPause")
767         key = CPlayerUIBase::BTN_PLAY_PAUSE;
768     else if (key_type == "favorite")
769         key = CPlayerUIBase::BTN_FAVOURITE;
770     else if (key_type == "mediaLib")
771         key = CPlayerUIBase::BTN_MEDIA_LIB;
772     else if (key_type == "showPlaylist")
773         key = CPlayerUIBase::BTN_SHOW_PLAYLIST;
774     else if (key_type == "addToPlaylist")
775         key = CPlayerUIBase::BTN_ADD_TO_PLAYLIST;
776     else if (key_type == "switchDisplay")
777         key = CPlayerUIBase::BTN_SWITCH_DISPLAY;
778     else if (key_type == "darkLightMode")
779         key = CPlayerUIBase::BTN_DARK_LIGHT;
780     else if (key_type == "locateTrack")
781         key = CPlayerUIBase::BTN_LOCATE_TO_CURRENT;
782     else if (key_type == "openFolder")
783         key = CPlayerUIBase::BTN_OPEN_FOLDER;
784     else if (key_type == "newPlaylist")
785         key = CPlayerUIBase::BTN_NEW_PLAYLIST;
786     else if (key_type == "playMyFavourite")
787         key = CPlayerUIBase::BTN_PLAY_MY_FAVOURITE;
788     else if (key_type == "medialibFolderSort")
789         key = CPlayerUIBase::BTN_MEDIALIB_FOLDER_SORT;
790     else if (key_type == "medialibPlaylistSort")
791         key = CPlayerUIBase::BTN_MEDIALIB_PLAYLIST_SORT;
792     else if (key_type == "karaoke")
793         key = CPlayerUIBase::BTN_KARAOKE;
794     else
795         key = CPlayerUIBase::BTN_INVALID;
796 }
797 
GetMaxWidth(CRect parent_rect) const798 int UiElement::Button::GetMaxWidth(CRect parent_rect) const
799 {
800     //显示文本,并且没有指定宽度时时跟随文本宽度
801     if (show_text && !IsWidthValid())
802     {
803         std::wstring text = ui->GetButtonText(key);
804         //第一次执行到这里时,由于rect还没有从layout元素中计算出来,因此这里做一下判断,如果高度为0,则直接获取height的值
805         int btn_height = rect.Height();
806         if (btn_height == 0)
807             btn_height = Element::height.GetValue(parent_rect);
808         int right_space = (btn_height - ui->DPI(16)) / 2;
809 
810         //计算文本宽度前先设置一下字体
811         UiFontGuard set_font(ui, font_size);
812 
813         int width_text{ ui->m_draw.GetTextExtent(text.c_str()).cx + right_space + btn_height };
814 
815         int width_max{ max_width.IsValid() ? max_width.GetValue(parent_rect) : INT_MAX };
816         return min(width_text, width_max);
817     }
818     else
819     {
820         return Element::GetMaxWidth(parent_rect);
821     }
822 }
823 
ClearRect()824 void UiElement::Button::ClearRect()
825 {
826     Element::ClearRect();
827     ui->m_buttons[key].rect = CRect();
828 }
829 
Draw()830 void UiElement::Text::Draw()
831 {
832     CalculateRect();
833     std::wstring draw_text{ GetText() };
834 
835     //设置字体
836     UiFontGuard set_font(ui, font_size);
837 
838     COLORREF text_color{};
839     if (color_mode == CPlayerUIBase::RCM_LIGHT)
840         text_color = ColorTable::WHITE;
841     else if (color_mode == CPlayerUIBase::RCM_DARK)
842         text_color = theApp.m_app_setting_data.theme_color.dark2;
843     else
844         text_color = ui->m_colors.color_text;
845 
846     int text_extent{ ui->m_draw.GetTextExtent(draw_text.c_str()).cx };  //文本的实际宽度
847     if (rect.Width() >= text_extent)    //如果绘图区域的宽度大于文本的实际宽度,则文本不需要滚动显示
848     {
849         ui->m_draw.DrawWindowText(rect, draw_text.c_str(), text_color, align);
850     }
851     else
852     {
853         switch (style)
854         {
855         case UiElement::Text::Static:
856             ui->m_draw.DrawWindowText(rect, draw_text.c_str(), text_color, align);
857             break;
858         case UiElement::Text::Scroll:
859             ui->m_draw.DrawScrollText(rect, draw_text.c_str(), text_color, ui->GetScrollTextPixel(), false, scroll_info, false);
860             break;
861         case UiElement::Text::Scroll2:
862             ui->m_draw.DrawScrollText2(rect, draw_text.c_str(), text_color, ui->GetScrollTextPixel(), false, scroll_info, false);
863             break;
864         default:
865             break;
866         }
867     }
868 
869     Element::Draw();
870 }
871 
GetMaxWidth(CRect parent_rect) const872 int UiElement::Text::GetMaxWidth(CRect parent_rect) const
873 {
874     if (!width_follow_text)
875         return UiElement::Element::GetMaxWidth(parent_rect);
876     else
877     {
878         int width_text{ ui->m_draw.GetTextExtent(GetText().c_str()).cx + ui->DPI(4) };
879         int width_max{ max_width.IsValid() ? max_width.GetValue(parent_rect) : INT_MAX };
880         return min(width_text, width_max);
881     }
882 }
883 
GetText() const884 std::wstring UiElement::Text::GetText() const
885 {
886     std::wstring draw_text{};
887     switch (type)
888     {
889     case UiElement::Text::UserDefine:
890         draw_text = text;
891         break;
892     case UiElement::Text::Title:
893         draw_text = CPlayer::GetInstance().GetCurrentSongInfo().GetTitle();
894         break;
895     case UiElement::Text::Artist:
896         draw_text = CPlayer::GetInstance().GetCurrentSongInfo().GetArtist();
897         break;
898     case UiElement::Text::Album:
899         draw_text = CPlayer::GetInstance().GetCurrentSongInfo().GetAlbum();
900         break;
901     case UiElement::Text::ArtistTitle:
902         draw_text = CPlayer::GetInstance().GetCurrentSongInfo().GetArtist() + L" - " + CPlayer::GetInstance().GetCurrentSongInfo().GetTitle();
903         break;
904     case UiElement::Text::ArtistAlbum:
905     {
906         //优先使用唱片集艺术家,如果为空,则使用艺术家
907         std::wstring artist_display{ CPlayer::GetInstance().GetCurrentSongInfo().album_artist };
908         if (artist_display.empty())
909             artist_display = CPlayer::GetInstance().GetCurrentSongInfo().GetArtist();
910         draw_text = artist_display + L" - " + CPlayer::GetInstance().GetCurrentSongInfo().GetAlbum();
911     }   break;
912     case UiElement::Text::Format:
913         draw_text = CPlayerUIBase::GetDisplayFormatString();
914         break;
915     case UiElement::Text::PlayTime:
916         draw_text = CPlayer::GetInstance().GetTimeString();
917         break;
918     case UiElement::Text::PlayTimeAndVolume:
919         if (show_volume)
920         {
921             static const wstring& mute_str = theApp.m_str_table.LoadText(L"UI_TXT_VOLUME_MUTE");
922             int volume = CPlayer::GetInstance().GetVolume();
923             if (volume <= 0)
924                 draw_text = theApp.m_str_table.LoadTextFormat(L"UI_TXT_VOLUME", { mute_str, L"" });
925             else
926                 draw_text = theApp.m_str_table.LoadTextFormat(L"UI_TXT_VOLUME", { volume, L"%" });
927         }
928         else
929         {
930             draw_text = CPlayer::GetInstance().GetTimeString();
931         }
932         break;
933     default:
934         break;
935     }
936     return draw_text;
937 }
938 
Draw()939 void UiElement::AlbumCover::Draw()
940 {
941     CalculateRect();
942     if (show_info)
943         ui->DrawAlbumCoverWithInfo(rect);
944     else
945         ui->DrawAlbumCover(rect);
946     Element::Draw();
947 }
948 
CalculateRect()949 void UiElement::AlbumCover::CalculateRect()
950 {
951     Element::CalculateRect();
952     CRect cover_rect{ rect };
953     //如果强制专辑封面为正方形,则在这里计算新的矩形区域
954     if (square)
955     {
956         int side{ min(rect.Width(), rect.Height()) };
957         if (rect.Width() > rect.Height())
958         {
959             cover_rect.left = rect.left + (rect.Width() - side) / 2;
960             cover_rect.right = cover_rect.left + side;
961         }
962         else if (rect.Width() < rect.Height())
963         {
964             cover_rect.top = rect.top + (rect.Height() - side) / 2;
965             cover_rect.bottom = cover_rect.top + side;
966         }
967         rect = cover_rect;
968     }
969 }
970 
Draw()971 void UiElement::Spectrum::Draw()
972 {
973     CalculateRect();
974     if (theApp.m_app_setting_data.show_spectrum)
975     {
976         ui->m_draw.DrawSpectrum(rect, type, draw_reflex, theApp.m_app_setting_data.spectrum_low_freq_in_center, fixed_width, align);
977         Element::Draw();
978     }
979 }
980 
IsEnable(CRect parent_rect) const981 bool UiElement::Spectrum::IsEnable(CRect parent_rect) const
982 {
983     if (theApp.m_app_setting_data.show_spectrum)
984         return UiElement::Element::IsEnable(parent_rect);
985     return false;
986 }
987 
Draw()988 void UiElement::TrackInfo::Draw()
989 {
990     CalculateRect();
991     ui->DrawSongInfo(rect, font_size);
992     Element::Draw();
993 }
994 
Draw()995 void UiElement::Toolbar::Draw()
996 {
997     CalculateRect();
998     ui->DrawToolBarWithoutBackground(rect, show_translate_btn);
999     Element::Draw();
1000 }
1001 
Draw()1002 void UiElement::ProgressBar::Draw()
1003 {
1004     CalculateRect();
1005     if (show_play_time)
1006     {
1007         ui->DrawProgressBar(rect, play_time_both_side);
1008     }
1009     else
1010     {
1011         ui->DrawProgess(rect);
1012     }
1013     Element::Draw();
1014 }
1015 
Draw()1016 void UiElement::Lyrics::Draw()
1017 {
1018     CalculateRect();
1019 
1020     bool big_font{ ui->m_ui_data.full_screen && ui->IsDrawLargeIcon() };
1021     CFont* lyric_font = &theApp.m_font_set.lyric.GetFont(big_font);
1022     CFont* lyric_tr_font = &theApp.m_font_set.lyric_translate.GetFont(big_font);
1023 
1024     if (use_default_font)   // 目前这个bool有些冗余,当字体与字号在m_font_set中解耦后有用
1025     {
1026         lyric_font = &theApp.m_font_set.GetFontBySize(font_size).GetFont(big_font);
1027         lyric_tr_font = &theApp.m_font_set.GetFontBySize(font_size - 1).GetFont(big_font);
1028     }
1029 
1030     //如果父元素中包含了矩形元素,则即使在“外观设置”中勾选了“歌词界面背景”,也不再为歌词区域绘制半透明背景
1031     ui->DrawLyrics(rect, lyric_font, lyric_tr_font, (!no_background && !IsParentRectangle()), show_song_info);
1032 
1033     ui->m_draw_data.lyric_rect = rect;
1034     Element::Draw();
1035 }
1036 
ClearRect()1037 void UiElement::Lyrics::ClearRect()
1038 {
1039     Element::ClearRect();
1040     ui->m_draw_data.lyric_rect = CRect();
1041 }
1042 
IsParentRectangle() const1043 bool UiElement::Lyrics::IsParentRectangle() const
1044 {
1045     const Element* ele{ this };
1046     while (ele != nullptr && ele->pParent != nullptr)
1047     {
1048         if (dynamic_cast<const Rectangle*>(ele) != nullptr)
1049             return true;
1050         ele = ele->pParent;
1051     }
1052     return false;
1053 }
1054 
Draw()1055 void UiElement::Volume::Draw()
1056 {
1057     CalculateRect();
1058     ui->DrawVolumeButton(rect, adj_btn_on_top, show_text);
1059     Element::Draw();
1060 }
1061 
Draw()1062 void UiElement::BeatIndicator::Draw()
1063 {
1064     CalculateRect();
1065     ui->DrawBeatIndicator(rect);
1066     Element::Draw();
1067 }
1068 
Draw()1069 void UiElement::ListElement::Draw()
1070 {
1071     CalculateRect();
1072     RestrictOffset();
1073     CalculateItemRects();
1074 
1075     if (last_row_count != GetRowCount())
1076     {
1077         OnRowCountChanged();
1078         last_row_count = GetRowCount();
1079     }
1080 
1081     ui->DrawList(rect, this, ItemHeight());
1082     Element::Draw();
1083 }
1084 
LButtonUp(CPoint point)1085 void UiElement::ListElement::LButtonUp(CPoint point)
1086 {
1087     mouse_pressed = false;
1088     scrollbar_handle_pressed = false;
1089     //设置按钮的按下状态
1090     for (int i{}; i < GetHoverButtonCount(); i++)
1091     {
1092         auto& btn{ GetHoverButtonState(i) };
1093         if (btn.pressed)
1094         {
1095             if (btn.rect.PtInRect(point))
1096                 OnHoverButtonClicked(i, GetListIndexByPoint(point));
1097             btn.pressed = false;
1098         }
1099     }
1100 }
1101 
LButtonDown(CPoint point)1102 void UiElement::ListElement::LButtonDown(CPoint point)
1103 {
1104     //点击了控件区域
1105     if (rect.PtInRect(point))
1106     {
1107         //点击了滚动条区域
1108         if (scrollbar_rect.PtInRect(point))
1109         {
1110             //点击了滚动条把手区域
1111             if (scrollbar_handle_rect.PtInRect(point))
1112             {
1113                 scrollbar_handle_pressed = true;
1114             }
1115             //点击了滚动条空白区域
1116             else
1117             {
1118                 mouse_pressed = false;
1119             }
1120         }
1121         //点击了列表区域
1122         else
1123         {
1124             //设置按钮的按下状态
1125             for (int i{}; i < GetHoverButtonCount(); i++)
1126             {
1127                 auto& btn{ GetHoverButtonState(i) };
1128                 btn.pressed = btn.rect.PtInRect(point);
1129             }
1130 
1131             int clicked_index{ GetListIndexByPoint(point) };        //点击的行
1132             //允许多选时
1133             if (IsMultipleSelectionEnable())
1134             {
1135                 //是否按下Ctrl键
1136                 if (GetKeyState(VK_CONTROL) & 0x80)
1137                 {
1138                     if (items_selected.contains(clicked_index))
1139                         items_selected.erase(clicked_index);
1140                     else
1141                         items_selected.insert(clicked_index);
1142                 }
1143                 //是否按下Shift键,并且至少选中了一行
1144                 else if (GetKeyState(VK_SHIFT) & 0x8000 && !items_selected.empty())
1145                 {
1146                     int first_selected = *items_selected.begin();   //选中的第一行
1147                     items_selected.clear();
1148                     //点击的行在选中的第一行后面
1149                     if (first_selected < clicked_index)
1150                     {
1151                         for (int i = first_selected; i <= clicked_index; i++)
1152                             items_selected.insert(i);
1153                     }
1154                     //点击的行在选中的第一行前面
1155                     else
1156                     {
1157                         for (int i = clicked_index; i <= first_selected; i++)
1158                             items_selected.insert(i);
1159                     }
1160                 }
1161                 else
1162                 {
1163                     SetItemSelected(clicked_index);
1164                 }
1165             }
1166             //仅单选时
1167             else
1168             {
1169                 SetItemSelected(clicked_index);
1170             }
1171             OnClicked();
1172             selected_item_scroll_info.Reset();
1173             mouse_pressed = true;
1174         }
1175         mouse_pressed_offset = playlist_offset;
1176         mouse_pressed_pos = point;
1177     }
1178     //点击了控件外
1179     else
1180     {
1181         mouse_pressed = false;
1182         //item_selected = -1;
1183     }
1184 }
1185 
MouseMove(CPoint point)1186 void UiElement::ListElement::MouseMove(CPoint point)
1187 {
1188     if (rect.IsRectEmpty())
1189         return;
1190 
1191     mouse_pos = point;
1192     hover = rect.PtInRect(point);
1193     scrollbar_hover = scrollbar_rect.PtInRect(point);
1194     if (scrollbar_handle_pressed)
1195     {
1196         int delta_scrollbar_offset = mouse_pressed_pos.y - point.y;  //滚动条移动的距离
1197         //将滚动条移动的距离转换成播放列表的位移
1198         int scroll_area_height = rect.Height() - scroll_handle_length_comp;
1199         if (scroll_area_height > 0)
1200         {
1201             int delta_playlist_offset = delta_scrollbar_offset * (ItemHeight() * GetDisplayRowCount()) / scroll_area_height;
1202             playlist_offset = mouse_pressed_offset - delta_playlist_offset;
1203         }
1204     }
1205     else if (mouse_pressed)
1206     {
1207         playlist_offset = mouse_pressed_offset + (mouse_pressed_pos.y - point.y);
1208     }
1209 
1210     //查找鼠标指向的行
1211     int row = GetListIndexByPoint(point);
1212 
1213     //如果显示了按钮
1214     bool mouse_in_btn{ false };
1215     if (GetHoverButtonCount() > 0)
1216     {
1217         for (int i{}; i < GetHoverButtonCount(); i++)
1218         {
1219             auto& btn{ GetHoverButtonState(i) };
1220             if (btn.rect.PtInRect(point) && rect.PtInRect(point))
1221             {
1222                 mouse_in_btn = true;
1223                 btn.hover = true;
1224                 static int last_row{ -1 };
1225                 static int last_btn_index{ -1 };
1226                 if (last_row != row || last_btn_index != i)
1227                 {
1228                     std::wstring btn_tooltip{ GetHoverButtonTooltip(i, row) };
1229                     ui->UpdateMouseToolTip(GetToolTipIndex(), btn_tooltip.c_str());
1230                     ui->UpdateMouseToolTipPosition(GetToolTipIndex(), btn.rect);
1231                 }
1232                 last_row = row;
1233                 last_btn_index = i;
1234             }
1235             else
1236             {
1237                 btn.hover = false;
1238             }
1239         }
1240     }
1241 
1242     //显示鼠标提示
1243     if (!mouse_in_btn && ShowTooltip() && hover && !scrollbar_hover && !scrollbar_handle_pressed)
1244     {
1245         if (row >= 0)
1246         {
1247             static int last_row{ -1 };
1248             if (last_row != row)
1249             {
1250                 last_row = row;
1251                 std::wstring str_tip = GetToolTipText(row);
1252 
1253                 ui->UpdateMouseToolTip(GetToolTipIndex(), str_tip.c_str());
1254                 int display_row = row;
1255                 AbsoluteRowToDisplayRow(display_row);
1256                 if (display_row >= 0 && display_row < static_cast<int>(item_rects.size()))
1257                     ui->UpdateMouseToolTipPosition(GetToolTipIndex(), item_rects[display_row]);
1258             }
1259         }
1260     }
1261 }
1262 
RButtunUp(CPoint point)1263 bool UiElement::ListElement::RButtunUp(CPoint point)
1264 {
1265     if (rect.PtInRect(point))
1266     {
1267         mouse_pressed = false;
1268         CMenu* menu{ GetContextMenu(GetItemSelected() >= 0 && !scrollbar_rect.PtInRect(point))};
1269         ShowContextMenu(menu, GetCmdRecivedWnd());
1270         return true;
1271     }
1272     return false;
1273 }
1274 
ShowContextMenu(CMenu * menu,CWnd * cmd_reciver)1275 void UiElement::ListElement::ShowContextMenu(CMenu* menu, CWnd* cmd_reciver)
1276 {
1277     if (menu != nullptr)
1278     {
1279         CPoint cursor_pos;
1280         GetCursorPos(&cursor_pos);
1281         if (cmd_reciver != nullptr)
1282         {
1283             //弹出右键菜单,当选择了一个菜单命令时向cmd_reciver发送WM_COMMAND消息
1284             menu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, cursor_pos.x, cursor_pos.y, cmd_reciver);
1285         }
1286         else
1287         {
1288             CUIWindowCmdHelper helper(this);
1289             helper.SetMenuState(menu);
1290             //使用TPM_RETURNCMD标志指定菜单命令使用返回值返回,TPM_NONOTIFY标志指定选择了菜单命令后不会向窗口发送WM_COMMAND消息,但是仍然必须传递一个有效的窗口句柄
1291             UINT command = menu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, cursor_pos.x, cursor_pos.y, theApp.m_pMainWnd);
1292             helper.OnUiCommand(command);
1293         }
1294     }
1295 }
1296 
1297 
RButtonDown(CPoint point)1298 void UiElement::ListElement::RButtonDown(CPoint point)
1299 {
1300     mouse_pressed = false;
1301     if (rect.PtInRect(point))
1302     {
1303         if (!scrollbar_rect.PtInRect(point))
1304         {
1305             int clicked_index{ GetListIndexByPoint(point) };        //点击的行
1306             if (!IsItemSelected(clicked_index))
1307             {
1308                 SetItemSelected(clicked_index);
1309                 OnClicked();
1310             }
1311             selected_item_scroll_info.Reset();
1312         }
1313     }
1314     else
1315     {
1316         items_selected.clear();
1317     }
1318 }
1319 
MouseWheel(int delta,CPoint point)1320 bool UiElement::ListElement::MouseWheel(int delta, CPoint point)
1321 {
1322     if (rect.PtInRect(point))
1323     {
1324         //一次滚动的行数
1325         int lines = rect.Height() / ItemHeight() / 2;
1326         if (lines > 3)
1327             lines = 3;
1328         if (lines < 1)
1329             lines = 1;
1330         playlist_offset += (-delta * lines * ItemHeight() / 120);  //120为鼠标滚轮一行时delta的值
1331         return true;
1332     }
1333     return false;
1334 }
1335 
MouseLeave()1336 void UiElement::ListElement::MouseLeave()
1337 {
1338     hover = false;
1339     mouse_pressed = false;
1340     scrollbar_hover = false;
1341     scrollbar_handle_pressed = false;
1342 }
1343 
DoubleClick(CPoint point)1344 bool UiElement::ListElement::DoubleClick(CPoint point)
1345 {
1346     if (rect.PtInRect(point) && !scrollbar_rect.PtInRect(point) && GetItemSelected() >= 0)
1347     {
1348         OnDoubleClicked();
1349     }
1350     return false;
1351 }
1352 
ClearRect()1353 void UiElement::ListElement::ClearRect()
1354 {
1355     Element::ClearRect();
1356     for (auto& btn : hover_buttons)
1357         btn.second.rect = CRect();
1358 }
1359 
EnsureItemVisible(int index)1360 void UiElement::ListElement::EnsureItemVisible(int index)
1361 {
1362     if (index <= 0)
1363     {
1364         playlist_offset = 0;
1365         return;
1366     }
1367 
1368     CalculateRect();
1369     CalculateItemRects();
1370 
1371     AbsoluteRowToDisplayRow(index);
1372     if (index < 0 || index >= static_cast<int>(item_rects.size()))
1373         return;
1374 
1375     CRect item_rect{ item_rects[index] };
1376     //确定当前项目是否处于可见状态
1377     if (item_rect.top > rect.top && item_rect.bottom < rect.bottom)
1378         return;
1379 
1380     //计算要使指定项可见时的偏移量
1381     int delta_offset{};
1382     //指定项目在播放列表上方
1383     if (item_rect.top < rect.top)
1384         delta_offset = rect.top - item_rect.top;
1385     //指定项目在播放列表下方
1386     else if (item_rect.bottom > rect.bottom)
1387         delta_offset = rect.bottom - item_rect.bottom;
1388     playlist_offset -= delta_offset;
1389 }
1390 
EnsureHighlightItemVisible()1391 void UiElement::ListElement::EnsureHighlightItemVisible()
1392 {
1393     int highlight_row{ GetHighlightRow() };
1394     if (highlight_row >= 0)
1395         EnsureItemVisible(highlight_row);
1396 }
1397 
RestrictOffset()1398 void UiElement::ListElement::RestrictOffset()
1399 {
1400     int& offset{ playlist_offset };
1401     if (offset < 0)
1402         offset = 0;
1403     int offset_max{ ItemHeight() * GetDisplayRowCount() - rect.Height() };
1404     if (offset_max <= 0)
1405         offset = 0;
1406     else if (offset > offset_max)
1407         offset = offset_max;
1408 }
1409 
CalculateItemRects()1410 void UiElement::ListElement::CalculateItemRects()
1411 {
1412     item_rects.resize(GetRowCount());
1413     for (size_t i{}; i < item_rects.size(); i++)
1414     {
1415         //计算每一行的矩形区域
1416         int start_y = -playlist_offset + rect.top + i * ItemHeight();
1417         CRect rect_item{ rect };
1418         rect_item.top = start_y;
1419         rect_item.bottom = rect_item.top + ItemHeight();
1420 
1421         //保存每一行的矩形区域
1422         item_rects[i] = rect_item;
1423     }
1424 }
1425 
ItemHeight() const1426 int UiElement::ListElement::ItemHeight() const
1427 {
1428     return ui->DPI(item_height);
1429 }
1430 
SetItemSelected(int index)1431 void UiElement::ListElement::SetItemSelected(int index)
1432 {
1433     items_selected.clear();
1434     if (index >= 0)
1435     {
1436         items_selected.insert(index);
1437         EnsureItemVisible(index);
1438     }
1439 }
1440 
GetItemSelected() const1441 int UiElement::ListElement::GetItemSelected() const
1442 {
1443     if (!items_selected.empty())
1444         return *items_selected.begin();
1445     return -1;
1446 }
1447 
SetItemsSelected(const vector<int> & indexes)1448 void UiElement::ListElement::SetItemsSelected(const vector<int>& indexes)
1449 {
1450     items_selected.clear();
1451     for (int index : indexes)
1452         items_selected.insert(index);
1453 }
1454 
GetItemsSelected(vector<int> & indexes) const1455 void UiElement::ListElement::GetItemsSelected(vector<int>& indexes) const
1456 {
1457     indexes.clear();
1458     for (int index : items_selected)
1459         indexes.push_back(index);
1460 }
1461 
IsItemSelected(int index) const1462 bool UiElement::ListElement::IsItemSelected(int index) const
1463 {
1464     auto iter = std::find(items_selected.begin(), items_selected.end(), index);
1465     return iter != items_selected.end();
1466 }
1467 
IsMultipleSelected() const1468 bool UiElement::ListElement::IsMultipleSelected() const
1469 {
1470     return items_selected.size() > 1;
1471 }
1472 
SelectAll()1473 void UiElement::ListElement::SelectAll()
1474 {
1475     if (IsMultipleSelectionEnable())
1476     {
1477         items_selected.clear();
1478         for (int i{}; i < GetRowCount(); i++)
1479             items_selected.insert(i);
1480     }
1481 }
1482 
SelectNone()1483 void UiElement::ListElement::SelectNone()
1484 {
1485     items_selected.clear();
1486 }
1487 
SelectReversed()1488 void UiElement::ListElement::SelectReversed()
1489 {
1490     if (IsMultipleSelectionEnable())
1491     {
1492         auto items_selected_old{ items_selected };
1493         items_selected.clear();
1494         for (int i{}; i < GetRowCount(); i++)
1495         {
1496             if (!items_selected_old.contains(i))
1497                 items_selected.insert(i);
1498         }
1499     }
1500 }
1501 
GetHoverButtonState(int btn_index)1502 IPlayerUI::UIButton& UiElement::ListElement::GetHoverButtonState(int btn_index)
1503 {
1504     return hover_buttons[btn_index];
1505 }
1506 
OnRowCountChanged()1507 void UiElement::ListElement::OnRowCountChanged()
1508 {
1509     //如果列表的行数有变化,则清除选中
1510     SelectNone();
1511     //清除搜索框
1512     if (related_search_box != nullptr)
1513         related_search_box->Clear();
1514 }
1515 
QuickSearch(const std::wstring & key_word)1516 void UiElement::ListElement::QuickSearch(const std::wstring& key_word)
1517 {
1518     searched = !key_word.empty();
1519 
1520     //查找匹配的序号
1521     search_result.clear();
1522     if (key_word.empty())
1523         return;
1524     for (int i = 0; i < GetRowCount(); i++)
1525     {
1526         if (IsItemMatchKeyWord(i, key_word))
1527             search_result.push_back(i);
1528     }
1529 }
1530 
IsItemMatchKeyWord(int row,const std::wstring & key_word)1531 bool UiElement::ListElement::IsItemMatchKeyWord(int row, const std::wstring& key_word)
1532 {
1533     bool rtn = false;
1534     //默认匹配每一列中的文本
1535     for (int i = 0; i < GetColumnCount(); i++)
1536     {
1537         std::wstring text = GetItemText(row, i);
1538         if (!text.empty() && theApp.m_chinese_pingyin_res.IsStringMatchWithPingyin(key_word, text))
1539             return true;
1540     }
1541     return false;
1542 }
1543 
GetDisplayRowCount()1544 int UiElement::ListElement::GetDisplayRowCount()
1545 {
1546     if (searched)
1547         return search_result.size();
1548     else
1549         return GetRowCount();
1550 }
1551 
IsRowDisplayed(int row)1552 bool UiElement::ListElement::IsRowDisplayed(int row)
1553 {
1554     if (row >= 0 && row < GetRowCount())
1555     {
1556         //搜索状态下,仅搜索结果中的行显示
1557         if (searched)
1558         {
1559             return CCommon::IsItemInVector(search_result, row);
1560         }
1561         //非搜索状态下,所有行都显示
1562         else
1563         {
1564             return true;
1565         }
1566     }
1567     return false;
1568 }
1569 
DisplayRowToAbsoluteRow(int & row)1570 void UiElement::ListElement::DisplayRowToAbsoluteRow(int& row)
1571 {
1572     if (searched)       //查找状态下需要转换行号
1573     {
1574         if (row >= 0 && row < static_cast<int>(search_result.size()))
1575             row = search_result[row];
1576         else
1577             row = -1;
1578     }
1579 }
1580 
AbsoluteRowToDisplayRow(int & row)1581 void UiElement::ListElement::AbsoluteRowToDisplayRow(int& row)
1582 {
1583     if (searched)       //查找状态下需要转换行号
1584     {
1585         bool row_exist{};
1586         for (int i{}; i < static_cast<int>(search_result.size()); i++)
1587         {
1588             if (row == search_result[i])
1589             {
1590                 row = i;
1591                 row_exist = true;
1592                 break;
1593             }
1594         }
1595         if (!row_exist)
1596             row = -1;
1597     }
1598 }
1599 
GetListIndexByPoint(CPoint point)1600 int UiElement::ListElement::GetListIndexByPoint(CPoint point)
1601 {
1602     int index = GetDisplayedIndexByPoint(point);
1603     DisplayRowToAbsoluteRow(index);
1604     return index;
1605 }
1606 
GetDisplayedIndexByPoint(CPoint point)1607 int UiElement::ListElement::GetDisplayedIndexByPoint(CPoint point)
1608 {
1609     for (size_t i{}; i < item_rects.size(); i++)
1610     {
1611         if (item_rects[i].PtInRect(point))
1612             return static_cast<int>(i);
1613     }
1614     return -1;
1615 }
1616 
GetItemText(int row,int col)1617 std::wstring UiElement::Playlist::GetItemText(int row, int col)
1618 {
1619     if (row >= 0 && row < GetRowCount())
1620     {
1621         //序号
1622         if (col == COL_INDEX)
1623         {
1624             return std::to_wstring(row + 1);
1625         }
1626         //曲目
1627         else if (col == COL_TRACK)
1628         {
1629             const SongInfo& song_info{ CPlayer::GetInstance().GetPlayList()[row] };
1630             std::wstring display_name{ CSongInfoHelper::GetDisplayStr(song_info, theApp.m_media_lib_setting_data.display_format) };
1631             return display_name;
1632         }
1633         //时间
1634         else if (col == COL_TIME)
1635         {
1636             const SongInfo& song_info{ CPlayer::GetInstance().GetPlayList()[row] };
1637             return song_info.length().toString();
1638         }
1639     }
1640 
1641     return std::wstring();
1642 }
1643 
GetColumnCount()1644 int UiElement::Playlist::GetColumnCount()
1645 {
1646     return COL_MAX;
1647 }
1648 
GetColumnWidth(int col,int total_width)1649 int UiElement::Playlist::GetColumnWidth(int col, int total_width)
1650 {
1651     const int index_width{ ui->DPI(40) };
1652     const int time_width{ ui->DPI(50) };
1653     if (col == COL_INDEX)
1654     {
1655         return index_width;
1656     }
1657     else if (col == COL_TIME)
1658     {
1659         return time_width;
1660     }
1661     else if (col == COL_TRACK)
1662     {
1663         return total_width - index_width - time_width;
1664     }
1665     return 0;
1666 }
1667 
GetEmptyString()1668 std::wstring UiElement::Playlist::GetEmptyString()
1669 {
1670     const wstring& info = theApp.m_str_table.LoadText(L"UI_PLAYLIST_EMPTY_INFO");
1671     return info;
1672 }
1673 
GetHighlightRow()1674 int UiElement::Playlist::GetHighlightRow()
1675 {
1676     int highlight_row = CPlayer::GetInstance().GetIndex();
1677     if (last_highlight_row != highlight_row)
1678     {
1679         EnsureItemVisible(highlight_row);
1680         last_highlight_row = highlight_row;
1681     }
1682     return highlight_row;
1683 }
1684 
GetColumnScrollTextWhenSelected()1685 int UiElement::Playlist::GetColumnScrollTextWhenSelected()
1686 {
1687     return COL_TRACK;
1688 }
1689 
ShowTooltip()1690 bool UiElement::Playlist::ShowTooltip()
1691 {
1692     return theApp.m_media_lib_setting_data.show_playlist_tooltip;
1693 }
1694 
GetToolTipText(int row)1695 std::wstring UiElement::Playlist::GetToolTipText(int row)
1696 {
1697     if (row >= 0 && row < CPlayer::GetInstance().GetSongNum())
1698     {
1699         const SongInfo& song_info = CPlayer::GetInstance().GetPlayList()[row];
1700         bool show_full_path = (!CPlayer::GetInstance().IsFolderMode() || CPlayer::GetInstance().IsContainSubFolder());
1701         std::wstring str_tip = CSongInfoHelper::GetPlaylistItemToolTip(song_info, true, show_full_path);
1702         return str_tip;
1703     }
1704 
1705     return std::wstring();
1706 }
1707 
GetToolTipIndex() const1708 int UiElement::Playlist::GetToolTipIndex() const
1709 {
1710     return TooltipIndex::PLAYLIST;
1711 }
1712 
GetContextMenu(bool item_selected)1713 CMenu* UiElement::Playlist::GetContextMenu(bool item_selected)
1714 {
1715     if (item_selected)
1716         return theApp.m_menu_mgr.GetMenu(MenuMgr::PlaylistMenu);
1717     else
1718         return theApp.m_menu_mgr.GetMenu(MenuMgr::PlaylistToolBarMenu);
1719     return nullptr;
1720 }
1721 
GetCmdRecivedWnd()1722 CWnd* UiElement::Playlist::GetCmdRecivedWnd()
1723 {
1724     //Playlist中的右键菜单命令在主窗口中响应
1725     return theApp.m_pMainWnd;
1726 }
1727 
OnDoubleClicked()1728 void UiElement::Playlist::OnDoubleClicked()
1729 {
1730     ::SendMessage(AfxGetMainWnd()->GetSafeHwnd(), WM_COMMAND, ID_PLAY_ITEM, 0);
1731 }
1732 
OnClicked()1733 void UiElement::Playlist::OnClicked()
1734 {
1735     CMusicPlayerDlg* pMainWnd = CMusicPlayerDlg::GetInstance();
1736     if (pMainWnd != nullptr)
1737     {
1738         std::vector<int> indexes;
1739         GetItemsSelected(indexes);
1740         pMainWnd->SetPlaylistSelected(indexes);
1741     }
1742 }
1743 
GetHoverButtonCount()1744 int UiElement::Playlist::GetHoverButtonCount()
1745 {
1746     return BTN_MAX;
1747 }
1748 
GetHoverButtonColumn()1749 int UiElement::Playlist::GetHoverButtonColumn()
1750 {
1751     return COL_TRACK;
1752 }
1753 
GetHoverButtonIcon(int index,int row)1754 IconMgr::IconType UiElement::Playlist::GetHoverButtonIcon(int index, int row)
1755 {
1756     switch (index)
1757     {
1758     case BTN_PLAY: return IconMgr::IT_Play;
1759     case BTN_ADD: return IconMgr::IT_Add;
1760     case BTN_FAVOURITE:
1761     {
1762         if (CPlayer::GetInstance().IsFavourite(row))
1763             return IconMgr::IT_Favorite_Off;
1764         else
1765             return IconMgr::IT_Favorite_On;
1766     }
1767     }
1768     return IconMgr::IT_NO_ICON;
1769 }
1770 
GetHoverButtonTooltip(int index,int row)1771 std::wstring UiElement::Playlist::GetHoverButtonTooltip(int index, int row)
1772 {
1773     switch (index)
1774     {
1775     case BTN_PLAY: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAY");
1776     case BTN_ADD: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_ADD_TO_PLAYLIST");
1777     case BTN_FAVOURITE: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_FAVOURITE");
1778     }
1779     return std::wstring();
1780 }
1781 
OnHoverButtonClicked(int btn_index,int row)1782 void UiElement::Playlist::OnHoverButtonClicked(int btn_index, int row)
1783 {
1784     CMusicPlayerCmdHelper helper;
1785     //点击了“播放”按钮
1786     if (btn_index == BTN_PLAY)
1787     {
1788         helper.OnPlayTrack(row);
1789     }
1790     //点击了“添加到播放列表”按钮
1791     else if (btn_index == BTN_ADD)
1792     {
1793         CMenu* menu = theApp.m_menu_mgr.GetMenu(MenuMgr::AddToPlaylistMenu);
1794         ShowContextMenu(menu, nullptr);
1795     }
1796     //点击了“添加到我喜欢的音乐”按钮
1797     else if (btn_index == BTN_FAVOURITE)
1798     {
1799         helper.OnAddRemoveFromFavourite(row);
1800     }
1801 }
1802 
GetUnHoverIconCount(int row)1803 int UiElement::Playlist::GetUnHoverIconCount(int row)
1804 {
1805     //鼠标未指向的列,如果曲目在“我喜欢的音乐”中,则显示红心图标
1806     if (CPlayer::GetInstance().IsFavourite(row))
1807         return 1;
1808     else
1809         return 0;
1810 }
1811 
GetUnHoverIcon(int index,int row)1812 IconMgr::IconType UiElement::Playlist::GetUnHoverIcon(int index, int row)
1813 {
1814     if (index == 0)
1815     {
1816         return IconMgr::IT_Favorite_Off;
1817     }
1818     return IconMgr::IT_NO_ICON;
1819 }
1820 
OnRowCountChanged()1821 void UiElement::Playlist::OnRowCountChanged()
1822 {
1823     ListElement::OnRowCountChanged();
1824     //播放列表行数改变时,通知主窗口取消播放列表选中项
1825     ::SendMessage(AfxGetMainWnd()->GetSafeHwnd(), WM_COMMAND, ID_PLAYLIST_SELECT_NONE, 0);
1826 }
1827 
IsItemMatchKeyWord(int row,const std::wstring & key_word)1828 bool UiElement::Playlist::IsItemMatchKeyWord(int row, const std::wstring& key_word)
1829 {
1830     if (row >= 0 && row < CPlayer::GetInstance().GetSongNum())
1831     {
1832         const SongInfo& song_info = CPlayer::GetInstance().GetPlayList()[row];
1833         return (theApp.m_chinese_pingyin_res.IsStringMatchWithPingyin(key_word, song_info.GetFileName())
1834             || theApp.m_chinese_pingyin_res.IsStringMatchWithPingyin(key_word, song_info.title)
1835             || theApp.m_chinese_pingyin_res.IsStringMatchWithPingyin(key_word, song_info.artist)
1836             || theApp.m_chinese_pingyin_res.IsStringMatchWithPingyin(key_word, song_info.album));
1837     }
1838     return false;
1839 }
1840 
GetRowCount()1841 int UiElement::Playlist::GetRowCount()
1842 {
1843     int song_num{ CPlayer::GetInstance().GetSongNum() };
1844     if (song_num == 1 && CPlayer::GetInstance().GetPlayList()[0].IsEmpty())     //不显示播放列表为空时的占位符
1845         song_num = 0;
1846     return song_num;
1847 }
1848 
1849 CListCache UiElement::RecentPlayedList::m_list_cache(LT_RECENT);
1850 
Draw()1851 void UiElement::RecentPlayedList::Draw()
1852 {
1853     m_list_cache.reload();
1854     ListElement::Draw();
1855 }
1856 
GetItemText(int row,int col)1857 std::wstring UiElement::RecentPlayedList::GetItemText(int row, int col)
1858 {
1859     if (row >= 0 && row < GetRowCount())
1860     {
1861         if (col == COL_NAME)
1862         {
1863             return m_list_cache.at(row).GetDisplayName();
1864         }
1865         else if (col == COL_COUNT)
1866         {
1867             return std::to_wstring(m_list_cache.at(row).total_num);
1868         }
1869     }
1870     return std::wstring();
1871 }
1872 
GetRowCount()1873 int UiElement::RecentPlayedList::GetRowCount()
1874 {
1875     return m_list_cache.size();
1876 }
1877 
GetColumnCount()1878 int UiElement::RecentPlayedList::GetColumnCount()
1879 {
1880     return COL_MAX;
1881 }
1882 
GetColumnWidth(int col,int total_width)1883 int UiElement::RecentPlayedList::GetColumnWidth(int col, int total_width)
1884 {
1885     const int count_width{ ui->DPI(40) };
1886     if (col == COL_NAME)
1887         return total_width - count_width;
1888     else if (col == COL_COUNT)
1889         return count_width;
1890     return 0;
1891 }
1892 
GetColumnScrollTextWhenSelected()1893 int UiElement::RecentPlayedList::GetColumnScrollTextWhenSelected()
1894 {
1895     return COL_NAME;
1896 }
1897 
GetIcon(int row)1898 IconMgr::IconType UiElement::RecentPlayedList::GetIcon(int row)
1899 {
1900     if (row >= 0 && row < GetRowCount())
1901     {
1902         return m_list_cache.at(row).GetTypeIcon();
1903     }
1904     return IconMgr::IT_NO_ICON;
1905 }
1906 
HasIcon()1907 bool UiElement::RecentPlayedList::HasIcon()
1908 {
1909     return true;
1910 }
1911 
OnDoubleClicked()1912 void UiElement::RecentPlayedList::OnDoubleClicked()
1913 {
1914     int sel_index = GetItemSelected();
1915     CMusicPlayerCmdHelper helper;
1916     helper.OnListItemSelected(m_list_cache.GetItem(sel_index), true);
1917 }
1918 
GetContextMenu(bool item_selected)1919 CMenu* UiElement::RecentPlayedList::GetContextMenu(bool item_selected)
1920 {
1921     if (item_selected)
1922     {
1923         return theApp.m_menu_mgr.GetMenu(MenuMgr::UiRecentPlayedMenu);
1924     }
1925     return nullptr;
1926 }
1927 
GetHoverButtonCount()1928 int UiElement::RecentPlayedList::GetHoverButtonCount()
1929 {
1930     return 1;
1931 }
1932 
GetHoverButtonColumn()1933 int UiElement::RecentPlayedList::GetHoverButtonColumn()
1934 {
1935     return COL_NAME;
1936 }
1937 
GetHoverButtonIcon(int index,int row)1938 IconMgr::IconType UiElement::RecentPlayedList::GetHoverButtonIcon(int index, int row)
1939 {
1940     if (index == 0)
1941         return IconMgr::IT_Play;
1942     return IconMgr::IT_NO_ICON;
1943 }
1944 
GetHoverButtonTooltip(int index,int row)1945 std::wstring UiElement::RecentPlayedList::GetHoverButtonTooltip(int index, int row)
1946 {
1947     if (index == 0)
1948         return theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAY");
1949     return std::wstring();
1950 }
1951 
OnHoverButtonClicked(int btn_index,int row)1952 void UiElement::RecentPlayedList::OnHoverButtonClicked(int btn_index, int row)
1953 {
1954     CMusicPlayerCmdHelper helper;
1955     //点击了“播放”按钮
1956     if (btn_index == 0)
1957     {
1958         if (row >= 0 && row < GetRowCount())
1959         {
1960             CMusicPlayerCmdHelper helper;
1961             helper.OnListItemSelected(m_list_cache.GetItem(row), true);
1962         }
1963     }
1964 }
1965 
GetItemText(int row,int col)1966 std::wstring UiElement::MediaLibItemList::GetItemText(int row, int col)
1967 {
1968     if (col == COL_NAME)
1969     {
1970         if (row >= 0 && row < CUiMediaLibItemMgr::Instance().GetItemCount(type))
1971             return CUiMediaLibItemMgr::Instance().GetItemDisplayName(type, row);
1972     }
1973     else if (col == COL_COUNT)
1974     {
1975         if (row >= 0 && row < CUiMediaLibItemMgr::Instance().GetItemCount(type))
1976             return std::to_wstring(CUiMediaLibItemMgr::Instance().GetItemSongCount(type, row));
1977     }
1978     return std::wstring();
1979 }
1980 
GetRowCount()1981 int UiElement::MediaLibItemList::GetRowCount()
1982 {
1983     return CUiMediaLibItemMgr::Instance().GetItemCount(type);
1984 }
1985 
GetColumnCount()1986 int UiElement::MediaLibItemList::GetColumnCount()
1987 {
1988     return COL_MAX;
1989 }
1990 
GetColumnWidth(int col,int total_width)1991 int UiElement::MediaLibItemList::GetColumnWidth(int col, int total_width)
1992 {
1993     const int count_width{ ui->DPI(40) };
1994     if (col == COL_NAME)
1995         return total_width - count_width;
1996     else if (col == COL_COUNT)
1997         return count_width;
1998     return 0;
1999 }
2000 
GetEmptyString()2001 std::wstring UiElement::MediaLibItemList::GetEmptyString()
2002 {
2003     if (CUiMediaLibItemMgr::Instance().IsLoading())
2004         return theApp.m_str_table.LoadText(L"UI_MEDIALIB_LIST_LOADING_INFO");
2005     else if (!CUiMediaLibItemMgr::Instance().IsInited())
2006         return theApp.m_str_table.LoadText(L"UI_MEDIALIB_LIST_UNINITED_INFO");
2007     else
2008         return theApp.m_str_table.LoadText(L"UI_MEDIALIB_LIST_EMPTY_INFO");
2009 }
2010 
GetHighlightRow()2011 int UiElement::MediaLibItemList::GetHighlightRow()
2012 {
2013     if (CPlayer::GetInstance().IsMediaLibMode() && CPlayer::GetInstance().GetMediaLibPlaylistType() == type)
2014     {
2015         int highlight_row = CUiMediaLibItemMgr::Instance().GetCurrentIndex(type);
2016         if (last_highlight_row != highlight_row)
2017         {
2018             EnsureItemVisible(highlight_row);
2019             last_highlight_row = highlight_row;
2020         }
2021         return highlight_row;
2022     }
2023     return -1;
2024 }
2025 
GetColumnScrollTextWhenSelected()2026 int UiElement::MediaLibItemList::GetColumnScrollTextWhenSelected()
2027 {
2028     return COL_NAME;
2029 }
2030 
GetContextMenu(bool item_selected)2031 CMenu* UiElement::MediaLibItemList::GetContextMenu(bool item_selected)
2032 {
2033     if (item_selected)
2034     {
2035         return theApp.m_menu_mgr.GetMenu(MenuMgr::UiLibLeftMenu);
2036     }
2037     return nullptr;
2038 }
2039 
OnDoubleClicked()2040 void UiElement::MediaLibItemList::OnDoubleClicked()
2041 {
2042     int item_selected = GetItemSelected();
2043     if (item_selected >= 0 && item_selected < CUiMediaLibItemMgr::Instance().GetItemCount(type))
2044     {
2045         std::wstring item_name = CUiMediaLibItemMgr::Instance().GetItemName(type, item_selected);
2046         CMusicPlayerCmdHelper helper;
2047         ListItem list_item{ LT_MEDIA_LIB, item_name, type };
2048         helper.OnListItemSelected(list_item, true);
2049     }
2050 }
2051 
GetHoverButtonCount()2052 int UiElement::MediaLibItemList::GetHoverButtonCount()
2053 {
2054     return BTN_MAX;
2055 }
2056 
GetHoverButtonColumn()2057 int UiElement::MediaLibItemList::GetHoverButtonColumn()
2058 {
2059     return COL_NAME;
2060 }
2061 
GetHoverButtonIcon(int index,int row)2062 IconMgr::IconType UiElement::MediaLibItemList::GetHoverButtonIcon(int index, int row)
2063 {
2064     switch (index)
2065     {
2066     case BTN_PLAY: return IconMgr::IT_Play;
2067     case BTN_ADD: return IconMgr::IT_Add;
2068     }
2069     return IconMgr::IT_NO_ICON;
2070 }
2071 
GetHoverButtonTooltip(int index,int row)2072 std::wstring UiElement::MediaLibItemList::GetHoverButtonTooltip(int index, int row)
2073 {
2074     switch (index)
2075     {
2076     case BTN_PLAY: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAY");
2077     case BTN_ADD: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_ADD_TO_PLAYLIST");
2078     }
2079     return std::wstring();
2080 }
2081 
OnHoverButtonClicked(int btn_index,int row)2082 void UiElement::MediaLibItemList::OnHoverButtonClicked(int btn_index, int row)
2083 {
2084     CMusicPlayerCmdHelper helper;
2085     //点击了“播放”按钮
2086     if (btn_index == BTN_PLAY)
2087     {
2088         int item_selected = GetItemSelected();
2089         if (item_selected >= 0 && item_selected < GetRowCount())
2090         {
2091             std::wstring item_name = CUiMediaLibItemMgr::Instance().GetItemName(type, item_selected);
2092             CMusicPlayerCmdHelper helper;
2093             ListItem list_item{ LT_MEDIA_LIB, item_name, type };
2094             helper.OnListItemSelected(list_item, true);
2095         }
2096     }
2097     //点击了“添加到播放列表”按钮
2098     else if (btn_index == BTN_ADD)
2099     {
2100         CMenu* menu = theApp.m_menu_mgr.GetMenu(MenuMgr::AddToPlaylistMenu);
2101         ShowContextMenu(menu, nullptr);
2102     }
2103 }
2104 
2105 CListCache UiElement::PlaylistIndicator::m_list_cache(LT_CURRENT);
2106 
Draw()2107 void UiElement::PlaylistIndicator::Draw()
2108 {
2109     m_list_cache.reload();
2110     CalculateRect();
2111     ui->DrawCurrentPlaylistIndicator(rect, this);
2112     Element::Draw();
2113 }
2114 
LButtonUp(CPoint point)2115 void UiElement::PlaylistIndicator::LButtonUp(CPoint point)
2116 {
2117     if (btn_drop_down.rect.PtInRect(point))
2118     {
2119         btn_drop_down.hover = false;
2120         CRect btn_rect = rect_name;
2121         AfxGetMainWnd()->ClientToScreen(&btn_rect);
2122         theApp.m_menu_mgr.GetMenu(MenuMgr::RecentFolderPlaylistMenu)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, btn_rect.left, btn_rect.bottom, AfxGetMainWnd());
2123     }
2124     else if (btn_menu.rect.PtInRect(point))
2125     {
2126         btn_menu.hover = false;
2127         CRect btn_rect = btn_menu.rect;
2128         AfxGetMainWnd()->ClientToScreen(&btn_rect);
2129         theApp.m_menu_mgr.GetMenu(MenuMgr::PlaylistToolBarMenu)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, btn_rect.left, btn_rect.bottom, AfxGetMainWnd());
2130     }
2131     btn_drop_down.pressed = false;
2132     btn_menu.pressed = false;
2133 }
2134 
LButtonDown(CPoint point)2135 void UiElement::PlaylistIndicator::LButtonDown(CPoint point)
2136 {
2137     btn_drop_down.pressed = (btn_drop_down.rect.PtInRect(point) != FALSE);
2138     btn_menu.pressed = (btn_menu.rect.PtInRect(point) != FALSE);
2139 }
2140 
MouseMove(CPoint point)2141 void UiElement::PlaylistIndicator::MouseMove(CPoint point)
2142 {
2143     btn_drop_down.hover = (btn_drop_down.rect.PtInRect(point) != FALSE);
2144     btn_menu.hover = (btn_menu.rect.PtInRect(point) != FALSE);
2145 
2146     if (btn_drop_down.hover)
2147         ui->UpdateMouseToolTipPosition(TooltipIndex::PLAYLIST_DROP_DOWN_BTN, btn_drop_down.rect);
2148     if (btn_menu.hover)
2149         ui->UpdateMouseToolTipPosition(TooltipIndex::PLAYLIST_MENU_BTN, btn_menu.rect);
2150 }
2151 
MouseLeave()2152 void UiElement::PlaylistIndicator::MouseLeave()
2153 {
2154     btn_drop_down.pressed = false;
2155     btn_drop_down.hover = false;
2156     btn_menu.pressed = false;
2157     btn_menu.hover = false;
2158 }
2159 
ClearRect()2160 void UiElement::PlaylistIndicator::ClearRect()
2161 {
2162     Element::ClearRect();
2163     btn_drop_down.rect = CRect();
2164     btn_menu.rect = CRect();
2165 }
2166 
ClassicalControlBar()2167 UiElement::ClassicalControlBar::ClassicalControlBar()
2168     : Element()
2169 {
2170     max_height.FromString("56");
2171 }
2172 
Draw()2173 void UiElement::ClassicalControlBar::Draw()
2174 {
2175     if (rect.Width() < ui->m_progress_on_top_threshold)
2176         max_height.FromString("56");
2177     else
2178         max_height.FromString("36");
2179     CalculateRect();
2180 
2181     ui->DrawControlBar(rect, show_switch_display_btn);
2182     Element::Draw();
2183 }
2184 
Draw()2185 void UiElement::NavigationBar::Draw()
2186 {
2187     CalculateRect();
2188     ui->DrawNavigationBar(rect, this);
2189     Element::Draw();
2190 }
2191 
LButtonUp(CPoint point)2192 void UiElement::NavigationBar::LButtonUp(CPoint point)
2193 {
2194     FindStackElement();
2195     if (stack_element != nullptr)
2196     {
2197         //查找点击的标签
2198         int _selected_index = -1;
2199         for (size_t i{}; i < item_rects.size(); i++)
2200         {
2201             if (item_rects[i].PtInRect(point))
2202             {
2203                 _selected_index = i;
2204                 break;
2205             }
2206         }
2207         if (_selected_index >= 0)
2208         {
2209             selected_index = _selected_index;
2210             stack_element->SetCurrentElement(selected_index);
2211         }
2212     }
2213 }
2214 
MouseMove(CPoint point)2215 void UiElement::NavigationBar::MouseMove(CPoint point)
2216 {
2217     int _hover_index{ -1 };
2218     if (rect.PtInRect(point))
2219     {
2220         for (size_t i{}; i < item_rects.size(); i++)
2221         {
2222             if (item_rects[i].PtInRect(point))
2223             {
2224                 _hover_index = i;
2225                 break;
2226             }
2227         }
2228     }
2229     hover_index = _hover_index;
2230 
2231     //显示鼠标提示
2232     if (icon_type == ICON_ONLY && hover_index >= 0)
2233     {
2234         if (last_hover_index != hover_index)
2235         {
2236             last_hover_index = hover_index;
2237             std::wstring str_tip = labels[hover_index];
2238             ui->UpdateMouseToolTip(TooltipIndex::TAB_ELEMENT, str_tip.c_str());
2239             ui->UpdateMouseToolTipPosition(TooltipIndex::TAB_ELEMENT, item_rects[hover_index]);
2240         }
2241     }
2242 }
2243 
RButtunUp(CPoint point)2244 bool UiElement::NavigationBar::RButtunUp(CPoint point)
2245 {
2246     //不弹出右键菜单
2247     return rect.PtInRect(point);
2248 }
2249 
MouseLeave()2250 void UiElement::NavigationBar::MouseLeave()
2251 {
2252     hover_index = -1;
2253 }
2254 
SelectedIndex()2255 int UiElement::NavigationBar::SelectedIndex()
2256 {
2257     FindStackElement();
2258     if (stack_element != nullptr)
2259         return stack_element->GetCurIndex();
2260     else
2261         return selected_index;
2262 }
2263 
FindStackElement()2264 void UiElement::NavigationBar::FindStackElement()
2265 {
2266     if (!find_stack_element)
2267     {
2268         stack_element = FindRelatedElement<StackElement>(this);
2269         find_stack_element = true;  //找过一次没找到就不找了
2270     }
2271 }
2272 
2273 CListCache UiElement::MediaLibFolder::m_list_cache(LT_FOLDER);
2274 
Draw()2275 void UiElement::MediaLibFolder::Draw()
2276 {
2277     m_list_cache.reload();
2278     ListElement::Draw();
2279 }
2280 
GetItemText(int row,int col)2281 std::wstring UiElement::MediaLibFolder::GetItemText(int row, int col)
2282 {
2283     if (col == COL_NAME)
2284     {
2285         return m_list_cache.at(row).path;
2286     }
2287     else if (col == COL_COUNT)
2288     {
2289         return std::to_wstring(m_list_cache.at(row).total_num);
2290     }
2291     return std::wstring();
2292 }
2293 
GetRowCount()2294 int UiElement::MediaLibFolder::GetRowCount()
2295 {
2296     return m_list_cache.size();
2297 }
2298 
GetColumnCount()2299 int UiElement::MediaLibFolder::GetColumnCount()
2300 {
2301     return COL_MAX;
2302 }
2303 
GetColumnWidth(int col,int total_width)2304 int UiElement::MediaLibFolder::GetColumnWidth(int col, int total_width)
2305 {
2306     const int count_width{ ui->DPI(40) };
2307     if (col == COL_NAME)
2308         return total_width - count_width;
2309     else if (col == COL_COUNT)
2310         return count_width;
2311     return 0;
2312 }
2313 
GetHighlightRow()2314 int UiElement::MediaLibFolder::GetHighlightRow()
2315 {
2316     return m_list_cache.playing_index();
2317 }
2318 
GetColumnScrollTextWhenSelected()2319 int UiElement::MediaLibFolder::GetColumnScrollTextWhenSelected()
2320 {
2321     return COL_NAME;
2322 }
2323 
GetContextMenu(bool item_selected)2324 CMenu* UiElement::MediaLibFolder::GetContextMenu(bool item_selected)
2325 {
2326     return theApp.m_menu_mgr.GetMenu(MenuMgr::LibSetPathMenu);
2327 }
2328 
OnDoubleClicked()2329 void UiElement::MediaLibFolder::OnDoubleClicked()
2330 {
2331     int item_selected = GetItemSelected();
2332     if (item_selected >= 0 && item_selected < GetRowCount())
2333     {
2334         ListItem list_item = m_list_cache.GetItem(item_selected);
2335         CMusicPlayerCmdHelper helper;
2336         helper.OnListItemSelected(list_item, true);
2337     }
2338 }
2339 
GetHoverButtonCount()2340 int UiElement::MediaLibFolder::GetHoverButtonCount()
2341 {
2342     return BTN_MAX;
2343 }
2344 
GetHoverButtonColumn()2345 int UiElement::MediaLibFolder::GetHoverButtonColumn()
2346 {
2347     return COL_NAME;
2348 }
2349 
GetHoverButtonIcon(int index,int row)2350 IconMgr::IconType UiElement::MediaLibFolder::GetHoverButtonIcon(int index, int row)
2351 {
2352     switch (index)
2353     {
2354     case BTN_PLAY: return IconMgr::IT_Play;
2355     case BTN_ADD: return IconMgr::IT_Add;
2356     }
2357     return IconMgr::IT_NO_ICON;
2358 }
2359 
GetHoverButtonTooltip(int index,int row)2360 std::wstring UiElement::MediaLibFolder::GetHoverButtonTooltip(int index, int row)
2361 {
2362     switch (index)
2363     {
2364     case BTN_PLAY: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAY");
2365     case BTN_ADD: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_ADD_TO_PLAYLIST");
2366     }
2367     return std::wstring();
2368 }
2369 
OnHoverButtonClicked(int btn_index,int row)2370 void UiElement::MediaLibFolder::OnHoverButtonClicked(int btn_index, int row)
2371 {
2372     //点击了“播放”按钮
2373     if (btn_index == BTN_PLAY)
2374     {
2375         if (row >= 0 && row < GetRowCount())
2376         {
2377             ListItem list_item = m_list_cache.GetItem(row);
2378             CMusicPlayerCmdHelper helper;
2379             helper.OnListItemSelected(list_item, true);
2380         }
2381     }
2382     //点击了“添加到播放列表”按钮
2383     else if (btn_index == BTN_ADD)
2384     {
2385         CMenu* menu = theApp.m_menu_mgr.GetMenu(MenuMgr::AddToPlaylistMenu);
2386         ShowContextMenu(menu, nullptr);
2387     }
2388 }
2389 
2390 CListCache UiElement::MediaLibPlaylist::m_list_cache(LT_PLAYLIST);
2391 
Draw()2392 void UiElement::MediaLibPlaylist::Draw()
2393 {
2394     m_list_cache.reload();
2395     ListElement::Draw();
2396 }
2397 
GetItemText(int row,int col)2398 std::wstring UiElement::MediaLibPlaylist::GetItemText(int row, int col)
2399 {
2400     if (col == COL_NAME)
2401     {
2402         return m_list_cache.at(row).GetDisplayName();
2403     }
2404     else if (col == COL_COUNT)
2405     {
2406         return std::to_wstring(m_list_cache.at(row).total_num);
2407     }
2408     return std::wstring();
2409 }
2410 
GetRowCount()2411 int UiElement::MediaLibPlaylist::GetRowCount()
2412 {
2413     return m_list_cache.size();
2414 }
2415 
GetColumnCount()2416 int UiElement::MediaLibPlaylist::GetColumnCount()
2417 {
2418     return COL_MAX;
2419 }
2420 
GetColumnWidth(int col,int total_width)2421 int UiElement::MediaLibPlaylist::GetColumnWidth(int col, int total_width)
2422 {
2423     const int count_width{ ui->DPI(40) };
2424     if (col == COL_NAME)
2425         return total_width - count_width;
2426     else if (col == COL_COUNT)
2427         return count_width;
2428     return 0;
2429 }
2430 
GetHighlightRow()2431 int UiElement::MediaLibPlaylist::GetHighlightRow()
2432 {
2433     return m_list_cache.playing_index();
2434 }
2435 
GetColumnScrollTextWhenSelected()2436 int UiElement::MediaLibPlaylist::GetColumnScrollTextWhenSelected()
2437 {
2438     return COL_NAME;
2439 }
2440 
GetContextMenu(bool item_selected)2441 CMenu* UiElement::MediaLibPlaylist::GetContextMenu(bool item_selected)
2442 {
2443     return theApp.m_menu_mgr.GetMenu(MenuMgr::LibPlaylistMenu);
2444 }
2445 
OnDoubleClicked()2446 void UiElement::MediaLibPlaylist::OnDoubleClicked()
2447 {
2448     int item_selected = GetItemSelected();
2449     ListItem list_item = m_list_cache.GetItem(item_selected);
2450     if (!list_item.empty())
2451     {
2452         CMusicPlayerCmdHelper helper;
2453         helper.OnListItemSelected(list_item, true);
2454     }
2455 }
2456 
GetHoverButtonCount()2457 int UiElement::MediaLibPlaylist::GetHoverButtonCount()
2458 {
2459     return 1;
2460 }
2461 
GetHoverButtonColumn()2462 int UiElement::MediaLibPlaylist::GetHoverButtonColumn()
2463 {
2464     return COL_NAME;
2465 }
2466 
GetHoverButtonIcon(int index,int row)2467 IconMgr::IconType UiElement::MediaLibPlaylist::GetHoverButtonIcon(int index, int row)
2468 {
2469     if (index == 0)
2470         return IconMgr::IT_Play;
2471     return IconMgr::IT_NO_ICON;
2472 }
2473 
GetHoverButtonTooltip(int index,int row)2474 std::wstring UiElement::MediaLibPlaylist::GetHoverButtonTooltip(int index, int row)
2475 {
2476     if (index == 0)
2477         return theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAY");
2478     return std::wstring();
2479 }
2480 
OnHoverButtonClicked(int btn_index,int row)2481 void UiElement::MediaLibPlaylist::OnHoverButtonClicked(int btn_index, int row)
2482 {
2483     //点击了“播放”按钮
2484     if (btn_index == 0)
2485     {
2486         ListItem list_item = m_list_cache.GetItem(row);
2487         if (!list_item.empty())
2488         {
2489             CMusicPlayerCmdHelper helper;
2490             helper.OnListItemSelected(list_item, true);
2491         }
2492     }
2493 }
2494 
GetItemText(int row,int col)2495 std::wstring UiElement::MyFavouriteList::GetItemText(int row, int col)
2496 {
2497     if (row >= 0 && row < GetRowCount())
2498     {
2499         //序号
2500         if (col == COL_INDEX)
2501         {
2502             return std::to_wstring(row + 1);
2503         }
2504         //曲目
2505         if (col == COL_TRACK)
2506         {
2507             if (row >= 0 && row < CUiMyFavouriteItemMgr::Instance().GetSongCount())
2508             {
2509                 const SongInfo& song_info{ CUiMyFavouriteItemMgr::Instance().GetSongInfo(row) };
2510                 std::wstring display_name{ CSongInfoHelper::GetDisplayStr(song_info, theApp.m_media_lib_setting_data.display_format) };
2511                 return display_name;
2512             }
2513         }
2514         //时间
2515         else if (col == COL_TIME)
2516         {
2517             const SongInfo& song_info{ CUiMyFavouriteItemMgr::Instance().GetSongInfo(row) };
2518             return song_info.length().toString();
2519         }
2520     }
2521     return std::wstring();
2522 }
2523 
GetRowCount()2524 int UiElement::MyFavouriteList::GetRowCount()
2525 {
2526     return CUiMyFavouriteItemMgr::Instance().GetSongCount();
2527 }
2528 
GetColumnCount()2529 int UiElement::MyFavouriteList::GetColumnCount()
2530 {
2531     return COL_MAX;
2532 }
2533 
GetColumnWidth(int col,int total_width)2534 int UiElement::MyFavouriteList::GetColumnWidth(int col, int total_width)
2535 {
2536     const int index_width{ ui->DPI(40) };
2537     const int time_width{ ui->DPI(50) };
2538     if (col == COL_INDEX)
2539     {
2540         return index_width;
2541     }
2542     else if (col == COL_TIME)
2543     {
2544         return time_width;
2545     }
2546     else if (col == COL_TRACK)
2547     {
2548         return total_width - index_width - time_width;
2549     }
2550     return 0;
2551 }
2552 
GetHighlightRow()2553 int UiElement::MyFavouriteList::GetHighlightRow()
2554 {
2555     if (CRecentList::Instance().IsPlayingSpecPlaylist(CRecentList::PT_FAVOURITE))
2556     {
2557         return CPlayer::GetInstance().GetIndex();
2558     }
2559     return -1;
2560 }
2561 
GetColumnScrollTextWhenSelected()2562 int UiElement::MyFavouriteList::GetColumnScrollTextWhenSelected()
2563 {
2564     return COL_TRACK;
2565 }
2566 
GetContextMenu(bool item_selected)2567 CMenu* UiElement::MyFavouriteList::GetContextMenu(bool item_selected)
2568 {
2569     if (item_selected)
2570     {
2571         return theApp.m_menu_mgr.GetMenu(MenuMgr::UiMyFavouriteMenu);
2572     }
2573     return nullptr;
2574 }
2575 
OnDoubleClicked()2576 void UiElement::MyFavouriteList::OnDoubleClicked()
2577 {
2578     int item_selected = GetItemSelected();
2579     if (item_selected >= 0 && item_selected < GetRowCount())
2580     {
2581         CMusicPlayerCmdHelper helper;
2582         SongInfo song_info{ CUiMyFavouriteItemMgr::Instance().GetSongInfo(item_selected) };
2583         helper.OnPlayMyFavourite(song_info);
2584     }
2585 }
2586 
GetEmptyString()2587 std::wstring UiElement::MyFavouriteList::GetEmptyString()
2588 {
2589     if (CUiMyFavouriteItemMgr::Instance().IsLoading())
2590         return theApp.m_str_table.LoadText(L"UI_MEDIALIB_LIST_LOADING_INFO");
2591     else if (!CUiMyFavouriteItemMgr::Instance().IsInited())
2592         return theApp.m_str_table.LoadText(L"UI_MEDIALIB_LIST_UNINITED_INFO");
2593     else
2594         return theApp.m_str_table.LoadText(L"UI_MEDIALIB_LIST_EMPTY_INFO");
2595 }
2596 
GetHoverButtonCount()2597 int UiElement::MyFavouriteList::GetHoverButtonCount()
2598 {
2599     return BTN_MAX;
2600 }
2601 
GetHoverButtonColumn()2602 int UiElement::MyFavouriteList::GetHoverButtonColumn()
2603 {
2604     return COL_TRACK;
2605 }
2606 
GetHoverButtonIcon(int index,int row)2607 IconMgr::IconType UiElement::MyFavouriteList::GetHoverButtonIcon(int index, int row)
2608 {
2609     switch (index)
2610     {
2611     case BTN_PLAY: return IconMgr::IT_Play;
2612     case BTN_ADD: return IconMgr::IT_Add;
2613     }
2614     return IconMgr::IT_NO_ICON;
2615 }
2616 
GetHoverButtonTooltip(int index,int row)2617 std::wstring UiElement::MyFavouriteList::GetHoverButtonTooltip(int index, int row)
2618 {
2619     switch (index)
2620     {
2621     case BTN_PLAY: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAY");
2622     case BTN_ADD: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_ADD_TO_PLAYLIST");
2623     }
2624     return std::wstring();
2625 }
2626 
OnHoverButtonClicked(int btn_index,int row)2627 void UiElement::MyFavouriteList::OnHoverButtonClicked(int btn_index, int row)
2628 {
2629     CMusicPlayerCmdHelper helper;
2630     //点击了“播放”按钮
2631     if (btn_index == BTN_PLAY)
2632     {
2633         int item_selected = GetItemSelected();
2634         if (item_selected >= 0 && item_selected < GetRowCount())
2635         {
2636             CMusicPlayerCmdHelper helper;
2637             SongInfo song_info{ CUiMyFavouriteItemMgr::Instance().GetSongInfo(item_selected) };
2638             helper.OnPlayMyFavourite(song_info);
2639         }
2640     }
2641     //点击了“添加到播放列表”按钮
2642     else if (btn_index == BTN_ADD)
2643     {
2644         CMenu* menu = theApp.m_menu_mgr.GetMenu(MenuMgr::AddToPlaylistMenu);
2645         ShowContextMenu(menu, nullptr);
2646     }
2647 }
2648 
IsMultipleSelectionEnable()2649 bool UiElement::MyFavouriteList::IsMultipleSelectionEnable()
2650 {
2651     return true;
2652 }
2653 
GetItemText(int row,int col)2654 std::wstring UiElement::AllTracksList::GetItemText(int row, int col)
2655 {
2656     if (row >= 0 && row < GetRowCount())
2657     {
2658         //序号
2659         if (col == COL_INDEX)
2660         {
2661             return std::to_wstring(row + 1);
2662         }
2663         //曲目
2664         if (col == COL_TRACK)
2665         {
2666             if (row >= 0 && row < CUiAllTracksMgr::Instance().GetSongCount())
2667             {
2668                 return CUiAllTracksMgr::Instance().GetItem(row).name;
2669             }
2670         }
2671         //时间
2672         else if (col == COL_TIME)
2673         {
2674             if (row >= 0 && row < CUiAllTracksMgr::Instance().GetSongCount())
2675             {
2676                 return CUiAllTracksMgr::Instance().GetItem(row).length.toString();
2677             }
2678         }
2679     }
2680     return std::wstring();
2681 }
2682 
GetRowCount()2683 int UiElement::AllTracksList::GetRowCount()
2684 {
2685     return CUiAllTracksMgr::Instance().GetSongCount();
2686 }
2687 
GetColumnCount()2688 int UiElement::AllTracksList::GetColumnCount()
2689 {
2690     return COL_MAX;
2691 }
2692 
GetColumnWidth(int col,int total_width)2693 int UiElement::AllTracksList::GetColumnWidth(int col, int total_width)
2694 {
2695     const int index_width{ ui->DPI(40) };
2696     const int time_width{ ui->DPI(50) };
2697     if (col == COL_INDEX)
2698     {
2699         return index_width;
2700     }
2701     else if (col == COL_TIME)
2702     {
2703         return time_width;
2704     }
2705     else if (col == COL_TRACK)
2706     {
2707         return total_width - index_width - time_width;
2708     }
2709     return 0;
2710 }
2711 
GetHighlightRow()2712 int UiElement::AllTracksList::GetHighlightRow()
2713 {
2714     int highlight_row = CUiAllTracksMgr::Instance().GetCurrentIndex();
2715     if (last_highlight_row != highlight_row)
2716     {
2717         EnsureItemVisible(highlight_row);
2718         last_highlight_row = highlight_row;
2719     }
2720     return highlight_row;
2721 }
2722 
GetColumnScrollTextWhenSelected()2723 int UiElement::AllTracksList::GetColumnScrollTextWhenSelected()
2724 {
2725     return COL_TRACK;
2726 }
2727 
GetContextMenu(bool item_selected)2728 CMenu* UiElement::AllTracksList::GetContextMenu(bool item_selected)
2729 {
2730     if (item_selected)
2731     {
2732         return theApp.m_menu_mgr.GetMenu(MenuMgr::LibRightMenu);
2733     }
2734     return nullptr;
2735 }
2736 
OnDoubleClicked()2737 void UiElement::AllTracksList::OnDoubleClicked()
2738 {
2739     int item_selected = GetItemSelected();
2740     if (item_selected >= 0 && item_selected < GetRowCount())
2741     {
2742         const SongInfo& song{ CUiAllTracksMgr::Instance().GetSongInfo(item_selected) };
2743         CMusicPlayerCmdHelper helper;
2744         helper.OnPlayAllTrack(song);
2745     }
2746 }
2747 
GetEmptyString()2748 std::wstring UiElement::AllTracksList::GetEmptyString()
2749 {
2750     if (CUiAllTracksMgr::Instance().IsLoading())
2751         return theApp.m_str_table.LoadText(L"UI_MEDIALIB_LIST_LOADING_INFO");
2752     else if (!CUiAllTracksMgr::Instance().IsInited())
2753         return theApp.m_str_table.LoadText(L"UI_MEDIALIB_LIST_UNINITED_INFO");
2754     else
2755         return theApp.m_str_table.LoadText(L"UI_MEDIALIB_LIST_EMPTY_INFO");
2756 }
2757 
GetHoverButtonCount()2758 int UiElement::AllTracksList::GetHoverButtonCount()
2759 {
2760     return BTN_MAX;
2761 }
2762 
GetHoverButtonColumn()2763 int UiElement::AllTracksList::GetHoverButtonColumn()
2764 {
2765     return COL_TRACK;
2766 }
2767 
GetHoverButtonIcon(int index,int row)2768 IconMgr::IconType UiElement::AllTracksList::GetHoverButtonIcon(int index, int row)
2769 {
2770     switch (index)
2771     {
2772     case BTN_PLAY: return IconMgr::IT_Play;
2773     case BTN_ADD: return IconMgr::IT_Add;
2774     case BTN_FAVOURITE:
2775     {
2776         if (CUiAllTracksMgr::Instance().GetItem(row).is_favourite)
2777             return IconMgr::IT_Favorite_Off;
2778         else
2779             return IconMgr::IT_Favorite_On;
2780     }
2781     }
2782     return IconMgr::IT_NO_ICON;
2783 }
2784 
GetHoverButtonTooltip(int index,int row)2785 std::wstring UiElement::AllTracksList::GetHoverButtonTooltip(int index, int row)
2786 {
2787     switch (index)
2788     {
2789     case BTN_PLAY: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAY");
2790     case BTN_ADD: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_ADD_TO_PLAYLIST");
2791     case BTN_FAVOURITE: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_FAVOURITE");
2792     }
2793     return std::wstring();
2794 }
2795 
OnHoverButtonClicked(int btn_index,int row)2796 void UiElement::AllTracksList::OnHoverButtonClicked(int btn_index, int row)
2797 {
2798     CMusicPlayerCmdHelper helper;
2799     //点击了“播放”按钮
2800     if (btn_index == BTN_PLAY)
2801     {
2802         const SongInfo& song{ CUiAllTracksMgr::Instance().GetSongInfo(row) };
2803         CMusicPlayerCmdHelper helper;
2804         helper.OnPlayAllTrack(song);
2805     }
2806     //点击了“添加到播放列表”按钮
2807     else if (btn_index == BTN_ADD)
2808     {
2809         CMenu* menu = theApp.m_menu_mgr.GetMenu(MenuMgr::AddToPlaylistMenu);
2810         ShowContextMenu(menu, nullptr);
2811     }
2812     //点击了“添加到我喜欢的音乐”按钮
2813     else if (btn_index == BTN_FAVOURITE)
2814     {
2815         const SongInfo& song{ CUiAllTracksMgr::Instance().GetSongInfo(row) };
2816         helper.OnAddRemoveFromFavourite(song);
2817         CUiAllTracksMgr::Instance().AddOrRemoveMyFavourite(row);        //更新UI中的显示
2818     }
2819 }
2820 
GetUnHoverIconCount(int row)2821 int UiElement::AllTracksList::GetUnHoverIconCount(int row)
2822 {
2823     //鼠标未指向的列,如果曲目在“我喜欢的音乐”中,则显示红心图标
2824     if (CUiAllTracksMgr::Instance().GetItem(row).is_favourite)
2825         return 1;
2826     else
2827         return 0;
2828 }
2829 
GetUnHoverIcon(int index,int row)2830 IconMgr::IconType UiElement::AllTracksList::GetUnHoverIcon(int index, int row)
2831 {
2832     if (index == 0)
2833     {
2834         return IconMgr::IT_Favorite_Off;
2835     }
2836     return IconMgr::IT_NO_ICON;
2837 }
2838 
IsMultipleSelectionEnable()2839 bool UiElement::AllTracksList::IsMultipleSelectionEnable()
2840 {
2841     return true;
2842 }
2843 
Draw()2844 void UiElement::MiniSpectrum::Draw()
2845 {
2846     CalculateRect();
2847     ui->DrawMiniSpectrum(rect);
2848     Element::Draw();
2849 }
2850 
GetWidth(CRect parent_rect) const2851 int UiElement::PlaceHolder::GetWidth(CRect parent_rect) const
2852 {
2853     if (IsHide())
2854     {
2855         return 0;
2856     }
2857     else
2858     {
2859         if (show_when_use_system_titlebar)
2860             return ui->TopRightButtonsWidth();
2861         else
2862             return Element::GetWidth(parent_rect);
2863     }
2864 }
2865 
GetHeight(CRect parent_rect) const2866 int UiElement::PlaceHolder::GetHeight(CRect parent_rect) const
2867 {
2868     if (IsHide())
2869         return 0;
2870     else
2871         return Element::GetHeight(parent_rect);
2872 }
2873 
IsWidthValid() const2874 bool UiElement::PlaceHolder::IsWidthValid() const
2875 {
2876     if (show_when_use_system_titlebar)
2877         return true;
2878     return Element::IsWidthValid();
2879 }
2880 
IsHide() const2881 bool UiElement::PlaceHolder::IsHide() const
2882 {
2883     //标题栏中的图标除了最小化和最大化/还原外是否都隐藏
2884     bool is_all_titlebar_icon_hide = !theApp.m_app_setting_data.show_minimode_btn_in_titlebar
2885         && !theApp.m_app_setting_data.show_fullscreen_btn_in_titlebar
2886         && !theApp.m_app_setting_data.show_skin_btn_in_titlebar
2887         && !theApp.m_app_setting_data.show_settings_btn_in_titlebar
2888         && !theApp.m_app_setting_data.show_dark_light_btn_in_titlebar
2889         ;
2890     //如果设置了“仅当使用系统标准标题栏时才显示”,并且没有使用系统标准标题栏,则不显示
2891     return (show_when_use_system_titlebar
2892         && !theApp.m_app_setting_data.show_window_frame
2893         && (!theApp.m_ui_data.full_screen) || (theApp.m_ui_data.show_menu_bar && is_all_titlebar_icon_hide));
2894 }
2895 
AddChild(std::shared_ptr<Node> child)2896 void UiElement::TreeElement::Node::AddChild(std::shared_ptr<Node> child)
2897 {
2898     child->parent = this;
2899     child_list.push_back(child);
2900 }
2901 
GetLevel() const2902 int UiElement::TreeElement::Node::GetLevel() const
2903 {
2904     int level{};
2905     const Node* node{ this };
2906     while (node != nullptr && node->parent != nullptr)
2907     {
2908         node = node->parent;
2909         level++;
2910     }
2911     return level;
2912 }
2913 
IterateNodeInOrder(std::function<bool (Node *)> func,bool ignore_invisible)2914 void UiElement::TreeElement::Node::IterateNodeInOrder(std::function<bool(Node*)> func, bool ignore_invisible)
2915 {
2916     std::stack<UiElement::TreeElement::Node*> nodeStack;
2917     nodeStack.push(this);
2918     while (!nodeStack.empty())
2919     {
2920         UiElement::TreeElement::Node* pCurNode = nodeStack.top();
2921         nodeStack.pop();
2922 
2923         if (func(pCurNode))
2924             break;
2925 
2926         //如果当前节点已经折叠,且需要忽略已折叠的节点,则不再遍历其子节点
2927         if (pCurNode->collapsed && ignore_invisible)
2928             continue;
2929 
2930         for (auto& child : pCurNode->child_list)
2931         {
2932             nodeStack.push(child.get());
2933         }
2934     }
2935 }
2936 
GetItemText(int row,int col)2937 std::wstring UiElement::TreeElement::GetItemText(int row, int col)
2938 {
2939     //查找节点
2940     const Node* node = GetNodeByIndex(row);
2941     if (node != nullptr)
2942     {
2943         auto iter = node->texts.find(col);
2944         if (iter != node->texts.end())
2945             return iter->second;
2946     }
2947     return std::wstring();
2948 }
2949 
GetRowCount()2950 int UiElement::TreeElement::GetRowCount()
2951 {
2952     int row_count{};
2953     IterateDisplayedNodeInOrder([&](const Node*) ->bool {
2954         row_count++;
2955         return false;
2956     });
2957     return row_count;
2958 }
2959 
QuickSearch(const std::wstring & key_word)2960 void UiElement::TreeElement::QuickSearch(const std::wstring& key_word)
2961 {
2962     tree_searched = !key_word.empty();
2963 
2964     tree_search_result.clear();
2965     if (key_word.empty())
2966         return;
2967     //遍历所有节点,获取匹配的节点,并添加到tree_search_result中
2968     auto& root_nodes{ GetRootNodes() };
2969     for (auto& root : root_nodes)
2970     {
2971         root->IterateNodeInOrder([&](Node* cur_node) ->bool {
2972             if (IsNodeMathcKeyWord(cur_node, key_word))
2973             {
2974                 tree_search_result.insert(cur_node);
2975                 cur_node->collapsed = false;    //匹配的节点全部展开
2976             }
2977             return false;
2978         }, false);
2979     }
2980 }
2981 
OnRowCountChanged()2982 void UiElement::TreeElement::OnRowCountChanged()
2983 {
2984     //树控件的行数变化可能只是节点的展开或折叠,因此不执行基类中OnRowCountChanged的处理。
2985 }
2986 
GetItemLevel(int row)2987 int UiElement::TreeElement::GetItemLevel(int row)
2988 {
2989     const Node* node = GetNodeByIndex(row);
2990     if (node != nullptr)
2991         return node->GetLevel();
2992     return 0;
2993 }
2994 
IsCollapsable(int row)2995 bool UiElement::TreeElement::IsCollapsable(int row)
2996 {
2997     const Node* node = GetNodeByIndex(row);
2998     if (node != nullptr)
2999         return !node->child_list.empty();
3000     return false;
3001 }
3002 
IsCollapsed(int row)3003 bool UiElement::TreeElement::IsCollapsed(int row)
3004 {
3005     const Node* node = GetNodeByIndex(row);
3006     if (node != nullptr)
3007         return node->collapsed;
3008     return false;
3009 }
3010 
LButtonUp(CPoint point)3011 void UiElement::TreeElement::LButtonUp(CPoint point)
3012 {
3013     //获取点击的行
3014     int row = GetListIndexByPoint(point);
3015     if (row >= 0)
3016     {
3017         auto iter = collapsd_rects.find(row);
3018         if (iter != collapsd_rects.end())
3019         {
3020             CRect rect_collapsd = iter->second;
3021             //点击了折叠标志
3022             if (rect_collapsd.PtInRect(point))
3023             {
3024                 Node* node = GetNodeByIndex(row);
3025                 node->collapsed = !node->collapsed;
3026             }
3027         }
3028     }
3029 
3030     ListElement::LButtonUp(point);
3031 }
3032 
MouseMove(CPoint point)3033 void UiElement::TreeElement::MouseMove(CPoint point)
3034 {
3035     //获取鼠标指向的行
3036     int row = GetListIndexByPoint(point);
3037     collaps_indicator_hover_row = -1;
3038     if (row >= 0)
3039     {
3040         auto iter = collapsd_rects.find(row);
3041         if (iter != collapsd_rects.end())
3042         {
3043             CRect rect_collapsd = iter->second;
3044             //指向了折叠标志
3045             if (rect_collapsd.PtInRect(point))
3046             {
3047                 collaps_indicator_hover_row = row;
3048             }
3049         }
3050     }
3051 
3052     ListElement::MouseMove(point);
3053 }
3054 
MouseLeave()3055 void UiElement::TreeElement::MouseLeave()
3056 {
3057     collaps_indicator_hover_row = -1;
3058     ListElement::MouseLeave();
3059 }
3060 
DoubleClick(CPoint point)3061 bool UiElement::TreeElement::DoubleClick(CPoint point)
3062 {
3063     //如果双击了折叠标志,则不执行双击动作
3064     for (const auto& rect : collapsd_rects)
3065     {
3066         if (rect.second.PtInRect(point))
3067             return false;
3068     }
3069     return ListElement::DoubleClick(point);
3070 }
3071 
GetNodeIndex(const Node * node)3072 int UiElement::TreeElement::GetNodeIndex(const Node* node)
3073 {
3074     int i{};
3075     int rtn_index{ -1 };
3076     IterateDisplayedNodeInOrder([&](const Node* cur_node) ->bool {
3077         if (cur_node == node)
3078         {
3079             rtn_index = i;
3080             return true;
3081         }
3082         i++;
3083         return false;
3084     });
3085 
3086     return rtn_index;
3087 }
3088 
GetNodeByIndex(int index)3089 UiElement::TreeElement::Node* UiElement::TreeElement::GetNodeByIndex(int index)
3090 {
3091     if (index >= 0)
3092     {
3093         Node* find_node{};
3094         int i{};
3095         IterateDisplayedNodeInOrder([&](Node* cur_node) ->bool {
3096             if (i == index)
3097             {
3098                 find_node = cur_node;
3099                 return true;
3100             }
3101             i++;
3102             return false;
3103         });
3104         return find_node;
3105     }
3106 
3107     return nullptr;
3108 }
3109 
IsNodeMathcKeyWord(const Node * node,const std::wstring & key_word)3110 bool UiElement::TreeElement::IsNodeMathcKeyWord(const Node* node, const std::wstring& key_word)
3111 {
3112     //判断节点本身是否匹配
3113     for (const auto& item : node->texts)
3114     {
3115         const std::wstring& text{ item.second };
3116         if (!text.empty() && theApp.m_chinese_pingyin_res.IsStringMatchWithPingyin(key_word, text))
3117             return true;
3118     }
3119 
3120     //如果节点本身不匹配,则遍历所有子节点,如果有一个子节点匹配,则节点匹配
3121     for (const auto& child : node->child_list)
3122     {
3123         if (IsNodeMathcKeyWord(child.get(), key_word))
3124             return true;
3125     }
3126 
3127     return false;
3128 }
3129 
IsNodeDisplayed(const Node * node)3130 bool UiElement::TreeElement::IsNodeDisplayed(const Node* node)
3131 {
3132     if (node != nullptr)
3133     {
3134         if (tree_searched)
3135             return tree_search_result.contains(node);
3136         else
3137             return true;
3138     }
3139     return false;
3140 }
3141 
IterateDisplayedNodeInOrder(std::function<bool (Node *)> func)3142 void UiElement::TreeElement::IterateDisplayedNodeInOrder(std::function<bool(Node*)> func)
3143 {
3144     const auto& root_nodes{ GetRootNodes() };
3145     for (const auto& root : root_nodes)
3146     {
3147         bool exit{};
3148         root->IterateNodeInOrder([&](Node* cur_node) ->bool {
3149             if (IsNodeDisplayed(cur_node))
3150             {
3151                 if (func(cur_node))
3152                 {
3153                     exit = true;
3154                     return true;
3155                 }
3156             }
3157             return false;
3158         }, true);
3159         if (exit)
3160             break;
3161     }
3162 }
3163 
TestTree()3164 UiElement::TestTree::TestTree()
3165 {
3166     //创建测试节点
3167     std::shared_ptr<Node> root1 = CreateNode(L"根节点1", nullptr);
3168     std::shared_ptr<Node> root2 = CreateNode(L"根节点2", nullptr);
3169 
3170     CreateNode(L"子节点11", root1);
3171     auto node12 = CreateNode(L"子节点12", root1);
3172 
3173     CreateNode(L"子节点121", node12);
3174     CreateNode(L"子节点122", node12);
3175 
3176     CreateNode(L"子节点21", root2);
3177     CreateNode(L"子节点22", root2);
3178 
3179     root_nodes.push_back(root1);
3180     root_nodes.push_back(root2);
3181 }
3182 
CreateNode(std::wstring name,std::shared_ptr<Node> parent)3183 std::shared_ptr<UiElement::TreeElement::Node> UiElement::TestTree::CreateNode(std::wstring name, std::shared_ptr<Node> parent)
3184 {
3185     std::shared_ptr<Node> node = std::make_shared<Node>();
3186     node->collapsed = true;
3187     node->texts[0] = name;
3188     if (parent != nullptr)
3189         parent->AddChild(node);
3190     return node;
3191 }
3192 
GetColumnCount()3193 int UiElement::TestTree::GetColumnCount()
3194 {
3195     return 1;
3196 }
3197 
GetColumnWidth(int col,int total_width)3198 int UiElement::TestTree::GetColumnWidth(int col, int total_width)
3199 {
3200     return total_width;
3201 }
3202 
GetRootNodes()3203 std::vector<std::shared_ptr<UiElement::TestTree::Node>>& UiElement::TestTree::GetRootNodes()
3204 {
3205     return root_nodes;
3206 }
3207 
CreateNode(std::wstring name,int song_num,std::shared_ptr<Node> parent)3208 std::shared_ptr<UiElement::TestTree::Node> UiElement::FolderExploreTree::CreateNode(std::wstring name, int song_num, std::shared_ptr<Node> parent)
3209 {
3210     std::shared_ptr<Node> node = std::make_shared<Node>();
3211     node->collapsed = true;
3212     node->texts[COL_NAME] = name;
3213     node->texts[COL_COUNT] = std::to_wstring(song_num);
3214     if (parent != nullptr)
3215         parent->AddChild(node);
3216     return node;
3217 }
3218 
GetNodePath(Node * node)3219 std::wstring UiElement::FolderExploreTree::GetNodePath(Node* node)
3220 {
3221     std::wstring path{ node->texts[COL_NAME] };
3222     Node* cur_node{ node };
3223     while (cur_node != nullptr && cur_node->parent != nullptr)
3224     {
3225         cur_node = cur_node->parent;
3226         std::wstring parent_name = cur_node->texts[COL_NAME];
3227         if (!parent_name.empty() && parent_name.back() != L'\\' && parent_name.back() != L'/')
3228             parent_name.push_back(L'\\');
3229         path = parent_name + path;
3230     }
3231 
3232     return path;
3233 }
3234 
GetSelectedPath()3235 std::wstring UiElement::FolderExploreTree::GetSelectedPath()
3236 {
3237     int item_selected = GetItemSelected();
3238     if (item_selected >= 0 && item_selected < GetRowCount())
3239     {
3240         auto selected_node = GetNodeByIndex(item_selected);
3241         if (selected_node != nullptr)
3242             return GetNodePath(selected_node);
3243     }
3244     return std::wstring();
3245 }
3246 
GetColumnCount()3247 int UiElement::FolderExploreTree::GetColumnCount()
3248 {
3249     return COL_MAX;
3250 }
3251 
GetColumnWidth(int col,int total_width)3252 int UiElement::FolderExploreTree::GetColumnWidth(int col, int total_width)
3253 {
3254     const int count_width{ ui->DPI(40) };
3255     if (col == COL_NAME)
3256         return total_width - count_width;
3257     else if (col == COL_COUNT)
3258         return count_width;
3259     return 0;
3260 }
3261 
GetColumnScrollTextWhenSelected()3262 int UiElement::FolderExploreTree::GetColumnScrollTextWhenSelected()
3263 {
3264     return COL_NAME;
3265 }
3266 
GetContextMenu(bool item_selected)3267 CMenu* UiElement::FolderExploreTree::GetContextMenu(bool item_selected)
3268 {
3269     if (item_selected)
3270     {
3271         return theApp.m_menu_mgr.GetMenu(MenuMgr::LibFolderExploreMenu);
3272     }
3273     return nullptr;
3274 }
3275 
OnDoubleClicked()3276 void UiElement::FolderExploreTree::OnDoubleClicked()
3277 {
3278     int item_selected = GetItemSelected();
3279     if (item_selected >= 0 && item_selected < GetRowCount())
3280     {
3281         auto selected_node = GetNodeByIndex(item_selected);
3282         if (selected_node != nullptr)
3283         {
3284             std::wstring folder_path = GetNodePath(selected_node);
3285             CMusicPlayerCmdHelper helper;
3286             helper.OnOpenFolder(folder_path, true, true);
3287         }
3288     }
3289 }
3290 
GetEmptyString()3291 std::wstring UiElement::FolderExploreTree::GetEmptyString()
3292 {
3293     if (CUiFolderExploreMgr::Instance().IsLoading())
3294         return theApp.m_str_table.LoadText(L"UI_MEDIALIB_LIST_LOADING_INFO");
3295     else if (!CUiFolderExploreMgr::Instance().IsInited())
3296         return theApp.m_str_table.LoadText(L"UI_MEDIALIB_LIST_UNINITED_INFO");
3297     else
3298         return theApp.m_str_table.LoadText(L"UI_MEDIALIB_LIST_EMPTY_INFO");
3299 }
3300 
GetHoverButtonCount()3301 int UiElement::FolderExploreTree::GetHoverButtonCount()
3302 {
3303     return BTN_MAX;
3304 }
3305 
GetHoverButtonColumn()3306 int UiElement::FolderExploreTree::GetHoverButtonColumn()
3307 {
3308     return COL_NAME;
3309 }
3310 
GetHoverButtonIcon(int index,int row)3311 IconMgr::IconType UiElement::FolderExploreTree::GetHoverButtonIcon(int index, int row)
3312 {
3313     switch (index)
3314     {
3315     case BTN_PLAY: return IconMgr::IT_Play;
3316     case BTN_ADD: return IconMgr::IT_Add;
3317     }
3318     return IconMgr::IT_NO_ICON;
3319 }
3320 
GetHoverButtonTooltip(int index,int row)3321 std::wstring UiElement::FolderExploreTree::GetHoverButtonTooltip(int index, int row)
3322 {
3323     switch (index)
3324     {
3325     case BTN_PLAY: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_PLAY");
3326     case BTN_ADD: return theApp.m_str_table.LoadText(L"UI_TIP_BTN_ADD_TO_PLAYLIST");
3327     }
3328     return std::wstring();
3329 }
3330 
OnHoverButtonClicked(int btn_index,int row)3331 void UiElement::FolderExploreTree::OnHoverButtonClicked(int btn_index, int row)
3332 {
3333     CMusicPlayerCmdHelper helper;
3334     //点击了“播放”按钮
3335     if (btn_index == 0)
3336     {
3337         if (row >= 0 && row < GetRowCount())
3338         {
3339             auto selected_node = GetNodeByIndex(row);
3340             if (selected_node != nullptr)
3341             {
3342                 std::wstring folder_path = GetNodePath(selected_node);
3343                 CMusicPlayerCmdHelper helper;
3344                 helper.OnOpenFolder(folder_path, true, true);
3345             }
3346         }
3347     }
3348     //点击了“添加到播放列表”按钮
3349     else if (btn_index == BTN_ADD)
3350     {
3351         CMenu* menu = theApp.m_menu_mgr.GetMenu(MenuMgr::AddToPlaylistMenu);
3352         ShowContextMenu(menu, nullptr);
3353     }
3354 }
3355 
IsMultipleSelectionEnable()3356 bool UiElement::FolderExploreTree::IsMultipleSelectionEnable()
3357 {
3358     return false;
3359 }
3360 
GetRootNodes()3361 std::vector<std::shared_ptr<UiElement::TestTree::Node>>& UiElement::FolderExploreTree::GetRootNodes()
3362 {
3363     return CUiFolderExploreMgr::Instance().GetRootNodes();
3364 }
3365 
SearchBox()3366 UiElement::SearchBox::SearchBox()
3367 {
3368 }
3369 
~SearchBox()3370 UiElement::SearchBox::~SearchBox()
3371 {
3372     CCommon::DeleteModelessDialog(search_box_ctrl);
3373 }
3374 
InitSearchBoxControl(CWnd * pWnd)3375 void UiElement::SearchBox::InitSearchBoxControl(CWnd* pWnd)
3376 {
3377     CCommon::DeleteModelessDialog(search_box_ctrl);
3378     search_box_ctrl = new CUiSearchBox(pWnd);
3379     search_box_ctrl->Create();
3380 }
3381 
OnKeyWordsChanged()3382 void UiElement::SearchBox::OnKeyWordsChanged()
3383 {
3384     FindListElement();
3385     if (list_element != nullptr)
3386         list_element->QuickSearch(key_word);
3387 }
3388 
Clear()3389 void UiElement::SearchBox::Clear()
3390 {
3391     search_box_ctrl->Clear();
3392 }
3393 
Draw()3394 void UiElement::SearchBox::Draw()
3395 {
3396     CalculateRect();
3397     ui->DrawSearchBox(rect, this);
3398     Element::Draw();
3399 }
3400 
MouseMove(CPoint point)3401 void UiElement::SearchBox::MouseMove(CPoint point)
3402 {
3403     hover = false;
3404     clear_btn.hover = false;
3405     //鼠标指向图标区域
3406     if (icon_rect.PtInRect(point))
3407     {
3408         clear_btn.hover = true;
3409         //更新鼠标提示
3410         if (!key_word.empty())
3411             ui->UpdateMouseToolTipPosition(TooltipIndex::SEARCHBOX_CLEAR_BTN, clear_btn.rect);
3412         else
3413             ui->UpdateMouseToolTipPosition(TooltipIndex::SEARCHBOX_CLEAR_BTN, CRect());
3414     }
3415     //指向搜索框区域
3416     else if (rect.PtInRect(point))
3417     {
3418         hover = true;
3419     }
3420 }
3421 
MouseLeave()3422 void UiElement::SearchBox::MouseLeave()
3423 {
3424     hover = false;
3425     clear_btn.hover = false;
3426 }
3427 
LButtonUp(CPoint point)3428 void UiElement::SearchBox::LButtonUp(CPoint point)
3429 {
3430     clear_btn.pressed = false;
3431     //点击清除按钮时清除搜索结果
3432     if (icon_rect.PtInRect(point))
3433     {
3434         search_box_ctrl->Clear();
3435     }
3436     //点击搜索框区域时显示搜索框控件
3437     else if (search_box_ctrl != nullptr && rect.PtInRect(point))
3438     {
3439         bool big_font{ ui->m_ui_data.full_screen && ui->IsDrawLargeIcon() };
3440         search_box_ctrl->Show(this, big_font);
3441     }
3442 }
3443 
LButtonDown(CPoint point)3444 void UiElement::SearchBox::LButtonDown(CPoint point)
3445 {
3446     if (icon_rect.PtInRect(point))
3447     {
3448         clear_btn.pressed = true;
3449     }
3450 }
3451 
FindListElement()3452 void UiElement::SearchBox::FindListElement()
3453 {
3454     if (!find_list_element)
3455     {
3456         list_element = FindRelatedElement<ListElement>(this);
3457         if (list_element != nullptr)
3458             list_element->SetRelatedSearchBox(this);
3459         find_list_element = true;  //找过一次没找到就不找了
3460     }
3461 }
3462 
3463 ////////////////////////////////////////////////////////////////////////////////////////
3464 ////////////////////////////////////////////////////////////////////////////////////////
CreateElement(const std::string & name,CPlayerUIBase * ui)3465 std::shared_ptr<UiElement::Element> CElementFactory::CreateElement(const std::string& name, CPlayerUIBase* ui)
3466 {
3467     std::shared_ptr<UiElement::Element> element;
3468     if (name == "verticalLayout")
3469     {
3470         auto layout = std::make_shared<UiElement::Layout>();
3471         layout->type = UiElement::Layout::Vertical;
3472         element = layout;
3473     }
3474     else if (name == "horizontalLayout")
3475     {
3476         auto layout = std::make_shared<UiElement::Layout>();
3477         layout->type = UiElement::Layout::Horizontal;
3478         element = layout;
3479     }
3480     else if (name == "stackElement")
3481         element = std::make_shared<UiElement::StackElement>();
3482     else if (name == "rectangle")
3483         element = std::make_shared<UiElement::Rectangle>();
3484     else if (name == "button")
3485         element = std::make_shared<UiElement::Button>();
3486     else if (name == "text")
3487         element = std::make_shared<UiElement::Text>();
3488     else if (name == "albumCover")
3489         element = std::make_shared<UiElement::AlbumCover>();
3490     else if (name == "spectrum")
3491         element = std::make_shared<UiElement::Spectrum>();
3492     else if (name == "trackInfo")
3493         element = std::make_shared<UiElement::TrackInfo>();
3494     else if (name == "toolbar")
3495         element = std::make_shared<UiElement::Toolbar>();
3496     else if (name == "progressBar")
3497         element = std::make_shared<UiElement::ProgressBar>();
3498     else if (name == "lyrics")
3499         element = std::make_shared<UiElement::Lyrics>();
3500     else if (name == "volume")
3501         element = std::make_shared<UiElement::Volume>();
3502     else if (name == "beatIndicator")
3503         element = std::make_shared<UiElement::BeatIndicator>();
3504     else if (name == "playlist")
3505         element = std::make_shared<UiElement::Playlist>();
3506     else if (name == "playlistIndicator")
3507         element = std::make_shared<UiElement::PlaylistIndicator>();
3508     else if (name == "classicalControlBar")
3509         element = std::make_shared<UiElement::ClassicalControlBar>();
3510     else if (name == "recentPlayedList")
3511         element = std::make_shared<UiElement::RecentPlayedList>();
3512     else if (name == "mediaLibItemList")
3513         element = std::make_shared<UiElement::MediaLibItemList>();
3514     else if (name == "navigationBar")
3515         element = std::make_shared<UiElement::NavigationBar>();
3516     else if (name == "mediaLibFolder")
3517         element = std::make_shared<UiElement::MediaLibFolder>();
3518     else if (name == "mediaLibPlaylist")
3519         element = std::make_shared<UiElement::MediaLibPlaylist>();
3520     else if (name == "myFavouriteList")
3521         element = std::make_shared<UiElement::MyFavouriteList>();
3522     else if (name == "allTracksList")
3523         element = std::make_shared<UiElement::AllTracksList>();
3524     else if (name == "miniSpectrum")
3525         element = std::make_shared<UiElement::MiniSpectrum>();
3526     else if (name == "placeHolder")
3527         element = std::make_shared<UiElement::PlaceHolder>();
3528     else if (name == "medialibFolderExplore")
3529         element = std::make_shared<UiElement::FolderExploreTree>();
3530     else if (name == "searchBox")
3531         element = std::make_shared<UiElement::SearchBox>();
3532     else if (name == "ui" || name == "root" || name == "element")
3533         element = std::make_shared<UiElement::Element>();
3534 
3535     if (element != nullptr)
3536         element->SetUi(ui);
3537     return element;
3538 }
3539