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