[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / guilib / GUISelectButtonControl.cpp
1 /*
2  *      Copyright (C) 2005-2013 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, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "GUISelectButtonControl.h"
22 #include "GUIWindowManager.h"
23 #include "utils/CharsetConverter.h"
24 #include "utils/TimeUtils.h"
25 #include "Key.h"
26
27 CGUISelectButtonControl::CGUISelectButtonControl(int parentID, int controlID,
28     float posX, float posY,
29     float width, float height,
30     const CTextureInfo& buttonFocus,
31     const CTextureInfo& button,
32     const CLabelInfo& labelInfo,
33     const CTextureInfo& selectBackground,
34     const CTextureInfo& selectArrowLeft,
35     const CTextureInfo& selectArrowLeftFocus,
36     const CTextureInfo& selectArrowRight,
37     const CTextureInfo& selectArrowRightFocus
38                                                 )
39     : CGUIButtonControl(parentID, controlID, posX, posY, width, height, buttonFocus, button, labelInfo)
40     , m_imgBackground(posX, posY, width, height, selectBackground)
41     , m_imgLeft(posX, posY, 16, 16, selectArrowLeft)
42     , m_imgLeftFocus(posX, posY, 16, 16, selectArrowLeftFocus)
43     , m_imgRight(posX, posY, 16, 16, selectArrowRight)
44     , m_imgRightFocus(posX, posY, 16, 16, selectArrowRightFocus)
45 {
46   m_bShowSelect = false;
47   m_iCurrentItem = -1;
48   m_iDefaultItem = -1;
49   m_iStartFrame = 0;
50   m_bLeftSelected = false;
51   m_bRightSelected = false;
52   m_bMovedLeft = false;
53   m_bMovedRight = false;
54   m_ticks = 0;
55   m_label.SetAlign(m_label.GetLabelInfo().align | XBFONT_CENTER_X);
56   ControlType = GUICONTROL_SELECTBUTTON;
57 }
58
59 CGUISelectButtonControl::~CGUISelectButtonControl(void)
60 {}
61
62 void CGUISelectButtonControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
63 {
64   if (m_bInvalidated)
65   {
66     m_imgBackground.SetWidth(m_width);
67     m_imgBackground.SetHeight(m_height);
68   }
69   // Are we in selection mode
70   if (m_bShowSelect)
71   {
72     // render background, left and right arrow
73     if (m_imgBackground.Process(currentTime))
74       MarkDirtyRegion();
75
76     CGUILabel::COLOR color = CGUILabel::COLOR_TEXT;
77
78     // User has moved left...
79     if (m_bMovedLeft)
80     {
81       m_iStartFrame++;
82       if (m_iStartFrame >= 10)
83       {
84         m_iStartFrame = 0;
85         m_bMovedLeft = false;
86         MarkDirtyRegion();
87       }
88       // If we are moving left
89       // render item text as disabled
90       color = CGUILabel::COLOR_DISABLED;
91     }
92
93     // Update arrow
94     m_imgLeftFocus.Process(currentTime);
95     m_imgLeft.Process(currentTime);
96
97     // User has moved right...
98     if (m_bMovedRight)
99     {
100       m_iStartFrame++;
101       if (m_iStartFrame >= 10)
102       {
103         m_iStartFrame = 0;
104         m_bMovedRight = false;
105         MarkDirtyRegion();
106       }
107       // If we are moving right
108       // render item text as disabled
109       color = CGUILabel::COLOR_DISABLED;
110     }
111
112     // Update arrow
113     m_imgRightFocus.Process(currentTime);
114     m_imgRight.Process(currentTime);
115
116     // Render text if a current item is available
117     if (m_iCurrentItem >= 0 && (unsigned)m_iCurrentItem < m_vecItems.size())
118     {
119       bool changed = m_label.SetMaxRect(m_posX, m_posY, m_width, m_height);
120       changed |= m_label.SetText(m_vecItems[m_iCurrentItem]);
121       changed |= m_label.SetColor(color);
122       changed |= m_label.Process(currentTime);
123       if (changed)
124         MarkDirtyRegion();
125     }
126
127     // Select current item, if user doesn't
128     // move left or right for 1.5 sec.
129     unsigned int ticksSpan = currentTime - m_ticks;
130     if (ticksSpan > 1500)
131     {
132       // User hasn't moved disable selection mode...
133       m_bShowSelect = false;
134       MarkDirtyRegion();
135
136       // ...and send a thread message.
137       // (Sending a message with SendMessage
138       // can result in a GPF.)
139       CGUIMessage message(GUI_MSG_CLICKED, GetID(), GetParentID() );
140       g_windowManager.SendThreadMessage(message);
141     }
142     CGUIControl::Process(currentTime, dirtyregions);
143   } // if (m_bShowSelect)
144   else
145     CGUIButtonControl::Process(currentTime, dirtyregions);
146 }
147
148 void CGUISelectButtonControl::Render()
149 {
150   if (m_bShowSelect)
151   {
152     // render background, left and right arrow
153     m_imgBackground.Render();
154
155     // Render arrows
156     if (m_bLeftSelected || m_bMovedLeft)
157       m_imgLeftFocus.Render();
158     else
159       m_imgLeft.Render();
160
161     if (m_bRightSelected || m_bMovedRight)
162       m_imgRightFocus.Render();
163     else
164       m_imgRight.Render();
165
166     // Render text if a current item is available
167     if (m_iCurrentItem >= 0 && (unsigned)m_iCurrentItem < m_vecItems.size())
168       m_label.Render();
169
170     CGUIControl::Render();
171   } // if (m_bShowSelect)
172   else
173   {
174     // No, render a normal button
175     CGUIButtonControl::Render();
176   }
177 }
178
179 bool CGUISelectButtonControl::OnMessage(CGUIMessage& message)
180 {
181   if ( message.GetControlId() == GetID() )
182   {
183     if (message.GetMessage() == GUI_MSG_LABEL_ADD)
184     {
185       if (m_vecItems.size() <= 0)
186       {
187         m_iCurrentItem = 0;
188         m_iDefaultItem = 0;
189       }
190       m_vecItems.push_back(message.GetLabel());
191       return true;
192     }
193     else if (message.GetMessage() == GUI_MSG_LABEL_RESET)
194     {
195       m_vecItems.erase(m_vecItems.begin(), m_vecItems.end());
196       m_iCurrentItem = -1;
197       m_iDefaultItem = -1;
198       return true;
199     }
200     else if (message.GetMessage() == GUI_MSG_ITEM_SELECTED)
201     {
202       message.SetParam1(m_iCurrentItem);
203       if (m_iCurrentItem >= 0 && m_iCurrentItem < (int)m_vecItems.size())
204         message.SetLabel(m_vecItems[m_iCurrentItem]);
205       return true;
206     }
207     else if (message.GetMessage() == GUI_MSG_ITEM_SELECT)
208     {
209       m_iDefaultItem = m_iCurrentItem = message.GetParam1();
210       return true;
211     }
212   }
213
214   return CGUIButtonControl::OnMessage(message);
215 }
216
217 bool CGUISelectButtonControl::OnAction(const CAction &action)
218 {
219   if (!m_bShowSelect)
220   {
221     if (action.GetID() == ACTION_SELECT_ITEM)
222     {
223       // Enter selection mode
224       m_bShowSelect = true;
225       SetInvalid();
226
227       // Start timer, if user doesn't select an item
228       // or moves left/right. The control will
229       // automatically select the current item.
230       m_ticks = CTimeUtils::GetFrameTime();
231       return true;
232     }
233     else
234       return CGUIButtonControl::OnAction(action);
235   }
236   else
237   {
238     if (action.GetID() == ACTION_SELECT_ITEM)
239     {
240       // User has selected an item, disable selection mode...
241       m_bShowSelect = false;
242       SetInvalid();
243
244       // ...and send a message.
245       CGUIMessage message(GUI_MSG_CLICKED, GetID(), GetParentID() );
246       SendWindowMessage(message);
247       return true;
248     }
249     if (action.GetID() == ACTION_MOVE_UP || action.GetID() == ACTION_MOVE_DOWN )
250     {
251       // Disable selection mode when moving up or down
252       m_bShowSelect = false;
253       m_iCurrentItem = m_iDefaultItem;
254       SetInvalid();
255     }
256     // call the base class
257     return CGUIButtonControl::OnAction(action);
258   }
259 }
260
261 void CGUISelectButtonControl::FreeResources(bool immediately)
262 {
263   CGUIButtonControl::FreeResources(immediately);
264
265   m_imgBackground.FreeResources(immediately);
266
267   m_imgLeft.FreeResources(immediately);
268   m_imgLeftFocus.FreeResources(immediately);
269
270   m_imgRight.FreeResources(immediately);
271   m_imgRightFocus.FreeResources(immediately);
272
273   m_bShowSelect = false;
274 }
275
276 void CGUISelectButtonControl::DynamicResourceAlloc(bool bOnOff)
277 {
278   CGUIControl::DynamicResourceAlloc(bOnOff);
279
280   m_imgBackground.DynamicResourceAlloc(bOnOff);
281
282   m_imgLeft.DynamicResourceAlloc(bOnOff);
283   m_imgLeftFocus.DynamicResourceAlloc(bOnOff);
284
285   m_imgRight.DynamicResourceAlloc(bOnOff);
286   m_imgRightFocus.DynamicResourceAlloc(bOnOff);
287 }
288
289 void CGUISelectButtonControl::AllocResources()
290 {
291   CGUIButtonControl::AllocResources();
292
293   m_imgBackground.AllocResources();
294
295   m_imgLeft.AllocResources();
296   m_imgLeftFocus.AllocResources();
297
298   m_imgRight.AllocResources();
299   m_imgRightFocus.AllocResources();
300
301   // Position right arrow
302   float posX = (m_posX + m_width - 8) - 16;
303   float posY = m_posY + (m_height - 16) / 2;
304   m_imgRight.SetPosition(posX, posY);
305   m_imgRightFocus.SetPosition(posX, posY);
306
307   // Position left arrow
308   posX = m_posX + 8;
309   m_imgLeft.SetPosition(posX, posY);
310   m_imgLeftFocus.SetPosition(posX, posY);
311 }
312
313 void CGUISelectButtonControl::SetInvalid()
314 {
315   CGUIButtonControl::SetInvalid();
316   m_imgBackground.SetInvalid();
317   m_imgLeft.SetInvalid();
318   m_imgLeftFocus.SetInvalid();
319   m_imgRight.SetInvalid();
320   m_imgRightFocus.SetInvalid();
321 }
322
323 void CGUISelectButtonControl::OnLeft()
324 {
325   if (m_bShowSelect)
326   {
327     // Set for visual feedback
328     m_bMovedLeft = true;
329     m_iStartFrame = 0;
330     SetInvalid();
331
332     // Reset timer for automatically selecting
333     // the current item.
334     m_ticks = CTimeUtils::GetFrameTime();
335
336     // Switch to previous item
337     if (m_vecItems.size() > 0)
338     {
339       m_iCurrentItem--;
340       if (m_iCurrentItem < 0)
341         m_iCurrentItem = (int)m_vecItems.size() - 1;
342     }
343   }
344   else
345   { // use the base class
346     CGUIButtonControl::OnLeft();
347   }
348 }
349
350 void CGUISelectButtonControl::OnRight()
351 {
352   if (m_bShowSelect)
353   {
354     // Set for visual feedback
355     m_bMovedRight = true;
356     m_iStartFrame = 0;
357     SetInvalid();
358
359     // Reset timer for automatically selecting
360     // the current item.
361     m_ticks = CTimeUtils::GetFrameTime();
362
363     // Switch to next item
364     if (m_vecItems.size() > 0)
365     {
366       m_iCurrentItem++;
367       if (m_iCurrentItem >= (int)m_vecItems.size())
368         m_iCurrentItem = 0;
369     }
370   }
371   else
372   { // use the base class
373     CGUIButtonControl::OnRight();
374   }
375 }
376
377 bool CGUISelectButtonControl::OnMouseOver(const CPoint &point)
378 {
379   bool ret = CGUIControl::OnMouseOver(point);
380   m_bLeftSelected = false;
381   m_bRightSelected = false;
382   if (m_imgLeft.HitTest(point))
383   { // highlight the left control, but don't start moving until we have clicked
384     m_bLeftSelected = true;
385   }
386   if (m_imgRight.HitTest(point))
387   { // highlight the right control, but don't start moving until we have clicked
388     m_bRightSelected = true;
389   }
390   // reset ticks
391   m_ticks = CTimeUtils::GetFrameTime();
392   return ret;
393 }
394
395 EVENT_RESULT CGUISelectButtonControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
396 {
397   if (event.m_id == ACTION_MOUSE_LEFT_CLICK)
398   {
399     if (m_bShowSelect && m_imgLeft.HitTest(point))
400       OnLeft();
401     else if (m_bShowSelect && m_imgRight.HitTest(point))
402       OnRight();
403     else // normal select
404       CGUIButtonControl::OnMouseEvent(point, event);
405     return EVENT_RESULT_HANDLED;
406   }
407   else if (event.m_id == ACTION_MOUSE_WHEEL_UP)
408   {
409     OnLeft();
410     return EVENT_RESULT_HANDLED;
411   }
412   else if (event.m_id == ACTION_MOUSE_WHEEL_DOWN)
413   {
414     OnRight();
415     return EVENT_RESULT_HANDLED;
416   }
417   return EVENT_RESULT_UNHANDLED;
418 }
419
420 void CGUISelectButtonControl::SetPosition(float posX, float posY)
421 {
422   float leftOffX = m_imgLeft.GetXPosition() - m_posX;
423   float leftOffY = m_imgLeft.GetYPosition() - m_posY;
424   float rightOffX = m_imgRight.GetXPosition() - m_posX;
425   float rightOffY = m_imgRight.GetYPosition() - m_posY;
426   float backOffX = m_imgBackground.GetXPosition() - m_posX;
427   float backOffY = m_imgBackground.GetYPosition() - m_posY;
428   CGUIButtonControl::SetPosition(posX, posY);
429   m_imgLeft.SetPosition(posX + leftOffX, posY + leftOffY);
430   m_imgLeftFocus.SetPosition(posX + leftOffX, posY + leftOffY);
431   m_imgRight.SetPosition(posX + rightOffX, posY + rightOffY);
432   m_imgRightFocus.SetPosition(posX + rightOffX, posY + rightOffY);
433   m_imgBackground.SetPosition(posX + backOffX, posY + backOffY);
434 }
435
436 bool CGUISelectButtonControl::UpdateColors()
437 {
438   bool changed = CGUIButtonControl::UpdateColors();
439   changed |= m_imgLeft.SetDiffuseColor(m_diffuseColor);
440   changed |= m_imgLeftFocus.SetDiffuseColor(m_diffuseColor);
441   changed |= m_imgRight.SetDiffuseColor(m_diffuseColor);
442   changed |= m_imgRightFocus.SetDiffuseColor(m_diffuseColor);
443   changed |= m_imgBackground.SetDiffuseColor(m_diffuseColor);
444
445   return changed;
446 }
447