[cstdstring] demise Format, replacing with StringUtils::Format
[vuplus_xbmc] / xbmc / guilib / GUISliderControl.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 "GUISliderControl.h"
22 #include "GUIInfoManager.h"
23 #include "Key.h"
24 #include "utils/MathUtils.h"
25 #include "utils/StringUtils.h"
26 #include "GUIWindowManager.h"
27
28 static const SliderAction actions[] = {
29   {"seek",    "PlayerControl(SeekPercentage(%2f))", PLAYER_PROGRESS, false},
30   {"volume",  "SetVolume(%2f)",                     PLAYER_VOLUME,   true}
31  };
32
33 CGUISliderControl::CGUISliderControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& backGroundTexture, const CTextureInfo& nibTexture, const CTextureInfo& nibTextureFocus, int iType)
34     : CGUIControl(parentID, controlID, posX, posY, width, height)
35     , m_guiBackground(posX, posY, width, height, backGroundTexture)
36     , m_guiSelectorLower(posX, posY, width, height, nibTexture)
37     , m_guiSelectorUpper(posX, posY, width, height, nibTexture)
38     , m_guiSelectorLowerFocus(posX, posY, width, height, nibTextureFocus)
39     , m_guiSelectorUpperFocus(posX, posY, width, height, nibTextureFocus)
40 {
41   m_iType = iType;
42   m_rangeSelection = false;
43   m_currentSelector = RangeSelectorLower; // use lower selector by default
44   m_percentValues[0] = 0;
45   m_percentValues[1] = 100;
46   m_iStart = 0;
47   m_iEnd = 100;
48   m_iInterval = 1;
49   m_fStart = 0.0f;
50   m_fEnd = 1.0f;
51   m_fInterval = 0.1f;
52   m_intValues[0] = m_iStart;
53   m_intValues[1] = m_iEnd;
54   m_floatValues[0] = m_fStart;
55   m_floatValues[1] = m_fEnd;
56   ControlType = GUICONTROL_SLIDER;
57   m_iInfoCode = 0;
58   m_dragging = false;
59   m_action = NULL;
60 }
61
62 CGUISliderControl::~CGUISliderControl(void)
63 {
64 }
65
66 void CGUISliderControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
67 {
68   bool dirty = false;
69
70   dirty |= m_guiBackground.SetPosition( m_posX, m_posY );
71   int infoCode = m_iInfoCode;
72   if (m_action && (!m_dragging || m_action->fireOnDrag))
73     infoCode = m_action->infoCode;
74   if (infoCode)
75   {
76     int val;
77     if (g_infoManager.GetInt(val, infoCode))
78       SetIntValue(val);
79   }
80
81   float fScaleY = m_height == 0 ? 1.0f : m_height / m_guiBackground.GetTextureHeight();
82
83   dirty |= m_guiBackground.SetHeight(m_height);
84   dirty |= m_guiBackground.SetWidth(m_width);
85   dirty |= m_guiBackground.Process(currentTime);
86
87   CGUITexture &nibLower = (m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorLower) ? m_guiSelectorLowerFocus : m_guiSelectorLower;
88   dirty |= ProcessSelector(nibLower, currentTime, fScaleY, RangeSelectorLower);
89   if (m_rangeSelection)
90   {
91     CGUITexture &nibUpper = (m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorUpper) ? m_guiSelectorUpperFocus : m_guiSelectorUpper;
92     dirty |= ProcessSelector(nibUpper, currentTime, fScaleY, RangeSelectorUpper);
93   }
94
95   if (dirty)
96     MarkDirtyRegion();
97
98   CGUIControl::Process(currentTime, dirtyregions);
99 }
100
101 bool CGUISliderControl::ProcessSelector(CGUITexture &nib, unsigned int currentTime, float fScaleY, RangeSelector selector)
102 {
103   bool dirty = false;
104   // we render the nib centered at the appropriate percentage, except where the nib
105   // would overflow the background image
106   dirty |= nib.SetHeight(nib.GetTextureHeight() * fScaleY);
107   dirty |= nib.SetWidth(nib.GetHeight() * 2);
108   CAspectRatio ratio(CAspectRatio::AR_KEEP);
109   ratio.align = ASPECT_ALIGN_LEFT | ASPECT_ALIGNY_CENTER;
110   dirty |= nib.SetAspectRatio(ratio);
111   dirty |= nib.Process(currentTime);
112   CRect rect = nib.GetRenderRect();
113
114   float offset = GetProportion(selector) * m_width - rect.Width() / 2;
115   if (offset > m_width - rect.Width())
116     offset = m_width - rect.Width();
117   if (offset < 0)
118     offset = 0;
119   dirty |= nib.SetPosition(m_guiBackground.GetXPosition() + offset, m_guiBackground.GetYPosition());
120   dirty |= nib.Process(currentTime); // need to process again as the position may have changed
121
122   return dirty;
123 }
124
125 void CGUISliderControl::Render()
126 {
127   m_guiBackground.Render();
128   CGUITexture &nibLower = (m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorLower) ? m_guiSelectorLowerFocus : m_guiSelectorLower;
129   nibLower.Render();
130   if (m_rangeSelection)
131   {
132     CGUITexture &nibUpper = (m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorUpper) ? m_guiSelectorUpperFocus : m_guiSelectorUpper;
133     nibUpper.Render();
134   }
135   CGUIControl::Render();
136 }
137
138 bool CGUISliderControl::OnMessage(CGUIMessage& message)
139 {
140   if (message.GetControlId() == GetID() )
141   {
142     switch (message.GetMessage())
143     {
144     case GUI_MSG_ITEM_SELECT:
145       SetPercentage( (float)message.GetParam1() );
146       return true;
147       break;
148
149     case GUI_MSG_LABEL_RESET:
150       {
151         SetPercentage(0, RangeSelectorLower);
152         SetPercentage(100, RangeSelectorUpper);
153         return true;
154       }
155       break;
156     }
157   }
158
159   return CGUIControl::OnMessage(message);
160 }
161
162 bool CGUISliderControl::OnAction(const CAction &action)
163 {
164   switch ( action.GetID() )
165   {
166   case ACTION_MOVE_LEFT:
167     //case ACTION_OSD_SHOW_VALUE_MIN:
168     Move(-1);
169     return true;
170
171   case ACTION_MOVE_RIGHT:
172     //case ACTION_OSD_SHOW_VALUE_PLUS:
173     Move(1);
174     return true;
175
176   case ACTION_SELECT_ITEM:
177     // switch between the two sliders
178     if (m_rangeSelection)
179       SwitchRangeSelector();
180     return true;
181
182   default:
183     break;
184   }
185
186   return CGUIControl::OnAction(action);
187 }
188
189 void CGUISliderControl::Move(int iNumSteps)
190 {
191   bool rangeSwap = false;
192   switch (m_iType)
193   {
194   case SPIN_CONTROL_TYPE_FLOAT:
195     {
196       float &value = m_floatValues[m_currentSelector];
197       value += m_fInterval * iNumSteps;
198       if (value < m_fStart) value = m_fStart;
199       if (value > m_fEnd) value = m_fEnd;
200       if (m_floatValues[0] > m_floatValues[1])
201       {
202         float valueLower = m_floatValues[0];
203         m_floatValues[0] = m_floatValues[1];
204         m_floatValues[1] = valueLower;
205         rangeSwap = true;
206       }
207       break;
208     }
209
210   case SPIN_CONTROL_TYPE_INT:
211     {
212       int &value = m_intValues[m_currentSelector];
213       value += m_iInterval * iNumSteps;
214       if (value < m_iStart) value = m_iStart;
215       if (value > m_iEnd) value = m_iEnd;
216       if (m_intValues[0] > m_intValues[1])
217       {
218         int valueLower = m_intValues[0];
219         m_intValues[0] = m_intValues[1];
220         m_intValues[1] = valueLower;
221         rangeSwap = true;
222       }
223       break;
224     }
225
226   default:
227     {
228       float &value = m_percentValues[m_currentSelector];
229       value += m_iInterval * iNumSteps;
230       if (value < 0) value = 0;
231       if (value > 100) value = 100;
232       if (m_percentValues[0] > m_percentValues[1])
233       {
234         float valueLower = m_percentValues[0];
235         m_percentValues[0] = m_percentValues[1];
236         m_percentValues[1] = valueLower;
237         rangeSwap = true;
238       }
239       break;
240     }
241   }
242
243   if (rangeSwap)
244     SwitchRangeSelector();
245
246   SendClick();
247 }
248
249 void CGUISliderControl::SendClick()
250 {
251   float percent = 100*GetProportion();
252   SEND_CLICK_MESSAGE(GetID(), GetParentID(), MathUtils::round_int(percent));
253   if (m_action && (!m_dragging || m_action->fireOnDrag))
254   {
255     CStdString action = StringUtils::Format(m_action->formatString, percent);
256     CGUIMessage message(GUI_MSG_EXECUTE, m_controlID, m_parentID);
257     message.SetStringParam(action);
258     g_windowManager.SendMessage(message);    
259   }
260 }
261
262 void CGUISliderControl::SetRangeSelection(bool rangeSelection)
263 {
264   if (m_rangeSelection == rangeSelection)
265     return;
266
267   m_rangeSelection = rangeSelection;
268   SetRangeSelector(RangeSelectorLower);
269   SetInvalid();
270 }
271
272 void CGUISliderControl::SetRangeSelector(RangeSelector selector)
273 {
274   if (m_currentSelector == selector)
275     return;
276
277   m_currentSelector = selector;
278   SetInvalid();
279 }
280
281 void CGUISliderControl::SwitchRangeSelector()
282 {
283   if (m_currentSelector == RangeSelectorLower)
284     SetRangeSelector(RangeSelectorUpper);
285   else
286     SetRangeSelector(RangeSelectorLower);
287 }
288
289 void CGUISliderControl::SetPercentage(float percent, RangeSelector selector /* = RangeSelectorLower */, bool updateCurrent /* = false */)
290 {
291   if (percent > 100) percent = 100;
292   else if (percent < 0) percent = 0;
293
294   float percentLower = selector == RangeSelectorLower ? percent : m_percentValues[0];
295   float percentUpper = selector == RangeSelectorUpper ? percent : m_percentValues[1];
296
297   if (!m_rangeSelection || percentLower <= percentUpper)
298   {
299     m_percentValues[0] = percentLower;
300     m_percentValues[1] = percentUpper;
301     if (updateCurrent)
302       m_currentSelector = selector;
303   }
304   else
305   {
306     m_percentValues[0] = percentUpper;
307     m_percentValues[1] = percentLower;
308     if (updateCurrent)
309         m_currentSelector = (selector == RangeSelectorLower ? RangeSelectorUpper : RangeSelectorLower);
310   }
311 }
312
313 float CGUISliderControl::GetPercentage(RangeSelector selector /* = RangeSelectorLower */) const
314 {
315   return m_percentValues[selector];
316 }
317
318 void CGUISliderControl::SetIntValue(int iValue, RangeSelector selector /* = RangeSelectorLower */, bool updateCurrent /* = false */)
319 {
320   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
321     SetFloatValue((float)iValue);
322   else if (m_iType == SPIN_CONTROL_TYPE_INT)
323   {
324     if (iValue > m_iEnd) iValue = m_iEnd;
325     else if (iValue < m_iStart) iValue = m_iStart;
326
327     int iValueLower = selector == RangeSelectorLower ? iValue : m_intValues[0];
328     int iValueUpper = selector == RangeSelectorUpper ? iValue : m_intValues[1];
329
330     if (!m_rangeSelection || iValueLower <= iValueUpper)
331     {
332       m_intValues[0] = iValueLower;
333       m_intValues[1] = iValueUpper;
334       if (updateCurrent)
335         m_currentSelector = selector;
336     }
337     else
338     {
339       m_intValues[0] = iValueUpper;
340       m_intValues[1] = iValueLower;
341       if (updateCurrent)
342         m_currentSelector = (selector == RangeSelectorLower ? RangeSelectorUpper : RangeSelectorLower);
343     }
344   }
345   else
346     SetPercentage((float)iValue);
347 }
348
349 int CGUISliderControl::GetIntValue(RangeSelector selector /* = RangeSelectorLower */) const
350 {
351   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
352     return (int)m_floatValues[selector];
353   else if (m_iType == SPIN_CONTROL_TYPE_INT)
354     return m_intValues[selector];
355   else
356     return MathUtils::round_int(m_percentValues[selector]);
357 }
358
359 void CGUISliderControl::SetFloatValue(float fValue, RangeSelector selector /* = RangeSelectorLower */, bool updateCurrent /* = false */)
360 {
361   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
362   {
363     if (fValue > m_fEnd) fValue = m_fEnd;
364     else if (fValue < m_fStart) fValue = m_fStart;
365
366     float fValueLower = selector == RangeSelectorLower ? fValue : m_floatValues[0];
367     float fValueUpper = selector == RangeSelectorUpper ? fValue : m_floatValues[1];
368
369     if (!m_rangeSelection || fValueLower <= fValueUpper)
370     {
371       m_floatValues[0] = fValueLower;
372       m_floatValues[1] = fValueUpper;
373       if (updateCurrent)
374         m_currentSelector = selector;
375     }
376     else
377     {
378       m_floatValues[0] = fValueUpper;
379       m_floatValues[1] = fValueLower;
380       if (updateCurrent)
381         m_currentSelector = (selector == RangeSelectorLower ? RangeSelectorUpper : RangeSelectorLower);
382     }
383   }
384   else if (m_iType == SPIN_CONTROL_TYPE_INT)
385     SetIntValue((int)fValue);
386   else
387     SetPercentage(fValue);
388 }
389
390 float CGUISliderControl::GetFloatValue(RangeSelector selector /* = RangeSelectorLower */) const
391 {
392   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
393     return m_floatValues[selector];
394   else if (m_iType == SPIN_CONTROL_TYPE_INT)
395     return (float)m_intValues[selector];
396   else
397     return m_percentValues[selector];
398 }
399
400 void CGUISliderControl::SetIntInterval(int iInterval)
401 {
402   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
403     m_fInterval = (float)iInterval;
404   else
405     m_iInterval = iInterval;
406 }
407
408 void CGUISliderControl::SetFloatInterval(float fInterval)
409 {
410   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
411     m_fInterval = fInterval;
412   else
413     m_iInterval = (int)fInterval;
414 }
415
416 void CGUISliderControl::SetRange(int iStart, int iEnd)
417 {
418   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
419     SetFloatRange((float)iStart,(float)iEnd);
420   else
421   {
422     m_intValues[0] = m_iStart = iStart;
423     m_intValues[1] = m_iEnd = iEnd;
424   }
425 }
426
427 void CGUISliderControl::SetFloatRange(float fStart, float fEnd)
428 {
429   if (m_iType == SPIN_CONTROL_TYPE_INT)
430     SetRange((int)fStart, (int)fEnd);
431   else
432   {
433     m_floatValues[0] = m_fStart = fStart;
434     m_floatValues[1] = m_fEnd = fEnd;
435   }
436 }
437
438 void CGUISliderControl::FreeResources(bool immediately)
439 {
440   CGUIControl::FreeResources(immediately);
441   m_guiBackground.FreeResources(immediately);
442   m_guiSelectorLower.FreeResources(immediately);
443   m_guiSelectorUpper.FreeResources(immediately);
444   m_guiSelectorLowerFocus.FreeResources(immediately);
445   m_guiSelectorUpperFocus.FreeResources(immediately);
446 }
447
448 void CGUISliderControl::DynamicResourceAlloc(bool bOnOff)
449 {
450   CGUIControl::DynamicResourceAlloc(bOnOff);
451   m_guiBackground.DynamicResourceAlloc(bOnOff);
452   m_guiSelectorLower.DynamicResourceAlloc(bOnOff);
453   m_guiSelectorUpper.DynamicResourceAlloc(bOnOff);
454   m_guiSelectorLowerFocus.DynamicResourceAlloc(bOnOff);
455   m_guiSelectorUpperFocus.DynamicResourceAlloc(bOnOff);
456 }
457
458 void CGUISliderControl::AllocResources()
459 {
460   CGUIControl::AllocResources();
461   m_guiBackground.AllocResources();
462   m_guiSelectorLower.AllocResources();
463   m_guiSelectorUpper.AllocResources();
464   m_guiSelectorLowerFocus.AllocResources();
465   m_guiSelectorUpperFocus.AllocResources();
466 }
467
468 void CGUISliderControl::SetInvalid()
469 {
470   CGUIControl::SetInvalid();
471   m_guiBackground.SetInvalid();
472   m_guiSelectorLower.SetInvalid();
473   m_guiSelectorUpper.SetInvalid();
474   m_guiSelectorLowerFocus.SetInvalid();
475   m_guiSelectorUpperFocus.SetInvalid();
476 }
477
478 bool CGUISliderControl::HitTest(const CPoint &point) const
479 {
480   if (m_guiBackground.HitTest(point)) return true;
481   if (m_guiSelectorLower.HitTest(point)) return true;
482   if (m_rangeSelection && m_guiSelectorUpper.HitTest(point)) return true;
483   return false;
484 }
485
486 void CGUISliderControl::SetFromPosition(const CPoint &point, bool guessSelector /* = false */)
487 {
488   float fPercent = (point.x - m_guiBackground.GetXPosition()) / m_guiBackground.GetWidth();
489   if (fPercent < 0) fPercent = 0;
490   if (fPercent > 1) fPercent = 1;
491
492   if (m_rangeSelection && guessSelector)
493   {
494     // choose selector which value is closer to value calculated from position
495     if (fabs(GetPercentage(RangeSelectorLower) - 100 * fPercent) <= fabs(GetPercentage(RangeSelectorUpper) - 100 * fPercent))
496       m_currentSelector = RangeSelectorLower;
497     else
498       m_currentSelector = RangeSelectorUpper;
499   }
500
501   switch (m_iType)
502   {
503   case SPIN_CONTROL_TYPE_FLOAT:
504     {
505       float fValue = m_fStart + (m_fEnd - m_fStart) * fPercent;
506       SetFloatValue(fValue, m_currentSelector, true);
507       break;
508     }
509
510   case SPIN_CONTROL_TYPE_INT:
511     {
512       int iValue = (int)(m_iStart + (float)(m_iEnd - m_iStart) * fPercent + 0.49f);
513       SetIntValue(iValue, m_currentSelector, true);
514       break;
515     }
516
517   default:
518     {
519       SetPercentage(fPercent * 100, m_currentSelector, true);
520       break;
521     }
522   }
523   SendClick();
524 }
525
526 EVENT_RESULT CGUISliderControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
527 {
528   m_dragging = false;
529   if (event.m_id == ACTION_MOUSE_DRAG)
530   {
531     m_dragging = true;
532     bool guessSelector = false;
533     if (event.m_state == 1)
534     { // grab exclusive access
535       CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
536       SendWindowMessage(msg);
537       guessSelector = true;
538     }
539     else if (event.m_state == 3)
540     { // release exclusive access
541       m_dragging = false;
542       CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
543       SendWindowMessage(msg);
544     }
545     SetFromPosition(point, guessSelector);
546     return EVENT_RESULT_HANDLED;
547   }
548   else if (event.m_id == ACTION_MOUSE_LEFT_CLICK && m_guiBackground.HitTest(point))
549   {
550     SetFromPosition(point, true);
551     return EVENT_RESULT_HANDLED;
552   }
553   else if (event.m_id == ACTION_MOUSE_WHEEL_UP)
554   {
555     Move(10);
556     return EVENT_RESULT_HANDLED;
557   }
558   else if (event.m_id == ACTION_MOUSE_WHEEL_DOWN)
559   {
560     Move(-10);
561     return EVENT_RESULT_HANDLED;
562   }
563   else if (event.m_id == ACTION_GESTURE_NOTIFY)
564   {
565     return EVENT_RESULT_PAN_HORIZONTAL_WITHOUT_INERTIA;
566   }  
567   else if (event.m_id == ACTION_GESTURE_BEGIN)
568   { // grab exclusive access
569     CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
570     SendWindowMessage(msg);
571     return EVENT_RESULT_HANDLED;
572   }
573   else if (event.m_id == ACTION_GESTURE_PAN)
574   { // do the drag 
575     SetFromPosition(point);
576     return EVENT_RESULT_HANDLED;
577   }
578   else if (event.m_id == ACTION_GESTURE_END)
579   { // release exclusive access
580     CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
581     SendWindowMessage(msg);
582     return EVENT_RESULT_HANDLED;
583   }
584   return EVENT_RESULT_UNHANDLED;
585 }
586
587 void CGUISliderControl::SetInfo(int iInfo)
588 {
589   m_iInfoCode = iInfo;
590 }
591
592 CStdString CGUISliderControl::GetDescription() const
593 {
594   if (!m_textValue.IsEmpty())
595     return m_textValue;
596   CStdString description;
597   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
598   {
599     if (m_rangeSelection)
600       description = StringUtils::Format("[%2.2f, %2.2f]", m_floatValues[0], m_floatValues[1]);
601     else
602       description = StringUtils::Format("%2.2f", m_floatValues[0]);
603   }
604   else if (m_iType == SPIN_CONTROL_TYPE_INT)
605   {
606     if (m_rangeSelection)
607       description = StringUtils::Format("[%i, %i]", m_intValues[0], m_intValues[1]);
608     else
609       description = StringUtils::Format("%i", m_intValues[0]);
610   }
611   else
612   {
613     if (m_rangeSelection)
614       description = StringUtils::Format("[%i%%, %i%%]", MathUtils::round_int(m_percentValues[0]), MathUtils::round_int(m_percentValues[1]));
615     else
616       description = StringUtils::Format("%i%%", MathUtils::round_int(m_percentValues[0]));
617   }
618   return description;
619 }
620
621 bool CGUISliderControl::UpdateColors()
622 {
623   bool changed = CGUIControl::UpdateColors();
624   changed |= m_guiBackground.SetDiffuseColor(m_diffuseColor);
625   changed |= m_guiSelectorLower.SetDiffuseColor(m_diffuseColor);
626   changed |= m_guiSelectorUpper.SetDiffuseColor(m_diffuseColor);
627   changed |= m_guiSelectorLowerFocus.SetDiffuseColor(m_diffuseColor);
628   changed |= m_guiSelectorUpperFocus.SetDiffuseColor(m_diffuseColor);
629
630   return changed;
631 }
632
633 float CGUISliderControl::GetProportion(RangeSelector selector /* = RangeSelectorLower */) const
634 {
635   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
636     return (GetFloatValue(selector) - m_fStart) / (m_fEnd - m_fStart);
637   else if (m_iType == SPIN_CONTROL_TYPE_INT)
638     return (float)(GetIntValue(selector) - m_iStart) / (float)(m_iEnd - m_iStart);
639   return 0.01f * GetPercentage(selector);
640 }
641
642 void CGUISliderControl::SetAction(const CStdString &action)
643 {
644   for (size_t i = 0; i < sizeof(actions)/sizeof(SliderAction); i++)
645   {
646     if (action.CompareNoCase(actions[i].action) == 0)
647     {
648       m_action = &actions[i];
649       return;
650     }
651   }
652   m_action = NULL;
653 }