fixed: Video OSD animations weren't reset on close/reopen.
[xbmc:xbmc-antiquated.git] / guilib / GUIControl.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "include.h"
23 #include "GUIControl.h"
24
25 #include "utils/GUIInfoManager.h"
26 #include "LocalizeStrings.h"
27 #include "GUIWindowManager.h"
28
29 using namespace std;
30
31 CGUIControl::CGUIControl()
32 {
33   m_hasRendered = false;
34   m_bHasFocus = false;
35   m_dwControlID = 0;
36   m_dwParentID = 0;
37   m_visible = VISIBLE;
38   m_visibleFromSkinCondition = true;
39   m_forceHidden = false;
40   m_visibleCondition = 0;
41   m_enableCondition = 0;
42   m_enabled = true;
43   m_diffuseColor = 0xffffffff;
44   m_posX = 0;
45   m_posY = 0;
46   m_dwControlLeft = 0;
47   m_dwControlRight = 0;
48   m_dwControlUp = 0;
49   m_dwControlDown = 0;
50   ControlType = GUICONTROL_UNKNOWN;
51   m_bInvalidated = true;
52   m_bAllocated=false;
53   m_parentControl = NULL;
54   m_hasCamera = false;
55 }
56
57 CGUIControl::CGUIControl(DWORD dwParentID, DWORD dwControlId, float posX, float posY, float width, float height)
58 : m_hitRect(posX, posY, posX + width, posY + height)
59 {
60   m_posX = posX;
61   m_posY = posY;
62   m_width = width;
63   m_height = height;
64   m_bHasFocus = false;
65   m_dwControlID = dwControlId;
66   m_dwParentID = dwParentID;
67   m_visible = VISIBLE;
68   m_visibleFromSkinCondition = true;
69   m_diffuseColor = 0xffffffff;
70   m_forceHidden = false;
71   m_visibleCondition = 0;
72   m_enableCondition = 0;
73   m_enabled = true;
74   m_dwControlLeft = 0;
75   m_dwControlRight = 0;
76   m_dwControlUp = 0;
77   m_dwControlDown = 0;
78   ControlType = GUICONTROL_UNKNOWN;
79   m_bInvalidated = true;
80   m_bAllocated=false;
81   m_hasRendered = false;
82   m_parentControl = NULL;
83   m_hasCamera = false;
84 }
85
86
87 CGUIControl::~CGUIControl(void)
88 {
89
90 }
91
92 void CGUIControl::AllocResources()
93 {
94   m_hasRendered = false;
95   m_bInvalidated = true;
96   m_bAllocated=true;
97 }
98
99 void CGUIControl::FreeResources()
100 {
101   if (m_bAllocated)
102   {
103     // Reset our animation states - not conditional anims though.
104     // I'm not sure if this is needed for most cases anyway.  I believe it's only here
105     // because some windows aren't loaded on demand
106     for (unsigned int i = 0; i < m_animations.size(); i++)
107     {
108       CAnimation &anim = m_animations[i];
109       if (anim.GetType() != ANIM_TYPE_CONDITIONAL)
110         anim.ResetAnimation();
111     }
112     m_bAllocated=false;
113   }
114   m_hasRendered = false;
115
116
117 bool CGUIControl::IsAllocated() const
118 {
119   return m_bAllocated;
120 }
121
122 void CGUIControl::DynamicResourceAlloc(bool bOnOff)
123 {
124
125 }
126
127 // the main render routine.
128 // 1. animate and set the animation transform
129 // 2. if visible, paint
130 // 3. reset the animation transform
131 void CGUIControl::DoRender(DWORD currentTime)
132 {
133   Animate(currentTime);
134   if (m_hasCamera)
135     g_graphicsContext.SetCameraPosition(m_camera);
136   if (IsVisible())
137     Render();
138   if (m_hasCamera)
139     g_graphicsContext.RestoreCameraPosition();
140   g_graphicsContext.RemoveTransform();
141 }
142
143 void CGUIControl::Render()
144 {
145   m_bInvalidated = false;
146   m_hasRendered = true;
147 }
148
149 bool CGUIControl::OnAction(const CAction &action)
150 {
151   switch (action.wID)
152   {
153   case ACTION_MOVE_DOWN:
154     if (!HasFocus()) return false;
155     OnDown();
156     return true;
157     break;
158
159   case ACTION_MOVE_UP:
160     if (!HasFocus()) return false;
161     OnUp();
162     return true;
163     break;
164
165   case ACTION_MOVE_LEFT:
166     if (!HasFocus()) return false;
167     OnLeft();
168     return true;
169     break;
170
171   case ACTION_MOVE_RIGHT:
172     if (!HasFocus()) return false;
173     OnRight();
174     return true;
175     break;
176   }
177   return false;
178 }
179
180 // Movement controls (derived classes can override)
181 void CGUIControl::OnUp()
182 {
183   if (HasFocus())
184   {
185     if (m_upActions.size())
186       ExecuteActions(m_upActions);
187     else if (m_dwControlID != m_dwControlUp)
188     {
189       // Send a message to the window with the sender set as the window
190       CGUIMessage msg(GUI_MSG_MOVE, GetParentID(), GetID(), ACTION_MOVE_UP);
191       SendWindowMessage(msg);
192     }
193   }
194 }
195
196 void CGUIControl::OnDown()
197 {
198   if (HasFocus())
199   {
200     if (m_downActions.size())
201       ExecuteActions(m_downActions);
202     else if (m_dwControlID != m_dwControlDown)
203     {
204       // Send a message to the window with the sender set as the window
205       CGUIMessage msg(GUI_MSG_MOVE, GetParentID(), GetID(), ACTION_MOVE_DOWN);
206       SendWindowMessage(msg);
207     }
208   }
209 }
210
211 void CGUIControl::OnLeft()
212 {
213   if (HasFocus())
214   {
215     if (m_leftActions.size())
216       ExecuteActions(m_leftActions);
217     else if (m_dwControlID != m_dwControlLeft)
218     {
219       // Send a message to the window with the sender set as the window
220       CGUIMessage msg(GUI_MSG_MOVE, GetParentID(), GetID(), ACTION_MOVE_LEFT);
221       SendWindowMessage(msg);
222     }
223   }
224 }
225
226 void CGUIControl::OnRight()
227 {
228   if (HasFocus())
229   {
230     if (m_rightActions.size())
231       ExecuteActions(m_rightActions);
232     else if (m_dwControlID != m_dwControlRight)
233     {
234       // Send a message to the window with the sender set as the window
235       CGUIMessage msg(GUI_MSG_MOVE, GetParentID(), GetID(), ACTION_MOVE_RIGHT);
236       SendWindowMessage(msg);
237     }
238   }
239 }
240
241 bool CGUIControl::SendWindowMessage(CGUIMessage &message)
242 {
243   CGUIWindow *pWindow = m_gWindowManager.GetWindow(GetParentID());
244   if (pWindow)
245     return pWindow->OnMessage(message);
246   return g_graphicsContext.SendMessage(message);
247 }
248
249 DWORD CGUIControl::GetID(void) const
250 {
251   return m_dwControlID;
252 }
253
254
255 DWORD CGUIControl::GetParentID(void) const
256 {
257   return m_dwParentID;
258 }
259
260 bool CGUIControl::HasFocus(void) const
261 {
262   return m_bHasFocus;
263 }
264
265 void CGUIControl::SetFocus(bool focus)
266 {
267   if (m_bHasFocus && !focus)
268     QueueAnimation(ANIM_TYPE_UNFOCUS);
269   else if (!m_bHasFocus && focus)
270     QueueAnimation(ANIM_TYPE_FOCUS);
271   m_bHasFocus = focus;
272 }
273
274 bool CGUIControl::OnMessage(CGUIMessage& message)
275 {
276   if ( message.GetControlId() == GetID() )
277   {
278     switch (message.GetMessage() )
279     {
280     case GUI_MSG_SETFOCUS:
281       // if control is disabled then move 2 the next control
282       if ( !CanFocus() )
283       {
284         CLog::Log(LOGERROR, "Control %lu in window %lu has been asked to focus, but it can't", GetID(), GetParentID());
285         return false;
286       }
287       SetFocus(true);
288       {
289         // inform our parent window that this has happened
290         CGUIMessage message(GUI_MSG_FOCUSED, GetParentID(), GetID());
291         if (m_parentControl)
292           m_parentControl->OnMessage(message);
293         else
294         SendWindowMessage(message);
295       }
296       return true;
297       break;
298
299     case GUI_MSG_LOSTFOCUS:
300       {
301         SetFocus(false);
302         // and tell our parent so it can unfocus
303         if (m_parentControl)
304           m_parentControl->OnMessage(message);
305         return true;
306       }
307       break;
308
309     case GUI_MSG_VISIBLE:
310       if (m_visibleCondition)
311         m_visible = g_infoManager.GetBool(m_visibleCondition, m_dwParentID) ? VISIBLE : HIDDEN;
312       else
313         m_visible = VISIBLE;
314       m_forceHidden = false;
315       return true;
316       break;
317
318     case GUI_MSG_HIDDEN:
319       m_forceHidden = true;
320       // reset any visible animations that are in process
321       if (IsAnimating(ANIM_TYPE_VISIBLE))
322       {
323 //        CLog::DebugLog("Resetting visible animation on control %i (we are %s)", m_dwControlID, m_visible ? "visible" : "hidden");
324         CAnimation *visibleAnim = GetAnimation(ANIM_TYPE_VISIBLE);
325         if (visibleAnim) visibleAnim->ResetAnimation();
326       }
327       return true;
328
329       // Note that the skin <enable> tag will override these messages
330     case GUI_MSG_ENABLED:
331       SetEnabled(true);
332       return true;
333
334     case GUI_MSG_DISABLED:
335       SetEnabled(false);
336       return true;
337     }
338   }
339   return false;
340 }
341
342 bool CGUIControl::CanFocus() const
343 {
344   if (!IsVisible() && !m_allowHiddenFocus) return false;
345   if (IsDisabled()) return false;
346   return true;
347 }
348
349 bool CGUIControl::IsVisible() const
350 {
351   if (m_forceHidden) return false;
352   return m_visible == VISIBLE;
353 }
354
355 bool CGUIControl::IsDisabled() const
356 {
357   return !m_enabled;
358 }
359
360 void CGUIControl::SetEnabled(bool bEnable)
361 {
362   m_enabled = bEnable;
363 }
364
365 void CGUIControl::SetEnableCondition(int condition)
366 {
367   m_enableCondition = condition;
368 }
369
370 void CGUIControl::SetPosition(float posX, float posY)
371 {
372   if ((m_posX != posX) || (m_posY != posY))
373   {
374     m_hitRect += CPoint(posX - m_posX, posY - m_posY);
375     m_posX = posX;
376     m_posY = posY;
377     Update();
378   }
379 }
380
381 void CGUIControl::SetColorDiffuse(const CGUIInfoColor &color)
382 {
383   m_diffuseColor = color;
384 }
385
386 float CGUIControl::GetXPosition() const
387 {
388   return m_posX;
389 }
390
391 float CGUIControl::GetYPosition() const
392 {
393   return m_posY;
394 }
395
396 float CGUIControl::GetWidth() const
397 {
398   return m_width;
399 }
400
401 float CGUIControl::GetHeight() const
402 {
403   return m_height;
404 }
405
406 void CGUIControl::SetNavigation(DWORD dwUp, DWORD dwDown, DWORD dwLeft, DWORD dwRight)
407 {
408   m_dwControlUp = dwUp;
409   m_dwControlDown = dwDown;
410   m_dwControlLeft = dwLeft;
411   m_dwControlRight = dwRight;
412 }
413
414 void CGUIControl::SetNavigationActions(const vector<CStdString> &up, const vector<CStdString> &down,
415                                        const vector<CStdString> &left, const vector<CStdString> &right)
416 {
417   m_leftActions = left;
418   m_rightActions = right;
419   m_upActions = up;
420   m_downActions = down;
421 }
422
423 void CGUIControl::SetWidth(float width)
424 {
425   if (m_width != width)
426   {
427     m_width = width;
428     m_hitRect.x2 = m_hitRect.x1 + width;
429     Update();
430   }
431 }
432
433 void CGUIControl::SetHeight(float height)
434 {
435   if (m_height != height)
436   {
437     m_height = height;
438     m_hitRect.y2 = m_hitRect.y1 + height;
439     Update();
440   }
441 }
442
443 void CGUIControl::SetVisible(bool bVisible)
444 {
445   // just force to hidden if necessary
446   m_forceHidden = !bVisible;
447 /*
448   if (m_visibleCondition)
449     bVisible = g_infoManager.GetBool(m_visibleCondition, m_dwParentID);
450   if (m_bVisible != bVisible)
451   {
452     m_visible = bVisible;
453     m_visibleFromSkinCondition = bVisible;
454     m_bInvalidated = true;
455   }*/
456 }
457
458 bool CGUIControl::HitTest(const CPoint &point) const
459 {
460   return m_hitRect.PtInRect(point);
461 }
462
463 // override this function to implement custom mouse behaviour
464 bool CGUIControl::OnMouseOver(const CPoint &point)
465 {
466   if (g_Mouse.GetState() != MOUSE_STATE_DRAG)
467     g_Mouse.SetState(MOUSE_STATE_FOCUS);
468   if (!CanFocus()) return false;
469   CGUIMessage msg(GUI_MSG_SETFOCUS, GetParentID(), GetID());
470   OnMessage(msg);
471   return true;
472 }
473
474 void CGUIControl::UpdateVisibility(const CGUIListItem *item)
475 {
476   if (m_visibleCondition)
477   {
478     bool bWasVisible = m_visibleFromSkinCondition;
479     m_visibleFromSkinCondition = g_infoManager.GetBool(m_visibleCondition, m_dwParentID, item);
480     if (!bWasVisible && m_visibleFromSkinCondition)
481     { // automatic change of visibility - queue the in effect
482   //    CLog::DebugLog("Visibility changed to visible for control id %i", m_dwControlID);
483       QueueAnimation(ANIM_TYPE_VISIBLE);
484     }
485     else if (bWasVisible && !m_visibleFromSkinCondition)
486     { // automatic change of visibility - do the out effect
487   //    CLog::DebugLog("Visibility changed to hidden for control id %i", m_dwControlID);
488       QueueAnimation(ANIM_TYPE_HIDDEN);
489     }
490   }
491   // check for conditional animations
492   for (unsigned int i = 0; i < m_animations.size(); i++)
493   {
494     CAnimation &anim = m_animations[i];
495     if (anim.GetType() == ANIM_TYPE_CONDITIONAL)
496       anim.UpdateCondition(GetParentID(), item);
497   }
498   // and check for conditional enabling - note this overrides SetEnabled() from the code currently
499   // this may need to be reviewed at a later date
500   if (m_enableCondition)
501     m_enabled = g_infoManager.GetBool(m_enableCondition, m_dwParentID, item);
502 }
503
504 void CGUIControl::SetInitialVisibility()
505 {
506   if (m_visibleCondition)
507   {
508     m_visibleFromSkinCondition = g_infoManager.GetBool(m_visibleCondition, m_dwParentID);
509     m_visible = m_visibleFromSkinCondition ? VISIBLE : HIDDEN;
510   //  CLog::DebugLog("Set initial visibility for control %i: %s", m_dwControlID, m_visible == VISIBLE ? "visible" : "hidden");
511     // no need to enquire every frame if we are always visible or always hidden
512     if (m_visibleCondition == SYSTEM_ALWAYS_TRUE || m_visibleCondition == SYSTEM_ALWAYS_FALSE)
513       m_visibleCondition = 0;
514   }
515   // and handle animation conditions as well
516   for (unsigned int i = 0; i < m_animations.size(); i++)
517   {
518     CAnimation &anim = m_animations[i];
519     if (anim.GetType() == ANIM_TYPE_CONDITIONAL)
520       anim.SetInitialCondition(GetParentID());
521   }
522 }
523
524 void CGUIControl::SetVisibleCondition(int visible, bool allowHiddenFocus)
525 {
526   m_visibleCondition = visible;
527   m_allowHiddenFocus = allowHiddenFocus;
528 }
529
530 void CGUIControl::SetAnimations(const vector<CAnimation> &animations)
531 {
532   m_animations = animations;
533 }
534
535 void CGUIControl::ResetAnimation(ANIMATION_TYPE type)
536 {
537   for (unsigned int i = 0; i < m_animations.size(); i++)
538   {
539     if (m_animations[i].GetType() == type)
540       m_animations[i].ResetAnimation();
541   }
542 }
543
544 void CGUIControl::ResetAnimations()
545 {
546   for (unsigned int i = 0; i < m_animations.size(); i++)
547     m_animations[i].ResetAnimation();
548 }
549
550 void CGUIControl::QueueAnimation(ANIMATION_TYPE animType)
551 {
552   // rule out the animations we shouldn't perform
553   if (!IsVisible() || !HasRendered()) 
554   { // hidden or never rendered - don't allow exit or entry animations for this control
555     if (animType == ANIM_TYPE_WINDOW_CLOSE)
556     { // could be animating a (delayed) window open anim, so reset it
557       ResetAnimation(ANIM_TYPE_WINDOW_OPEN);
558       return;
559     }
560   }
561   if (!IsVisible())
562   { // hidden - only allow hidden anims if we're animating a visible anim
563     if (animType == ANIM_TYPE_HIDDEN && !IsAnimating(ANIM_TYPE_VISIBLE))
564     {
565       // update states to force it hidden
566       UpdateStates(animType, ANIM_PROCESS_NORMAL, ANIM_STATE_APPLIED);
567       return;
568     }
569     if (animType == ANIM_TYPE_WINDOW_OPEN)
570       return;
571   }
572   CAnimation *reverseAnim = GetAnimation((ANIMATION_TYPE)-animType, false);
573   CAnimation *forwardAnim = GetAnimation(animType);
574   // we first check whether the reverse animation is in progress (and reverse it)
575   // then we check for the normal animation, and queue it
576   if (reverseAnim && reverseAnim->IsReversible() && (reverseAnim->GetState() == ANIM_STATE_IN_PROCESS || reverseAnim->GetState() == ANIM_STATE_DELAYED))
577   {
578     reverseAnim->QueueAnimation(ANIM_PROCESS_REVERSE);
579     if (forwardAnim) forwardAnim->ResetAnimation();
580   }
581   else if (forwardAnim)
582   {
583     forwardAnim->QueueAnimation(ANIM_PROCESS_NORMAL);
584     if (reverseAnim) reverseAnim->ResetAnimation();
585   }
586   else
587   { // hidden and visible animations delay the change of state.  If there is no animations
588     // to perform, then we should just change the state straightaway
589     if (reverseAnim) reverseAnim->ResetAnimation();
590     UpdateStates(animType, ANIM_PROCESS_NORMAL, ANIM_STATE_APPLIED);
591   }
592 }
593
594 CAnimation *CGUIControl::GetAnimation(ANIMATION_TYPE type, bool checkConditions /* = true */)
595 {
596   for (unsigned int i = 0; i < m_animations.size(); i++)
597   {
598     if (m_animations[i].GetType() == type)
599     {
600       if (!checkConditions || !m_animations[i].GetCondition() || g_infoManager.GetBool(m_animations[i].GetCondition()))
601         return &m_animations[i];
602     }
603   }
604   return NULL;
605 }
606
607 void CGUIControl::UpdateStates(ANIMATION_TYPE type, ANIMATION_PROCESS currentProcess, ANIMATION_STATE currentState)
608 {
609   // Make sure control is hidden or visible at the appropriate times
610   // while processing a visible or hidden animation it needs to be visible,
611   // but when finished a hidden operation it needs to be hidden
612   if (type == ANIM_TYPE_VISIBLE)
613   {
614     if (currentProcess == ANIM_PROCESS_REVERSE)
615     {
616       if (currentState == ANIM_STATE_APPLIED)
617         m_visible = HIDDEN;
618     }
619     else if (currentProcess == ANIM_PROCESS_NORMAL)
620     {
621       if (currentState == ANIM_STATE_DELAYED)
622         m_visible = DELAYED;
623       else
624         m_visible = m_visibleFromSkinCondition ? VISIBLE : HIDDEN;
625     }
626   }
627   else if (type == ANIM_TYPE_HIDDEN)
628   {
629     if (currentProcess == ANIM_PROCESS_NORMAL)  // a hide animation
630     {
631       if (currentState == ANIM_STATE_APPLIED)
632         m_visible = HIDDEN; // finished
633       else
634         m_visible = VISIBLE; // have to be visible until we are finished
635     }
636     else if (currentProcess == ANIM_PROCESS_REVERSE)  // a visible animation
637     { // no delay involved here - just make sure it's visible
638       m_visible = m_visibleFromSkinCondition ? VISIBLE : HIDDEN;
639     }
640   }
641   else if (type == ANIM_TYPE_WINDOW_OPEN)
642   {
643     if (currentProcess == ANIM_PROCESS_NORMAL)
644     {
645       if (currentState == ANIM_STATE_DELAYED)
646         m_visible = DELAYED; // delayed
647       else
648         m_visible = m_visibleFromSkinCondition ? VISIBLE : HIDDEN;
649     }
650   }
651   else if (type == ANIM_TYPE_FOCUS)
652   {
653     // call the focus function if we have finished a focus animation
654     // (buttons can "click" on focus)
655     if (currentProcess == ANIM_PROCESS_NORMAL && currentState == ANIM_STATE_APPLIED)
656       OnFocus();
657   }
658 }
659
660 void CGUIControl::Animate(DWORD currentTime)
661 {
662   // check visible state outside the loop, as it could change
663   GUIVISIBLE visible = m_visible;
664   m_transform.Reset();
665   CPoint center(m_posX + m_width * 0.5f, m_posY + m_height * 0.5f);
666   for (unsigned int i = 0; i < m_animations.size(); i++)
667   {
668     CAnimation &anim = m_animations[i];
669     anim.Animate(currentTime, HasRendered() || visible == DELAYED);
670     // Update the control states (such as visibility)
671     UpdateStates(anim.GetType(), anim.GetProcess(), anim.GetState());
672     // and render the animation effect
673     anim.RenderAnimation(m_transform, center);
674
675 /*    // debug stuff
676     if (anim.currentProcess != ANIM_PROCESS_NONE)
677     {
678       if (anim.effect == EFFECT_TYPE_ZOOM)
679       {
680         if (IsVisible())
681           CLog::DebugLog("Animating control %d with a %s zoom effect %s. Amount is %2.1f, visible=%s", m_dwControlID, anim.type == ANIM_TYPE_CONDITIONAL ? (anim.lastCondition ? "conditional_on" : "conditional_off") : (anim.type == ANIM_TYPE_VISIBLE ? "visible" : "hidden"), anim.currentProcess == ANIM_PROCESS_NORMAL ? "normal" : "reverse", anim.amount, IsVisible() ? "true" : "false");
682       }
683       else if (anim.effect == EFFECT_TYPE_FADE)
684       {
685         if (IsVisible())
686           CLog::DebugLog("Animating control %d with a %s fade effect %s. Amount is %2.1f. Visible=%s", m_dwControlID, anim.type == ANIM_TYPE_CONDITIONAL ? (anim.lastCondition ? "conditional_on" : "conditional_off") : (anim.type == ANIM_TYPE_VISIBLE ? "visible" : "hidden"), anim.currentProcess == ANIM_PROCESS_NORMAL ? "normal" : "reverse", anim.amount, IsVisible() ? "true" : "false");
687       }
688     }*/
689   }
690   g_graphicsContext.AddTransform(m_transform);
691 }
692
693 bool CGUIControl::IsAnimating(ANIMATION_TYPE animType)
694 {
695   for (unsigned int i = 0; i < m_animations.size(); i++)
696   {
697     CAnimation &anim = m_animations[i];
698     if (anim.GetType() == animType)
699     {
700       if (anim.GetQueuedProcess() == ANIM_PROCESS_NORMAL)
701         return true;
702       if (anim.GetProcess() == ANIM_PROCESS_NORMAL)
703         return true;
704     }
705     else if (anim.GetType() == -animType)
706     {
707       if (anim.GetQueuedProcess() == ANIM_PROCESS_REVERSE)
708         return true;
709       if (anim.GetProcess() == ANIM_PROCESS_REVERSE)
710         return true;
711     }
712   }
713   return false;
714 }
715
716 DWORD CGUIControl::GetNextControl(int direction) const
717 {
718   switch (direction)
719   {
720   case ACTION_MOVE_UP:
721     return m_dwControlUp;
722   case ACTION_MOVE_DOWN:
723     return m_dwControlDown;
724   case ACTION_MOVE_LEFT:
725     return m_dwControlLeft;
726   case ACTION_MOVE_RIGHT:
727     return m_dwControlRight;
728   default:
729     return -1;
730   }
731 }
732
733 // input the point with respect to this control to hit, and return
734 // the control and the point with respect to his control if we have a hit
735 bool CGUIControl::CanFocusFromPoint(const CPoint &point, CGUIControl **control, CPoint &controlPoint) const
736 {
737   controlPoint = point;
738   m_transform.InverseTransformPosition(controlPoint.x, controlPoint.y);
739   if (CanFocus() && HitTest(controlPoint))
740   {
741     *control = (CGUIControl *)this;
742     return true;
743   }
744   *control = NULL;
745   return false;
746 }
747
748 void CGUIControl::UnfocusFromPoint(const CPoint &point)
749 {
750   CPoint controlPoint(point);
751   m_transform.InverseTransformPosition(controlPoint.x, controlPoint.y);
752   if (!HitTest(controlPoint))
753     SetFocus(false);
754 }
755
756 bool CGUIControl::HasID(DWORD dwID) const
757 {
758   return GetID() == dwID;
759 }
760
761 bool CGUIControl::HasVisibleID(DWORD dwID) const
762 {
763   return GetID() == dwID && IsVisible();
764 }
765
766 void CGUIControl::SaveStates(vector<CControlState> &states)
767 {
768   // empty for now - do nothing with the majority of controls
769 }
770
771 void CGUIControl::SetHitRect(const CRect &rect)
772 {
773   m_hitRect = rect;
774 }
775
776 void CGUIControl::SetCamera(const CPoint &camera)
777 {
778   m_camera = camera;
779   m_hasCamera = true;
780 }
781
782 void CGUIControl::ExecuteActions(const vector<CStdString> &actions)
783 {
784   // we should really save anything we need, as the action may cause the window to close
785   DWORD savedID = GetID();
786   DWORD savedParent = GetParentID();
787   vector<CStdString> savedActions = actions;
788
789   for (unsigned int i = 0; i < savedActions.size(); i++)
790   {
791     CGUIMessage message(GUI_MSG_EXECUTE, savedID, savedParent);
792     message.SetStringParam(savedActions[i]);
793     g_graphicsContext.SendMessage(message);
794   }
795 }
796