[guilib] fix labelcontrols with auto width always being marked as dirty if they speci...
[vuplus_xbmc] / xbmc / guilib / GUIDialog.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://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, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "GUIDialog.h"
22 #include "GUIWindowManager.h"
23 #include "GUILabelControl.h"
24 #include "GUIAudioManager.h"
25 #include "threads/SingleLock.h"
26 #include "utils/TimeUtils.h"
27 #include "Application.h"
28 #include "ApplicationMessenger.h"
29 #include "Key.h"
30
31 CGUIDialog::CGUIDialog(int id, const CStdString &xmlFile)
32     : CGUIWindow(id, xmlFile)
33 {
34   m_bModal = true;
35   m_wasRunning = false;
36   m_renderOrder = 1;
37   m_autoClosing = false;
38   m_showStartTime = 0;
39   m_showDuration = 0;
40   m_enableSound = true;
41   m_bAutoClosed = false;
42 }
43
44 CGUIDialog::~CGUIDialog(void)
45 {}
46
47 void CGUIDialog::OnWindowLoaded()
48 {
49   CGUIWindow::OnWindowLoaded();
50
51   // Clip labels to extents
52   if (m_children.size())
53   {
54     CGUIControl* pBase = m_children[0];
55
56     for (iControls p = m_children.begin() + 1; p != m_children.end(); ++p)
57     {
58       if ((*p)->GetControlType() == CGUIControl::GUICONTROL_LABEL)
59       {
60         CGUILabelControl* pLabel = (CGUILabelControl*)(*p);
61
62         if (!pLabel->GetWidth())
63         {
64           float spacing = (pLabel->GetXPosition() - pBase->GetXPosition()) * 2;
65           pLabel->SetWidth(pBase->GetWidth() - spacing);
66         }
67       }
68     }
69   }
70 }
71
72 bool CGUIDialog::OnAction(const CAction &action)
73 {
74   // keyboard or controller movement should prevent autoclosing
75   if (!action.IsMouse() && m_autoClosing)
76     SetAutoClose(m_showDuration);
77
78   return CGUIWindow::OnAction(action);
79 }
80
81 bool CGUIDialog::OnBack(int actionID)
82 {
83   Close();
84   return true;
85 }
86
87 bool CGUIDialog::OnMessage(CGUIMessage& message)
88 {
89   switch ( message.GetMessage() )
90   {
91   case GUI_MSG_WINDOW_DEINIT:
92     {
93       CGUIWindow *pWindow = g_windowManager.GetWindow(g_windowManager.GetActiveWindow());
94       if (pWindow)
95         g_windowManager.ShowOverlay(pWindow->GetOverlayState());
96
97       CGUIWindow::OnMessage(message);
98       return true;
99     }
100   case GUI_MSG_WINDOW_INIT:
101     {
102       CGUIWindow::OnMessage(message);
103       m_showStartTime = 0;
104       return true;
105     }
106   }
107
108   return CGUIWindow::OnMessage(message);
109 }
110
111 void CGUIDialog::OnDeinitWindow(int nextWindowID)
112 {
113   if (m_active)
114   {
115     g_windowManager.RemoveDialog(GetID());
116     m_autoClosing = false;
117   }
118   CGUIWindow::OnDeinitWindow(nextWindowID);
119 }
120
121 void CGUIDialog::DoProcess(unsigned int currentTime, CDirtyRegionList &dirtyregions)
122 {
123   UpdateVisibility();
124
125   // if we were running but now we're not, mark us dirty
126   if (!m_active && m_wasRunning)
127     dirtyregions.push_back(m_renderRegion);
128
129   if (m_active)
130     CGUIWindow::DoProcess(currentTime, dirtyregions);
131
132   m_wasRunning = m_active;
133 }
134
135 void CGUIDialog::UpdateVisibility()
136 {
137   if (m_visibleCondition)
138   {
139     if (m_visibleCondition->Get())
140       Show();
141     else
142       Close();
143   }
144   
145   if (m_autoClosing)
146   { // check if our timer is running
147     if (!m_showStartTime)
148     {
149       if (HasProcessed()) // start timer
150         m_showStartTime = CTimeUtils::GetFrameTime();
151     }
152     else
153     {
154       if (m_showStartTime + m_showDuration < CTimeUtils::GetFrameTime() && !m_closing)
155       {
156         m_bAutoClosed = true;
157         Close();
158       }
159     }
160   }
161 }
162
163 void CGUIDialog::DoModal_Internal(int iWindowID /*= WINDOW_INVALID */, const CStdString &param /* = "" */)
164 {
165   //Lock graphic context here as it is sometimes called from non rendering threads
166   //maybe we should have a critical section per window instead??
167   CSingleLock lock(g_graphicsContext);
168
169   if (!g_windowManager.Initialized())
170     return; // don't do anything
171
172   m_closing = false;
173   m_bModal = true;
174   // set running before it's added to the window manager, else the auto-show code
175   // could show it as well if we are in a different thread from
176   // the main rendering thread (this should really be handled via
177   // a thread message though IMO)
178   m_active = true;
179   g_windowManager.RouteToWindow(this);
180
181   // active this window...
182   CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0, 0, WINDOW_INVALID, iWindowID);
183   msg.SetStringParam(param);
184   OnMessage(msg);
185
186   if (!m_windowLoaded)
187     Close(true);
188
189   lock.Leave();
190
191   while (m_active && !g_application.m_bStop)
192   {
193     g_windowManager.ProcessRenderLoop();
194   }
195 }
196
197 void CGUIDialog::Show_Internal()
198 {
199   //Lock graphic context here as it is sometimes called from non rendering threads
200   //maybe we should have a critical section per window instead??
201   CSingleLock lock(g_graphicsContext);
202
203   if (m_active && !m_closing && !IsAnimating(ANIM_TYPE_WINDOW_CLOSE)) return;
204
205   if (!g_windowManager.Initialized())
206     return; // don't do anything
207
208   m_bModal = false;
209
210   // set running before it's added to the window manager, else the auto-show code
211   // could show it as well if we are in a different thread from
212   // the main rendering thread (this should really be handled via
213   // a thread message though IMO)
214   m_active = true;
215   m_closing = false;
216   g_windowManager.AddModeless(this);
217
218   // active this window...
219   CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0, 0);
220   OnMessage(msg);
221 }
222
223 void CGUIDialog::DoModal(int iWindowID /*= WINDOW_INVALID */, const CStdString &param)
224 {
225   if (!g_application.IsCurrentThread())
226   {
227     // make sure graphics lock is not held
228     CSingleExit leaveIt(g_graphicsContext);
229     CApplicationMessenger::Get().DoModal(this, iWindowID, param);
230   }
231   else
232     DoModal_Internal(iWindowID, param);
233 }
234
235 void CGUIDialog::Show()
236 {
237   if (!g_application.IsCurrentThread())
238   {
239     // make sure graphics lock is not held
240     CSingleExit leaveIt(g_graphicsContext);
241     CApplicationMessenger::Get().Show(this);
242   }
243   else
244     Show_Internal();
245 }
246
247 void CGUIDialog::Render()
248 {
249   if (!m_active)
250     return;
251
252   CGUIWindow::Render();
253 }
254
255 void CGUIDialog::SetDefaults()
256 {
257   CGUIWindow::SetDefaults();
258   m_renderOrder = 1;
259 }
260
261 void CGUIDialog::SetAutoClose(unsigned int timeoutMs)
262 {
263    m_autoClosing = true;
264    m_showDuration = timeoutMs;
265    ResetAutoClose();
266 }
267
268 void CGUIDialog::ResetAutoClose(void)
269 {
270   if (m_autoClosing && m_active)
271     m_showStartTime = CTimeUtils::GetFrameTime();
272 }