[WASAPI] fix stream types and frequencies enumeration
[xbmc.git] / xbmc / guilib / GUIControlGroup.cpp
blob61142c7b5d93f2c76f4b261853ca1da371a15043
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "GUIControlGroup.h"
11 #include "GUIMessage.h"
12 #include "input/mouse/MouseEvent.h"
14 #include <cassert>
15 #include <utility>
17 using namespace KODI;
19 CGUIControlGroup::CGUIControlGroup()
21 m_defaultControl = 0;
22 m_defaultAlways = false;
23 m_focusedControl = 0;
24 m_renderFocusedLast = false;
25 ControlType = GUICONTROL_GROUP;
28 CGUIControlGroup::CGUIControlGroup(int parentID, int controlID, float posX, float posY, float width, float height)
29 : CGUIControlLookup(parentID, controlID, posX, posY, width, height)
31 m_defaultControl = 0;
32 m_defaultAlways = false;
33 m_focusedControl = 0;
34 m_renderFocusedLast = false;
35 ControlType = GUICONTROL_GROUP;
38 CGUIControlGroup::CGUIControlGroup(const CGUIControlGroup &from)
39 : CGUIControlLookup(from)
41 m_defaultControl = from.m_defaultControl;
42 m_defaultAlways = from.m_defaultAlways;
43 m_renderFocusedLast = from.m_renderFocusedLast;
45 // run through and add our controls
46 for (auto *i : from.m_children)
47 AddControl(i->Clone());
49 // defaults
50 m_focusedControl = 0;
51 ControlType = GUICONTROL_GROUP;
54 CGUIControlGroup::~CGUIControlGroup(void)
56 ClearAll();
59 void CGUIControlGroup::AllocResources()
61 CGUIControl::AllocResources();
62 for (auto *control : m_children)
64 if (!control->IsDynamicallyAllocated())
65 control->AllocResources();
69 void CGUIControlGroup::FreeResources(bool immediately)
71 CGUIControl::FreeResources(immediately);
72 for (auto *control : m_children)
74 control->FreeResources(immediately);
78 void CGUIControlGroup::DynamicResourceAlloc(bool bOnOff)
80 for (auto *control : m_children)
82 control->DynamicResourceAlloc(bOnOff);
86 void CGUIControlGroup::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
88 CPoint pos(GetPosition());
89 CServiceBroker::GetWinSystem()->GetGfxContext().SetOrigin(pos.x, pos.y);
91 CRect rect;
92 for (auto *control : m_children)
94 control->UpdateVisibility(nullptr);
95 unsigned int oldDirty = dirtyregions.size();
96 control->DoProcess(currentTime, dirtyregions);
97 if (control->IsVisible() || (oldDirty != dirtyregions.size())) // visible or dirty (was visible?)
98 rect.Union(control->GetRenderRegion());
101 CServiceBroker::GetWinSystem()->GetGfxContext().RestoreOrigin();
102 CGUIControl::Process(currentTime, dirtyregions);
103 m_renderRegion = rect;
106 void CGUIControlGroup::Render()
108 CPoint pos(GetPosition());
109 CServiceBroker::GetWinSystem()->GetGfxContext().SetOrigin(pos.x, pos.y);
110 CGUIControl *focusedControl = NULL;
111 if (CServiceBroker::GetWinSystem()->GetGfxContext().GetRenderOrder() ==
112 RENDER_ORDER_FRONT_TO_BACK)
114 for (auto it = m_children.rbegin(); it != m_children.rend(); ++it)
116 if (m_renderFocusedLast && (*it)->HasFocus())
117 focusedControl = (*it);
118 else
119 (*it)->DoRender();
122 else
124 for (auto* control : m_children)
126 if (m_renderFocusedLast && control->HasFocus())
127 focusedControl = control;
128 else
129 control->DoRender();
132 if (focusedControl)
133 focusedControl->DoRender();
134 CGUIControl::Render();
135 CServiceBroker::GetWinSystem()->GetGfxContext().RestoreOrigin();
138 void CGUIControlGroup::RenderEx()
140 for (auto *control : m_children)
141 control->RenderEx();
142 CGUIControl::RenderEx();
145 bool CGUIControlGroup::OnAction(const CAction &action)
147 return false;
150 bool CGUIControlGroup::HasFocus() const
152 for (auto *control : m_children)
154 if (control->HasFocus())
155 return true;
157 return false;
160 bool CGUIControlGroup::OnMessage(CGUIMessage& message)
162 switch (message.GetMessage() )
164 case GUI_MSG_ITEM_SELECT:
166 if (message.GetControlId() == GetID())
168 m_focusedControl = message.GetParam1();
169 return true;
171 break;
173 case GUI_MSG_ITEM_SELECTED:
175 if (message.GetControlId() == GetID())
177 message.SetParam1(m_focusedControl);
178 return true;
180 break;
182 case GUI_MSG_FOCUSED:
183 { // a control has been focused
184 m_focusedControl = message.GetControlId();
185 SetFocus(true);
186 // tell our parent thatwe have focus
187 if (m_parentControl)
188 m_parentControl->OnMessage(message);
189 return true;
191 case GUI_MSG_SETFOCUS:
193 // first try our last focused control...
194 if (!m_defaultAlways && m_focusedControl)
196 CGUIControl *control = GetFirstFocusableControl(m_focusedControl);
197 if (control)
199 CGUIMessage msg(GUI_MSG_SETFOCUS, GetParentID(), control->GetID());
200 return control->OnMessage(msg);
203 // ok, no previously focused control, try the default control first
204 if (m_defaultControl)
206 CGUIControl *control = GetFirstFocusableControl(m_defaultControl);
207 if (control)
209 CGUIMessage msg(GUI_MSG_SETFOCUS, GetParentID(), control->GetID());
210 return control->OnMessage(msg);
213 // no success with the default control, so just find one to focus
214 CGUIControl *control = GetFirstFocusableControl(0);
215 if (control)
217 CGUIMessage msg(GUI_MSG_SETFOCUS, GetParentID(), control->GetID());
218 return control->OnMessage(msg);
220 // unsuccessful
221 return false;
222 break;
224 case GUI_MSG_LOSTFOCUS:
226 // set all subcontrols unfocused
227 for (auto *control : m_children)
228 control->SetFocus(false);
229 if (!GetControl(message.GetParam1()))
230 { // we don't have the new id, so unfocus
231 SetFocus(false);
232 if (m_parentControl)
233 m_parentControl->OnMessage(message);
235 return true;
237 break;
238 case GUI_MSG_PAGE_CHANGE:
239 case GUI_MSG_REFRESH_THUMBS:
240 case GUI_MSG_REFRESH_LIST:
241 case GUI_MSG_WINDOW_RESIZE:
242 { // send to all child controls (make sure the target is the control id)
243 for (auto *control : m_children)
245 CGUIMessage msg(message.GetMessage(), message.GetSenderId(), control->GetID(), message.GetParam1());
246 control->OnMessage(msg);
248 return true;
250 break;
251 case GUI_MSG_REFRESH_TIMER:
252 if (!IsVisible() || !IsVisibleFromSkin())
253 return true;
254 break;
256 bool handled(false);
257 //not intended for any specific control, send to all childs and our base handler.
258 if (message.GetControlId() == 0)
260 for (auto *control : m_children)
262 handled |= control->OnMessage(message);
264 return CGUIControl::OnMessage(message) || handled;
266 // if it's intended for us, then so be it
267 if (message.GetControlId() == GetID())
268 return CGUIControl::OnMessage(message);
270 return SendControlMessage(message);
273 bool CGUIControlGroup::SendControlMessage(CGUIMessage &message)
275 IDCollector collector(m_idCollector);
277 CGUIControl *ctrl(GetControl(message.GetControlId(), collector.m_collector));
278 // see if a child matches, and send to the child control if so
279 if (ctrl && ctrl->OnMessage(message))
280 return true;
282 // Unhandled - send to all matching invisible controls as well
283 bool handled(false);
284 for (auto *control : *collector.m_collector)
285 if (control->OnMessage(message))
286 handled = true;
288 return handled;
291 bool CGUIControlGroup::CanFocus() const
293 if (!CGUIControl::CanFocus()) return false;
294 // see if we have any children that can be focused
295 for (auto *control : m_children)
297 if (control->CanFocus())
298 return true;
300 return false;
303 void CGUIControlGroup::AssignDepth()
305 CGUIControl* focusedControl = nullptr;
306 if (m_children.size())
308 for (auto* control : m_children)
310 if (m_renderFocusedLast && control->HasFocus())
311 focusedControl = control;
312 else
313 control->AssignDepth();
316 if (focusedControl)
317 focusedControl->AssignDepth();
320 void CGUIControlGroup::SetInitialVisibility()
322 CGUIControl::SetInitialVisibility();
323 for (auto *control : m_children)
324 control->SetInitialVisibility();
327 void CGUIControlGroup::QueueAnimation(ANIMATION_TYPE animType)
329 CGUIControl::QueueAnimation(animType);
330 // send window level animations to our children as well
331 if (animType == ANIM_TYPE_WINDOW_OPEN || animType == ANIM_TYPE_WINDOW_CLOSE)
333 for (auto *control : m_children)
334 control->QueueAnimation(animType);
338 void CGUIControlGroup::ResetAnimation(ANIMATION_TYPE animType)
340 CGUIControl::ResetAnimation(animType);
341 // send window level animations to our children as well
342 if (animType == ANIM_TYPE_WINDOW_OPEN || animType == ANIM_TYPE_WINDOW_CLOSE)
344 for (auto *control : m_children)
345 control->ResetAnimation(animType);
349 void CGUIControlGroup::ResetAnimations()
350 { // resets all animations, regardless of condition
351 CGUIControl::ResetAnimations();
352 for (auto *control : m_children)
353 control->ResetAnimations();
356 bool CGUIControlGroup::IsAnimating(ANIMATION_TYPE animType)
358 if (CGUIControl::IsAnimating(animType))
359 return true;
361 if (IsVisible())
363 for (auto *control : m_children)
365 if (control->IsAnimating(animType))
366 return true;
369 return false;
372 bool CGUIControlGroup::HasAnimation(ANIMATION_TYPE animType)
374 if (CGUIControl::HasAnimation(animType))
375 return true;
377 if (IsVisible())
379 for (auto *control : m_children)
381 if (control->HasAnimation(animType))
382 return true;
385 return false;
388 EVENT_RESULT CGUIControlGroup::SendMouseEvent(const CPoint& point, const MOUSE::CMouseEvent& event)
390 // transform our position into child coordinates
391 CPoint childPoint(point);
392 m_transform.InverseTransformPosition(childPoint.x, childPoint.y);
394 if (CGUIControl::CanFocus())
396 CPoint pos(GetPosition());
397 // run through our controls in reverse order (so that last rendered is checked first)
398 for (rControls i = m_children.rbegin(); i != m_children.rend(); ++i)
400 CGUIControl *child = *i;
401 EVENT_RESULT ret = child->SendMouseEvent(childPoint - pos, event);
402 if (ret)
403 { // we've handled the action, and/or have focused an item
404 return ret;
407 // none of our children want the event, but we may want it.
408 EVENT_RESULT ret;
409 if (HitTest(childPoint) && (ret = OnMouseEvent(childPoint, event)))
410 return ret;
412 m_focusedControl = 0;
413 return EVENT_RESULT_UNHANDLED;
416 void CGUIControlGroup::UnfocusFromPoint(const CPoint &point)
418 CPoint controlCoords(point);
419 m_transform.InverseTransformPosition(controlCoords.x, controlCoords.y);
420 controlCoords -= GetPosition();
421 for (auto *child : m_children)
423 child->UnfocusFromPoint(controlCoords);
425 CGUIControl::UnfocusFromPoint(point);
428 int CGUIControlGroup::GetFocusedControlID() const
430 if (m_focusedControl) return m_focusedControl;
431 CGUIControl *control = GetFocusedControl();
432 if (control) return control->GetID();
433 return 0;
436 CGUIControl *CGUIControlGroup::GetFocusedControl() const
438 // try lookup first
439 if (m_focusedControl)
441 // we may have multiple controls with same id - we pick first that has focus
442 std::pair<LookupMap::const_iterator, LookupMap::const_iterator> range = GetLookupControls(m_focusedControl);
444 for (LookupMap::const_iterator i = range.first; i != range.second; ++i)
446 if (i->second->HasFocus())
447 return i->second;
451 // if lookup didn't find focused control, iterate m_children to find it
452 for (auto *control : m_children)
454 // Avoid calling HasFocus() on control group as it will (possibly) recursively
455 // traverse entire group tree just to check if there is focused control.
456 // We are recursively traversing it here so no point in doing it twice.
457 CGUIControlGroup *groupControl(dynamic_cast<CGUIControlGroup*>(control));
458 if (groupControl)
460 CGUIControl* focusedControl = groupControl->GetFocusedControl();
461 if (focusedControl)
462 return focusedControl;
464 else if (control->HasFocus())
465 return control;
467 return NULL;
470 // in the case of id == 0, we don't match id
471 CGUIControl *CGUIControlGroup::GetFirstFocusableControl(int id)
473 if (!CanFocus()) return NULL;
474 if (id && id == GetID()) return this; // we're focusable and they want us
475 for (auto *pControl : m_children)
477 CGUIControlGroup *group(dynamic_cast<CGUIControlGroup*>(pControl));
478 if (group)
480 CGUIControl *control = group->GetFirstFocusableControl(id);
481 if (control) return control;
483 if ((!id || pControl->GetID() == id) && pControl->CanFocus())
484 return pControl;
486 return NULL;
489 void CGUIControlGroup::AddControl(CGUIControl *control, int position /* = -1*/)
491 if (!control) return;
492 if (position < 0 || position > (int)m_children.size())
493 position = (int)m_children.size();
494 m_children.insert(m_children.begin() + position, control);
495 control->SetParentControl(this);
496 control->SetControlStats(m_controlStats);
497 control->SetPushUpdates(m_pushedUpdates);
498 AddLookup(control);
499 SetInvalid();
502 bool CGUIControlGroup::InsertControl(CGUIControl *control, const CGUIControl *insertPoint)
504 // find our position
505 for (unsigned int i = 0; i < m_children.size(); i++)
507 CGUIControl *child = m_children[i];
508 CGUIControlGroup *group(dynamic_cast<CGUIControlGroup*>(child));
509 if (group && group->InsertControl(control, insertPoint))
510 return true;
511 else if (child == insertPoint)
513 AddControl(control, i);
514 return true;
517 return false;
520 void CGUIControlGroup::SaveStates(std::vector<CControlState> &states)
522 // save our state, and that of our children
523 states.emplace_back(GetID(), m_focusedControl);
524 for (auto *control : m_children)
525 control->SaveStates(states);
528 // Note: This routine doesn't delete the control. It just removes it from the control list
529 bool CGUIControlGroup::RemoveControl(const CGUIControl *control)
531 for (iControls it = m_children.begin(); it != m_children.end(); ++it)
533 CGUIControl *child = *it;
534 CGUIControlGroup *group(dynamic_cast<CGUIControlGroup*>(child));
535 if (group && group->RemoveControl(control))
536 return true;
537 if (control == child)
539 m_children.erase(it);
540 RemoveLookup(child);
541 SetInvalid();
542 return true;
545 return false;
548 void CGUIControlGroup::ClearAll()
550 // first remove from the lookup table
551 RemoveLookup();
553 // and delete all our children
554 for (auto *control : m_children)
556 delete control;
558 m_focusedControl = 0;
559 m_children.clear();
560 ClearLookup();
561 SetInvalid();
564 #ifdef _DEBUG
565 void CGUIControlGroup::DumpTextureUse()
567 for (auto *control : m_children)
568 control->DumpTextureUse();
570 #endif