[WASAPI] fix stream types and frequencies enumeration
[xbmc.git] / xbmc / guilib / GUIControl.cpp
blob624df972796945471bbd8ee9d00c58a82538d453
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 "GUIControl.h"
11 #include "GUIAction.h"
12 #include "GUIComponent.h"
13 #include "GUIControlProfiler.h"
14 #include "GUIInfoManager.h"
15 #include "GUIMessage.h"
16 #include "GUITexture.h"
17 #include "GUIWindowManager.h"
18 #include "ServiceBroker.h"
19 #include "input/InputManager.h"
20 #include "input/actions/Action.h"
21 #include "input/actions/ActionIDs.h"
22 #include "input/mouse/MouseEvent.h"
23 #include "input/mouse/MouseStat.h"
24 #include "utils/log.h"
26 using namespace KODI;
27 using namespace GUILIB;
29 CGUIControl::CGUIControl()
31 m_hasProcessed = false;
32 m_bHasFocus = false;
33 m_controlID = 0;
34 m_parentID = 0;
35 m_visible = VISIBLE;
36 m_visibleFromSkinCondition = true;
37 m_forceHidden = false;
38 m_enabled = true;
39 m_posX = 0;
40 m_posY = 0;
41 m_width = 0;
42 m_height = 0;
43 ControlType = GUICONTROL_UNKNOWN;
44 m_bInvalidated = true;
45 m_bAllocated=false;
46 m_parentControl = NULL;
47 m_hasCamera = false;
48 m_pushedUpdates = false;
49 m_pulseOnSelect = false;
50 m_controlDirtyState = DIRTY_STATE_CONTROL;
51 m_stereo = 0.0f;
52 m_controlStats = nullptr;
55 CGUIControl::CGUIControl(int parentID, int controlID, float posX, float posY, float width, float height)
56 : m_hitRect(posX, posY, posX + width, posY + height),
57 m_diffuseColor(0xffffffff)
59 m_posX = posX;
60 m_posY = posY;
61 m_width = width;
62 m_height = height;
63 m_bHasFocus = false;
64 m_controlID = controlID;
65 m_parentID = parentID;
66 m_visible = VISIBLE;
67 m_visibleFromSkinCondition = true;
68 m_forceHidden = false;
69 m_enabled = true;
70 ControlType = GUICONTROL_UNKNOWN;
71 m_bInvalidated = true;
72 m_bAllocated=false;
73 m_hasProcessed = false;
74 m_parentControl = NULL;
75 m_hasCamera = false;
76 m_pushedUpdates = false;
77 m_pulseOnSelect = false;
78 m_controlDirtyState = DIRTY_STATE_CONTROL;
79 m_stereo = 0.0f;
80 m_controlStats = nullptr;
83 CGUIControl::CGUIControl(const CGUIControl &) = default;
85 CGUIControl::~CGUIControl(void) = default;
87 void CGUIControl::AllocResources()
89 m_hasProcessed = false;
90 m_bInvalidated = true;
91 m_bAllocated=true;
94 void CGUIControl::FreeResources(bool immediately)
96 if (m_bAllocated)
98 // Reset our animation states - not conditional anims though.
99 // I'm not sure if this is needed for most cases anyway. I believe it's only here
100 // because some windows aren't loaded on demand
101 for (unsigned int i = 0; i < m_animations.size(); i++)
103 CAnimation &anim = m_animations[i];
104 if (anim.GetType() != ANIM_TYPE_CONDITIONAL)
105 anim.ResetAnimation();
107 m_bAllocated=false;
109 m_hasProcessed = false;
112 void CGUIControl::DynamicResourceAlloc(bool bOnOff)
117 // the main processing routine.
118 // 1. animate and set animation transform
119 // 2. if visible, process
120 // 3. reset the animation transform
121 void CGUIControl::DoProcess(unsigned int currentTime, CDirtyRegionList &dirtyregions)
123 CRect dirtyRegion = m_renderRegion;
125 bool changed = (m_controlDirtyState & DIRTY_STATE_CONTROL) != 0 || (m_bInvalidated && IsVisible());
126 m_controlDirtyState = 0;
128 if (Animate(currentTime))
129 MarkDirtyRegion();
131 // if the control changed culling state from true to false, mark it
132 const bool culled = m_transform.alpha <= 0.01f;
133 if (m_isCulled != culled)
135 m_isCulled = false;
136 MarkDirtyRegion();
138 m_isCulled = culled;
140 if (IsVisible())
142 m_cachedTransform = CServiceBroker::GetWinSystem()->GetGfxContext().AddTransform(m_transform);
143 if (m_hasCamera)
144 CServiceBroker::GetWinSystem()->GetGfxContext().SetCameraPosition(m_camera);
146 Process(currentTime, dirtyregions);
147 m_bInvalidated = false;
149 if (dirtyRegion != m_renderRegion)
151 dirtyRegion.Union(m_renderRegion);
152 changed = true;
155 if (m_hasCamera)
156 CServiceBroker::GetWinSystem()->GetGfxContext().RestoreCameraPosition();
157 CServiceBroker::GetWinSystem()->GetGfxContext().RemoveTransform();
160 UpdateControlStats();
162 changed |= (m_controlDirtyState & DIRTY_STATE_CONTROL) != 0;
164 if (changed)
166 dirtyregions.emplace_back(dirtyRegion);
170 void CGUIControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
172 // update our render region
173 m_renderRegion = CServiceBroker::GetWinSystem()->GetGfxContext().GenerateAABB(CalcRenderRegion());
174 m_hasProcessed = true;
177 // the main render routine.
178 // 1. set the animation transform
179 // 2. if visible, paint
180 // 3. reset the animation transform
181 void CGUIControl::DoRender()
183 if (IsControlRenderable() &&
184 !m_renderRegion.Intersects(CServiceBroker::GetWinSystem()->GetGfxContext().GetScissors()))
185 return;
187 if (IsVisible() && !m_isCulled)
189 bool hasStereo =
190 m_stereo != 0.0f &&
191 CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode() !=
192 RENDER_STEREO_MODE_MONO &&
193 CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode() != RENDER_STEREO_MODE_OFF;
195 CServiceBroker::GetWinSystem()->GetGfxContext().SetTransform(m_cachedTransform);
196 if (m_hasCamera)
197 CServiceBroker::GetWinSystem()->GetGfxContext().SetCameraPosition(m_camera);
198 if (hasStereo)
199 CServiceBroker::GetWinSystem()->GetGfxContext().SetStereoFactor(m_stereo);
201 GUIPROFILER_RENDER_BEGIN(this);
203 if (m_hitColor != 0xffffffff)
205 KODI::UTILS::COLOR::Color color =
206 CServiceBroker::GetWinSystem()->GetGfxContext().MergeAlpha(m_hitColor);
207 CGUITexture::DrawQuad(CServiceBroker::GetWinSystem()->GetGfxContext().GenerateAABB(m_hitRect), color);
210 Render();
212 GUIPROFILER_RENDER_END(this);
214 if (hasStereo)
215 CServiceBroker::GetWinSystem()->GetGfxContext().RestoreStereoFactor();
216 if (m_hasCamera)
217 CServiceBroker::GetWinSystem()->GetGfxContext().RestoreCameraPosition();
218 CServiceBroker::GetWinSystem()->GetGfxContext().RemoveTransform();
222 bool CGUIControl::OnAction(const CAction &action)
224 if (HasFocus())
226 switch (action.GetID())
228 case ACTION_MOVE_DOWN:
229 OnDown();
230 return true;
232 case ACTION_MOVE_UP:
233 OnUp();
234 return true;
236 case ACTION_MOVE_LEFT:
237 OnLeft();
238 return true;
240 case ACTION_MOVE_RIGHT:
241 OnRight();
242 return true;
244 case ACTION_SHOW_INFO:
245 return OnInfo();
247 case ACTION_NAV_BACK:
248 return OnBack();
250 case ACTION_NEXT_CONTROL:
251 OnNextControl();
252 return true;
254 case ACTION_PREV_CONTROL:
255 OnPrevControl();
256 return true;
259 return false;
262 bool CGUIControl::Navigate(int direction) const
264 if (HasFocus())
266 CGUIMessage msg(GUI_MSG_MOVE, GetParentID(), GetID(), direction);
267 return SendWindowMessage(msg);
269 return false;
272 // Movement controls (derived classes can override)
273 void CGUIControl::OnUp()
275 Navigate(ACTION_MOVE_UP);
278 void CGUIControl::OnDown()
280 Navigate(ACTION_MOVE_DOWN);
283 void CGUIControl::OnLeft()
285 Navigate(ACTION_MOVE_LEFT);
288 void CGUIControl::OnRight()
290 Navigate(ACTION_MOVE_RIGHT);
293 bool CGUIControl::OnBack()
295 return Navigate(ACTION_NAV_BACK);
298 bool CGUIControl::OnInfo()
300 CGUIAction action = GetAction(ACTION_SHOW_INFO);
301 if (action.HasAnyActions())
302 return action.ExecuteActions(GetID(), GetParentID());
303 return false;
306 void CGUIControl::OnNextControl()
308 Navigate(ACTION_NEXT_CONTROL);
311 void CGUIControl::OnPrevControl()
313 Navigate(ACTION_PREV_CONTROL);
316 bool CGUIControl::SendWindowMessage(CGUIMessage &message) const
318 CGUIWindow *pWindow = CServiceBroker::GetGUI()->GetWindowManager().GetWindow(GetParentID());
319 if (pWindow)
320 return pWindow->OnMessage(message);
321 return CServiceBroker::GetGUI()->GetWindowManager().SendMessage(message);
324 int CGUIControl::GetID(void) const
326 return m_controlID;
330 int CGUIControl::GetParentID(void) const
332 return m_parentID;
335 bool CGUIControl::HasFocus(void) const
337 return m_bHasFocus;
340 void CGUIControl::SetFocus(bool focus)
342 if (m_bHasFocus && !focus)
343 QueueAnimation(ANIM_TYPE_UNFOCUS);
344 else if (!m_bHasFocus && focus)
345 QueueAnimation(ANIM_TYPE_FOCUS);
346 m_bHasFocus = focus;
349 bool CGUIControl::OnMessage(CGUIMessage& message)
351 if ( message.GetControlId() == GetID() )
353 switch (message.GetMessage() )
355 case GUI_MSG_SETFOCUS:
356 // if control is disabled then move 2 the next control
357 if ( !CanFocus() )
359 CLog::Log(LOGERROR,
360 "Control {} in window {} has been asked to focus, "
361 "but it can't",
362 GetID(), GetParentID());
363 return false;
365 SetFocus(true);
367 // inform our parent window that this has happened
368 CGUIMessage message(GUI_MSG_FOCUSED, GetParentID(), GetID());
369 if (m_parentControl)
370 m_parentControl->OnMessage(message);
372 return true;
373 break;
375 case GUI_MSG_LOSTFOCUS:
377 SetFocus(false);
378 // and tell our parent so it can unfocus
379 if (m_parentControl)
380 m_parentControl->OnMessage(message);
381 return true;
383 break;
385 case GUI_MSG_VISIBLE:
386 SetVisible(true, true);
387 return true;
388 break;
390 case GUI_MSG_HIDDEN:
391 SetVisible(false);
392 return true;
394 // Note that the skin <enable> tag will override these messages
395 case GUI_MSG_ENABLED:
396 SetEnabled(true);
397 return true;
399 case GUI_MSG_DISABLED:
400 SetEnabled(false);
401 return true;
403 case GUI_MSG_WINDOW_RESIZE:
404 // invalidate controls to get them to recalculate sizing information
405 SetInvalid();
406 return true;
409 return false;
412 bool CGUIControl::CanFocus() const
414 if (!IsVisible() && !m_allowHiddenFocus) return false;
415 if (IsDisabled()) return false;
416 return true;
419 bool CGUIControl::IsVisible() const
421 if (m_forceHidden)
422 return false;
423 return m_visible == VISIBLE;
426 bool CGUIControl::IsDisabled() const
428 return !m_enabled;
431 void CGUIControl::SetEnabled(bool bEnable)
433 if (bEnable != m_enabled)
435 m_enabled = bEnable;
436 SetInvalid();
440 void CGUIControl::SetEnableCondition(const std::string &expression)
442 if (expression == "true")
443 m_enabled = true;
444 else if (expression == "false")
445 m_enabled = false;
446 else
447 m_enableCondition = CServiceBroker::GetGUI()->GetInfoManager().Register(expression, GetParentID());
450 void CGUIControl::SetPosition(float posX, float posY)
452 if ((m_posX != posX) || (m_posY != posY))
454 MarkDirtyRegion();
456 m_hitRect += CPoint(posX - m_posX, posY - m_posY);
457 m_posX = posX;
458 m_posY = posY;
460 SetInvalid();
464 bool CGUIControl::SetColorDiffuse(const GUIINFO::CGUIInfoColor &color)
466 bool changed = m_diffuseColor != color;
467 m_diffuseColor = color;
468 return changed;
471 float CGUIControl::GetXPosition() const
473 return m_posX;
476 float CGUIControl::GetYPosition() const
478 return m_posY;
481 float CGUIControl::GetWidth() const
483 return m_width;
486 float CGUIControl::GetHeight() const
488 return m_height;
491 void CGUIControl::AssignDepth()
493 m_cachedTransform.depth = CServiceBroker::GetWinSystem()->GetGfxContext().GetDepth();
496 void CGUIControl::MarkDirtyRegion(const unsigned int dirtyState)
498 // if the control is culled, bail
499 if (dirtyState == DIRTY_STATE_CONTROL && m_isCulled)
500 return;
501 if (!m_controlDirtyState && m_parentControl)
502 m_parentControl->MarkDirtyRegion(DIRTY_STATE_CHILD);
504 m_controlDirtyState |= dirtyState;
507 CRect CGUIControl::CalcRenderRegion() const
509 CPoint tl(GetXPosition(), GetYPosition());
510 CPoint br(tl.x + GetWidth(), tl.y + GetHeight());
512 return CRect(tl.x, tl.y, br.x, br.y);
515 void CGUIControl::SetActions(const ActionMap &actions)
517 m_actions = actions;
520 void CGUIControl::SetAction(int actionID, const CGUIAction &action, bool replace /*= true*/)
522 ActionMap::iterator i = m_actions.find(actionID);
523 if (i == m_actions.end() || !i->second.HasAnyActions() || replace)
524 m_actions[actionID] = action;
527 void CGUIControl::SetWidth(float width)
529 if (m_width != width)
531 MarkDirtyRegion();
532 m_width = width;
533 m_hitRect.x2 = m_hitRect.x1 + width;
534 SetInvalid();
538 void CGUIControl::SetHeight(float height)
540 if (m_height != height)
542 MarkDirtyRegion();
543 m_height = height;
544 m_hitRect.y2 = m_hitRect.y1 + height;
545 SetInvalid();
549 void CGUIControl::SetVisible(bool bVisible, bool setVisState)
551 if (bVisible && setVisState)
552 { //! @todo currently we only update m_visible from GUI_MSG_VISIBLE (SET_CONTROL_VISIBLE)
553 //! otherwise we just set m_forceHidden
554 GUIVISIBLE visible;
555 if (m_visibleCondition)
556 visible = m_visibleCondition->Get(INFO::DEFAULT_CONTEXT) ? VISIBLE : HIDDEN;
557 else
558 visible = VISIBLE;
559 if (visible != m_visible)
561 m_visible = visible;
562 SetInvalid();
565 if (m_forceHidden == bVisible)
567 m_forceHidden = !bVisible;
568 SetInvalid();
569 if (m_forceHidden)
570 MarkDirtyRegion();
572 if (m_forceHidden)
573 { // reset any visible animations that are in process
574 if (IsAnimating(ANIM_TYPE_VISIBLE))
576 // CLog::Log(LOGDEBUG, "Resetting visible animation on control {} (we are {})", m_controlID, m_visible ? "visible" : "hidden");
577 CAnimation *visibleAnim = GetAnimation(ANIM_TYPE_VISIBLE);
578 if (visibleAnim) visibleAnim->ResetAnimation();
583 bool CGUIControl::HitTest(const CPoint &point) const
585 return m_hitRect.PtInRect(point);
588 EVENT_RESULT CGUIControl::SendMouseEvent(const CPoint& point, const MOUSE::CMouseEvent& event)
590 CPoint childPoint(point);
591 m_transform.InverseTransformPosition(childPoint.x, childPoint.y);
592 if (!CanFocusFromPoint(childPoint))
593 return EVENT_RESULT_UNHANDLED;
595 bool handled = event.m_id != ACTION_MOUSE_MOVE || OnMouseOver(childPoint);
596 EVENT_RESULT ret = OnMouseEvent(childPoint, event);
597 if (ret)
598 return ret;
599 return (handled && (event.m_id == ACTION_MOUSE_MOVE)) ? EVENT_RESULT_HANDLED : EVENT_RESULT_UNHANDLED;
602 // override this function to implement custom mouse behaviour
603 bool CGUIControl::OnMouseOver(const CPoint &point)
605 if (CServiceBroker::GetInputManager().GetMouseState() != MOUSE_STATE_DRAG)
606 CServiceBroker::GetInputManager().SetMouseState(MOUSE_STATE_FOCUS);
607 if (!CanFocus()) return false;
608 if (!HasFocus())
610 CGUIMessage msg(GUI_MSG_SETFOCUS, GetParentID(), GetID());
611 OnMessage(msg);
613 return true;
616 void CGUIControl::UpdateVisibility(const CGUIListItem *item)
618 if (m_visibleCondition)
620 bool bWasVisible = m_visibleFromSkinCondition;
621 m_visibleFromSkinCondition = m_visibleCondition->Get(INFO::DEFAULT_CONTEXT, item);
622 if (!bWasVisible && m_visibleFromSkinCondition)
623 { // automatic change of visibility - queue the in effect
624 // CLog::Log(LOGDEBUG, "Visibility changed to visible for control id {}", m_controlID);
625 QueueAnimation(ANIM_TYPE_VISIBLE);
627 else if (bWasVisible && !m_visibleFromSkinCondition)
628 { // automatic change of visibility - do the out effect
629 // CLog::Log(LOGDEBUG, "Visibility changed to hidden for control id {}", m_controlID);
630 QueueAnimation(ANIM_TYPE_HIDDEN);
633 // check for conditional animations
634 for (unsigned int i = 0; i < m_animations.size(); i++)
636 CAnimation &anim = m_animations[i];
637 if (anim.GetType() == ANIM_TYPE_CONDITIONAL)
638 anim.UpdateCondition(item);
640 // and check for conditional enabling - note this overrides SetEnabled() from the code currently
641 // this may need to be reviewed at a later date
642 bool enabled = m_enabled;
643 if (m_enableCondition)
644 m_enabled = m_enableCondition->Get(INFO::DEFAULT_CONTEXT, item);
646 if (m_enabled != enabled)
647 MarkDirtyRegion();
649 m_allowHiddenFocus.Update(INFO::DEFAULT_CONTEXT, item);
650 if (UpdateColors(item))
651 MarkDirtyRegion();
652 // and finally, update our control information (if not pushed)
653 if (!m_pushedUpdates)
654 UpdateInfo(item);
657 bool CGUIControl::UpdateColors(const CGUIListItem* item)
659 return m_diffuseColor.Update(item);
662 void CGUIControl::SetInitialVisibility()
664 if (m_visibleCondition)
666 m_visibleFromSkinCondition = m_visibleCondition->Get(INFO::DEFAULT_CONTEXT);
667 m_visible = m_visibleFromSkinCondition ? VISIBLE : HIDDEN;
668 // CLog::Log(LOGDEBUG, "Set initial visibility for control {}: {}", m_controlID, m_visible == VISIBLE ? "visible" : "hidden");
670 else if (m_visible == DELAYED)
671 m_visible = VISIBLE;
672 // and handle animation conditions as well
673 for (unsigned int i = 0; i < m_animations.size(); i++)
675 CAnimation &anim = m_animations[i];
676 if (anim.GetType() == ANIM_TYPE_CONDITIONAL)
677 anim.SetInitialCondition();
679 // and check for conditional enabling - note this overrides SetEnabled() from the code currently
680 // this may need to be reviewed at a later date
681 if (m_enableCondition)
682 m_enabled = m_enableCondition->Get(INFO::DEFAULT_CONTEXT);
683 m_allowHiddenFocus.Update(INFO::DEFAULT_CONTEXT);
684 UpdateColors(nullptr);
686 MarkDirtyRegion();
689 void CGUIControl::SetVisibleCondition(const std::string &expression, const std::string &allowHiddenFocus)
691 if (expression == "true")
692 m_visible = VISIBLE;
693 else if (expression == "false")
694 m_visible = HIDDEN;
695 else // register with the infomanager for updates
696 m_visibleCondition = CServiceBroker::GetGUI()->GetInfoManager().Register(expression, GetParentID());
697 m_allowHiddenFocus.Parse(allowHiddenFocus, GetParentID());
700 void CGUIControl::SetAnimations(const std::vector<CAnimation> &animations)
702 m_animations = animations;
703 MarkDirtyRegion();
706 void CGUIControl::ResetAnimation(ANIMATION_TYPE type)
708 MarkDirtyRegion();
710 for (unsigned int i = 0; i < m_animations.size(); i++)
712 if (m_animations[i].GetType() == type)
713 m_animations[i].ResetAnimation();
717 void CGUIControl::ResetAnimations()
719 MarkDirtyRegion();
721 for (unsigned int i = 0; i < m_animations.size(); i++)
722 m_animations[i].ResetAnimation();
724 MarkDirtyRegion();
727 bool CGUIControl::CheckAnimation(ANIMATION_TYPE animType)
729 // rule out the animations we shouldn't perform
730 if (!IsVisible() || !HasProcessed())
731 { // hidden or never processed - don't allow exit or entry animations for this control
732 if (animType == ANIM_TYPE_WINDOW_CLOSE)
733 { // could be animating a (delayed) window open anim, so reset it
734 ResetAnimation(ANIM_TYPE_WINDOW_OPEN);
735 return false;
738 if (!IsVisible())
739 { // hidden - only allow hidden anims if we're animating a visible anim
740 if (animType == ANIM_TYPE_HIDDEN && !IsAnimating(ANIM_TYPE_VISIBLE))
742 // update states to force it hidden
743 UpdateStates(animType, ANIM_PROCESS_NORMAL, ANIM_STATE_APPLIED);
744 return false;
746 if (animType == ANIM_TYPE_WINDOW_OPEN)
747 return false;
749 return true;
752 void CGUIControl::QueueAnimation(ANIMATION_TYPE animType)
754 if (!CheckAnimation(animType))
755 return;
757 MarkDirtyRegion();
759 CAnimation *reverseAnim = GetAnimation((ANIMATION_TYPE)-animType, false);
760 CAnimation *forwardAnim = GetAnimation(animType);
761 // we first check whether the reverse animation is in progress (and reverse it)
762 // then we check for the normal animation, and queue it
763 if (reverseAnim && reverseAnim->IsReversible() && (reverseAnim->GetState() == ANIM_STATE_IN_PROCESS || reverseAnim->GetState() == ANIM_STATE_DELAYED))
765 reverseAnim->QueueAnimation(ANIM_PROCESS_REVERSE);
766 if (forwardAnim) forwardAnim->ResetAnimation();
768 else if (forwardAnim)
770 forwardAnim->QueueAnimation(ANIM_PROCESS_NORMAL);
771 if (reverseAnim) reverseAnim->ResetAnimation();
773 else
774 { // hidden and visible animations delay the change of state. If there is no animations
775 // to perform, then we should just change the state straightaway
776 if (reverseAnim) reverseAnim->ResetAnimation();
777 UpdateStates(animType, ANIM_PROCESS_NORMAL, ANIM_STATE_APPLIED);
781 CAnimation *CGUIControl::GetAnimation(ANIMATION_TYPE type, bool checkConditions /* = true */)
783 for (unsigned int i = 0; i < m_animations.size(); i++)
785 CAnimation &anim = m_animations[i];
786 if (anim.GetType() == type)
788 if (!checkConditions || anim.CheckCondition())
789 return &anim;
792 return NULL;
795 bool CGUIControl::HasAnimation(ANIMATION_TYPE type)
797 return (NULL != GetAnimation(type, true));
800 void CGUIControl::UpdateStates(ANIMATION_TYPE type, ANIMATION_PROCESS currentProcess, ANIMATION_STATE currentState)
802 // Make sure control is hidden or visible at the appropriate times
803 // while processing a visible or hidden animation it needs to be visible,
804 // but when finished a hidden operation it needs to be hidden
805 if (type == ANIM_TYPE_VISIBLE)
807 if (currentProcess == ANIM_PROCESS_REVERSE)
809 if (currentState == ANIM_STATE_APPLIED)
810 m_visible = HIDDEN;
812 else if (currentProcess == ANIM_PROCESS_NORMAL)
814 if (currentState == ANIM_STATE_DELAYED)
815 m_visible = DELAYED;
816 else
817 m_visible = m_visibleFromSkinCondition ? VISIBLE : HIDDEN;
820 else if (type == ANIM_TYPE_HIDDEN)
822 if (currentProcess == ANIM_PROCESS_NORMAL) // a hide animation
824 if (currentState == ANIM_STATE_APPLIED)
825 m_visible = HIDDEN; // finished
826 else
827 m_visible = VISIBLE; // have to be visible until we are finished
829 else if (currentProcess == ANIM_PROCESS_REVERSE) // a visible animation
830 { // no delay involved here - just make sure it's visible
831 m_visible = m_visibleFromSkinCondition ? VISIBLE : HIDDEN;
834 else if (type == ANIM_TYPE_WINDOW_OPEN)
836 if (currentProcess == ANIM_PROCESS_NORMAL)
838 if (currentState == ANIM_STATE_DELAYED)
839 m_visible = DELAYED; // delayed
840 else
841 m_visible = m_visibleFromSkinCondition ? VISIBLE : HIDDEN;
844 else if (type == ANIM_TYPE_FOCUS)
846 // call the focus function if we have finished a focus animation
847 // (buttons can "click" on focus)
848 if (currentProcess == ANIM_PROCESS_NORMAL && currentState == ANIM_STATE_APPLIED)
849 OnFocus();
851 else if (type == ANIM_TYPE_UNFOCUS)
853 // call the unfocus function if we have finished a focus animation
854 // (buttons can "click" on focus)
855 if (currentProcess == ANIM_PROCESS_NORMAL && currentState == ANIM_STATE_APPLIED)
856 OnUnFocus();
860 bool CGUIControl::Animate(unsigned int currentTime)
862 // check visible state outside the loop, as it could change
863 GUIVISIBLE visible = m_visible;
865 m_transform.Reset();
866 bool changed = false;
868 CPoint center(GetXPosition() + GetWidth() * 0.5f, GetYPosition() + GetHeight() * 0.5f);
869 for (unsigned int i = 0; i < m_animations.size(); i++)
871 CAnimation &anim = m_animations[i];
872 anim.Animate(currentTime, HasProcessed() || visible == DELAYED);
873 // Update the control states (such as visibility)
874 UpdateStates(anim.GetType(), anim.GetProcess(), anim.GetState());
875 // and render the animation effect
876 changed |= (anim.GetProcess() != ANIM_PROCESS_NONE);
877 anim.RenderAnimation(m_transform, center);
879 // debug stuff
880 //if (anim.GetProcess() != ANIM_PROCESS_NONE && IsVisible())
882 // CLog::Log(LOGDEBUG, "Animating control {}", m_controlID);
886 return changed;
889 bool CGUIControl::IsAnimating(ANIMATION_TYPE animType)
891 for (unsigned int i = 0; i < m_animations.size(); i++)
893 CAnimation &anim = m_animations[i];
894 if (anim.GetType() == animType)
896 if (anim.GetQueuedProcess() == ANIM_PROCESS_NORMAL)
897 return true;
898 if (anim.GetProcess() == ANIM_PROCESS_NORMAL)
899 return true;
901 else if (anim.GetType() == -animType)
903 if (anim.GetQueuedProcess() == ANIM_PROCESS_REVERSE)
904 return true;
905 if (anim.GetProcess() == ANIM_PROCESS_REVERSE)
906 return true;
909 return false;
912 CGUIAction CGUIControl::GetAction(int actionID) const
914 ActionMap::const_iterator i = m_actions.find(actionID);
915 if (i != m_actions.end())
916 return i->second;
917 return CGUIAction();
920 bool CGUIControl::CanFocusFromPoint(const CPoint &point) const
922 return CanFocus() && HitTest(point);
925 void CGUIControl::UnfocusFromPoint(const CPoint &point)
927 if (HasFocus())
929 CPoint controlPoint(point);
930 m_transform.InverseTransformPosition(controlPoint.x, controlPoint.y);
931 if (!HitTest(controlPoint))
933 SetFocus(false);
935 // and tell our parent so it can unfocus
936 if (m_parentControl)
938 CGUIMessage msgLostFocus(GUI_MSG_LOSTFOCUS, GetID(), GetID());
939 m_parentControl->OnMessage(msgLostFocus);
945 void CGUIControl::SaveStates(std::vector<CControlState> &states)
947 // empty for now - do nothing with the majority of controls
950 CGUIControl *CGUIControl::GetControl(int iControl, std::vector<CGUIControl*> *idCollector)
952 return (iControl == m_controlID) ? this : nullptr;
956 void CGUIControl::UpdateControlStats()
958 if (m_controlStats)
960 ++m_controlStats->nCountTotal;
961 if (IsVisible() && IsVisibleFromSkin())
962 ++m_controlStats->nCountVisible;
966 bool CGUIControl::IsControlRenderable()
968 switch (ControlType)
970 case GUICONTAINER_EPGGRID:
971 case GUICONTAINER_FIXEDLIST:
972 case GUICONTAINER_LIST:
973 case GUICONTAINER_PANEL:
974 case GUICONTAINER_WRAPLIST:
975 case GUICONTROL_GROUP:
976 case GUICONTROL_GROUPLIST:
977 case GUICONTROL_LISTGROUP:
978 return false;
979 default:
980 return true;
984 void CGUIControl::SetHitRect(const CRect& rect, const KODI::UTILS::COLOR::Color& color)
986 m_hitRect = rect;
987 m_hitColor = color;
990 void CGUIControl::SetCamera(const CPoint &camera)
992 m_camera = camera;
993 m_hasCamera = true;
996 CPoint CGUIControl::GetRenderPosition() const
998 float z = 0;
999 CPoint point(GetPosition());
1000 m_transform.TransformPosition(point.x, point.y, z);
1001 if (m_parentControl)
1002 point += m_parentControl->GetRenderPosition();
1003 return point;
1006 void CGUIControl::SetStereoFactor(const float &factor)
1008 m_stereo = factor;