[cstdstring] demise Format, replacing with StringUtils::Format
[vuplus_xbmc] / xbmc / guilib / GUIScrollBarControl.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 "GUIScrollBarControl.h"
22 #include "Key.h"
23 #include "utils/StringUtils.h"
24
25 #define MIN_NIB_SIZE 4.0f
26
27 CGUIScrollBar::CGUIScrollBar(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& backGroundTexture, const CTextureInfo& barTexture, const CTextureInfo& barTextureFocus, const CTextureInfo& nibTexture, const CTextureInfo& nibTextureFocus, ORIENTATION orientation, bool showOnePage)
28     : CGUIControl(parentID, controlID, posX, posY, width, height)
29     , m_guiBackground(posX, posY, width, height, backGroundTexture)
30     , m_guiBarNoFocus(posX, posY, width, height, barTexture)
31     , m_guiBarFocus(posX, posY, width, height, barTextureFocus)
32     , m_guiNibNoFocus(posX, posY, width, height, nibTexture)
33     , m_guiNibFocus(posX, posY, width, height, nibTextureFocus)
34 {
35   m_guiNibNoFocus.SetAspectRatio(CAspectRatio::AR_CENTER);
36   m_guiNibFocus.SetAspectRatio(CAspectRatio::AR_CENTER);
37   m_numItems = 100;
38   m_offset = 0;
39   m_pageSize = 10;
40   ControlType = GUICONTROL_SCROLLBAR;
41   m_orientation = orientation;
42   m_showOnePage = showOnePage;
43 }
44
45 CGUIScrollBar::~CGUIScrollBar(void)
46 {
47 }
48
49 void CGUIScrollBar::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
50 {
51   bool changed = false;
52
53   if (m_bInvalidated)
54     changed |= UpdateBarSize();
55
56   changed |= m_guiBackground.Process(currentTime);
57   changed |= m_guiBarNoFocus.Process(currentTime);
58   changed |= m_guiBarFocus.Process(currentTime);
59   changed |= m_guiNibNoFocus.Process(currentTime);
60   changed |= m_guiNibFocus.Process(currentTime);
61
62   if (changed)
63     MarkDirtyRegion();
64
65   CGUIControl::Process(currentTime, dirtyregions);
66 }
67
68 void CGUIScrollBar::Render()
69 {
70   m_guiBackground.Render();
71   if (m_bHasFocus)
72   {
73     m_guiBarFocus.Render();
74     m_guiNibFocus.Render();
75   }
76   else
77   {
78     m_guiBarNoFocus.Render();
79     m_guiNibNoFocus.Render();
80   }
81
82   CGUIControl::Render();
83 }
84
85 bool CGUIScrollBar::OnMessage(CGUIMessage& message)
86 {
87   switch (message.GetMessage())
88   {
89   case GUI_MSG_ITEM_SELECT:
90     SetValue(message.GetParam1());
91     return true;
92   case GUI_MSG_LABEL_RESET:
93     SetRange(message.GetParam1(), message.GetParam2());
94     return true;
95   case GUI_MSG_PAGE_UP:
96     Move(-1);
97     return true;
98   case GUI_MSG_PAGE_DOWN:
99     Move(1);
100     return true;
101   }
102   return CGUIControl::OnMessage(message);
103 }
104
105 bool CGUIScrollBar::OnAction(const CAction &action)
106 {
107   switch ( action.GetID() )
108   {
109   case ACTION_MOVE_LEFT:
110     if (m_orientation == HORIZONTAL)
111     {
112       if(Move( -1))
113         return true;
114     }
115     break;
116
117   case ACTION_MOVE_RIGHT:
118     if (m_orientation == HORIZONTAL)
119     {
120       if(Move(1))
121         return true;
122     }
123     break;
124   case ACTION_MOVE_UP:
125     if (m_orientation == VERTICAL)
126     {
127       if(Move(-1))
128         return true;
129     }
130     break;
131
132   case ACTION_MOVE_DOWN:
133     if (m_orientation == VERTICAL)
134     {
135       if(Move(1))
136         return true;
137     }
138     break;
139   }
140   return CGUIControl::OnAction(action);
141 }
142
143 bool CGUIScrollBar::Move(int numSteps)
144 {
145   if (numSteps < 0 && m_offset == 0) // we are at the beginning - can't scroll up/left anymore
146     return false;
147   if (numSteps > 0 && m_offset == std::max(m_numItems - m_pageSize, 0)) // we are at the end - we can't scroll down/right anymore
148     return false;
149
150   m_offset += numSteps * m_pageSize;
151   if (m_offset > m_numItems - m_pageSize) m_offset = m_numItems - m_pageSize;
152   if (m_offset < 0) m_offset = 0;
153   CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_offset);
154   SendWindowMessage(message);
155   SetInvalid();
156   return true;
157 }
158
159 void CGUIScrollBar::SetRange(int pageSize, int numItems)
160 {
161   if (m_pageSize != pageSize || m_numItems != numItems)
162   {
163     m_pageSize = pageSize;
164     m_numItems = numItems;
165     m_offset = 0;
166     SetInvalid();
167   }
168 }
169
170 void CGUIScrollBar::SetValue(int value)
171 {
172   if (m_offset != value)
173   {
174     m_offset = value;
175     SetInvalid();
176   }
177 }
178
179 void CGUIScrollBar::FreeResources(bool immediately)
180 {
181   CGUIControl::FreeResources(immediately);
182   m_guiBackground.FreeResources(immediately);
183   m_guiBarNoFocus.FreeResources(immediately);
184   m_guiBarFocus.FreeResources(immediately);
185   m_guiNibNoFocus.FreeResources(immediately);
186   m_guiNibFocus.FreeResources(immediately);
187 }
188
189 void CGUIScrollBar::DynamicResourceAlloc(bool bOnOff)
190 {
191   CGUIControl::DynamicResourceAlloc(bOnOff);
192   m_guiBackground.DynamicResourceAlloc(bOnOff);
193   m_guiBarNoFocus.DynamicResourceAlloc(bOnOff);
194   m_guiBarFocus.DynamicResourceAlloc(bOnOff);
195   m_guiNibNoFocus.DynamicResourceAlloc(bOnOff);
196   m_guiNibFocus.DynamicResourceAlloc(bOnOff);
197 }
198
199 void CGUIScrollBar::AllocResources()
200 {
201   CGUIControl::AllocResources();
202   m_guiBackground.AllocResources();
203   m_guiBarNoFocus.AllocResources();
204   m_guiBarFocus.AllocResources();
205   m_guiNibNoFocus.AllocResources();
206   m_guiNibFocus.AllocResources();
207 }
208
209 void CGUIScrollBar::SetInvalid()
210 {
211   CGUIControl::SetInvalid();
212   m_guiBackground.SetInvalid();
213   m_guiBarFocus.SetInvalid();
214   m_guiBarFocus.SetInvalid();
215   m_guiNibNoFocus.SetInvalid();
216   m_guiNibFocus.SetInvalid();
217 }
218
219 bool CGUIScrollBar::UpdateBarSize()
220 {
221   bool changed = false;
222
223   // scale our textures to suit
224   if (m_orientation == VERTICAL)
225   {
226     // calculate the height to display the nib at
227     float percent = (m_numItems == 0) ? 0 : (float)m_pageSize / m_numItems;
228     float nibSize = GetHeight() * percent;
229     if (nibSize < m_guiNibFocus.GetTextureHeight() + 2 * MIN_NIB_SIZE) nibSize = m_guiNibFocus.GetTextureHeight() + 2 * MIN_NIB_SIZE;
230     if (nibSize > GetHeight()) nibSize = GetHeight();
231
232     changed |= m_guiBarNoFocus.SetHeight(nibSize);
233     changed |= m_guiBarFocus.SetHeight(nibSize);
234     changed |= m_guiNibNoFocus.SetHeight(nibSize);
235     changed |= m_guiNibFocus.SetHeight(nibSize);
236     // nibSize may be altered by the border size of the nib (and bar).
237     nibSize = std::max(m_guiBarFocus.GetHeight(), m_guiNibFocus.GetHeight());
238
239     // and the position
240     percent = (m_numItems == m_pageSize) ? 0 : (float)m_offset / (m_numItems - m_pageSize);
241     float nibPos = (GetHeight() - nibSize) * percent;
242     if (nibPos < 0) nibPos = 0;
243     if (nibPos > GetHeight() - nibSize) nibPos = GetHeight() - nibSize;
244
245     changed |= m_guiBarNoFocus.SetPosition(GetXPosition(), GetYPosition() + nibPos);
246     changed |= m_guiBarFocus.SetPosition(GetXPosition(), GetYPosition() + nibPos);
247     changed |= m_guiNibNoFocus.SetPosition(GetXPosition(), GetYPosition() + nibPos);
248     changed |= m_guiNibFocus.SetPosition(GetXPosition(), GetYPosition() + nibPos);
249   }
250   else
251   {
252     // calculate the height to display the nib at
253     float percent = (m_numItems == 0) ? 0 : (float)m_pageSize / m_numItems;
254     float nibSize = GetWidth() * percent + 0.5f;
255     if (nibSize < m_guiNibFocus.GetTextureWidth() + 2 * MIN_NIB_SIZE) nibSize = m_guiNibFocus.GetTextureWidth() + 2 * MIN_NIB_SIZE;
256     if (nibSize > GetWidth()) nibSize = GetWidth();
257
258     changed |= m_guiBarNoFocus.SetWidth(nibSize);
259     changed |= m_guiBarFocus.SetWidth(nibSize);
260     changed |= m_guiNibNoFocus.SetWidth(nibSize);
261     changed |= m_guiNibFocus.SetWidth(nibSize);
262
263     // and the position
264     percent = (m_numItems == m_pageSize) ? 0 : (float)m_offset / (m_numItems - m_pageSize);
265     float nibPos = (GetWidth() - nibSize) * percent;
266     if (nibPos < 0) nibPos = 0;
267     if (nibPos > GetWidth() - nibSize) nibPos = GetWidth() - nibSize;
268
269     changed |= m_guiBarNoFocus.SetPosition(GetXPosition() + nibPos, GetYPosition());
270     changed |= m_guiBarFocus.SetPosition(GetXPosition() + nibPos, GetYPosition());
271     changed |= m_guiNibNoFocus.SetPosition(GetXPosition() + nibPos, GetYPosition());
272     changed |= m_guiNibFocus.SetPosition(GetXPosition() + nibPos, GetYPosition());
273   }
274
275   return changed;
276 }
277
278 bool CGUIScrollBar::HitTest(const CPoint &point) const
279 {
280   if (m_guiBackground.HitTest(point)) return true;
281   if (m_guiBarNoFocus.HitTest(point)) return true;
282   return false;
283 }
284
285 void CGUIScrollBar::SetFromPosition(const CPoint &point)
286 {
287   float fPercent;
288   if (m_orientation == VERTICAL)
289     fPercent = (point.y - m_guiBackground.GetYPosition() - 0.5f*m_guiBarFocus.GetHeight()) / m_guiBackground.GetHeight();
290   else
291     fPercent = (point.x - m_guiBackground.GetXPosition() - 0.5f*m_guiBarFocus.GetWidth()) / m_guiBackground.GetWidth();
292   if (fPercent < 0) fPercent = 0;
293   if (fPercent > 1) fPercent = 1;
294
295   int offset = (int)(floor(fPercent * m_numItems + 0.5f));
296
297   if (m_offset != offset)
298   {
299     m_offset = offset;
300     CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_offset);
301     SendWindowMessage(message);
302     SetInvalid();
303   }
304 }
305
306 EVENT_RESULT CGUIScrollBar::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
307 {
308   if (event.m_id == ACTION_MOUSE_DRAG)
309   {
310     if (event.m_state == 1)
311     { // we want exclusive access
312       CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
313       SendWindowMessage(msg);
314     }
315     else if (event.m_state == 3)
316     { // we're done with exclusive access
317       CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
318       SendWindowMessage(msg);
319     }
320     SetFromPosition(point);
321     return EVENT_RESULT_HANDLED;
322   }
323   else if (event.m_id == ACTION_MOUSE_LEFT_CLICK && m_guiBackground.HitTest(point))
324   {
325     SetFromPosition(point);
326     return EVENT_RESULT_HANDLED;
327   }
328   else if (event.m_id == ACTION_MOUSE_WHEEL_UP)
329   {
330     Move(-1);
331     return EVENT_RESULT_HANDLED;
332   }
333   else if (event.m_id == ACTION_MOUSE_WHEEL_DOWN)
334   {
335     Move(1);
336     return EVENT_RESULT_HANDLED;
337   }  
338   else if (event.m_id == ACTION_GESTURE_NOTIFY)
339   {
340     return (m_orientation == HORIZONTAL) ? EVENT_RESULT_PAN_HORIZONTAL_WITHOUT_INERTIA : EVENT_RESULT_PAN_VERTICAL_WITHOUT_INERTIA;
341   }  
342   else if (event.m_id == ACTION_GESTURE_BEGIN)
343   { // grab exclusive access
344     CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
345     SendWindowMessage(msg);
346     return EVENT_RESULT_HANDLED;
347   }
348   else if (event.m_id == ACTION_GESTURE_PAN)
349   { // do the drag 
350     SetFromPosition(point);
351     return EVENT_RESULT_HANDLED;
352   }
353   else if (event.m_id == ACTION_GESTURE_END)
354   { // release exclusive access
355     CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
356     SendWindowMessage(msg);
357     return EVENT_RESULT_HANDLED;
358   }
359   
360   return EVENT_RESULT_UNHANDLED;
361 }
362
363 CStdString CGUIScrollBar::GetDescription() const
364 {
365   return StringUtils::Format("%i/%i", m_offset, m_numItems);
366 }
367
368 bool CGUIScrollBar::UpdateColors()
369 {
370   bool changed = CGUIControl::UpdateColors();
371   changed |= m_guiBackground.SetDiffuseColor(m_diffuseColor);
372   changed |= m_guiBarNoFocus.SetDiffuseColor(m_diffuseColor);
373   changed |= m_guiBarFocus.SetDiffuseColor(m_diffuseColor);
374   changed |= m_guiNibNoFocus.SetDiffuseColor(m_diffuseColor);
375   changed |= m_guiNibFocus.SetDiffuseColor(m_diffuseColor);
376
377   return changed;
378 }
379
380 bool CGUIScrollBar::IsVisible() const
381 {
382   // page controls can be optionally disabled if the number of pages is 1
383   if (m_numItems <= m_pageSize && !m_showOnePage)
384     return false;
385   return CGUIControl::IsVisible();
386 }