xref: /MusicPlayer2/MusicPlayer2/UserUi.cpp (revision 21fd5365fd2c7325929631455035f3376d2c9835)
1 #include "stdafx.h"
2 #include "UserUi.h"
3 #include "UiSearchBox.h"
4 
CUserUi(CWnd * pMainWnd,const std::wstring & xml_path)5 CUserUi::CUserUi(CWnd* pMainWnd, const std::wstring& xml_path)
6     : CPlayerUIBase(theApp.m_ui_data, pMainWnd), m_xml_path(xml_path)
7 {
8     size_t length;
9     const char* xml_contents = CCommon::GetFileContent(m_xml_path.c_str(), length);
10     LoadFromContents(std::string(xml_contents, length));
11     delete[] xml_contents;
12 }
13 
CUserUi(CWnd * pMainWnd,UINT id)14 CUserUi::CUserUi(CWnd* pMainWnd, UINT id)
15     : CPlayerUIBase(theApp.m_ui_data, pMainWnd)
16 {
17     string xml = CCommon::GetTextResourceRawData(id);
18     LoadFromContents(xml);
19 }
20 
21 
~CUserUi()22 CUserUi::~CUserUi()
23 {
24 }
25 
LoadFromContents(const std::string & xml_contents)26 void CUserUi::LoadFromContents(const std::string& xml_contents)
27 {
28     m_stack_elements.clear();
29     tinyxml2::XMLDocument xml_doc;
30     xml_doc.Parse(xml_contents.c_str());
31     tinyxml2::XMLElement* root = xml_doc.RootElement();
32     m_ui_name = CCommon::StrToUnicode(CTinyXml2Helper::ElementAttribute(root, "name"), CodeType::UTF8_NO_BOM);
33     ReplaceUiStringRes(m_ui_name);
34     std::string ui_index = CTinyXml2Helper::ElementAttribute(root, "index");
35     if (!ui_index.empty())
36         m_index = atoi(ui_index.c_str());
37     CTinyXml2Helper::IterateChildNode(root, [&](tinyxml2::XMLElement* xml_child)
38         {
39             std::string item_name = CTinyXml2Helper::ElementName(xml_child);
40             if (item_name == "ui")
41             {
42                 std::string str_type = CTinyXml2Helper::ElementAttribute(xml_child, "type");
43                 if (str_type == "big")
44                     m_root_ui_big = BuildUiElementFromXmlNode(xml_child);
45                 else if (str_type == "narrow")
46                     m_root_ui_narrow = BuildUiElementFromXmlNode(xml_child);
47                 else if (str_type == "small")
48                     m_root_ui_small = BuildUiElementFromXmlNode(xml_child);
49                 else
50                     m_root_default = BuildUiElementFromXmlNode(xml_child);
51             }
52         });
53 }
54 
SetIndex(int index)55 void CUserUi::SetIndex(int index)
56 {
57     m_index = index;
58 }
59 
IsIndexValid() const60 bool CUserUi::IsIndexValid() const
61 {
62     return m_index != INT_MAX;
63 }
64 
IterateAllElements(std::function<bool (UiElement::Element *)> func,bool visible_only)65 void CUserUi::IterateAllElements(std::function<bool(UiElement::Element*)> func, bool visible_only)
66 {
67     std::shared_ptr<UiElement::Element> draw_element = GetCurrentTypeUi();
68     draw_element->IterateAllElements(func, visible_only);
69 }
70 
IterateAllElementsInAllUi(std::function<bool (UiElement::Element *)> func)71 void CUserUi::IterateAllElementsInAllUi(std::function<bool(UiElement::Element*)> func)
72 {
73     m_root_ui_big->IterateAllElements(func);
74     m_root_ui_narrow->IterateAllElements(func);
75     m_root_ui_small->IterateAllElements(func);
76     m_root_default->IterateAllElements(func);
77 }
78 
VolumeAdjusted()79 void CUserUi::VolumeAdjusted()
80 {
81     IterateAllElements([this](UiElement::Element* element) ->bool
82         {
83             UiElement::Text* text_element{ dynamic_cast<UiElement::Text*>(element) };
84             if (text_element != nullptr)
85             {
86                 text_element->show_volume = true;
87             }
88             return false;
89         });
90     KillTimer(theApp.m_pMainWnd->GetSafeHwnd(), SHOW_VOLUME_TIMER_ID);
91     //设置一个音量显示时间的定时器(音量显示保持1.5秒)
92     SetTimer(theApp.m_pMainWnd->GetSafeHwnd(), SHOW_VOLUME_TIMER_ID, 1500, NULL);
93 }
94 
ResetVolumeToPlayTime()95 void CUserUi::ResetVolumeToPlayTime()
96 {
97     KillTimer(theApp.m_pMainWnd->GetSafeHwnd(), SHOW_VOLUME_TIMER_ID);
98     IterateAllElements([this](UiElement::Element* element) ->bool
99         {
100             UiElement::Text* text_element{ dynamic_cast<UiElement::Text*>(element) };
101             if (text_element != nullptr)
102             {
103                 text_element->show_volume = false;
104             }
105             return false;
106         });
107 }
108 
PlaylistLocateToCurrent()109 void CUserUi::PlaylistLocateToCurrent()
110 {
111     //遍历Playlist元素
112     IterateAllElements([&](UiElement::Element* element) ->bool {
113         UiElement::Playlist* playlist_element{ dynamic_cast<UiElement::Playlist*>(element) };
114         if (playlist_element != nullptr)
115         {
116             playlist_element->EnsureHighlightItemVisible();
117         }
118         return false;
119     });
120 }
121 
ListLocateToCurrent()122 void CUserUi::ListLocateToCurrent()
123 {
124     //遍历ListElement元素
125     IterateAllElements([&](UiElement::Element* element) ->bool {
126         UiElement::ListElement* playlist_element{ dynamic_cast<UiElement::ListElement*>(element) };
127         if (playlist_element != nullptr)
128         {
129             playlist_element->EnsureHighlightItemVisible();
130         }
131         return false;
132     });
133 }
134 
InitSearchBox(CWnd * pWnd)135 void CUserUi::InitSearchBox(CWnd* pWnd)
136 {
137     IterateAllElementsInAllUi([&](UiElement::Element* element) ->bool {
138         UiElement::SearchBox* search_box{ dynamic_cast<UiElement::SearchBox*>(element) };
139         if (search_box != nullptr)
140             search_box->InitSearchBoxControl(pWnd);
141         return false;
142     });
143 }
144 
SaveStatackElementIndex(CArchive & archive)145 void CUserUi::SaveStatackElementIndex(CArchive& archive)
146 {
147     //遍历StackElement元素
148     IterateAllElementsInAllUi([&](UiElement::Element* element) ->bool
149         {
150             UiElement::StackElement* stack_element{ dynamic_cast<UiElement::StackElement*>(element) };
151             if (stack_element != nullptr)
152             {
153                 archive << static_cast<BYTE>(stack_element->GetCurIndex());
154             }
155             return false;
156         });
157 }
158 
LoadStatackElementIndex(CArchive & archive)159 void CUserUi::LoadStatackElementIndex(CArchive& archive)
160 {
161     IterateAllElementsInAllUi([&](UiElement::Element* element) ->bool
162         {
163             UiElement::StackElement* stack_element{ dynamic_cast<UiElement::StackElement*>(element) };
164             if (stack_element != nullptr)
165             {
166                 BYTE stack_element_index;
167                 archive >> stack_element_index;
168                 stack_element->SetCurrentElement(stack_element_index);
169             }
170             return false;
171         });
172 
173 }
174 
175 
_DrawInfo(CRect draw_rect,bool reset)176 void CUserUi::_DrawInfo(CRect draw_rect, bool reset)
177 {
178     std::shared_ptr<UiElement::Element> draw_element = GetCurrentTypeUi();
179     if (draw_element != nullptr)
180     {
181         if (m_ui_data.full_screen)  //全屏模式下,最外侧的边距需要加宽
182         {
183             draw_rect.DeflateRect(EdgeMargin(true), EdgeMargin(false));
184         }
185         draw_element->SetRect(draw_rect);
186         draw_element->Draw();
187         //绘制音量调整按钮
188         DrawVolumnAdjBtn();
189     }
190     //绘制右上角图标
191     DrawTopRightIcons();
192 
193     //全屏模式时在右上角绘制时间
194     if (m_ui_data.full_screen)
195     {
196         DrawCurrentTime();
197     }
198     m_draw_data.thumbnail_rect = draw_rect;
199 }
200 
GetCurrentTypeUi() const201 std::shared_ptr<UiElement::Element> CUserUi::GetCurrentTypeUi() const
202 {
203     std::shared_ptr<UiElement::Element> draw_element;
204     //根据不同的窗口大小选择不同的界面元素的根节点绘图
205     auto ui_size = GetUiSize();
206     //<ui type="small">
207     if (ui_size == CPlayerUIBase::UiSize::SMALL)
208     {
209         if (m_root_ui_small != nullptr)
210             draw_element = m_root_ui_small;
211         else if (m_root_ui_narrow != nullptr)
212             draw_element = m_root_ui_narrow;
213         else
214             draw_element = m_root_default;
215     }
216     //<ui type="big">
217     else if (ui_size == CPlayerUIBase::UiSize::BIG)
218     {
219         if (m_root_ui_big != nullptr)
220             draw_element = m_root_ui_big;
221         else
222             draw_element = m_root_default;
223     }
224     //<ui type="narrow">
225     else
226     {
227         if (m_root_ui_narrow != nullptr)
228             draw_element = m_root_ui_narrow;
229         else
230             draw_element = m_root_default;
231     }
232     return draw_element;
233 }
234 
GetUIName()235 wstring CUserUi::GetUIName()
236 {
237     return m_ui_name;
238 }
239 
LButtonUp(CPoint point)240 bool CUserUi::LButtonUp(CPoint point)
241 {
242     if (!CPlayerUIBase::LButtonUp(point) && !CPlayerUIBase::PointInMenubarArea(point) && !CPlayerUIBase::PointInTitlebarArea(point))
243     {
244         const auto& stack_elements{ GetStackElements() };
245         for (const auto& element : stack_elements)
246         {
247             UiElement::StackElement* stack_element = dynamic_cast<UiElement::StackElement*>(element.get());
248             if (stack_element != nullptr)
249             {
250                 bool pressed = stack_element->indicator.pressed;
251                 stack_element->indicator.pressed = false;
252 
253                 if ((pressed && stack_element->indicator.rect.PtInRect(point) && stack_element->indicator.enable)
254                     || (stack_element->click_to_switch && stack_element->GetRect().PtInRect(point)))
255                 {
256                     m_draw_data.lyric_rect.SetRectEmpty();
257                     stack_element->SwitchDisplay();
258                     return true;
259                 }
260             }
261         }
262 
263         //遍历所有元素
264         IterateAllElements([point](UiElement::Element* element) ->bool
265             {
266                 if (element != nullptr)
267                 {
268                     element->LButtonUp(point);
269                 }
270                 return false;
271             });
272     }
273     return false;
274 }
275 
LButtonDown(CPoint point)276 bool CUserUi::LButtonDown(CPoint point)
277 {
278     if (!CPlayerUIBase::LButtonDown(point) && !CPlayerUIBase::PointInMenubarArea(point) && !CPlayerUIBase::PointInTitlebarArea(point))
279     {
280         //遍历StackElement
281         auto& stack_elements{ GetStackElements() };
282         for (auto& element : stack_elements)
283         {
284             UiElement::StackElement* stack_element{ dynamic_cast<UiElement::StackElement*>(element.get()) };
285             if (stack_element != nullptr && stack_element->indicator.enable && stack_element->indicator.rect.PtInRect(point) != FALSE)
286                 stack_element->indicator.pressed = true;
287         }
288 
289         //遍历所有元素
290         IterateAllElements([point](UiElement::Element* element) ->bool
291             {
292                 if (element != nullptr)
293                 {
294                     element->LButtonDown(point);
295                 }
296                 return false;
297             });
298     }
299     return false;
300 }
301 
MouseMove(CPoint point)302 void CUserUi::MouseMove(CPoint point)
303 {
304     bool mouse_in_draw_area{ !CPlayerUIBase::PointInMenubarArea(point) && !CPlayerUIBase::PointInTitlebarArea(point) };
305     if (mouse_in_draw_area)
306     {
307         auto& stack_elements{ GetStackElements() };
308         for (auto& element : stack_elements)
309         {
310             UiElement::StackElement* stack_element{ dynamic_cast<UiElement::StackElement*>(element.get()) };
311             if (stack_element != nullptr)
312             {
313                 if (stack_element->indicator.enable)
314                     stack_element->indicator.hover = (stack_element->indicator.rect.PtInRect(point) != FALSE);
315                 bool hover{ stack_element->GetRect().PtInRect(point) != FALSE };
316                 if (!stack_element->mouse_hover && hover)
317                     UpdateToolTipPositionLater();
318                 stack_element->mouse_hover = hover;
319             }
320         }
321 
322         //遍历所有元素
323         IterateAllElements([point](UiElement::Element* element) ->bool
324             {
325                 if (element != nullptr)
326                 {
327                     element->MouseMove(point);
328                 }
329                 return false;
330             });
331     }
332 
333     //鼠标离开绘图区域后发送MouseLeave消息
334     if (m_last_mouse_in_draw_area && !mouse_in_draw_area)
335     {
336         IterateAllElements([point](UiElement::Element* element) ->bool {
337             if (element != nullptr)
338                 element->MouseLeave();
339             return false;
340         });
341     }
342 
343     m_last_mouse_in_draw_area = mouse_in_draw_area;
344     CPlayerUIBase::MouseMove(point);
345 }
346 
MouseLeave()347 void CUserUi::MouseLeave()
348 {
349     auto& stack_elements{ GetStackElements() };
350     for (auto& element : stack_elements)
351     {
352         UiElement::StackElement* stack_element{ dynamic_cast<UiElement::StackElement*>(element.get()) };
353         if (stack_element != nullptr)
354         {
355             //清除StackElement中的mouse_hover状态
356             stack_element->mouse_hover = false;
357         }
358     }
359 
360     //遍历所有元素
361     IterateAllElements([](UiElement::Element* element) ->bool
362         {
363             if (element != nullptr)
364             {
365                 element->MouseLeave();
366             }
367             return false;
368         });
369 
370     CPlayerUIBase::MouseLeave();
371 }
372 
373 
RButtonUp(CPoint point)374 void CUserUi::RButtonUp(CPoint point)
375 {
376     //遍历所有元素
377     bool rtn = false;
378     if (!CPlayerUIBase::PointInMenubarArea(point) && !CPlayerUIBase::PointInTitlebarArea(point))
379     {
380         IterateAllElements([&](UiElement::Element* element) ->bool
381             {
382                 if (element != nullptr)
383                 {
384                     if (element->RButtunUp(point))
385                     {
386                         rtn = true;
387                         return true;
388                     }
389                 }
390                 return false;
391             });
392     }
393     if (!rtn)
394         CPlayerUIBase::RButtonUp(point);
395 }
396 
397 
RButtonDown(CPoint point)398 void CUserUi::RButtonDown(CPoint point)
399 {
400     //遍历所有元素
401     if (!CPlayerUIBase::PointInMenubarArea(point) && !CPlayerUIBase::PointInTitlebarArea(point))
402     {
403         IterateAllElements([point](UiElement::Element* element) ->bool
404             {
405                 if (element != nullptr)
406                 {
407                     element->RButtonDown(point);
408                 }
409                 return false;
410             });
411     }
412     CPlayerUIBase::RButtonDown(point);
413 }
414 
MouseWheel(int delta,CPoint point)415 bool CUserUi::MouseWheel(int delta, CPoint point)
416 {
417     //遍历所有元素
418     bool rtn = false;
419     IterateAllElements([&](UiElement::Element* element) ->bool
420         {
421             if (element != nullptr)
422             {
423                 if (element->MouseWheel(delta, point))
424                 {
425                     rtn = true;
426                     return true;
427                 }
428             }
429             return false;
430         });
431 
432     if (!rtn)
433     {
434         //遍历stackElement元素
435         IterateAllElements([&](UiElement::Element* element) ->bool
436             {
437                 UiElement::StackElement* stack_element{ dynamic_cast<UiElement::StackElement*>(element) };
438                 if (stack_element != nullptr)
439                 {
440                     //如果鼠标指向指示器,或者指定了scroll_to_switch属性时鼠标指向stackElement区域,通过鼠标滚轮切换显示
441                     if ((stack_element->show_indicator && stack_element->indicator.rect.PtInRect(point)) || (stack_element->scroll_to_switch && stack_element->GetRect().PtInRect(point)))
442                     {
443                         stack_element->SwitchDisplay(delta > 0);
444                         rtn = true;
445                         return true;
446                     }
447                 }
448                 return false;
449             });
450     }
451 
452     if (rtn)
453         return true;
454     return CPlayerUIBase::MouseWheel(delta, point);
455 }
456 
DoubleClick(CPoint point)457 bool CUserUi::DoubleClick(CPoint point)
458 {
459     //遍历所有元素
460     bool rtn = false;
461     IterateAllElements([&](UiElement::Element* element) ->bool
462         {
463             if (element != nullptr)
464             {
465                 if (element->DoubleClick(point))
466                 {
467                     rtn = true;
468                     return true;
469                 }
470             }
471             return false;
472         });
473 
474     if (rtn)
475         return true;
476     return CPlayerUIBase::DoubleClick(point);
477 }
478 
UiSizeChanged()479 void CUserUi::UiSizeChanged()
480 {
481     ListLocateToCurrent();
482 }
483 
SetCursor()484 bool CUserUi::SetCursor()
485 {
486     bool cursor_changed = false;
487     //如果鼠标指向搜索框,则更改鼠标指针
488     IterateAllElements<UiElement::SearchBox>([&](UiElement::SearchBox* search_box) ->bool {
489         if (search_box->hover)
490         {
491             ::SetCursor(::LoadCursor(NULL, IDC_IBEAM));
492             cursor_changed = true;
493             return true;
494         }
495         return false;
496     }, true);
497 
498     if (cursor_changed)
499         return true;
500 
501     return CPlayerUIBase::SetCursor();
502 }
503 
GetUiIndex()504 int CUserUi::GetUiIndex()
505 {
506     return m_index;
507 }
508 
BuildUiElementFromXmlNode(tinyxml2::XMLElement * xml_node)509 std::shared_ptr<UiElement::Element> CUserUi::BuildUiElementFromXmlNode(tinyxml2::XMLElement* xml_node)
510 {
511     CElementFactory factory;
512     //获取节点名称
513     std::string item_name = CTinyXml2Helper::ElementName(xml_node);
514     //根据节点名称创建ui元素
515     std::shared_ptr<UiElement::Element> element = factory.CreateElement(item_name, this);
516     if (element != nullptr)
517     {
518         static UiElement::Element* current_build_ui_element{};      //正在创建ui元素
519         if (item_name == "ui")
520             current_build_ui_element = element.get();
521 
522         element->name = item_name;
523         //设置元素的基类属性
524         std::string str_x = CTinyXml2Helper::ElementAttribute(xml_node, "x");
525         std::string str_y = CTinyXml2Helper::ElementAttribute(xml_node, "y");
526         std::string str_proportion = CTinyXml2Helper::ElementAttribute(xml_node, "proportion");
527         std::string str_width = CTinyXml2Helper::ElementAttribute(xml_node, "width");
528         std::string str_height = CTinyXml2Helper::ElementAttribute(xml_node, "height");
529         std::string str_max_width = CTinyXml2Helper::ElementAttribute(xml_node, "max-width");
530         std::string str_max_height = CTinyXml2Helper::ElementAttribute(xml_node, "max-height");
531         std::string str_min_width = CTinyXml2Helper::ElementAttribute(xml_node, "min-width");
532         std::string str_min_height = CTinyXml2Helper::ElementAttribute(xml_node, "min-height");
533         std::string str_margin = CTinyXml2Helper::ElementAttribute(xml_node, "margin");
534         std::string str_margin_left = CTinyXml2Helper::ElementAttribute(xml_node, "margin-left");
535         std::string str_margin_right = CTinyXml2Helper::ElementAttribute(xml_node, "margin-right");
536         std::string str_margin_top = CTinyXml2Helper::ElementAttribute(xml_node, "margin-top");
537         std::string str_margin_bottom = CTinyXml2Helper::ElementAttribute(xml_node, "margin-bottom");
538         std::string str_hide_width = CTinyXml2Helper::ElementAttribute(xml_node, "hide-width");
539         std::string str_hide_height = CTinyXml2Helper::ElementAttribute(xml_node, "hide-height");
540         if (!str_x.empty())
541             element->x.FromString(str_x);
542         if (!str_y.empty())
543             element->y.FromString(str_y);
544         if (!str_proportion.empty())
545             element->proportion = max(atoi(str_proportion.c_str()), 1);
546         if (!str_width.empty())
547             element->width.FromString(str_width);
548         if (!str_height.empty())
549             element->height.FromString(str_height);
550         if (!str_max_width.empty())
551             element->max_width.FromString(str_max_width);
552         if (!str_max_height.empty())
553             element->max_height.FromString(str_max_height);
554         if (!str_min_width.empty())
555             element->min_width.FromString(str_min_width);
556         if (!str_min_height.empty())
557             element->min_height.FromString(str_min_height);
558 
559         if (!str_margin.empty())
560         {
561             element->margin_left.FromString(str_margin);
562             element->margin_right.FromString(str_margin);
563             element->margin_top.FromString(str_margin);
564             element->margin_bottom.FromString(str_margin);
565         }
566         if (!str_margin_left.empty())
567             element->margin_left.FromString(str_margin_left);
568         if (!str_margin_right.empty())
569             element->margin_right.FromString(str_margin_right);
570         if (!str_margin_top.empty())
571             element->margin_top.FromString(str_margin_top);
572         if (!str_margin_bottom.empty())
573             element->margin_bottom.FromString(str_margin_bottom);
574 
575         if (!str_hide_width.empty())
576             element->hide_width.FromString(str_hide_width);
577         if (!str_hide_height.empty())
578             element->hide_height.FromString(str_hide_height);
579 
580         //设置ListElement的属性
581         UiElement::ListElement* list_element = dynamic_cast<UiElement::ListElement*>(element.get());
582         if (list_element != nullptr)
583         {
584             int item_height{};
585             CTinyXml2Helper::GetElementAttributeInt(xml_node, "item_height", item_height);
586             if (item_height > 0)
587                 list_element->item_height = item_height;
588             CTinyXml2Helper::GetElementAttributeInt(xml_node, "font_size", list_element->font_size);
589         }
590 
591         //根据节点的类型设置元素独有的属性
592         //按钮
593         if (item_name == "button")
594         {
595             UiElement::Button* button = dynamic_cast<UiElement::Button*>(element.get());
596             if (button != nullptr)
597             {
598                 std::string str_key = CTinyXml2Helper::ElementAttribute(xml_node, "key");   //按钮的类型
599                 button->FromString(str_key);
600                 std::string str_big_icon = CTinyXml2Helper::ElementAttribute(xml_node, "bigIcon");
601                 button->big_icon = CTinyXml2Helper::StringToBool(str_big_icon.c_str());
602                 CTinyXml2Helper::GetElementAttributeBool(xml_node, "show_text", button->show_text);
603                 CTinyXml2Helper::GetElementAttributeInt(xml_node, "font_size", button->font_size);
604             }
605         }
606         else if (item_name == "rectangle")
607         {
608             UiElement::Rectangle* rectangle = dynamic_cast<UiElement::Rectangle*>(element.get());
609             if (rectangle != nullptr)
610             {
611                 std::string str_no_corner_radius = CTinyXml2Helper::ElementAttribute(xml_node, "no_corner_radius");
612                 rectangle->no_corner_radius = CTinyXml2Helper::StringToBool(str_no_corner_radius.c_str());
613                 std::string str_theme_color = CTinyXml2Helper::ElementAttribute(xml_node, "theme_color");
614                 if (!str_theme_color.empty())
615                     rectangle->theme_color = CTinyXml2Helper::StringToBool(str_theme_color.c_str());
616                 std::string str_color_mode = CTinyXml2Helper::ElementAttribute(xml_node, "color_mode");
617                 if (str_color_mode == "dark")
618                     rectangle->color_mode = CPlayerUIBase::RCM_DARK;
619                 else if (str_color_mode == "light")
620                     rectangle->color_mode = CPlayerUIBase::RCM_LIGHT;
621                 else
622                     rectangle->color_mode = CPlayerUIBase::RCM_AUTO;
623             }
624         }
625         //文本
626         else if (item_name == "text")
627         {
628             UiElement::Text* text = dynamic_cast<UiElement::Text*>(element.get());
629             if (text != nullptr)
630             {
631                 //text
632                 std::string str_text = CTinyXml2Helper::ElementAttribute(xml_node, "text");
633                 text->text = CCommon::StrToUnicode(str_text, CodeType::UTF8_NO_BOM);
634                 ReplaceUiStringRes(text->text);
635                 //alignment
636                 std::string str_alignment = CTinyXml2Helper::ElementAttribute(xml_node, "alignment");
637                 if (str_alignment == "left")
638                     text->align = Alignment::LEFT;
639                 else if (str_alignment == "right")
640                     text->align = Alignment::RIGHT;
641                 else if (str_alignment == "center")
642                     text->align = Alignment::CENTER;
643                 //style
644                 std::string str_style = CTinyXml2Helper::ElementAttribute(xml_node, "style");
645                 if (str_style == "static")
646                     text->style = UiElement::Text::Static;
647                 else if (str_style == "scroll")
648                     text->style = UiElement::Text::Scroll;
649                 else if (str_style == "scroll2")
650                     text->style = UiElement::Text::Scroll2;
651                 //type
652                 std::string str_type = CTinyXml2Helper::ElementAttribute(xml_node, "type");
653                 if (str_type == "userDefine")
654                     text->type = UiElement::Text::UserDefine;
655                 else if (str_type == "title")
656                     text->type = UiElement::Text::Title;
657                 else if (str_type == "artist")
658                     text->type = UiElement::Text::Artist;
659                 else if (str_type == "album")
660                     text->type = UiElement::Text::Album;
661                 else if (str_type == "artist_title")
662                     text->type = UiElement::Text::ArtistTitle;
663                 else if (str_type == "artist_album")
664                     text->type = UiElement::Text::ArtistAlbum;
665                 else if (str_type == "format")
666                     text->type = UiElement::Text::Format;
667                 else if (str_type == "play_time")
668                     text->type = UiElement::Text::PlayTime;
669                 else if (str_type == "play_time_and_volume")
670                     text->type = UiElement::Text::PlayTimeAndVolume;
671                 //font_size
672                 std::string str_font_size = CTinyXml2Helper::ElementAttribute(xml_node, "font_size");
673                 text->font_size = atoi(str_font_size.c_str());
674                 if (text->font_size == 0)
675                     text->font_size = 9;
676                 else if (text->font_size < 8)
677                     text->font_size = 8;
678                 else if (text->font_size > 16)
679                     text->font_size = 16;
680                 // max_width_follow_text 优先级低于 max-width
681                 std::string str_width_follow_text = CTinyXml2Helper::ElementAttribute(xml_node, "width_follow_text");
682                 if (str_width_follow_text == "true")
683                     text->width_follow_text = true;
684                 else if (str_width_follow_text == "false")
685                     text->width_follow_text = false;
686                 std::string str_color_mode = CTinyXml2Helper::ElementAttribute(xml_node, "color_mode");
687                 if (str_color_mode == "dark")
688                     text->color_mode = CPlayerUIBase::RCM_DARK;
689                 else if (str_color_mode == "light")
690                     text->color_mode = CPlayerUIBase::RCM_LIGHT;
691                 else
692                     text->color_mode = CPlayerUIBase::RCM_AUTO;
693             }
694         }
695         //专辑封面
696         else if (item_name == "albumCover")
697         {
698             UiElement::AlbumCover* album_cover = dynamic_cast<UiElement::AlbumCover*>(element.get());
699             if (album_cover != nullptr)
700             {
701                 std::string str_square = CTinyXml2Helper::ElementAttribute(xml_node, "square");
702                 album_cover->square = CTinyXml2Helper::StringToBool(str_square.c_str());
703                 std::string str_show_info = CTinyXml2Helper::ElementAttribute(xml_node, "show_info");
704                 album_cover->show_info = CTinyXml2Helper::StringToBool(str_show_info.c_str());
705             }
706         }
707         //频谱分析
708         else if (item_name == "spectrum")
709         {
710             UiElement::Spectrum* spectrum = dynamic_cast<UiElement::Spectrum*>(element.get());
711             if (spectrum != nullptr)
712             {
713                 std::string str_draw_reflex = CTinyXml2Helper::ElementAttribute(xml_node, "draw_reflex");
714                 spectrum->draw_reflex = CTinyXml2Helper::StringToBool(str_draw_reflex.c_str());
715                 std::string str_fixed_width = CTinyXml2Helper::ElementAttribute(xml_node, "fixed_width");
716                 spectrum->fixed_width = CTinyXml2Helper::StringToBool(str_fixed_width.c_str());
717                 std::string str_type = CTinyXml2Helper::ElementAttribute(xml_node, "type");
718                 if (str_type == "64col")
719                     spectrum->type = CUIDrawer::SC_64;
720                 else if (str_type == "32col")
721                     spectrum->type = CUIDrawer::SC_32;
722                 else if (str_type == "16col")
723                     spectrum->type = CUIDrawer::SC_16;
724                 else if (str_type == "8col")
725                     spectrum->type = CUIDrawer::SC_8;
726                 //alignment
727                 std::string str_alignment = CTinyXml2Helper::ElementAttribute(xml_node, "alignment");
728                 if (str_alignment == "left")
729                     spectrum->align = Alignment::LEFT;
730                 else if (str_alignment == "right")
731                     spectrum->align = Alignment::RIGHT;
732                 else if (str_alignment == "center")
733                     spectrum->align = Alignment::CENTER;
734             }
735         }
736         //工具条
737         else if (item_name == "toolbar")
738         {
739             UiElement::Toolbar* toolbar = dynamic_cast<UiElement::Toolbar*>(element.get());
740             if (toolbar != nullptr)
741             {
742                 std::string str_show_translate_btn = CTinyXml2Helper::ElementAttribute(xml_node, "show_translate_btn");
743                 toolbar->show_translate_btn = CTinyXml2Helper::StringToBool(str_show_translate_btn.c_str());
744             }
745         }
746         //进度条
747         else if (item_name == "progressBar")
748         {
749             UiElement::ProgressBar* progress_bar = dynamic_cast<UiElement::ProgressBar*>(element.get());
750             if (progress_bar != nullptr)
751             {
752                 std::string str_show_play_time = CTinyXml2Helper::ElementAttribute(xml_node, "show_play_time");
753                 progress_bar->show_play_time = CTinyXml2Helper::StringToBool(str_show_play_time.c_str());
754                 std::string str_play_time_both_side = CTinyXml2Helper::ElementAttribute(xml_node, "play_time_both_side");
755                 progress_bar->play_time_both_side = CTinyXml2Helper::StringToBool(str_play_time_both_side.c_str());
756             }
757         }
758         //音量
759         else if (item_name == "volume")
760         {
761             UiElement::Volume* volume = dynamic_cast<UiElement::Volume*>(element.get());
762             if (volume != nullptr)
763             {
764                 std::string str_show_text = CTinyXml2Helper::ElementAttribute(xml_node, "show_text");
765                 volume->show_text = CTinyXml2Helper::StringToBool(str_show_text.c_str());
766                 std::string str_adj_btn_on_top = CTinyXml2Helper::ElementAttribute(xml_node, "adj_btn_on_top");
767                 volume->adj_btn_on_top = CTinyXml2Helper::StringToBool(str_adj_btn_on_top.c_str());
768             }
769         }
770         //堆叠元素
771         else if (item_name == "stackElement")
772         {
773             m_stack_elements[current_build_ui_element].push_back(element);
774             UiElement::StackElement* stack_element = dynamic_cast<UiElement::StackElement*>(element.get());
775             if (stack_element != nullptr)
776             {
777                 CTinyXml2Helper::GetElementAttributeBool(xml_node, "click_to_switch", stack_element->click_to_switch);
778                 CTinyXml2Helper::GetElementAttributeBool(xml_node, "hover_to_switch", stack_element->hover_to_switch);
779                 CTinyXml2Helper::GetElementAttributeBool(xml_node, "scroll_to_switch", stack_element->scroll_to_switch);
780                 CTinyXml2Helper::GetElementAttributeBool(xml_node, "show_indicator", stack_element->show_indicator);
781                 CTinyXml2Helper::GetElementAttributeInt(xml_node, "indicator_offset", stack_element->indicator_offset);
782             }
783         }
784         //播放控制栏
785         else if (item_name == "classicalControlBar")
786         {
787             UiElement::ClassicalControlBar* classicalControlBar = dynamic_cast<UiElement::ClassicalControlBar*>(element.get());
788             if (classicalControlBar != nullptr)
789             {
790                 CTinyXml2Helper::GetElementAttributeBool(xml_node, "show_switch_display_btn", classicalControlBar->show_switch_display_btn);
791             }
792         }
793         //歌词
794         else if (item_name == "lyrics")
795         {
796             UiElement::Lyrics* lyrics = dynamic_cast<UiElement::Lyrics*>(element.get());
797             if (lyrics != nullptr)
798             {
799                 CTinyXml2Helper::GetElementAttributeBool(xml_node, "no_background", lyrics->no_background);
800                 CTinyXml2Helper::GetElementAttributeBool(xml_node, "use_default_font", lyrics->use_default_font);
801                 CTinyXml2Helper::GetElementAttributeInt(xml_node, "font_size", lyrics->font_size);
802                 CTinyXml2Helper::GetElementAttributeBool(xml_node, "show_song_info", lyrics->show_song_info);
803             }
804         }
805         //媒体库列表
806         else if (item_name == "mediaLibItemList")
807         {
808             UiElement::MediaLibItemList* mediaLibItemList = dynamic_cast<UiElement::MediaLibItemList*>(element.get());
809             if (mediaLibItemList != nullptr)
810             {
811                 std::string str_type = CTinyXml2Helper::ElementAttribute(xml_node, "type");
812                 if (str_type == "artist")
813                     mediaLibItemList->type = CMediaClassifier::CT_ARTIST;
814                 else if (str_type == "album")
815                     mediaLibItemList->type = CMediaClassifier::CT_ALBUM;
816                 else if (str_type == "genre")
817                     mediaLibItemList->type = CMediaClassifier::CT_GENRE;
818                 else if (str_type == "year")
819                     mediaLibItemList->type = CMediaClassifier::CT_YEAR;
820                 else if (str_type == "file_type")
821                     mediaLibItemList->type = CMediaClassifier::CT_TYPE;
822                 else if (str_type == "bitrate")
823                     mediaLibItemList->type = CMediaClassifier::CT_BITRATE;
824                 else if (str_type == "rating")
825                     mediaLibItemList->type = CMediaClassifier::CT_RATING;
826             }
827         }
828         //导航栏
829         else if (item_name == "navigationBar")
830         {
831             UiElement::NavigationBar* tab_emelent = dynamic_cast<UiElement::NavigationBar*>(element.get());
832             if (tab_emelent != nullptr)
833             {
834                 std::string str_item_list = CTinyXml2Helper::ElementAttribute(xml_node, "item_list");
835                 CCommon::StringSplit(str_item_list, ',', tab_emelent->tab_list);
836 
837                 std::string str_icon_type = CTinyXml2Helper::ElementAttribute(xml_node, "icon_type");
838                 if (str_icon_type == "icon_and_text")
839                     tab_emelent->icon_type = UiElement::NavigationBar::ICON_AND_TEXT;
840                 else if (str_icon_type == "icon_only")
841                     tab_emelent->icon_type = UiElement::NavigationBar::ICON_ONLY;
842                 else if (str_icon_type == "text_only")
843                     tab_emelent->icon_type = UiElement::NavigationBar::TEXT_ONLY;
844 
845                 std::string str_orientation = CTinyXml2Helper::ElementAttribute(xml_node, "orientation");
846                 if (str_orientation == "horizontal")
847                     tab_emelent->orientation = UiElement::NavigationBar::Horizontal;
848                 else if (str_orientation == "vertical")
849                     tab_emelent->orientation = UiElement::NavigationBar::Vertical;
850 
851                 CTinyXml2Helper::GetElementAttributeInt(xml_node, "item_space", tab_emelent->item_space);
852                 CTinyXml2Helper::GetElementAttributeInt(xml_node, "item_height", tab_emelent->item_height);
853                 CTinyXml2Helper::GetElementAttributeInt(xml_node, "font_size", tab_emelent->font_size);
854             }
855         }
856         else if (item_name == "playlistIndicator")
857         {
858             UiElement::PlaylistIndicator* playlist_indicator = dynamic_cast<UiElement::PlaylistIndicator*>(element.get());
859             if (playlist_indicator != nullptr)
860             {
861                 CTinyXml2Helper::GetElementAttributeInt(xml_node, "font_size", playlist_indicator->font_size);
862             }
863         }
864         else if (item_name == "trackInfo")
865         {
866             UiElement::TrackInfo* track_info = dynamic_cast<UiElement::TrackInfo*>(element.get());
867             if (track_info != nullptr)
868             {
869                 CTinyXml2Helper::GetElementAttributeInt(xml_node, "font_size", track_info->font_size);
870             }
871         }
872         else if (item_name == "placeHolder")
873         {
874             UiElement::PlaceHolder* place_holder = dynamic_cast<UiElement::PlaceHolder*>(element.get());
875             if (place_holder != nullptr)
876             {
877                 CTinyXml2Helper::GetElementAttributeBool(xml_node, "show_when_use_system_titlebar", place_holder->show_when_use_system_titlebar);
878             }
879         }
880 
881         //递归调用此函数创建子节点
882         CTinyXml2Helper::IterateChildNode(xml_node, [&](tinyxml2::XMLElement* xml_child)
883             {
884                 std::shared_ptr<UiElement::Element> ui_child = BuildUiElementFromXmlNode(xml_child);
885                 if (ui_child != nullptr)
886                 {
887                     element->AddChild(ui_child);
888                 }
889             });
890     }
891     return element;
892 }
893 
GetStackElements() const894 const std::vector<std::shared_ptr<UiElement::Element>>& CUserUi::GetStackElements() const
895 {
896     auto iter = m_stack_elements.find(GetCurrentTypeUi().get());
897     if (iter != m_stack_elements.end())
898         return iter->second;
899     static std::vector<std::shared_ptr<UiElement::Element>> vec_empty;
900     return vec_empty;
901 }
902 
SwitchStackElement()903 void CUserUi::SwitchStackElement()
904 {
905     m_draw_data.lyric_rect.SetRectEmpty();
906     auto& stack_elements{ GetStackElements() };
907     if (!stack_elements.empty())
908     {
909         UiElement::StackElement* stack_element = dynamic_cast<UiElement::StackElement*>(stack_elements.front().get());
910         if (stack_element != nullptr)
911             stack_element->SwitchDisplay();
912     }
913 }
914 
915 //////////////////////////////////////////////////////////////////////////////////
916 //////////////////////////////////////////////////////////////////////////////////
917 
UniqueUiIndex(std::vector<std::shared_ptr<CUserUi>> & ui_list)918 void CUserUi::UniqueUiIndex(std::vector<std::shared_ptr<CUserUi>>& ui_list)
919 {
920     for (auto& ui : ui_list)
921     {
922         if (ui != nullptr)
923         {
924             //遍历UI列表,获取当前UI的序号
925             int ui_index = ui->GetUiIndex();
926             //如果还有其他UI的序号和当前UI相同
927             auto ui_matched_index = FindUiByIndex(ui_list, ui_index, ui);
928             if (ui_matched_index != nullptr)
929             {
930                 //将找到的UI的序号设置为最大序号加1
931                 ui_matched_index->SetIndex(GetMaxUiIndex(ui_list) + 1);
932             }
933         }
934     }
935 }
936 
FindUiByIndex(const std::vector<std::shared_ptr<CUserUi>> & ui_list,int ui_index,std::shared_ptr<CUserUi> except)937 std::shared_ptr<CUserUi> CUserUi::FindUiByIndex(const std::vector<std::shared_ptr<CUserUi>>& ui_list, int ui_index, std::shared_ptr<CUserUi> except)
938 {
939     for (const auto& ui : ui_list)
940     {
941         if (ui != nullptr && ui != except && ui->GetUiIndex() == ui_index)
942             return ui;
943     }
944     return nullptr;
945 }
946 
GetMaxUiIndex(const std::vector<std::shared_ptr<CUserUi>> & ui_list)947 int CUserUi::GetMaxUiIndex(const std::vector<std::shared_ptr<CUserUi>>& ui_list)
948 {
949     int index_max{};
950     for (const auto& ui : ui_list)
951     {
952         if (ui != nullptr && ui->GetUiIndex() > index_max)
953             index_max = ui->GetUiIndex();
954     }
955     return index_max;
956 }
957