Merge pull request #22816 from CastagnaIT/fix_tx3g
[xbmc.git] / xbmc / guilib / GUISpinControl.cpp
blobf0a0f3980b0f41fb3b43212b550bd586f09b367a
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "GUISpinControl.h"
11 #include "GUIMessage.h"
12 #include "input/Key.h"
13 #include "utils/StringUtils.h"
15 #include <stdio.h>
17 #define SPIN_BUTTON_DOWN 1
18 #define SPIN_BUTTON_UP 2
20 namespace
22 // Additional space between text and spin buttons
23 constexpr float TEXT_SPACE = 5.0f;
24 } // unnamed namespace
26 CGUISpinControl::CGUISpinControl(int parentID,
27 int controlID,
28 float posX,
29 float posY,
30 float width,
31 float height,
32 const CTextureInfo& textureUp,
33 const CTextureInfo& textureDown,
34 const CTextureInfo& textureUpFocus,
35 const CTextureInfo& textureDownFocus,
36 const CTextureInfo& textureUpDisabled,
37 const CTextureInfo& textureDownDisabled,
38 const CLabelInfo& labelInfo,
39 int iType)
40 : CGUIControl(parentID, controlID, posX, posY, width, height),
41 m_imgspinUp(CGUITexture::CreateTexture(posX, posY, width, height, textureUp)),
42 m_imgspinDown(CGUITexture::CreateTexture(posX, posY, width, height, textureDown)),
43 m_imgspinUpFocus(CGUITexture::CreateTexture(posX, posY, width, height, textureUpFocus)),
44 m_imgspinDownFocus(CGUITexture::CreateTexture(posX, posY, width, height, textureDownFocus)),
45 m_imgspinUpDisabled(CGUITexture::CreateTexture(posX, posY, width, height, textureUpDisabled)),
46 m_imgspinDownDisabled(
47 CGUITexture::CreateTexture(posX, posY, width, height, textureDownDisabled)),
48 m_label(posX, posY, width, height, labelInfo)
50 m_bReverse = false;
51 m_iStart = 0;
52 m_iEnd = 100;
53 m_fStart = 0.0f;
54 m_fEnd = 1.0f;
55 m_fInterval = 0.1f;
56 m_iValue = 0;
57 m_fValue = 0.0;
58 m_iType = iType;
59 m_iSelect = SPIN_BUTTON_DOWN;
60 m_bShowRange = false;
61 m_iTypedPos = 0;
62 strcpy(m_szTyped, "");
63 ControlType = GUICONTROL_SPIN;
64 m_currentItem = 0;
65 m_numItems = 10;
66 m_itemsPerPage = 10;
67 m_showOnePage = true;
70 CGUISpinControl::CGUISpinControl(const CGUISpinControl& control)
71 : CGUIControl(control),
72 m_iStart(control.m_iStart),
73 m_iEnd(control.m_iEnd),
74 m_fStart(control.m_fStart),
75 m_fEnd(control.m_fEnd),
76 m_iValue(control.m_iValue),
77 m_fValue(control.m_fValue),
78 m_iType(control.m_iType),
79 m_iSelect(control.m_iSelect),
80 m_bReverse(control.m_bReverse),
81 m_fInterval(control.m_fInterval),
82 m_vecLabels(control.m_vecLabels),
83 m_vecValues(control.m_vecValues),
84 m_vecStrValues(control.m_vecStrValues),
85 m_imgspinUp(control.m_imgspinUp->Clone()),
86 m_imgspinDown(control.m_imgspinDown->Clone()),
87 m_imgspinUpFocus(control.m_imgspinUpFocus->Clone()),
88 m_imgspinDownFocus(control.m_imgspinDownFocus->Clone()),
89 m_imgspinUpDisabled(control.m_imgspinUpDisabled->Clone()),
90 m_imgspinDownDisabled(control.m_imgspinDownDisabled->Clone()),
91 m_label(control.m_label),
92 m_bShowRange(control.m_bShowRange),
93 m_iTypedPos(control.m_iTypedPos),
94 m_currentItem(control.m_currentItem),
95 m_itemsPerPage(control.m_itemsPerPage),
96 m_numItems(control.m_numItems),
97 m_showOnePage(control.m_showOnePage)
99 std::strcpy(m_szTyped, control.m_szTyped);
102 bool CGUISpinControl::OnAction(const CAction &action)
104 switch (action.GetID())
106 case REMOTE_0:
107 case REMOTE_1:
108 case REMOTE_2:
109 case REMOTE_3:
110 case REMOTE_4:
111 case REMOTE_5:
112 case REMOTE_6:
113 case REMOTE_7:
114 case REMOTE_8:
115 case REMOTE_9:
117 if (strlen(m_szTyped) >= 3)
119 m_iTypedPos = 0;
120 strcpy(m_szTyped, "");
122 int iNumber = action.GetID() - REMOTE_0;
124 m_szTyped[m_iTypedPos] = iNumber + '0';
125 m_iTypedPos++;
126 m_szTyped[m_iTypedPos] = 0;
127 int iValue;
128 sscanf(m_szTyped, "%i", &iValue);
129 switch (m_iType)
131 case SPIN_CONTROL_TYPE_INT:
133 if (iValue < m_iStart || iValue > m_iEnd)
135 m_iTypedPos = 0;
136 m_szTyped[m_iTypedPos] = iNumber + '0';
137 m_iTypedPos++;
138 m_szTyped[m_iTypedPos] = 0;
139 sscanf(m_szTyped, "%i", &iValue);
140 if (iValue < m_iStart || iValue > m_iEnd)
142 m_iTypedPos = 0;
143 strcpy(m_szTyped, "");
144 return true;
147 m_iValue = iValue;
148 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
149 SendWindowMessage(msg);
151 break;
153 case SPIN_CONTROL_TYPE_TEXT:
155 if (iValue < 0 || iValue >= (int)m_vecLabels.size())
157 m_iTypedPos = 0;
158 m_szTyped[m_iTypedPos] = iNumber + '0';
159 m_iTypedPos++;
160 m_szTyped[m_iTypedPos] = 0;
161 sscanf(m_szTyped, "%i", &iValue);
162 if (iValue < 0 || iValue >= (int)m_vecLabels.size())
164 m_iTypedPos = 0;
165 strcpy(m_szTyped, "");
166 return true;
169 m_iValue = iValue;
170 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
171 SendWindowMessage(msg);
173 break;
176 return true;
178 break;
179 case ACTION_PAGE_UP:
180 if (!m_bReverse)
181 PageDown();
182 else
183 PageUp();
184 return true;
185 break;
186 case ACTION_PAGE_DOWN:
187 if (!m_bReverse)
188 PageUp();
189 else
190 PageDown();
191 return true;
192 break;
193 case ACTION_SELECT_ITEM:
194 if (m_iSelect == SPIN_BUTTON_UP)
196 MoveUp();
197 return true;
199 if (m_iSelect == SPIN_BUTTON_DOWN)
201 MoveDown();
202 return true;
204 break;
206 /* static float m_fSmoothScrollOffset = 0.0f;
207 if (action.GetID() == ACTION_SCROLL_UP)
209 m_fSmoothScrollOffset += action.GetAmount() * action.GetAmount();
210 bool handled = false;
211 while (m_fSmoothScrollOffset > 0.4)
213 handled = true;
214 m_fSmoothScrollOffset -= 0.4f;
215 MoveDown();
217 return handled;
219 return CGUIControl::OnAction(action);
222 void CGUISpinControl::OnLeft()
224 if (m_iSelect == SPIN_BUTTON_UP)
226 // select the down button
227 m_iSelect = SPIN_BUTTON_DOWN;
228 MarkDirtyRegion();
230 else
231 { // base class
232 CGUIControl::OnLeft();
236 void CGUISpinControl::OnRight()
238 if (m_iSelect == SPIN_BUTTON_DOWN)
240 // select the up button
241 m_iSelect = SPIN_BUTTON_UP;
242 MarkDirtyRegion();
244 else
245 { // base class
246 CGUIControl::OnRight();
250 void CGUISpinControl::Clear()
252 m_vecLabels.clear();
253 m_vecValues.clear();
254 m_vecStrValues.clear();
255 SetValue(0);
258 bool CGUISpinControl::OnMessage(CGUIMessage& message)
260 if (CGUIControl::OnMessage(message) )
261 return true;
262 if (message.GetControlId() == GetID() )
264 switch (message.GetMessage())
266 case GUI_MSG_ITEM_SELECT:
267 if (SPIN_CONTROL_TYPE_PAGE == m_iType)
269 m_currentItem = message.GetParam1();
270 return true;
272 SetValue( message.GetParam1());
273 if (message.GetParam2() == SPIN_BUTTON_DOWN || message.GetParam2() == SPIN_BUTTON_UP)
274 m_iSelect = message.GetParam2();
275 return true;
276 break;
278 case GUI_MSG_LABEL_RESET:
279 if (SPIN_CONTROL_TYPE_PAGE == m_iType)
281 m_itemsPerPage = message.GetParam1();
282 m_numItems = message.GetParam2();
283 return true;
286 Clear();
287 return true;
289 break;
291 case GUI_MSG_SHOWRANGE:
292 if (message.GetParam1() )
293 m_bShowRange = true;
294 else
295 m_bShowRange = false;
296 break;
298 case GUI_MSG_SET_LABELS:
299 if (message.GetPointer())
301 auto labels =
302 static_cast<const std::vector<std::pair<std::string, int>>*>(message.GetPointer());
303 Clear();
304 for (const auto& i : *labels)
305 AddLabel(i.first, i.second);
306 SetValue( message.GetParam1());
308 break;
310 case GUI_MSG_LABEL_ADD:
312 AddLabel(message.GetLabel(), message.GetParam1());
313 return true;
315 break;
317 case GUI_MSG_ITEM_SELECTED:
319 message.SetParam1( GetValue() );
320 message.SetParam2(m_iSelect);
322 if (m_iType == SPIN_CONTROL_TYPE_TEXT)
324 if ( m_iValue >= 0 && m_iValue < (int)m_vecLabels.size() )
325 message.SetLabel( m_vecLabels[m_iValue]);
327 return true;
330 case GUI_MSG_PAGE_UP:
331 if (CanMoveUp())
332 MoveUp();
333 return true;
335 case GUI_MSG_PAGE_DOWN:
336 if (CanMoveDown())
337 MoveDown();
338 return true;
340 case GUI_MSG_MOVE_OFFSET:
342 int count = message.GetParam1();
343 while (count < 0)
345 MoveUp();
346 count++;
348 while (count > 0)
350 MoveDown();
351 count--;
353 return true;
358 return false;
361 void CGUISpinControl::AllocResources()
363 CGUIControl::AllocResources();
364 m_imgspinUp->AllocResources();
365 m_imgspinUpFocus->AllocResources();
366 m_imgspinDown->AllocResources();
367 m_imgspinDownFocus->AllocResources();
368 m_imgspinUpDisabled->AllocResources();
369 m_imgspinDownDisabled->AllocResources();
371 m_imgspinDownFocus->SetPosition(m_posX, m_posY);
372 m_imgspinDown->SetPosition(m_posX, m_posY);
373 m_imgspinDownDisabled->SetPosition(m_posX, m_posY);
374 m_imgspinUp->SetPosition(m_posX + m_imgspinDown->GetWidth(), m_posY);
375 m_imgspinUpFocus->SetPosition(m_posX + m_imgspinDownFocus->GetWidth(), m_posY);
376 m_imgspinUpDisabled->SetPosition(m_posX + m_imgspinDownDisabled->GetWidth(), m_posY);
379 void CGUISpinControl::FreeResources(bool immediately)
381 CGUIControl::FreeResources(immediately);
382 m_imgspinUp->FreeResources(immediately);
383 m_imgspinUpFocus->FreeResources(immediately);
384 m_imgspinDown->FreeResources(immediately);
385 m_imgspinDownFocus->FreeResources(immediately);
386 m_imgspinUpDisabled->FreeResources(immediately);
387 m_imgspinDownDisabled->FreeResources(immediately);
388 m_iTypedPos = 0;
389 strcpy(m_szTyped, "");
392 void CGUISpinControl::DynamicResourceAlloc(bool bOnOff)
394 CGUIControl::DynamicResourceAlloc(bOnOff);
395 m_imgspinUp->DynamicResourceAlloc(bOnOff);
396 m_imgspinUpFocus->DynamicResourceAlloc(bOnOff);
397 m_imgspinDown->DynamicResourceAlloc(bOnOff);
398 m_imgspinDownFocus->DynamicResourceAlloc(bOnOff);
399 m_imgspinUpDisabled->DynamicResourceAlloc(bOnOff);
400 m_imgspinDownDisabled->DynamicResourceAlloc(bOnOff);
403 void CGUISpinControl::SetInvalid()
405 CGUIControl::SetInvalid();
406 m_label.SetInvalid();
407 m_imgspinUp->SetInvalid();
408 m_imgspinUpFocus->SetInvalid();
409 m_imgspinDown->SetInvalid();
410 m_imgspinDownFocus->SetInvalid();
411 m_imgspinUpDisabled->SetInvalid();
412 m_imgspinDownDisabled->SetInvalid();
415 void CGUISpinControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
417 bool changed = false;
419 if (!HasFocus())
421 m_iTypedPos = 0;
422 strcpy(m_szTyped, "");
425 std::string text;
427 if (m_iType == SPIN_CONTROL_TYPE_INT)
429 if (m_bShowRange)
431 text = StringUtils::Format("{}/{}", m_iValue, m_iEnd);
433 else
435 text = std::to_string(m_iValue);
438 else if (m_iType == SPIN_CONTROL_TYPE_PAGE)
440 // work out number of pages and current page
441 int numPages = (m_numItems + m_itemsPerPage - 1) / m_itemsPerPage;
442 int currentPage = m_currentItem / m_itemsPerPage + 1;
443 if (m_currentItem >= m_numItems - m_itemsPerPage)
444 currentPage = numPages;
445 text = StringUtils::Format("{}/{}", currentPage, numPages);
447 else if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
449 if (m_bShowRange)
451 text = StringUtils::Format("{:02.2f}/{:02.2f}", m_fValue, m_fEnd);
453 else
455 text = StringUtils::Format("{:02.2f}", m_fValue);
458 else
460 if (m_iValue >= 0 && m_iValue < (int)m_vecLabels.size() )
462 if (m_bShowRange)
464 text = StringUtils::Format("({}/{}) {}", m_iValue + 1, (int)m_vecLabels.size(),
465 m_vecLabels[m_iValue]);
467 else
469 text = m_vecLabels[m_iValue];
472 else
473 text = StringUtils::Format("?{}?", m_iValue);
476 changed |= m_label.SetText(text);
478 float textWidth = m_label.GetTextWidth() + 2 * m_label.GetLabelInfo().offsetX;
479 // Position the arrows
480 bool arrowsOnRight(0 != (m_label.GetLabelInfo().align & (XBFONT_RIGHT | XBFONT_CENTER_X)));
481 if (!arrowsOnRight)
483 changed |= m_imgspinDownFocus->SetPosition(m_posX + textWidth + TEXT_SPACE, m_posY);
484 changed |= m_imgspinDown->SetPosition(m_posX + textWidth + TEXT_SPACE, m_posY);
485 changed |= m_imgspinDownDisabled->SetPosition(m_posX + textWidth + TEXT_SPACE, m_posY);
486 changed |= m_imgspinUpFocus->SetPosition(
487 m_posX + textWidth + TEXT_SPACE + m_imgspinDown->GetWidth(), m_posY);
488 changed |= m_imgspinUp->SetPosition(m_posX + textWidth + TEXT_SPACE + m_imgspinDown->GetWidth(),
489 m_posY);
490 changed |= m_imgspinUpDisabled->SetPosition(
491 m_posX + textWidth + TEXT_SPACE + m_imgspinDownDisabled->GetWidth(), m_posY);
494 changed |= m_imgspinDownFocus->Process(currentTime);
495 changed |= m_imgspinDown->Process(currentTime);
496 changed |= m_imgspinUp->Process(currentTime);
497 changed |= m_imgspinUpFocus->Process(currentTime);
498 changed |= m_imgspinUpDisabled->Process(currentTime);
499 changed |= m_imgspinDownDisabled->Process(currentTime);
500 changed |= m_label.Process(currentTime);
502 if (changed)
503 MarkDirtyRegion();
505 CGUIControl::Process(currentTime, dirtyregions);
508 void CGUISpinControl::Render()
510 if (m_label.GetLabelInfo().font)
512 float textWidth = m_label.GetTextWidth() + 2 * m_label.GetLabelInfo().offsetX;
513 // Position the arrows
514 bool arrowsOnRight(0 != (m_label.GetLabelInfo().align & (XBFONT_RIGHT | XBFONT_CENTER_X)));
516 if (arrowsOnRight)
517 RenderText(m_posX - TEXT_SPACE - textWidth, m_posY, textWidth, m_height);
518 else
519 RenderText(m_posX + m_imgspinDown->GetWidth() + m_imgspinUp->GetWidth() + TEXT_SPACE, m_posY,
520 textWidth, m_height);
522 // set our hit rectangle for MouseOver events
523 m_hitRect = m_label.GetRenderRect();
526 if (HasFocus())
528 if (m_iSelect == SPIN_BUTTON_UP)
529 m_imgspinUpFocus->Render();
530 else
531 m_imgspinUp->Render();
533 if (m_iSelect == SPIN_BUTTON_DOWN)
534 m_imgspinDownFocus->Render();
535 else
536 m_imgspinDown->Render();
538 else if (!HasFocus() && !IsDisabled())
540 m_imgspinUp->Render();
541 m_imgspinDown->Render();
543 else
545 m_imgspinUpDisabled->Render();
546 m_imgspinDownDisabled->Render();
549 CGUIControl::Render();
552 void CGUISpinControl::RenderText(float posX, float posY, float width, float height)
554 m_label.SetMaxRect(posX, posY, width, height);
555 m_label.SetColor(GetTextColor());
556 m_label.Render();
559 CGUILabel::COLOR CGUISpinControl::GetTextColor() const
561 if (IsDisabled())
562 return CGUILabel::COLOR_DISABLED;
563 else if (HasFocus())
564 return CGUILabel::COLOR_FOCUSED;
565 return CGUILabel::COLOR_TEXT;
568 void CGUISpinControl::SetRange(int iStart, int iEnd)
570 m_iStart = iStart;
571 m_iEnd = iEnd;
574 void CGUISpinControl::SetFloatRange(float fStart, float fEnd)
576 m_fStart = fStart;
577 m_fEnd = fEnd;
580 void CGUISpinControl::SetValueFromLabel(const std::string &label)
582 if (m_iType == SPIN_CONTROL_TYPE_TEXT)
584 m_iValue = 0;
585 for (unsigned int i = 0; i < m_vecLabels.size(); i++)
586 if (label == m_vecLabels[i])
587 m_iValue = i;
589 else
590 m_iValue = atoi(label.c_str());
592 MarkDirtyRegion();
593 SetInvalid();
596 void CGUISpinControl::SetValue(int iValue)
598 if (m_iType == SPIN_CONTROL_TYPE_TEXT)
600 m_iValue = 0;
601 for (unsigned int i = 0; i < m_vecValues.size(); i++)
602 if (iValue == m_vecValues[i])
603 m_iValue = i;
605 else
606 m_iValue = iValue;
608 MarkDirtyRegion();
609 SetInvalid();
612 void CGUISpinControl::SetFloatValue(float fValue)
614 m_fValue = fValue;
617 void CGUISpinControl::SetStringValue(const std::string& strValue)
619 if (m_iType == SPIN_CONTROL_TYPE_TEXT)
621 m_iValue = 0;
622 for (unsigned int i = 0; i < m_vecStrValues.size(); i++)
623 if (strValue == m_vecStrValues[i])
624 m_iValue = i;
627 SetInvalid();
630 int CGUISpinControl::GetValue() const
632 if (m_iType == SPIN_CONTROL_TYPE_TEXT)
634 if (m_iValue >= 0 && m_iValue < (int)m_vecValues.size())
635 return m_vecValues[m_iValue];
637 return m_iValue;
640 float CGUISpinControl::GetFloatValue() const
642 return m_fValue;
645 std::string CGUISpinControl::GetStringValue() const
647 if (m_iType == SPIN_CONTROL_TYPE_TEXT && m_iValue >= 0 && m_iValue < (int)m_vecLabels.size())
649 if (m_iValue < (int)m_vecStrValues.size())
650 return m_vecStrValues[m_iValue];
652 return m_vecLabels[m_iValue];
654 return "";
657 void CGUISpinControl::AddLabel(const std::string& strLabel, int iValue)
659 m_vecLabels.push_back(strLabel);
660 m_vecValues.push_back(iValue);
663 void CGUISpinControl::AddLabel(const std::string& strLabel, const std::string& strValue)
665 m_vecLabels.push_back(strLabel);
666 m_vecStrValues.push_back(strValue);
669 const std::string CGUISpinControl::GetLabel() const
671 if (m_iValue >= 0 && m_iValue < (int)m_vecLabels.size())
673 return m_vecLabels[m_iValue];
675 return "";
678 void CGUISpinControl::SetPosition(float posX, float posY)
680 CGUIControl::SetPosition(posX, posY);
682 m_imgspinDownFocus->SetPosition(posX, posY);
683 m_imgspinDown->SetPosition(posX, posY);
684 m_imgspinDownDisabled->SetPosition(posX, posY);
686 m_imgspinUp->SetPosition(m_posX + m_imgspinDown->GetWidth(), m_posY);
687 m_imgspinUpFocus->SetPosition(m_posX + m_imgspinDownFocus->GetWidth(), m_posY);
688 m_imgspinUpDisabled->SetPosition(m_posX + m_imgspinDownDisabled->GetWidth(), m_posY);
691 float CGUISpinControl::GetWidth() const
693 return m_imgspinDown->GetWidth() * 2;
696 bool CGUISpinControl::CanMoveUp(bool bTestReverse)
698 // test for reverse...
699 if (bTestReverse && m_bReverse) return CanMoveDown(false);
701 switch (m_iType)
703 case SPIN_CONTROL_TYPE_PAGE:
704 return m_currentItem > 0;
705 case SPIN_CONTROL_TYPE_INT:
707 if (m_iValue - 1 >= m_iStart)
708 return true;
709 return false;
711 break;
713 case SPIN_CONTROL_TYPE_FLOAT:
715 if (m_fValue - m_fInterval >= m_fStart)
716 return true;
717 return false;
719 break;
721 case SPIN_CONTROL_TYPE_TEXT:
723 if (m_iValue - 1 >= 0)
724 return true;
725 return false;
727 break;
729 return false;
732 bool CGUISpinControl::CanMoveDown(bool bTestReverse)
734 // test for reverse...
735 if (bTestReverse && m_bReverse) return CanMoveUp(false);
736 switch (m_iType)
738 case SPIN_CONTROL_TYPE_PAGE:
739 return m_currentItem < m_numItems;
740 case SPIN_CONTROL_TYPE_INT:
742 if (m_iValue + 1 <= m_iEnd)
743 return true;
744 return false;
746 break;
748 case SPIN_CONTROL_TYPE_FLOAT:
750 if (m_fValue + m_fInterval <= m_fEnd)
751 return true;
752 return false;
754 break;
756 case SPIN_CONTROL_TYPE_TEXT:
758 if (m_iValue + 1 < (int)m_vecLabels.size())
759 return true;
760 return false;
762 break;
764 return false;
767 void CGUISpinControl::PageUp()
769 switch (m_iType)
771 case SPIN_CONTROL_TYPE_INT:
773 if (m_iValue - 10 >= m_iStart)
774 m_iValue -= 10;
775 else
776 m_iValue = m_iStart;
777 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
778 SendWindowMessage(msg);
779 return ;
781 break;
782 case SPIN_CONTROL_TYPE_PAGE:
783 ChangePage(-10);
784 break;
785 case SPIN_CONTROL_TYPE_TEXT:
787 if (m_iValue - 10 >= 0)
788 m_iValue -= 10;
789 else
790 m_iValue = 0;
791 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
792 SendWindowMessage(msg);
793 return ;
795 break;
800 void CGUISpinControl::PageDown()
802 switch (m_iType)
804 case SPIN_CONTROL_TYPE_INT:
806 if (m_iValue + 10 <= m_iEnd)
807 m_iValue += 10;
808 else
809 m_iValue = m_iEnd;
810 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
811 SendWindowMessage(msg);
812 return ;
814 break;
815 case SPIN_CONTROL_TYPE_PAGE:
816 ChangePage(10);
817 break;
818 case SPIN_CONTROL_TYPE_TEXT:
820 if (m_iValue + 10 < (int)m_vecLabels.size() )
821 m_iValue += 10;
822 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
823 SendWindowMessage(msg);
825 break;
829 void CGUISpinControl::MoveUp(bool bTestReverse)
831 if (bTestReverse && m_bReverse)
832 { // actually should move down.
833 MoveDown(false);
834 return ;
836 switch (m_iType)
838 case SPIN_CONTROL_TYPE_INT:
840 if (m_iValue - 1 >= m_iStart)
841 m_iValue--;
842 else if (m_iValue == m_iStart)
843 m_iValue = m_iEnd;
844 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
845 SendWindowMessage(msg);
846 return ;
848 break;
850 case SPIN_CONTROL_TYPE_PAGE:
851 ChangePage(-1);
852 break;
854 case SPIN_CONTROL_TYPE_FLOAT:
856 if (m_fValue - m_fInterval >= m_fStart)
857 m_fValue -= m_fInterval;
858 else
859 m_fValue = m_fEnd;
860 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
861 SendWindowMessage(msg);
862 return ;
864 break;
866 case SPIN_CONTROL_TYPE_TEXT:
868 if (m_iValue - 1 >= 0)
869 m_iValue--;
870 else if (m_iValue == 0)
871 m_iValue = (int)m_vecLabels.size() - 1;
872 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
873 SendWindowMessage(msg);
874 return ;
876 break;
880 void CGUISpinControl::MoveDown(bool bTestReverse)
882 if (bTestReverse && m_bReverse)
883 { // actually should move up.
884 MoveUp(false);
885 return ;
887 switch (m_iType)
889 case SPIN_CONTROL_TYPE_INT:
891 if (m_iValue + 1 <= m_iEnd)
892 m_iValue++;
893 else if (m_iValue == m_iEnd)
894 m_iValue = m_iStart;
895 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
896 SendWindowMessage(msg);
897 return ;
899 break;
901 case SPIN_CONTROL_TYPE_PAGE:
902 ChangePage(1);
903 break;
905 case SPIN_CONTROL_TYPE_FLOAT:
907 if (m_fValue + m_fInterval <= m_fEnd)
908 m_fValue += m_fInterval;
909 else
910 m_fValue = m_fStart;
911 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
912 SendWindowMessage(msg);
913 return ;
915 break;
917 case SPIN_CONTROL_TYPE_TEXT:
919 if (m_iValue + 1 < (int)m_vecLabels.size() )
920 m_iValue++;
921 else if (m_iValue == (int)m_vecLabels.size() - 1)
922 m_iValue = 0;
923 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
924 SendWindowMessage(msg);
925 return ;
927 break;
930 void CGUISpinControl::SetReverse(bool bReverse)
932 m_bReverse = bReverse;
935 void CGUISpinControl::SetFloatInterval(float fInterval)
937 m_fInterval = fInterval;
940 void CGUISpinControl::SetShowRange(bool bOnoff)
942 m_bShowRange = bOnoff;
945 int CGUISpinControl::GetMinimum() const
947 switch (m_iType)
949 case SPIN_CONTROL_TYPE_PAGE:
950 return 0;
951 case SPIN_CONTROL_TYPE_INT:
952 return m_iStart;
953 break;
955 case SPIN_CONTROL_TYPE_TEXT:
956 return 1;
957 break;
959 case SPIN_CONTROL_TYPE_FLOAT:
960 return (int)(m_fStart*10.0f);
961 break;
963 return 0;
966 int CGUISpinControl::GetMaximum() const
968 switch (m_iType)
970 case SPIN_CONTROL_TYPE_PAGE:
971 return m_numItems;
972 case SPIN_CONTROL_TYPE_INT:
973 return m_iEnd;
974 break;
976 case SPIN_CONTROL_TYPE_TEXT:
977 return (int)m_vecLabels.size();
978 break;
980 case SPIN_CONTROL_TYPE_FLOAT:
981 return (int)(m_fEnd*10.0f);
982 break;
984 return 100;
987 bool CGUISpinControl::HitTest(const CPoint &point) const
989 if (m_imgspinUpFocus->HitTest(point) || m_imgspinDownFocus->HitTest(point))
990 return true;
991 return CGUIControl::HitTest(point);
994 bool CGUISpinControl::OnMouseOver(const CPoint &point)
996 int select = m_iSelect;
997 if (m_imgspinDownFocus->HitTest(point))
998 m_iSelect = SPIN_BUTTON_DOWN;
999 else
1000 m_iSelect = SPIN_BUTTON_UP;
1002 if (select != m_iSelect)
1003 MarkDirtyRegion();
1005 return CGUIControl::OnMouseOver(point);
1008 EVENT_RESULT CGUISpinControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
1010 if (event.m_id == ACTION_MOUSE_LEFT_CLICK)
1012 if (m_imgspinUpFocus->HitTest(point))
1013 MoveUp();
1014 else if (m_imgspinDownFocus->HitTest(point))
1015 MoveDown();
1016 return EVENT_RESULT_HANDLED;
1018 else if (event.m_id == ACTION_MOUSE_WHEEL_UP)
1020 if (m_imgspinUpFocus->HitTest(point) || m_imgspinDownFocus->HitTest(point))
1022 MoveUp();
1023 return EVENT_RESULT_HANDLED;
1026 else if (event.m_id == ACTION_MOUSE_WHEEL_DOWN)
1028 if (m_imgspinUpFocus->HitTest(point) || m_imgspinDownFocus->HitTest(point))
1030 MoveDown();
1031 return EVENT_RESULT_HANDLED;
1034 return EVENT_RESULT_UNHANDLED;
1037 std::string CGUISpinControl::GetDescription() const
1039 return StringUtils::Format("{}/{}", 1 + GetValue(), GetMaximum());
1042 bool CGUISpinControl::IsFocusedOnUp() const
1044 return (m_iSelect == SPIN_BUTTON_UP);
1047 void CGUISpinControl::ChangePage(int amount)
1049 m_currentItem += amount * m_itemsPerPage;
1050 if (m_currentItem > m_numItems - m_itemsPerPage)
1051 m_currentItem = m_numItems - m_itemsPerPage;
1052 if (m_currentItem < 0)
1053 m_currentItem = 0;
1054 CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_currentItem);
1055 SendWindowMessage(message);
1058 bool CGUISpinControl::UpdateColors(const CGUIListItem* item)
1060 bool changed = CGUIControl::UpdateColors(nullptr);
1061 changed |= m_label.UpdateColors();
1062 changed |= m_imgspinDownFocus->SetDiffuseColor(m_diffuseColor);
1063 changed |= m_imgspinDown->SetDiffuseColor(m_diffuseColor);
1064 changed |= m_imgspinUp->SetDiffuseColor(m_diffuseColor);
1065 changed |= m_imgspinUpFocus->SetDiffuseColor(m_diffuseColor);
1066 changed |= m_imgspinUpDisabled->SetDiffuseColor(m_diffuseColor);
1067 changed |= m_imgspinDownDisabled->SetDiffuseColor(m_diffuseColor);
1069 return changed;
1072 bool CGUISpinControl::IsVisible() const
1074 // page controls can be optionally disabled if the number of pages is 1
1075 if (m_iType == SPIN_CONTROL_TYPE_PAGE && m_numItems <= m_itemsPerPage && !m_showOnePage)
1076 return false;
1077 return CGUIControl::IsVisible();