1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "GUISliderControl.h"
10 
11 #include "GUIComponent.h"
12 #include "GUIInfoManager.h"
13 #include "GUIWindowManager.h"
14 #include "ServiceBroker.h"
15 #include "guilib/guiinfo/GUIInfoLabels.h"
16 #include "input/Key.h"
17 #include "utils/MathUtils.h"
18 #include "utils/StringUtils.h"
19 
20 static const SliderAction actions[] = {
21   {"seek",     "PlayerControl(SeekPercentage(%2f))", PLAYER_PROGRESS,                 false},
22   {"pvr.seek", "PVR.SeekPercentage(%2f)",            PVR_TIMESHIFT_PROGRESS_PLAY_POS, false},
23   {"volume",   "SetVolume(%2f)",                     PLAYER_VOLUME,                   true}
24  };
25 
CGUISliderControl(int parentID,int controlID,float posX,float posY,float width,float height,const CTextureInfo & backGroundTexture,const CTextureInfo & nibTexture,const CTextureInfo & nibTextureFocus,int iType,ORIENTATION orientation)26 CGUISliderControl::CGUISliderControl(int parentID,
27                                      int controlID,
28                                      float posX,
29                                      float posY,
30                                      float width,
31                                      float height,
32                                      const CTextureInfo& backGroundTexture,
33                                      const CTextureInfo& nibTexture,
34                                      const CTextureInfo& nibTextureFocus,
35                                      int iType,
36                                      ORIENTATION orientation)
37   : CGUIControl(parentID, controlID, posX, posY, width, height),
38     m_guiBackground(CGUITexture::CreateTexture(posX, posY, width, height, backGroundTexture)),
39     m_guiSelectorLower(CGUITexture::CreateTexture(posX, posY, width, height, nibTexture)),
40     m_guiSelectorUpper(CGUITexture::CreateTexture(posX, posY, width, height, nibTexture)),
41     m_guiSelectorLowerFocus(CGUITexture::CreateTexture(posX, posY, width, height, nibTextureFocus)),
42     m_guiSelectorUpperFocus(CGUITexture::CreateTexture(posX, posY, width, height, nibTextureFocus))
43 {
44   m_iType = iType;
45   m_rangeSelection = false;
46   m_currentSelector = RangeSelectorLower; // use lower selector by default
47   m_percentValues[0] = 0;
48   m_percentValues[1] = 100;
49   m_iStart = 0;
50   m_iEnd = 100;
51   m_iInterval = 1;
52   m_fStart = 0.0f;
53   m_fEnd = 1.0f;
54   m_fInterval = 0.1f;
55   m_intValues[0] = m_iStart;
56   m_intValues[1] = m_iEnd;
57   m_floatValues[0] = m_fStart;
58   m_floatValues[1] = m_fEnd;
59   ControlType = GUICONTROL_SLIDER;
60   m_orientation = orientation;
61   m_iInfoCode = 0;
62   m_dragging = false;
63   m_action = NULL;
64 }
65 
CGUISliderControl(const CGUISliderControl & control)66 CGUISliderControl::CGUISliderControl(const CGUISliderControl& control)
67   : CGUIControl(control),
68     m_guiBackground(control.m_guiBackground->Clone()),
69     m_guiSelectorLower(control.m_guiSelectorLower->Clone()),
70     m_guiSelectorUpper(control.m_guiSelectorUpper->Clone()),
71     m_guiSelectorLowerFocus(control.m_guiSelectorLowerFocus->Clone()),
72     m_guiSelectorUpperFocus(control.m_guiSelectorUpperFocus->Clone()),
73     m_iType(control.m_iType),
74     m_rangeSelection(control.m_rangeSelection),
75     m_currentSelector(control.m_currentSelector),
76     m_percentValues(control.m_percentValues),
77     m_intValues(control.m_intValues),
78     m_iStart(control.m_iStart),
79     m_iInterval(control.m_iInterval),
80     m_iEnd(control.m_iEnd),
81     m_floatValues(control.m_floatValues),
82     m_fStart(control.m_fStart),
83     m_fInterval(control.m_fInterval),
84     m_fEnd(control.m_fEnd),
85     m_iInfoCode(control.m_iInfoCode),
86     m_textValue(control.m_textValue),
87     m_action(control.m_action),
88     m_dragging(control.m_dragging),
89     m_orientation(control.m_orientation)
90 {
91 }
92 
Process(unsigned int currentTime,CDirtyRegionList & dirtyregions)93 void CGUISliderControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
94 {
95   bool dirty = false;
96 
97   dirty |= m_guiBackground->SetPosition(m_posX, m_posY);
98   int infoCode = m_iInfoCode;
99   if (m_action && (!m_dragging || m_action->fireOnDrag))
100     infoCode = m_action->infoCode;
101   if (infoCode)
102   {
103     int val;
104     if (CServiceBroker::GetGUI()->GetInfoManager().GetInt(val, infoCode))
105       SetIntValue(val);
106   }
107 
108   dirty |= m_guiBackground->SetHeight(m_height);
109   dirty |= m_guiBackground->SetWidth(m_width);
110   dirty |= m_guiBackground->Process(currentTime);
111 
112   CGUITexture* nibLower =
113       (IsActive() && m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorLower)
114           ? m_guiSelectorLowerFocus.get()
115           : m_guiSelectorLower.get();
116 
117   float fScale = 1.0f;
118 
119   if (m_orientation == HORIZONTAL && m_guiBackground->GetTextureHeight() != 0)
120     fScale = m_height / m_guiBackground->GetTextureHeight();
121   else if (m_width != 0 && nibLower->GetTextureWidth() != 0)
122     fScale = m_width / nibLower->GetTextureWidth();
123   dirty |= ProcessSelector(nibLower, currentTime, fScale, RangeSelectorLower);
124   if (m_rangeSelection)
125   {
126     CGUITexture* nibUpper =
127         (IsActive() && m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorUpper)
128             ? m_guiSelectorUpperFocus.get()
129             : m_guiSelectorUpper.get();
130 
131     if (m_orientation == HORIZONTAL && m_guiBackground->GetTextureHeight() != 0)
132       fScale = m_height / m_guiBackground->GetTextureHeight();
133     else if (m_width != 0 && nibUpper->GetTextureWidth() != 0)
134       fScale = m_width / nibUpper->GetTextureWidth();
135 
136     dirty |= ProcessSelector(nibUpper, currentTime, fScale, RangeSelectorUpper);
137   }
138 
139   if (dirty)
140     MarkDirtyRegion();
141 
142   CGUIControl::Process(currentTime, dirtyregions);
143 }
144 
ProcessSelector(CGUITexture * nib,unsigned int currentTime,float fScale,RangeSelector selector)145 bool CGUISliderControl::ProcessSelector(CGUITexture* nib,
146                                         unsigned int currentTime,
147                                         float fScale,
148                                         RangeSelector selector)
149 {
150   bool dirty = false;
151   // we render the nib centered at the appropriate percentage, except where the nib
152   // would overflow the background image
153   if (m_orientation == HORIZONTAL)
154   {
155     dirty |= nib->SetHeight(nib->GetTextureHeight() * fScale);
156     dirty |= nib->SetWidth(nib->GetHeight() * 2);
157   }
158   else
159   {
160     dirty |= nib->SetWidth(nib->GetTextureWidth() * fScale);
161     dirty |= nib->SetHeight(nib->GetWidth() * 2);
162   }
163   CAspectRatio ratio(CAspectRatio::AR_KEEP);
164   ratio.align = ASPECT_ALIGN_LEFT | ASPECT_ALIGNY_CENTER;
165   dirty |= nib->SetAspectRatio(ratio);
166   dirty |= nib->Process(currentTime);
167   CRect rect = nib->GetRenderRect();
168 
169   float offset;
170   if (m_orientation == HORIZONTAL)
171   {
172     offset = GetProportion(selector) * m_width - rect.Width() / 2;
173     if (offset > m_width - rect.Width())
174       offset = m_width - rect.Width();
175     if (offset < 0)
176       offset = 0;
177     dirty |=
178         nib->SetPosition(m_guiBackground->GetXPosition() + offset, m_guiBackground->GetYPosition());
179   }
180   else
181   {
182     offset = GetProportion(selector) * m_height - rect.Height() / 2;
183     if (offset > m_height - rect.Height())
184       offset = m_height - rect.Height();
185     if (offset < 0)
186       offset = 0;
187     dirty |=
188         nib->SetPosition(m_guiBackground->GetXPosition(),
189                          m_guiBackground->GetYPosition() + m_guiBackground->GetHeight() - offset -
190                              ((nib->GetHeight() - rect.Height()) / 2 + rect.Height()));
191   }
192   dirty |= nib->Process(currentTime); // need to process again as the position may have changed
193 
194   return dirty;
195 }
196 
Render()197 void CGUISliderControl::Render()
198 {
199   m_guiBackground->Render();
200   CGUITexture* nibLower =
201       (IsActive() && m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorLower)
202           ? m_guiSelectorLowerFocus.get()
203           : m_guiSelectorLower.get();
204   nibLower->Render();
205   if (m_rangeSelection)
206   {
207     CGUITexture* nibUpper =
208         (IsActive() && m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorUpper)
209             ? m_guiSelectorUpperFocus.get()
210             : m_guiSelectorUpper.get();
211     nibUpper->Render();
212   }
213   CGUIControl::Render();
214 }
215 
OnMessage(CGUIMessage & message)216 bool CGUISliderControl::OnMessage(CGUIMessage& message)
217 {
218   if (message.GetControlId() == GetID() )
219   {
220     switch (message.GetMessage())
221     {
222     case GUI_MSG_ITEM_SELECT:
223       SetPercentage( (float)message.GetParam1() );
224       return true;
225       break;
226 
227     case GUI_MSG_LABEL_RESET:
228       {
229         SetPercentage(0, RangeSelectorLower);
230         SetPercentage(100, RangeSelectorUpper);
231         return true;
232       }
233       break;
234     }
235   }
236 
237   return CGUIControl::OnMessage(message);
238 }
239 
OnAction(const CAction & action)240 bool CGUISliderControl::OnAction(const CAction &action)
241 {
242   switch ( action.GetID() )
243   {
244   case ACTION_MOVE_LEFT:
245     if (IsActive() && m_orientation == HORIZONTAL)
246     {
247       Move(-1);
248       return true;
249     }
250     break;
251 
252   case ACTION_MOVE_RIGHT:
253     if (IsActive() && m_orientation == HORIZONTAL)
254     {
255       Move(1);
256       return true;
257     }
258     break;
259 
260   case ACTION_MOVE_UP:
261     if (IsActive() && m_orientation == VERTICAL)
262     {
263       Move(1);
264       return true;
265     }
266     break;
267 
268   case ACTION_MOVE_DOWN:
269     if (IsActive() && m_orientation == VERTICAL)
270     {
271       Move(-1);
272       return true;
273     }
274     break;
275 
276   case ACTION_SELECT_ITEM:
277     if (m_rangeSelection)
278       SwitchRangeSelector();
279     return true;
280 
281   default:
282     break;
283   }
284   return CGUIControl::OnAction(action);
285 }
286 
Move(int iNumSteps)287 void CGUISliderControl::Move(int iNumSteps)
288 {
289   bool rangeSwap = false;
290   switch (m_iType)
291   {
292   case SLIDER_CONTROL_TYPE_FLOAT:
293     {
294       float &value = m_floatValues[m_currentSelector];
295       value += m_fInterval * iNumSteps;
296       if (value < m_fStart) value = m_fStart;
297       if (value > m_fEnd) value = m_fEnd;
298       if (m_floatValues[0] > m_floatValues[1])
299       {
300         float valueLower = m_floatValues[0];
301         m_floatValues[0] = m_floatValues[1];
302         m_floatValues[1] = valueLower;
303         rangeSwap = true;
304       }
305       break;
306     }
307 
308   case SLIDER_CONTROL_TYPE_INT:
309     {
310       int &value = m_intValues[m_currentSelector];
311       value += m_iInterval * iNumSteps;
312       if (value < m_iStart) value = m_iStart;
313       if (value > m_iEnd) value = m_iEnd;
314       if (m_intValues[0] > m_intValues[1])
315       {
316         int valueLower = m_intValues[0];
317         m_intValues[0] = m_intValues[1];
318         m_intValues[1] = valueLower;
319         rangeSwap = true;
320       }
321       break;
322     }
323 
324   case SLIDER_CONTROL_TYPE_PERCENTAGE:
325   default:
326     {
327       float &value = m_percentValues[m_currentSelector];
328       value += m_iInterval * iNumSteps;
329       if (value < 0) value = 0;
330       if (value > 100) value = 100;
331       if (m_percentValues[0] > m_percentValues[1])
332       {
333         float valueLower = m_percentValues[0];
334         m_percentValues[0] = m_percentValues[1];
335         m_percentValues[1] = valueLower;
336         rangeSwap = true;
337       }
338       break;
339     }
340   }
341 
342   if (rangeSwap)
343     SwitchRangeSelector();
344 
345   SendClick();
346 }
347 
SendClick()348 void CGUISliderControl::SendClick()
349 {
350   float percent = 100*GetProportion();
351   SEND_CLICK_MESSAGE(GetID(), GetParentID(), MathUtils::round_int(percent));
352   if (m_action && (!m_dragging || m_action->fireOnDrag))
353   {
354     std::string action = StringUtils::Format(m_action->formatString, percent);
355     CGUIMessage message(GUI_MSG_EXECUTE, m_controlID, m_parentID);
356     message.SetStringParam(action);
357     CServiceBroker::GetGUI()->GetWindowManager().SendMessage(message);
358   }
359 }
360 
SetRangeSelection(bool rangeSelection)361 void CGUISliderControl::SetRangeSelection(bool rangeSelection)
362 {
363   if (m_rangeSelection == rangeSelection)
364     return;
365 
366   m_rangeSelection = rangeSelection;
367   SetRangeSelector(RangeSelectorLower);
368   SetInvalid();
369 }
370 
SetRangeSelector(RangeSelector selector)371 void CGUISliderControl::SetRangeSelector(RangeSelector selector)
372 {
373   if (m_currentSelector == selector)
374     return;
375 
376   m_currentSelector = selector;
377   SetInvalid();
378 }
379 
SwitchRangeSelector()380 void CGUISliderControl::SwitchRangeSelector()
381 {
382   if (m_currentSelector == RangeSelectorLower)
383     SetRangeSelector(RangeSelectorUpper);
384   else
385     SetRangeSelector(RangeSelectorLower);
386 }
387 
SetPercentage(float percent,RangeSelector selector,bool updateCurrent)388 void CGUISliderControl::SetPercentage(float percent, RangeSelector selector /* = RangeSelectorLower */, bool updateCurrent /* = false */)
389 {
390   if (percent > 100) percent = 100;
391   else if (percent < 0) percent = 0;
392 
393   float percentLower = selector == RangeSelectorLower ? percent : m_percentValues[0];
394   float percentUpper = selector == RangeSelectorUpper ? percent : m_percentValues[1];
395   float oldValues[2] = { m_percentValues[0],m_percentValues[1] };
396 
397 
398   if (!m_rangeSelection || percentLower <= percentUpper)
399   {
400     m_percentValues[0] = percentLower;
401     m_percentValues[1] = percentUpper;
402     if (updateCurrent)
403       m_currentSelector = selector;
404   }
405   else
406   {
407     m_percentValues[0] = percentUpper;
408     m_percentValues[1] = percentLower;
409     if (updateCurrent)
410         m_currentSelector = (selector == RangeSelectorLower ? RangeSelectorUpper : RangeSelectorLower);
411   }
412   if (oldValues[0] != m_percentValues[0] || oldValues[1] != m_percentValues[1])
413     MarkDirtyRegion();
414 }
415 
GetPercentage(RangeSelector selector) const416 float CGUISliderControl::GetPercentage(RangeSelector selector /* = RangeSelectorLower */) const
417 {
418   return m_percentValues[selector];
419 }
420 
SetIntValue(int iValue,RangeSelector selector,bool updateCurrent)421 void CGUISliderControl::SetIntValue(int iValue, RangeSelector selector /* = RangeSelectorLower */, bool updateCurrent /* = false */)
422 {
423   if (m_iType == SLIDER_CONTROL_TYPE_FLOAT)
424     SetFloatValue((float)iValue, selector, updateCurrent);
425   else if (m_iType == SLIDER_CONTROL_TYPE_INT)
426   {
427     if (iValue > m_iEnd) iValue = m_iEnd;
428     else if (iValue < m_iStart) iValue = m_iStart;
429 
430     int iValueLower = selector == RangeSelectorLower ? iValue : m_intValues[0];
431     int iValueUpper = selector == RangeSelectorUpper ? iValue : m_intValues[1];
432 
433     if (!m_rangeSelection || iValueLower <= iValueUpper)
434     {
435       m_intValues[0] = iValueLower;
436       m_intValues[1] = iValueUpper;
437       if (updateCurrent)
438         m_currentSelector = selector;
439     }
440     else
441     {
442       m_intValues[0] = iValueUpper;
443       m_intValues[1] = iValueLower;
444       if (updateCurrent)
445         m_currentSelector = (selector == RangeSelectorLower ? RangeSelectorUpper : RangeSelectorLower);
446     }
447   }
448   else
449     SetPercentage((float)iValue, selector, updateCurrent);
450 }
451 
GetIntValue(RangeSelector selector) const452 int CGUISliderControl::GetIntValue(RangeSelector selector /* = RangeSelectorLower */) const
453 {
454   if (m_iType == SLIDER_CONTROL_TYPE_FLOAT)
455     return (int)m_floatValues[selector];
456   else if (m_iType == SLIDER_CONTROL_TYPE_INT)
457     return m_intValues[selector];
458   else
459     return MathUtils::round_int(m_percentValues[selector]);
460 }
461 
SetFloatValue(float fValue,RangeSelector selector,bool updateCurrent)462 void CGUISliderControl::SetFloatValue(float fValue, RangeSelector selector /* = RangeSelectorLower */, bool updateCurrent /* = false */)
463 {
464   if (m_iType == SLIDER_CONTROL_TYPE_FLOAT)
465   {
466     if (fValue > m_fEnd) fValue = m_fEnd;
467     else if (fValue < m_fStart) fValue = m_fStart;
468 
469     float fValueLower = selector == RangeSelectorLower ? fValue : m_floatValues[0];
470     float fValueUpper = selector == RangeSelectorUpper ? fValue : m_floatValues[1];
471 
472     if (!m_rangeSelection || fValueLower <= fValueUpper)
473     {
474       m_floatValues[0] = fValueLower;
475       m_floatValues[1] = fValueUpper;
476       if (updateCurrent)
477         m_currentSelector = selector;
478     }
479     else
480     {
481       m_floatValues[0] = fValueUpper;
482       m_floatValues[1] = fValueLower;
483       if (updateCurrent)
484         m_currentSelector = (selector == RangeSelectorLower ? RangeSelectorUpper : RangeSelectorLower);
485     }
486   }
487   else if (m_iType == SLIDER_CONTROL_TYPE_INT)
488     SetIntValue((int)fValue, selector, updateCurrent);
489   else
490     SetPercentage(fValue, selector, updateCurrent);
491 }
492 
GetFloatValue(RangeSelector selector) const493 float CGUISliderControl::GetFloatValue(RangeSelector selector /* = RangeSelectorLower */) const
494 {
495   if (m_iType == SLIDER_CONTROL_TYPE_FLOAT)
496     return m_floatValues[selector];
497   else if (m_iType == SLIDER_CONTROL_TYPE_INT)
498     return (float)m_intValues[selector];
499   else
500     return m_percentValues[selector];
501 }
502 
SetIntInterval(int iInterval)503 void CGUISliderControl::SetIntInterval(int iInterval)
504 {
505   if (m_iType == SLIDER_CONTROL_TYPE_FLOAT)
506     m_fInterval = (float)iInterval;
507   else
508     m_iInterval = iInterval;
509 }
510 
SetFloatInterval(float fInterval)511 void CGUISliderControl::SetFloatInterval(float fInterval)
512 {
513   if (m_iType == SLIDER_CONTROL_TYPE_FLOAT)
514     m_fInterval = fInterval;
515   else
516     m_iInterval = (int)fInterval;
517 }
518 
SetRange(int iStart,int iEnd)519 void CGUISliderControl::SetRange(int iStart, int iEnd)
520 {
521   if (m_iType == SLIDER_CONTROL_TYPE_FLOAT)
522     SetFloatRange((float)iStart,(float)iEnd);
523   else
524   {
525     m_intValues[0] = m_iStart = iStart;
526     m_intValues[1] = m_iEnd = iEnd;
527   }
528 }
529 
SetFloatRange(float fStart,float fEnd)530 void CGUISliderControl::SetFloatRange(float fStart, float fEnd)
531 {
532   if (m_iType == SLIDER_CONTROL_TYPE_INT)
533     SetRange((int)fStart, (int)fEnd);
534   else
535   {
536     m_floatValues[0] = m_fStart = fStart;
537     m_floatValues[1] = m_fEnd = fEnd;
538   }
539 }
540 
FreeResources(bool immediately)541 void CGUISliderControl::FreeResources(bool immediately)
542 {
543   CGUIControl::FreeResources(immediately);
544   m_guiBackground->FreeResources(immediately);
545   m_guiSelectorLower->FreeResources(immediately);
546   m_guiSelectorUpper->FreeResources(immediately);
547   m_guiSelectorLowerFocus->FreeResources(immediately);
548   m_guiSelectorUpperFocus->FreeResources(immediately);
549 }
550 
DynamicResourceAlloc(bool bOnOff)551 void CGUISliderControl::DynamicResourceAlloc(bool bOnOff)
552 {
553   CGUIControl::DynamicResourceAlloc(bOnOff);
554   m_guiBackground->DynamicResourceAlloc(bOnOff);
555   m_guiSelectorLower->DynamicResourceAlloc(bOnOff);
556   m_guiSelectorUpper->DynamicResourceAlloc(bOnOff);
557   m_guiSelectorLowerFocus->DynamicResourceAlloc(bOnOff);
558   m_guiSelectorUpperFocus->DynamicResourceAlloc(bOnOff);
559 }
560 
AllocResources()561 void CGUISliderControl::AllocResources()
562 {
563   CGUIControl::AllocResources();
564   m_guiBackground->AllocResources();
565   m_guiSelectorLower->AllocResources();
566   m_guiSelectorUpper->AllocResources();
567   m_guiSelectorLowerFocus->AllocResources();
568   m_guiSelectorUpperFocus->AllocResources();
569 }
570 
SetInvalid()571 void CGUISliderControl::SetInvalid()
572 {
573   CGUIControl::SetInvalid();
574   m_guiBackground->SetInvalid();
575   m_guiSelectorLower->SetInvalid();
576   m_guiSelectorUpper->SetInvalid();
577   m_guiSelectorLowerFocus->SetInvalid();
578   m_guiSelectorUpperFocus->SetInvalid();
579 }
580 
HitTest(const CPoint & point) const581 bool CGUISliderControl::HitTest(const CPoint &point) const
582 {
583   if (m_guiBackground->HitTest(point))
584     return true;
585   if (m_guiSelectorLower->HitTest(point))
586     return true;
587   if (m_rangeSelection && m_guiSelectorUpper->HitTest(point))
588     return true;
589   return false;
590 }
591 
SetFromPosition(const CPoint & point,bool guessSelector)592 void CGUISliderControl::SetFromPosition(const CPoint &point, bool guessSelector /* = false */)
593 {
594 
595   float fPercent;
596   if (m_orientation == HORIZONTAL)
597     fPercent = (point.x - m_guiBackground->GetXPosition()) / m_guiBackground->GetWidth();
598   else
599     fPercent = (m_guiBackground->GetYPosition() + m_guiBackground->GetHeight() - point.y) /
600                m_guiBackground->GetHeight();
601 
602   if (fPercent < 0) fPercent = 0;
603   if (fPercent > 1) fPercent = 1;
604 
605   if (m_rangeSelection && guessSelector)
606   {
607     // choose selector which value is closer to value calculated from position
608     if (fabs(GetPercentage(RangeSelectorLower) - 100 * fPercent) <= fabs(GetPercentage(RangeSelectorUpper) - 100 * fPercent))
609       m_currentSelector = RangeSelectorLower;
610     else
611       m_currentSelector = RangeSelectorUpper;
612   }
613 
614   switch (m_iType)
615   {
616   case SLIDER_CONTROL_TYPE_FLOAT:
617     {
618       float fValue = m_fStart + (m_fEnd - m_fStart) * fPercent;
619       SetFloatValue(fValue, m_currentSelector, true);
620       break;
621     }
622 
623   case SLIDER_CONTROL_TYPE_INT:
624     {
625       int iValue = (int)(m_iStart + (float)(m_iEnd - m_iStart) * fPercent + 0.49f);
626       SetIntValue(iValue, m_currentSelector, true);
627       break;
628     }
629 
630   case SLIDER_CONTROL_TYPE_PERCENTAGE:
631   default:
632     {
633       SetPercentage(fPercent * 100, m_currentSelector, true);
634       break;
635     }
636   }
637   SendClick();
638 }
639 
OnMouseEvent(const CPoint & point,const CMouseEvent & event)640 EVENT_RESULT CGUISliderControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
641 {
642   m_dragging = false;
643   if (event.m_id == ACTION_MOUSE_DRAG)
644   {
645     m_dragging = true;
646     bool guessSelector = false;
647     if (event.m_state == 1)
648     { // grab exclusive access
649       CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
650       SendWindowMessage(msg);
651       guessSelector = true;
652     }
653     else if (event.m_state == 3)
654     { // release exclusive access
655       m_dragging = false;
656       CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
657       SendWindowMessage(msg);
658     }
659     SetFromPosition(point, guessSelector);
660     return EVENT_RESULT_HANDLED;
661   }
662   else if (event.m_id == ACTION_MOUSE_LEFT_CLICK && m_guiBackground->HitTest(point))
663   {
664     SetFromPosition(point, true);
665     return EVENT_RESULT_HANDLED;
666   }
667   else if (event.m_id == ACTION_MOUSE_WHEEL_UP)
668   {
669     if (m_guiBackground->HitTest(point))
670     {
671       Move(10);
672       return EVENT_RESULT_HANDLED;
673     }
674   }
675   else if (event.m_id == ACTION_MOUSE_WHEEL_DOWN)
676   {
677     if (m_guiBackground->HitTest(point))
678     {
679       Move(-10);
680       return EVENT_RESULT_HANDLED;
681     }
682   }
683   else if (event.m_id == ACTION_GESTURE_NOTIFY)
684   {
685     return EVENT_RESULT_PAN_HORIZONTAL_WITHOUT_INERTIA;
686   }
687   else if (event.m_id == ACTION_GESTURE_BEGIN)
688   { // grab exclusive access
689     CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
690     SendWindowMessage(msg);
691     return EVENT_RESULT_HANDLED;
692   }
693   else if (event.m_id == ACTION_GESTURE_PAN)
694   { // do the drag
695     SetFromPosition(point);
696     return EVENT_RESULT_HANDLED;
697   }
698   else if (event.m_id == ACTION_GESTURE_END || event.m_id == ACTION_GESTURE_ABORT)
699   { // release exclusive access
700     CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
701     SendWindowMessage(msg);
702     return EVENT_RESULT_HANDLED;
703   }
704   return EVENT_RESULT_UNHANDLED;
705 }
706 
SetInfo(int iInfo)707 void CGUISliderControl::SetInfo(int iInfo)
708 {
709   m_iInfoCode = iInfo;
710 }
711 
GetDescription() const712 std::string CGUISliderControl::GetDescription() const
713 {
714   if (!m_textValue.empty())
715     return m_textValue;
716   std::string description;
717   if (m_iType == SLIDER_CONTROL_TYPE_FLOAT)
718   {
719     if (m_rangeSelection)
720       description = StringUtils::Format("[%2.2f, %2.2f]", m_floatValues[0], m_floatValues[1]);
721     else
722       description = StringUtils::Format("%2.2f", m_floatValues[0]);
723   }
724   else if (m_iType == SLIDER_CONTROL_TYPE_INT)
725   {
726     if (m_rangeSelection)
727       description = StringUtils::Format("[%i, %i]", m_intValues[0], m_intValues[1]);
728     else
729       description = StringUtils::Format("%i", m_intValues[0]);
730   }
731   else
732   {
733     if (m_rangeSelection)
734       description = StringUtils::Format("[%i%%, %i%%]", MathUtils::round_int(m_percentValues[0]), MathUtils::round_int(m_percentValues[1]));
735     else
736       description = StringUtils::Format("%i%%", MathUtils::round_int(m_percentValues[0]));
737   }
738   return description;
739 }
740 
UpdateColors()741 bool CGUISliderControl::UpdateColors()
742 {
743   bool changed = CGUIControl::UpdateColors();
744   changed |= m_guiBackground->SetDiffuseColor(m_diffuseColor);
745   changed |= m_guiSelectorLower->SetDiffuseColor(m_diffuseColor);
746   changed |= m_guiSelectorUpper->SetDiffuseColor(m_diffuseColor);
747   changed |= m_guiSelectorLowerFocus->SetDiffuseColor(m_diffuseColor);
748   changed |= m_guiSelectorUpperFocus->SetDiffuseColor(m_diffuseColor);
749 
750   return changed;
751 }
752 
GetProportion(RangeSelector selector) const753 float CGUISliderControl::GetProportion(RangeSelector selector /* = RangeSelectorLower */) const
754 {
755   if (m_iType == SLIDER_CONTROL_TYPE_FLOAT)
756     return m_fStart != m_fEnd ? (GetFloatValue(selector) - m_fStart) / (m_fEnd - m_fStart) : 0.0f;
757   else if (m_iType == SLIDER_CONTROL_TYPE_INT)
758     return m_iStart != m_iEnd ? (float)(GetIntValue(selector) - m_iStart) / (float)(m_iEnd - m_iStart) : 0.0f;
759   return 0.01f * GetPercentage(selector);
760 }
761 
SetAction(const std::string & action)762 void CGUISliderControl::SetAction(const std::string &action)
763 {
764   for (const SliderAction& a : actions)
765   {
766     if (StringUtils::EqualsNoCase(action, a.action))
767     {
768       m_action = &a;
769       return;
770     }
771   }
772   m_action = NULL;
773 }
774