[Test] Added tests for CUtil::SplitParams
[xbmc.git] / xbmc / guilib / GUISpinControl.cpp
blob2545985a345dae7c2b67e594897888eb64f7e338
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/actions/Action.h"
13 #include "input/actions/ActionIDs.h"
14 #include "input/mouse/MouseEvent.h"
15 #include "utils/StringUtils.h"
17 #include <stdio.h>
19 #define SPIN_BUTTON_DOWN 1
20 #define SPIN_BUTTON_UP 2
22 using namespace KODI;
24 namespace
26 // Additional space between text and spin buttons
27 constexpr float TEXT_SPACE = 5.0f;
28 } // unnamed namespace
30 CGUISpinControl::CGUISpinControl(int parentID,
31 int controlID,
32 float posX,
33 float posY,
34 float width,
35 float height,
36 const CTextureInfo& textureUp,
37 const CTextureInfo& textureDown,
38 const CTextureInfo& textureUpFocus,
39 const CTextureInfo& textureDownFocus,
40 const CTextureInfo& textureUpDisabled,
41 const CTextureInfo& textureDownDisabled,
42 const CLabelInfo& labelInfo,
43 int iType)
44 : CGUIControl(parentID, controlID, posX, posY, width, height),
45 m_imgspinUp(CGUITexture::CreateTexture(posX, posY, width, height, textureUp)),
46 m_imgspinDown(CGUITexture::CreateTexture(posX, posY, width, height, textureDown)),
47 m_imgspinUpFocus(CGUITexture::CreateTexture(posX, posY, width, height, textureUpFocus)),
48 m_imgspinDownFocus(CGUITexture::CreateTexture(posX, posY, width, height, textureDownFocus)),
49 m_imgspinUpDisabled(CGUITexture::CreateTexture(posX, posY, width, height, textureUpDisabled)),
50 m_imgspinDownDisabled(
51 CGUITexture::CreateTexture(posX, posY, width, height, textureDownDisabled)),
52 m_label(posX, posY, width, height, labelInfo)
54 m_bReverse = false;
55 m_iStart = 0;
56 m_iEnd = 100;
57 m_fStart = 0.0f;
58 m_fEnd = 1.0f;
59 m_fInterval = 0.1f;
60 m_iValue = 0;
61 m_fValue = 0.0;
62 m_iType = iType;
63 m_iSelect = SPIN_BUTTON_DOWN;
64 m_bShowRange = false;
65 m_iTypedPos = 0;
66 strcpy(m_szTyped, "");
67 ControlType = GUICONTROL_SPIN;
68 m_currentItem = 0;
69 m_numItems = 10;
70 m_itemsPerPage = 10;
71 m_showOnePage = true;
74 CGUISpinControl::CGUISpinControl(const CGUISpinControl& control)
75 : CGUIControl(control),
76 m_iStart(control.m_iStart),
77 m_iEnd(control.m_iEnd),
78 m_fStart(control.m_fStart),
79 m_fEnd(control.m_fEnd),
80 m_iValue(control.m_iValue),
81 m_fValue(control.m_fValue),
82 m_iType(control.m_iType),
83 m_iSelect(control.m_iSelect),
84 m_bReverse(control.m_bReverse),
85 m_fInterval(control.m_fInterval),
86 m_vecLabels(control.m_vecLabels),
87 m_vecValues(control.m_vecValues),
88 m_vecStrValues(control.m_vecStrValues),
89 m_imgspinUp(control.m_imgspinUp->Clone()),
90 m_imgspinDown(control.m_imgspinDown->Clone()),
91 m_imgspinUpFocus(control.m_imgspinUpFocus->Clone()),
92 m_imgspinDownFocus(control.m_imgspinDownFocus->Clone()),
93 m_imgspinUpDisabled(control.m_imgspinUpDisabled->Clone()),
94 m_imgspinDownDisabled(control.m_imgspinDownDisabled->Clone()),
95 m_label(control.m_label),
96 m_bShowRange(control.m_bShowRange),
97 m_iTypedPos(control.m_iTypedPos),
98 m_currentItem(control.m_currentItem),
99 m_itemsPerPage(control.m_itemsPerPage),
100 m_numItems(control.m_numItems),
101 m_showOnePage(control.m_showOnePage)
103 std::strcpy(m_szTyped, control.m_szTyped);
106 bool CGUISpinControl::OnAction(const CAction &action)
108 switch (action.GetID())
110 case REMOTE_0:
111 case REMOTE_1:
112 case REMOTE_2:
113 case REMOTE_3:
114 case REMOTE_4:
115 case REMOTE_5:
116 case REMOTE_6:
117 case REMOTE_7:
118 case REMOTE_8:
119 case REMOTE_9:
121 if (strlen(m_szTyped) >= 3)
123 m_iTypedPos = 0;
124 strcpy(m_szTyped, "");
126 int iNumber = action.GetID() - REMOTE_0;
128 m_szTyped[m_iTypedPos] = iNumber + '0';
129 m_iTypedPos++;
130 m_szTyped[m_iTypedPos] = 0;
131 int iValue;
132 sscanf(m_szTyped, "%i", &iValue);
133 switch (m_iType)
135 case SPIN_CONTROL_TYPE_INT:
137 if (iValue < m_iStart || iValue > m_iEnd)
139 m_iTypedPos = 0;
140 m_szTyped[m_iTypedPos] = iNumber + '0';
141 m_iTypedPos++;
142 m_szTyped[m_iTypedPos] = 0;
143 sscanf(m_szTyped, "%i", &iValue);
144 if (iValue < m_iStart || iValue > m_iEnd)
146 m_iTypedPos = 0;
147 strcpy(m_szTyped, "");
148 return true;
151 m_iValue = iValue;
152 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
153 SendWindowMessage(msg);
155 break;
157 case SPIN_CONTROL_TYPE_TEXT:
159 if (iValue < 0 || iValue >= (int)m_vecLabels.size())
161 m_iTypedPos = 0;
162 m_szTyped[m_iTypedPos] = iNumber + '0';
163 m_iTypedPos++;
164 m_szTyped[m_iTypedPos] = 0;
165 sscanf(m_szTyped, "%i", &iValue);
166 if (iValue < 0 || iValue >= (int)m_vecLabels.size())
168 m_iTypedPos = 0;
169 strcpy(m_szTyped, "");
170 return true;
173 m_iValue = iValue;
174 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
175 SendWindowMessage(msg);
177 break;
180 return true;
182 break;
183 case ACTION_PAGE_UP:
184 if (!m_bReverse)
185 PageDown();
186 else
187 PageUp();
188 return true;
189 break;
190 case ACTION_PAGE_DOWN:
191 if (!m_bReverse)
192 PageUp();
193 else
194 PageDown();
195 return true;
196 break;
197 case ACTION_SELECT_ITEM:
198 if (m_iSelect == SPIN_BUTTON_UP)
200 MoveUp();
201 return true;
203 if (m_iSelect == SPIN_BUTTON_DOWN)
205 MoveDown();
206 return true;
208 break;
210 /* static float m_fSmoothScrollOffset = 0.0f;
211 if (action.GetID() == ACTION_SCROLL_UP)
213 m_fSmoothScrollOffset += action.GetAmount() * action.GetAmount();
214 bool handled = false;
215 while (m_fSmoothScrollOffset > 0.4)
217 handled = true;
218 m_fSmoothScrollOffset -= 0.4f;
219 MoveDown();
221 return handled;
223 return CGUIControl::OnAction(action);
226 void CGUISpinControl::OnLeft()
228 if (m_iSelect == SPIN_BUTTON_UP)
230 // select the down button
231 m_iSelect = SPIN_BUTTON_DOWN;
232 MarkDirtyRegion();
234 else
235 { // base class
236 CGUIControl::OnLeft();
240 void CGUISpinControl::OnRight()
242 if (m_iSelect == SPIN_BUTTON_DOWN)
244 // select the up button
245 m_iSelect = SPIN_BUTTON_UP;
246 MarkDirtyRegion();
248 else
249 { // base class
250 CGUIControl::OnRight();
254 void CGUISpinControl::Clear()
256 m_vecLabels.clear();
257 m_vecValues.clear();
258 m_vecStrValues.clear();
259 SetValue(0);
262 bool CGUISpinControl::OnMessage(CGUIMessage& message)
264 if (CGUIControl::OnMessage(message) )
265 return true;
266 if (message.GetControlId() == GetID() )
268 switch (message.GetMessage())
270 case GUI_MSG_ITEM_SELECT:
271 if (SPIN_CONTROL_TYPE_PAGE == m_iType)
273 m_currentItem = message.GetParam1();
274 return true;
276 SetValue( message.GetParam1());
277 if (message.GetParam2() == SPIN_BUTTON_DOWN || message.GetParam2() == SPIN_BUTTON_UP)
278 m_iSelect = message.GetParam2();
279 return true;
280 break;
282 case GUI_MSG_LABEL_RESET:
283 if (SPIN_CONTROL_TYPE_PAGE == m_iType)
285 m_itemsPerPage = message.GetParam1();
286 m_numItems = message.GetParam2();
287 return true;
290 Clear();
291 return true;
293 break;
295 case GUI_MSG_SHOWRANGE:
296 if (message.GetParam1() )
297 m_bShowRange = true;
298 else
299 m_bShowRange = false;
300 break;
302 case GUI_MSG_SET_LABELS:
303 if (message.GetPointer())
305 auto labels =
306 static_cast<const std::vector<std::pair<std::string, int>>*>(message.GetPointer());
307 Clear();
308 for (const auto& i : *labels)
309 AddLabel(i.first, i.second);
310 SetValue( message.GetParam1());
312 break;
314 case GUI_MSG_LABEL_ADD:
316 AddLabel(message.GetLabel(), message.GetParam1());
317 return true;
319 break;
321 case GUI_MSG_ITEM_SELECTED:
323 message.SetParam1( GetValue() );
324 message.SetParam2(m_iSelect);
326 if (m_iType == SPIN_CONTROL_TYPE_TEXT)
328 if ( m_iValue >= 0 && m_iValue < (int)m_vecLabels.size() )
329 message.SetLabel( m_vecLabels[m_iValue]);
331 return true;
334 case GUI_MSG_PAGE_UP:
335 if (CanMoveUp())
336 MoveUp();
337 return true;
339 case GUI_MSG_PAGE_DOWN:
340 if (CanMoveDown())
341 MoveDown();
342 return true;
344 case GUI_MSG_MOVE_OFFSET:
346 int count = message.GetParam1();
347 while (count < 0)
349 MoveUp();
350 count++;
352 while (count > 0)
354 MoveDown();
355 count--;
357 return true;
362 return false;
365 void CGUISpinControl::AllocResources()
367 CGUIControl::AllocResources();
368 m_imgspinUp->AllocResources();
369 m_imgspinUpFocus->AllocResources();
370 m_imgspinDown->AllocResources();
371 m_imgspinDownFocus->AllocResources();
372 m_imgspinUpDisabled->AllocResources();
373 m_imgspinDownDisabled->AllocResources();
375 m_imgspinDownFocus->SetPosition(m_posX, m_posY);
376 m_imgspinDown->SetPosition(m_posX, m_posY);
377 m_imgspinDownDisabled->SetPosition(m_posX, m_posY);
378 m_imgspinUp->SetPosition(m_posX + m_imgspinDown->GetWidth(), m_posY);
379 m_imgspinUpFocus->SetPosition(m_posX + m_imgspinDownFocus->GetWidth(), m_posY);
380 m_imgspinUpDisabled->SetPosition(m_posX + m_imgspinDownDisabled->GetWidth(), m_posY);
383 void CGUISpinControl::FreeResources(bool immediately)
385 CGUIControl::FreeResources(immediately);
386 m_imgspinUp->FreeResources(immediately);
387 m_imgspinUpFocus->FreeResources(immediately);
388 m_imgspinDown->FreeResources(immediately);
389 m_imgspinDownFocus->FreeResources(immediately);
390 m_imgspinUpDisabled->FreeResources(immediately);
391 m_imgspinDownDisabled->FreeResources(immediately);
392 m_iTypedPos = 0;
393 strcpy(m_szTyped, "");
396 void CGUISpinControl::DynamicResourceAlloc(bool bOnOff)
398 CGUIControl::DynamicResourceAlloc(bOnOff);
399 m_imgspinUp->DynamicResourceAlloc(bOnOff);
400 m_imgspinUpFocus->DynamicResourceAlloc(bOnOff);
401 m_imgspinDown->DynamicResourceAlloc(bOnOff);
402 m_imgspinDownFocus->DynamicResourceAlloc(bOnOff);
403 m_imgspinUpDisabled->DynamicResourceAlloc(bOnOff);
404 m_imgspinDownDisabled->DynamicResourceAlloc(bOnOff);
407 void CGUISpinControl::SetInvalid()
409 CGUIControl::SetInvalid();
410 m_label.SetInvalid();
411 m_imgspinUp->SetInvalid();
412 m_imgspinUpFocus->SetInvalid();
413 m_imgspinDown->SetInvalid();
414 m_imgspinDownFocus->SetInvalid();
415 m_imgspinUpDisabled->SetInvalid();
416 m_imgspinDownDisabled->SetInvalid();
419 void CGUISpinControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
421 bool changed = false;
423 if (!HasFocus())
425 m_iTypedPos = 0;
426 strcpy(m_szTyped, "");
429 std::string text;
431 if (m_iType == SPIN_CONTROL_TYPE_INT)
433 if (m_bShowRange)
435 text = StringUtils::Format("{}/{}", m_iValue, m_iEnd);
437 else
439 text = std::to_string(m_iValue);
442 else if (m_iType == SPIN_CONTROL_TYPE_PAGE)
444 // work out number of pages and current page
445 int numPages = (m_numItems + m_itemsPerPage - 1) / m_itemsPerPage;
446 int currentPage = m_currentItem / m_itemsPerPage + 1;
447 if (m_currentItem >= m_numItems - m_itemsPerPage)
448 currentPage = numPages;
449 text = StringUtils::Format("{}/{}", currentPage, numPages);
451 else if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
453 if (m_bShowRange)
455 text = StringUtils::Format("{:02.2f}/{:02.2f}", m_fValue, m_fEnd);
457 else
459 text = StringUtils::Format("{:02.2f}", m_fValue);
462 else
464 if (m_iValue >= 0 && m_iValue < (int)m_vecLabels.size() )
466 if (m_bShowRange)
468 text = StringUtils::Format("({}/{}) {}", m_iValue + 1, (int)m_vecLabels.size(),
469 m_vecLabels[m_iValue]);
471 else
473 text = m_vecLabels[m_iValue];
476 else
477 text = StringUtils::Format("?{}?", m_iValue);
480 changed |= m_label.SetText(text);
482 float textWidth = m_label.GetTextWidth() + 2 * m_label.GetLabelInfo().offsetX;
483 // Position the arrows
484 bool arrowsOnRight(0 != (m_label.GetLabelInfo().align & (XBFONT_RIGHT | XBFONT_CENTER_X)));
485 if (!arrowsOnRight)
487 changed |= m_imgspinDownFocus->SetPosition(m_posX + textWidth + TEXT_SPACE, m_posY);
488 changed |= m_imgspinDown->SetPosition(m_posX + textWidth + TEXT_SPACE, m_posY);
489 changed |= m_imgspinDownDisabled->SetPosition(m_posX + textWidth + TEXT_SPACE, m_posY);
490 changed |= m_imgspinUpFocus->SetPosition(
491 m_posX + textWidth + TEXT_SPACE + m_imgspinDown->GetWidth(), m_posY);
492 changed |= m_imgspinUp->SetPosition(m_posX + textWidth + TEXT_SPACE + m_imgspinDown->GetWidth(),
493 m_posY);
494 changed |= m_imgspinUpDisabled->SetPosition(
495 m_posX + textWidth + TEXT_SPACE + m_imgspinDownDisabled->GetWidth(), m_posY);
498 changed |= m_imgspinDownFocus->Process(currentTime);
499 changed |= m_imgspinDown->Process(currentTime);
500 changed |= m_imgspinUp->Process(currentTime);
501 changed |= m_imgspinUpFocus->Process(currentTime);
502 changed |= m_imgspinUpDisabled->Process(currentTime);
503 changed |= m_imgspinDownDisabled->Process(currentTime);
504 changed |= m_label.Process(currentTime);
506 if (changed)
507 MarkDirtyRegion();
509 CGUIControl::Process(currentTime, dirtyregions);
512 void CGUISpinControl::Render()
514 if (m_label.GetLabelInfo().font)
516 float textWidth = m_label.GetTextWidth() + 2 * m_label.GetLabelInfo().offsetX;
517 // Position the arrows
518 bool arrowsOnRight(0 != (m_label.GetLabelInfo().align & (XBFONT_RIGHT | XBFONT_CENTER_X)));
520 if (arrowsOnRight)
521 RenderText(m_posX - TEXT_SPACE - textWidth, m_posY, textWidth, m_height);
522 else
523 RenderText(m_posX + m_imgspinDown->GetWidth() + m_imgspinUp->GetWidth() + TEXT_SPACE, m_posY,
524 textWidth, m_height);
526 // set our hit rectangle for MouseOver events
527 m_hitRect = m_label.GetRenderRect();
530 if (HasFocus())
532 if (m_iSelect == SPIN_BUTTON_UP)
533 m_imgspinUpFocus->Render();
534 else
535 m_imgspinUp->Render();
537 if (m_iSelect == SPIN_BUTTON_DOWN)
538 m_imgspinDownFocus->Render();
539 else
540 m_imgspinDown->Render();
542 else if (!HasFocus() && !IsDisabled())
544 m_imgspinUp->Render();
545 m_imgspinDown->Render();
547 else
549 m_imgspinUpDisabled->Render();
550 m_imgspinDownDisabled->Render();
553 CGUIControl::Render();
556 void CGUISpinControl::RenderText(float posX, float posY, float width, float height)
558 m_label.SetMaxRect(posX, posY, width, height);
559 m_label.SetColor(GetTextColor());
560 m_label.Render();
563 CGUILabel::COLOR CGUISpinControl::GetTextColor() const
565 if (IsDisabled())
566 return CGUILabel::COLOR_DISABLED;
567 else if (HasFocus())
568 return CGUILabel::COLOR_FOCUSED;
569 return CGUILabel::COLOR_TEXT;
572 void CGUISpinControl::SetRange(int iStart, int iEnd)
574 m_iStart = iStart;
575 m_iEnd = iEnd;
578 void CGUISpinControl::SetFloatRange(float fStart, float fEnd)
580 m_fStart = fStart;
581 m_fEnd = fEnd;
584 void CGUISpinControl::SetValueFromLabel(const std::string &label)
586 if (m_iType == SPIN_CONTROL_TYPE_TEXT)
588 m_iValue = 0;
589 for (unsigned int i = 0; i < m_vecLabels.size(); i++)
590 if (label == m_vecLabels[i])
591 m_iValue = i;
593 else
594 m_iValue = atoi(label.c_str());
596 MarkDirtyRegion();
597 SetInvalid();
600 void CGUISpinControl::SetValue(int iValue)
602 if (m_iType == SPIN_CONTROL_TYPE_TEXT)
604 m_iValue = 0;
605 for (unsigned int i = 0; i < m_vecValues.size(); i++)
606 if (iValue == m_vecValues[i])
607 m_iValue = i;
609 else
610 m_iValue = iValue;
612 MarkDirtyRegion();
613 SetInvalid();
616 void CGUISpinControl::SetFloatValue(float fValue)
618 m_fValue = fValue;
621 void CGUISpinControl::SetStringValue(const std::string& strValue)
623 if (m_iType == SPIN_CONTROL_TYPE_TEXT)
625 m_iValue = 0;
626 for (unsigned int i = 0; i < m_vecStrValues.size(); i++)
627 if (strValue == m_vecStrValues[i])
628 m_iValue = i;
631 SetInvalid();
634 int CGUISpinControl::GetValue() const
636 if (m_iType == SPIN_CONTROL_TYPE_TEXT)
638 if (m_iValue >= 0 && m_iValue < (int)m_vecValues.size())
639 return m_vecValues[m_iValue];
641 return m_iValue;
644 float CGUISpinControl::GetFloatValue() const
646 return m_fValue;
649 std::string CGUISpinControl::GetStringValue() const
651 if (m_iType == SPIN_CONTROL_TYPE_TEXT && m_iValue >= 0 && m_iValue < (int)m_vecLabels.size())
653 if (m_iValue < (int)m_vecStrValues.size())
654 return m_vecStrValues[m_iValue];
656 return m_vecLabels[m_iValue];
658 return "";
661 void CGUISpinControl::AddLabel(const std::string& strLabel, int iValue)
663 m_vecLabels.push_back(strLabel);
664 m_vecValues.push_back(iValue);
667 void CGUISpinControl::AddLabel(const std::string& strLabel, const std::string& strValue)
669 m_vecLabels.push_back(strLabel);
670 m_vecStrValues.push_back(strValue);
673 const std::string CGUISpinControl::GetLabel() const
675 if (m_iValue >= 0 && m_iValue < (int)m_vecLabels.size())
677 return m_vecLabels[m_iValue];
679 return "";
682 void CGUISpinControl::SetPosition(float posX, float posY)
684 CGUIControl::SetPosition(posX, posY);
686 m_imgspinDownFocus->SetPosition(posX, posY);
687 m_imgspinDown->SetPosition(posX, posY);
688 m_imgspinDownDisabled->SetPosition(posX, posY);
690 m_imgspinUp->SetPosition(m_posX + m_imgspinDown->GetWidth(), m_posY);
691 m_imgspinUpFocus->SetPosition(m_posX + m_imgspinDownFocus->GetWidth(), m_posY);
692 m_imgspinUpDisabled->SetPosition(m_posX + m_imgspinDownDisabled->GetWidth(), m_posY);
695 float CGUISpinControl::GetWidth() const
697 return m_imgspinDown->GetWidth() * 2;
700 bool CGUISpinControl::CanMoveUp(bool bTestReverse)
702 // test for reverse...
703 if (bTestReverse && m_bReverse) return CanMoveDown(false);
705 switch (m_iType)
707 case SPIN_CONTROL_TYPE_PAGE:
708 return m_currentItem > 0;
709 case SPIN_CONTROL_TYPE_INT:
711 if (m_iValue - 1 >= m_iStart)
712 return true;
713 return false;
715 break;
717 case SPIN_CONTROL_TYPE_FLOAT:
719 if (m_fValue - m_fInterval >= m_fStart)
720 return true;
721 return false;
723 break;
725 case SPIN_CONTROL_TYPE_TEXT:
727 if (m_iValue - 1 >= 0)
728 return true;
729 return false;
731 break;
733 return false;
736 bool CGUISpinControl::CanMoveDown(bool bTestReverse)
738 // test for reverse...
739 if (bTestReverse && m_bReverse) return CanMoveUp(false);
740 switch (m_iType)
742 case SPIN_CONTROL_TYPE_PAGE:
743 return m_currentItem < m_numItems;
744 case SPIN_CONTROL_TYPE_INT:
746 if (m_iValue + 1 <= m_iEnd)
747 return true;
748 return false;
750 break;
752 case SPIN_CONTROL_TYPE_FLOAT:
754 if (m_fValue + m_fInterval <= m_fEnd)
755 return true;
756 return false;
758 break;
760 case SPIN_CONTROL_TYPE_TEXT:
762 if (m_iValue + 1 < (int)m_vecLabels.size())
763 return true;
764 return false;
766 break;
768 return false;
771 void CGUISpinControl::PageUp()
773 switch (m_iType)
775 case SPIN_CONTROL_TYPE_INT:
777 if (m_iValue - 10 >= m_iStart)
778 m_iValue -= 10;
779 else
780 m_iValue = m_iStart;
781 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
782 SendWindowMessage(msg);
783 return ;
785 break;
786 case SPIN_CONTROL_TYPE_PAGE:
787 ChangePage(-10);
788 break;
789 case SPIN_CONTROL_TYPE_TEXT:
791 if (m_iValue - 10 >= 0)
792 m_iValue -= 10;
793 else
794 m_iValue = 0;
795 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
796 SendWindowMessage(msg);
797 return ;
799 break;
804 void CGUISpinControl::PageDown()
806 switch (m_iType)
808 case SPIN_CONTROL_TYPE_INT:
810 if (m_iValue + 10 <= m_iEnd)
811 m_iValue += 10;
812 else
813 m_iValue = m_iEnd;
814 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
815 SendWindowMessage(msg);
816 return ;
818 break;
819 case SPIN_CONTROL_TYPE_PAGE:
820 ChangePage(10);
821 break;
822 case SPIN_CONTROL_TYPE_TEXT:
824 if (m_iValue + 10 < (int)m_vecLabels.size() )
825 m_iValue += 10;
826 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
827 SendWindowMessage(msg);
829 break;
833 void CGUISpinControl::MoveUp(bool bTestReverse)
835 if (bTestReverse && m_bReverse)
836 { // actually should move down.
837 MoveDown(false);
838 return ;
840 switch (m_iType)
842 case SPIN_CONTROL_TYPE_INT:
844 if (m_iValue - 1 >= m_iStart)
845 m_iValue--;
846 else if (m_iValue == m_iStart)
847 m_iValue = m_iEnd;
848 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
849 SendWindowMessage(msg);
850 return ;
852 break;
854 case SPIN_CONTROL_TYPE_PAGE:
855 ChangePage(-1);
856 break;
858 case SPIN_CONTROL_TYPE_FLOAT:
860 if (m_fValue - m_fInterval >= m_fStart)
861 m_fValue -= m_fInterval;
862 else
863 m_fValue = m_fEnd;
864 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
865 SendWindowMessage(msg);
866 return ;
868 break;
870 case SPIN_CONTROL_TYPE_TEXT:
872 if (m_iValue - 1 >= 0)
873 m_iValue--;
874 else if (m_iValue == 0)
875 m_iValue = (int)m_vecLabels.size() - 1;
876 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
877 SendWindowMessage(msg);
878 return ;
880 break;
884 void CGUISpinControl::MoveDown(bool bTestReverse)
886 if (bTestReverse && m_bReverse)
887 { // actually should move up.
888 MoveUp(false);
889 return ;
891 switch (m_iType)
893 case SPIN_CONTROL_TYPE_INT:
895 if (m_iValue + 1 <= m_iEnd)
896 m_iValue++;
897 else if (m_iValue == m_iEnd)
898 m_iValue = m_iStart;
899 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
900 SendWindowMessage(msg);
901 return ;
903 break;
905 case SPIN_CONTROL_TYPE_PAGE:
906 ChangePage(1);
907 break;
909 case SPIN_CONTROL_TYPE_FLOAT:
911 if (m_fValue + m_fInterval <= m_fEnd)
912 m_fValue += m_fInterval;
913 else
914 m_fValue = m_fStart;
915 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
916 SendWindowMessage(msg);
917 return ;
919 break;
921 case SPIN_CONTROL_TYPE_TEXT:
923 if (m_iValue + 1 < (int)m_vecLabels.size() )
924 m_iValue++;
925 else if (m_iValue == (int)m_vecLabels.size() - 1)
926 m_iValue = 0;
927 CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
928 SendWindowMessage(msg);
929 return ;
931 break;
934 void CGUISpinControl::SetReverse(bool bReverse)
936 m_bReverse = bReverse;
939 void CGUISpinControl::SetFloatInterval(float fInterval)
941 m_fInterval = fInterval;
944 void CGUISpinControl::SetShowRange(bool bOnoff)
946 m_bShowRange = bOnoff;
949 int CGUISpinControl::GetMinimum() const
951 switch (m_iType)
953 case SPIN_CONTROL_TYPE_PAGE:
954 return 0;
955 case SPIN_CONTROL_TYPE_INT:
956 return m_iStart;
957 break;
959 case SPIN_CONTROL_TYPE_TEXT:
960 return 1;
961 break;
963 case SPIN_CONTROL_TYPE_FLOAT:
964 return (int)(m_fStart*10.0f);
965 break;
967 return 0;
970 int CGUISpinControl::GetMaximum() const
972 switch (m_iType)
974 case SPIN_CONTROL_TYPE_PAGE:
975 return m_numItems;
976 case SPIN_CONTROL_TYPE_INT:
977 return m_iEnd;
978 break;
980 case SPIN_CONTROL_TYPE_TEXT:
981 return (int)m_vecLabels.size();
982 break;
984 case SPIN_CONTROL_TYPE_FLOAT:
985 return (int)(m_fEnd*10.0f);
986 break;
988 return 100;
991 bool CGUISpinControl::HitTest(const CPoint &point) const
993 if (m_imgspinUpFocus->HitTest(point) || m_imgspinDownFocus->HitTest(point))
994 return true;
995 return CGUIControl::HitTest(point);
998 bool CGUISpinControl::OnMouseOver(const CPoint &point)
1000 int select = m_iSelect;
1001 if (m_imgspinDownFocus->HitTest(point))
1002 m_iSelect = SPIN_BUTTON_DOWN;
1003 else
1004 m_iSelect = SPIN_BUTTON_UP;
1006 if (select != m_iSelect)
1007 MarkDirtyRegion();
1009 return CGUIControl::OnMouseOver(point);
1012 EVENT_RESULT CGUISpinControl::OnMouseEvent(const CPoint& point, const MOUSE::CMouseEvent& event)
1014 if (event.m_id == ACTION_MOUSE_LEFT_CLICK)
1016 if (m_imgspinUpFocus->HitTest(point))
1017 MoveUp();
1018 else if (m_imgspinDownFocus->HitTest(point))
1019 MoveDown();
1020 return EVENT_RESULT_HANDLED;
1022 else if (event.m_id == ACTION_MOUSE_WHEEL_UP)
1024 if (m_imgspinUpFocus->HitTest(point) || m_imgspinDownFocus->HitTest(point))
1026 MoveUp();
1027 return EVENT_RESULT_HANDLED;
1030 else if (event.m_id == ACTION_MOUSE_WHEEL_DOWN)
1032 if (m_imgspinUpFocus->HitTest(point) || m_imgspinDownFocus->HitTest(point))
1034 MoveDown();
1035 return EVENT_RESULT_HANDLED;
1038 return EVENT_RESULT_UNHANDLED;
1041 std::string CGUISpinControl::GetDescription() const
1043 return StringUtils::Format("{}/{}", 1 + GetValue(), GetMaximum());
1046 bool CGUISpinControl::IsFocusedOnUp() const
1048 return (m_iSelect == SPIN_BUTTON_UP);
1051 void CGUISpinControl::ChangePage(int amount)
1053 m_currentItem += amount * m_itemsPerPage;
1054 if (m_currentItem > m_numItems - m_itemsPerPage)
1055 m_currentItem = m_numItems - m_itemsPerPage;
1056 if (m_currentItem < 0)
1057 m_currentItem = 0;
1058 CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_currentItem);
1059 SendWindowMessage(message);
1062 bool CGUISpinControl::UpdateColors(const CGUIListItem* item)
1064 bool changed = CGUIControl::UpdateColors(nullptr);
1065 changed |= m_label.UpdateColors();
1066 changed |= m_imgspinDownFocus->SetDiffuseColor(m_diffuseColor);
1067 changed |= m_imgspinDown->SetDiffuseColor(m_diffuseColor);
1068 changed |= m_imgspinUp->SetDiffuseColor(m_diffuseColor);
1069 changed |= m_imgspinUpFocus->SetDiffuseColor(m_diffuseColor);
1070 changed |= m_imgspinUpDisabled->SetDiffuseColor(m_diffuseColor);
1071 changed |= m_imgspinDownDisabled->SetDiffuseColor(m_diffuseColor);
1073 return changed;
1076 bool CGUISpinControl::IsVisible() const
1078 // page controls can be optionally disabled if the number of pages is 1
1079 if (m_iType == SPIN_CONTROL_TYPE_PAGE && m_numItems <= m_itemsPerPage && !m_showOnePage)
1080 return false;
1081 return CGUIControl::IsVisible();