summaryrefslogtreecommitdiffstats
path: root/xbmc/guilib/GUISpinControl.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--xbmc/guilib/GUISpinControl.cpp1078
1 files changed, 1078 insertions, 0 deletions
diff --git a/xbmc/guilib/GUISpinControl.cpp b/xbmc/guilib/GUISpinControl.cpp
new file mode 100644
index 0000000..f0a0f39
--- /dev/null
+++ b/xbmc/guilib/GUISpinControl.cpp
@@ -0,0 +1,1078 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "GUISpinControl.h"
+
+#include "GUIMessage.h"
+#include "input/Key.h"
+#include "utils/StringUtils.h"
+
+#include <stdio.h>
+
+#define SPIN_BUTTON_DOWN 1
+#define SPIN_BUTTON_UP 2
+
+namespace
+{
+// Additional space between text and spin buttons
+constexpr float TEXT_SPACE = 5.0f;
+} // unnamed namespace
+
+CGUISpinControl::CGUISpinControl(int parentID,
+ int controlID,
+ float posX,
+ float posY,
+ float width,
+ float height,
+ const CTextureInfo& textureUp,
+ const CTextureInfo& textureDown,
+ const CTextureInfo& textureUpFocus,
+ const CTextureInfo& textureDownFocus,
+ const CTextureInfo& textureUpDisabled,
+ const CTextureInfo& textureDownDisabled,
+ const CLabelInfo& labelInfo,
+ int iType)
+ : CGUIControl(parentID, controlID, posX, posY, width, height),
+ m_imgspinUp(CGUITexture::CreateTexture(posX, posY, width, height, textureUp)),
+ m_imgspinDown(CGUITexture::CreateTexture(posX, posY, width, height, textureDown)),
+ m_imgspinUpFocus(CGUITexture::CreateTexture(posX, posY, width, height, textureUpFocus)),
+ m_imgspinDownFocus(CGUITexture::CreateTexture(posX, posY, width, height, textureDownFocus)),
+ m_imgspinUpDisabled(CGUITexture::CreateTexture(posX, posY, width, height, textureUpDisabled)),
+ m_imgspinDownDisabled(
+ CGUITexture::CreateTexture(posX, posY, width, height, textureDownDisabled)),
+ m_label(posX, posY, width, height, labelInfo)
+{
+ m_bReverse = false;
+ m_iStart = 0;
+ m_iEnd = 100;
+ m_fStart = 0.0f;
+ m_fEnd = 1.0f;
+ m_fInterval = 0.1f;
+ m_iValue = 0;
+ m_fValue = 0.0;
+ m_iType = iType;
+ m_iSelect = SPIN_BUTTON_DOWN;
+ m_bShowRange = false;
+ m_iTypedPos = 0;
+ strcpy(m_szTyped, "");
+ ControlType = GUICONTROL_SPIN;
+ m_currentItem = 0;
+ m_numItems = 10;
+ m_itemsPerPage = 10;
+ m_showOnePage = true;
+}
+
+CGUISpinControl::CGUISpinControl(const CGUISpinControl& control)
+ : CGUIControl(control),
+ m_iStart(control.m_iStart),
+ m_iEnd(control.m_iEnd),
+ m_fStart(control.m_fStart),
+ m_fEnd(control.m_fEnd),
+ m_iValue(control.m_iValue),
+ m_fValue(control.m_fValue),
+ m_iType(control.m_iType),
+ m_iSelect(control.m_iSelect),
+ m_bReverse(control.m_bReverse),
+ m_fInterval(control.m_fInterval),
+ m_vecLabels(control.m_vecLabels),
+ m_vecValues(control.m_vecValues),
+ m_vecStrValues(control.m_vecStrValues),
+ m_imgspinUp(control.m_imgspinUp->Clone()),
+ m_imgspinDown(control.m_imgspinDown->Clone()),
+ m_imgspinUpFocus(control.m_imgspinUpFocus->Clone()),
+ m_imgspinDownFocus(control.m_imgspinDownFocus->Clone()),
+ m_imgspinUpDisabled(control.m_imgspinUpDisabled->Clone()),
+ m_imgspinDownDisabled(control.m_imgspinDownDisabled->Clone()),
+ m_label(control.m_label),
+ m_bShowRange(control.m_bShowRange),
+ m_iTypedPos(control.m_iTypedPos),
+ m_currentItem(control.m_currentItem),
+ m_itemsPerPage(control.m_itemsPerPage),
+ m_numItems(control.m_numItems),
+ m_showOnePage(control.m_showOnePage)
+{
+ std::strcpy(m_szTyped, control.m_szTyped);
+}
+
+bool CGUISpinControl::OnAction(const CAction &action)
+{
+ switch (action.GetID())
+ {
+ case REMOTE_0:
+ case REMOTE_1:
+ case REMOTE_2:
+ case REMOTE_3:
+ case REMOTE_4:
+ case REMOTE_5:
+ case REMOTE_6:
+ case REMOTE_7:
+ case REMOTE_8:
+ case REMOTE_9:
+ {
+ if (strlen(m_szTyped) >= 3)
+ {
+ m_iTypedPos = 0;
+ strcpy(m_szTyped, "");
+ }
+ int iNumber = action.GetID() - REMOTE_0;
+
+ m_szTyped[m_iTypedPos] = iNumber + '0';
+ m_iTypedPos++;
+ m_szTyped[m_iTypedPos] = 0;
+ int iValue;
+ sscanf(m_szTyped, "%i", &iValue);
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (iValue < m_iStart || iValue > m_iEnd)
+ {
+ m_iTypedPos = 0;
+ m_szTyped[m_iTypedPos] = iNumber + '0';
+ m_iTypedPos++;
+ m_szTyped[m_iTypedPos] = 0;
+ sscanf(m_szTyped, "%i", &iValue);
+ if (iValue < m_iStart || iValue > m_iEnd)
+ {
+ m_iTypedPos = 0;
+ strcpy(m_szTyped, "");
+ return true;
+ }
+ }
+ m_iValue = iValue;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (iValue < 0 || iValue >= (int)m_vecLabels.size())
+ {
+ m_iTypedPos = 0;
+ m_szTyped[m_iTypedPos] = iNumber + '0';
+ m_iTypedPos++;
+ m_szTyped[m_iTypedPos] = 0;
+ sscanf(m_szTyped, "%i", &iValue);
+ if (iValue < 0 || iValue >= (int)m_vecLabels.size())
+ {
+ m_iTypedPos = 0;
+ strcpy(m_szTyped, "");
+ return true;
+ }
+ }
+ m_iValue = iValue;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ }
+ break;
+
+ }
+ return true;
+ }
+ break;
+ case ACTION_PAGE_UP:
+ if (!m_bReverse)
+ PageDown();
+ else
+ PageUp();
+ return true;
+ break;
+ case ACTION_PAGE_DOWN:
+ if (!m_bReverse)
+ PageUp();
+ else
+ PageDown();
+ return true;
+ break;
+ case ACTION_SELECT_ITEM:
+ if (m_iSelect == SPIN_BUTTON_UP)
+ {
+ MoveUp();
+ return true;
+ }
+ if (m_iSelect == SPIN_BUTTON_DOWN)
+ {
+ MoveDown();
+ return true;
+ }
+ break;
+ }
+/* static float m_fSmoothScrollOffset = 0.0f;
+ if (action.GetID() == ACTION_SCROLL_UP)
+ {
+ m_fSmoothScrollOffset += action.GetAmount() * action.GetAmount();
+ bool handled = false;
+ while (m_fSmoothScrollOffset > 0.4)
+ {
+ handled = true;
+ m_fSmoothScrollOffset -= 0.4f;
+ MoveDown();
+ }
+ return handled;
+ }*/
+ return CGUIControl::OnAction(action);
+}
+
+void CGUISpinControl::OnLeft()
+{
+ if (m_iSelect == SPIN_BUTTON_UP)
+ {
+ // select the down button
+ m_iSelect = SPIN_BUTTON_DOWN;
+ MarkDirtyRegion();
+ }
+ else
+ { // base class
+ CGUIControl::OnLeft();
+ }
+}
+
+void CGUISpinControl::OnRight()
+{
+ if (m_iSelect == SPIN_BUTTON_DOWN)
+ {
+ // select the up button
+ m_iSelect = SPIN_BUTTON_UP;
+ MarkDirtyRegion();
+ }
+ else
+ { // base class
+ CGUIControl::OnRight();
+ }
+}
+
+void CGUISpinControl::Clear()
+{
+ m_vecLabels.clear();
+ m_vecValues.clear();
+ m_vecStrValues.clear();
+ SetValue(0);
+}
+
+bool CGUISpinControl::OnMessage(CGUIMessage& message)
+{
+ if (CGUIControl::OnMessage(message) )
+ return true;
+ if (message.GetControlId() == GetID() )
+ {
+ switch (message.GetMessage())
+ {
+ case GUI_MSG_ITEM_SELECT:
+ if (SPIN_CONTROL_TYPE_PAGE == m_iType)
+ {
+ m_currentItem = message.GetParam1();
+ return true;
+ }
+ SetValue( message.GetParam1());
+ if (message.GetParam2() == SPIN_BUTTON_DOWN || message.GetParam2() == SPIN_BUTTON_UP)
+ m_iSelect = message.GetParam2();
+ return true;
+ break;
+
+ case GUI_MSG_LABEL_RESET:
+ if (SPIN_CONTROL_TYPE_PAGE == m_iType)
+ {
+ m_itemsPerPage = message.GetParam1();
+ m_numItems = message.GetParam2();
+ return true;
+ }
+ {
+ Clear();
+ return true;
+ }
+ break;
+
+ case GUI_MSG_SHOWRANGE:
+ if (message.GetParam1() )
+ m_bShowRange = true;
+ else
+ m_bShowRange = false;
+ break;
+
+ case GUI_MSG_SET_LABELS:
+ if (message.GetPointer())
+ {
+ auto labels =
+ static_cast<const std::vector<std::pair<std::string, int>>*>(message.GetPointer());
+ Clear();
+ for (const auto& i : *labels)
+ AddLabel(i.first, i.second);
+ SetValue( message.GetParam1());
+ }
+ break;
+
+ case GUI_MSG_LABEL_ADD:
+ {
+ AddLabel(message.GetLabel(), message.GetParam1());
+ return true;
+ }
+ break;
+
+ case GUI_MSG_ITEM_SELECTED:
+ {
+ message.SetParam1( GetValue() );
+ message.SetParam2(m_iSelect);
+
+ if (m_iType == SPIN_CONTROL_TYPE_TEXT)
+ {
+ if ( m_iValue >= 0 && m_iValue < (int)m_vecLabels.size() )
+ message.SetLabel( m_vecLabels[m_iValue]);
+ }
+ return true;
+ }
+
+ case GUI_MSG_PAGE_UP:
+ if (CanMoveUp())
+ MoveUp();
+ return true;
+
+ case GUI_MSG_PAGE_DOWN:
+ if (CanMoveDown())
+ MoveDown();
+ return true;
+
+ case GUI_MSG_MOVE_OFFSET:
+ {
+ int count = message.GetParam1();
+ while (count < 0)
+ {
+ MoveUp();
+ count++;
+ }
+ while (count > 0)
+ {
+ MoveDown();
+ count--;
+ }
+ return true;
+ }
+
+ }
+ }
+ return false;
+}
+
+void CGUISpinControl::AllocResources()
+{
+ CGUIControl::AllocResources();
+ m_imgspinUp->AllocResources();
+ m_imgspinUpFocus->AllocResources();
+ m_imgspinDown->AllocResources();
+ m_imgspinDownFocus->AllocResources();
+ m_imgspinUpDisabled->AllocResources();
+ m_imgspinDownDisabled->AllocResources();
+
+ m_imgspinDownFocus->SetPosition(m_posX, m_posY);
+ m_imgspinDown->SetPosition(m_posX, m_posY);
+ m_imgspinDownDisabled->SetPosition(m_posX, m_posY);
+ m_imgspinUp->SetPosition(m_posX + m_imgspinDown->GetWidth(), m_posY);
+ m_imgspinUpFocus->SetPosition(m_posX + m_imgspinDownFocus->GetWidth(), m_posY);
+ m_imgspinUpDisabled->SetPosition(m_posX + m_imgspinDownDisabled->GetWidth(), m_posY);
+}
+
+void CGUISpinControl::FreeResources(bool immediately)
+{
+ CGUIControl::FreeResources(immediately);
+ m_imgspinUp->FreeResources(immediately);
+ m_imgspinUpFocus->FreeResources(immediately);
+ m_imgspinDown->FreeResources(immediately);
+ m_imgspinDownFocus->FreeResources(immediately);
+ m_imgspinUpDisabled->FreeResources(immediately);
+ m_imgspinDownDisabled->FreeResources(immediately);
+ m_iTypedPos = 0;
+ strcpy(m_szTyped, "");
+}
+
+void CGUISpinControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_imgspinUp->DynamicResourceAlloc(bOnOff);
+ m_imgspinUpFocus->DynamicResourceAlloc(bOnOff);
+ m_imgspinDown->DynamicResourceAlloc(bOnOff);
+ m_imgspinDownFocus->DynamicResourceAlloc(bOnOff);
+ m_imgspinUpDisabled->DynamicResourceAlloc(bOnOff);
+ m_imgspinDownDisabled->DynamicResourceAlloc(bOnOff);
+}
+
+void CGUISpinControl::SetInvalid()
+{
+ CGUIControl::SetInvalid();
+ m_label.SetInvalid();
+ m_imgspinUp->SetInvalid();
+ m_imgspinUpFocus->SetInvalid();
+ m_imgspinDown->SetInvalid();
+ m_imgspinDownFocus->SetInvalid();
+ m_imgspinUpDisabled->SetInvalid();
+ m_imgspinDownDisabled->SetInvalid();
+}
+
+void CGUISpinControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
+{
+ bool changed = false;
+
+ if (!HasFocus())
+ {
+ m_iTypedPos = 0;
+ strcpy(m_szTyped, "");
+ }
+
+ std::string text;
+
+ if (m_iType == SPIN_CONTROL_TYPE_INT)
+ {
+ if (m_bShowRange)
+ {
+ text = StringUtils::Format("{}/{}", m_iValue, m_iEnd);
+ }
+ else
+ {
+ text = std::to_string(m_iValue);
+ }
+ }
+ else if (m_iType == SPIN_CONTROL_TYPE_PAGE)
+ {
+ // work out number of pages and current page
+ int numPages = (m_numItems + m_itemsPerPage - 1) / m_itemsPerPage;
+ int currentPage = m_currentItem / m_itemsPerPage + 1;
+ if (m_currentItem >= m_numItems - m_itemsPerPage)
+ currentPage = numPages;
+ text = StringUtils::Format("{}/{}", currentPage, numPages);
+ }
+ else if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
+ {
+ if (m_bShowRange)
+ {
+ text = StringUtils::Format("{:02.2f}/{:02.2f}", m_fValue, m_fEnd);
+ }
+ else
+ {
+ text = StringUtils::Format("{:02.2f}", m_fValue);
+ }
+ }
+ else
+ {
+ if (m_iValue >= 0 && m_iValue < (int)m_vecLabels.size() )
+ {
+ if (m_bShowRange)
+ {
+ text = StringUtils::Format("({}/{}) {}", m_iValue + 1, (int)m_vecLabels.size(),
+ m_vecLabels[m_iValue]);
+ }
+ else
+ {
+ text = m_vecLabels[m_iValue];
+ }
+ }
+ else
+ text = StringUtils::Format("?{}?", m_iValue);
+ }
+
+ changed |= m_label.SetText(text);
+
+ float textWidth = m_label.GetTextWidth() + 2 * m_label.GetLabelInfo().offsetX;
+ // Position the arrows
+ bool arrowsOnRight(0 != (m_label.GetLabelInfo().align & (XBFONT_RIGHT | XBFONT_CENTER_X)));
+ if (!arrowsOnRight)
+ {
+ changed |= m_imgspinDownFocus->SetPosition(m_posX + textWidth + TEXT_SPACE, m_posY);
+ changed |= m_imgspinDown->SetPosition(m_posX + textWidth + TEXT_SPACE, m_posY);
+ changed |= m_imgspinDownDisabled->SetPosition(m_posX + textWidth + TEXT_SPACE, m_posY);
+ changed |= m_imgspinUpFocus->SetPosition(
+ m_posX + textWidth + TEXT_SPACE + m_imgspinDown->GetWidth(), m_posY);
+ changed |= m_imgspinUp->SetPosition(m_posX + textWidth + TEXT_SPACE + m_imgspinDown->GetWidth(),
+ m_posY);
+ changed |= m_imgspinUpDisabled->SetPosition(
+ m_posX + textWidth + TEXT_SPACE + m_imgspinDownDisabled->GetWidth(), m_posY);
+ }
+
+ changed |= m_imgspinDownFocus->Process(currentTime);
+ changed |= m_imgspinDown->Process(currentTime);
+ changed |= m_imgspinUp->Process(currentTime);
+ changed |= m_imgspinUpFocus->Process(currentTime);
+ changed |= m_imgspinUpDisabled->Process(currentTime);
+ changed |= m_imgspinDownDisabled->Process(currentTime);
+ changed |= m_label.Process(currentTime);
+
+ if (changed)
+ MarkDirtyRegion();
+
+ CGUIControl::Process(currentTime, dirtyregions);
+}
+
+void CGUISpinControl::Render()
+{
+ if (m_label.GetLabelInfo().font)
+ {
+ float textWidth = m_label.GetTextWidth() + 2 * m_label.GetLabelInfo().offsetX;
+ // Position the arrows
+ bool arrowsOnRight(0 != (m_label.GetLabelInfo().align & (XBFONT_RIGHT | XBFONT_CENTER_X)));
+
+ if (arrowsOnRight)
+ RenderText(m_posX - TEXT_SPACE - textWidth, m_posY, textWidth, m_height);
+ else
+ RenderText(m_posX + m_imgspinDown->GetWidth() + m_imgspinUp->GetWidth() + TEXT_SPACE, m_posY,
+ textWidth, m_height);
+
+ // set our hit rectangle for MouseOver events
+ m_hitRect = m_label.GetRenderRect();
+ }
+
+ if (HasFocus())
+ {
+ if (m_iSelect == SPIN_BUTTON_UP)
+ m_imgspinUpFocus->Render();
+ else
+ m_imgspinUp->Render();
+
+ if (m_iSelect == SPIN_BUTTON_DOWN)
+ m_imgspinDownFocus->Render();
+ else
+ m_imgspinDown->Render();
+ }
+ else if (!HasFocus() && !IsDisabled())
+ {
+ m_imgspinUp->Render();
+ m_imgspinDown->Render();
+ }
+ else
+ {
+ m_imgspinUpDisabled->Render();
+ m_imgspinDownDisabled->Render();
+ }
+
+ CGUIControl::Render();
+}
+
+void CGUISpinControl::RenderText(float posX, float posY, float width, float height)
+{
+ m_label.SetMaxRect(posX, posY, width, height);
+ m_label.SetColor(GetTextColor());
+ m_label.Render();
+}
+
+CGUILabel::COLOR CGUISpinControl::GetTextColor() const
+{
+ if (IsDisabled())
+ return CGUILabel::COLOR_DISABLED;
+ else if (HasFocus())
+ return CGUILabel::COLOR_FOCUSED;
+ return CGUILabel::COLOR_TEXT;
+}
+
+void CGUISpinControl::SetRange(int iStart, int iEnd)
+{
+ m_iStart = iStart;
+ m_iEnd = iEnd;
+}
+
+void CGUISpinControl::SetFloatRange(float fStart, float fEnd)
+{
+ m_fStart = fStart;
+ m_fEnd = fEnd;
+}
+
+void CGUISpinControl::SetValueFromLabel(const std::string &label)
+{
+ if (m_iType == SPIN_CONTROL_TYPE_TEXT)
+ {
+ m_iValue = 0;
+ for (unsigned int i = 0; i < m_vecLabels.size(); i++)
+ if (label == m_vecLabels[i])
+ m_iValue = i;
+ }
+ else
+ m_iValue = atoi(label.c_str());
+
+ MarkDirtyRegion();
+ SetInvalid();
+}
+
+void CGUISpinControl::SetValue(int iValue)
+{
+ if (m_iType == SPIN_CONTROL_TYPE_TEXT)
+ {
+ m_iValue = 0;
+ for (unsigned int i = 0; i < m_vecValues.size(); i++)
+ if (iValue == m_vecValues[i])
+ m_iValue = i;
+ }
+ else
+ m_iValue = iValue;
+
+ MarkDirtyRegion();
+ SetInvalid();
+}
+
+void CGUISpinControl::SetFloatValue(float fValue)
+{
+ m_fValue = fValue;
+}
+
+void CGUISpinControl::SetStringValue(const std::string& strValue)
+{
+ if (m_iType == SPIN_CONTROL_TYPE_TEXT)
+ {
+ m_iValue = 0;
+ for (unsigned int i = 0; i < m_vecStrValues.size(); i++)
+ if (strValue == m_vecStrValues[i])
+ m_iValue = i;
+ }
+
+ SetInvalid();
+}
+
+int CGUISpinControl::GetValue() const
+{
+ if (m_iType == SPIN_CONTROL_TYPE_TEXT)
+ {
+ if (m_iValue >= 0 && m_iValue < (int)m_vecValues.size())
+ return m_vecValues[m_iValue];
+ }
+ return m_iValue;
+}
+
+float CGUISpinControl::GetFloatValue() const
+{
+ return m_fValue;
+}
+
+std::string CGUISpinControl::GetStringValue() const
+{
+ if (m_iType == SPIN_CONTROL_TYPE_TEXT && m_iValue >= 0 && m_iValue < (int)m_vecLabels.size())
+ {
+ if (m_iValue < (int)m_vecStrValues.size())
+ return m_vecStrValues[m_iValue];
+
+ return m_vecLabels[m_iValue];
+ }
+ return "";
+}
+
+void CGUISpinControl::AddLabel(const std::string& strLabel, int iValue)
+{
+ m_vecLabels.push_back(strLabel);
+ m_vecValues.push_back(iValue);
+}
+
+void CGUISpinControl::AddLabel(const std::string& strLabel, const std::string& strValue)
+{
+ m_vecLabels.push_back(strLabel);
+ m_vecStrValues.push_back(strValue);
+}
+
+const std::string CGUISpinControl::GetLabel() const
+{
+ if (m_iValue >= 0 && m_iValue < (int)m_vecLabels.size())
+ {
+ return m_vecLabels[m_iValue];
+ }
+ return "";
+}
+
+void CGUISpinControl::SetPosition(float posX, float posY)
+{
+ CGUIControl::SetPosition(posX, posY);
+
+ m_imgspinDownFocus->SetPosition(posX, posY);
+ m_imgspinDown->SetPosition(posX, posY);
+ m_imgspinDownDisabled->SetPosition(posX, posY);
+
+ m_imgspinUp->SetPosition(m_posX + m_imgspinDown->GetWidth(), m_posY);
+ m_imgspinUpFocus->SetPosition(m_posX + m_imgspinDownFocus->GetWidth(), m_posY);
+ m_imgspinUpDisabled->SetPosition(m_posX + m_imgspinDownDisabled->GetWidth(), m_posY);
+}
+
+float CGUISpinControl::GetWidth() const
+{
+ return m_imgspinDown->GetWidth() * 2;
+}
+
+bool CGUISpinControl::CanMoveUp(bool bTestReverse)
+{
+ // test for reverse...
+ if (bTestReverse && m_bReverse) return CanMoveDown(false);
+
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_PAGE:
+ return m_currentItem > 0;
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (m_iValue - 1 >= m_iStart)
+ return true;
+ return false;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_FLOAT:
+ {
+ if (m_fValue - m_fInterval >= m_fStart)
+ return true;
+ return false;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (m_iValue - 1 >= 0)
+ return true;
+ return false;
+ }
+ break;
+ }
+ return false;
+}
+
+bool CGUISpinControl::CanMoveDown(bool bTestReverse)
+{
+ // test for reverse...
+ if (bTestReverse && m_bReverse) return CanMoveUp(false);
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_PAGE:
+ return m_currentItem < m_numItems;
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (m_iValue + 1 <= m_iEnd)
+ return true;
+ return false;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_FLOAT:
+ {
+ if (m_fValue + m_fInterval <= m_fEnd)
+ return true;
+ return false;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (m_iValue + 1 < (int)m_vecLabels.size())
+ return true;
+ return false;
+ }
+ break;
+ }
+ return false;
+}
+
+void CGUISpinControl::PageUp()
+{
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (m_iValue - 10 >= m_iStart)
+ m_iValue -= 10;
+ else
+ m_iValue = m_iStart;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+ case SPIN_CONTROL_TYPE_PAGE:
+ ChangePage(-10);
+ break;
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (m_iValue - 10 >= 0)
+ m_iValue -= 10;
+ else
+ m_iValue = 0;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+ }
+
+}
+
+void CGUISpinControl::PageDown()
+{
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (m_iValue + 10 <= m_iEnd)
+ m_iValue += 10;
+ else
+ m_iValue = m_iEnd;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+ case SPIN_CONTROL_TYPE_PAGE:
+ ChangePage(10);
+ break;
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (m_iValue + 10 < (int)m_vecLabels.size() )
+ m_iValue += 10;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ }
+ break;
+ }
+}
+
+void CGUISpinControl::MoveUp(bool bTestReverse)
+{
+ if (bTestReverse && m_bReverse)
+ { // actually should move down.
+ MoveDown(false);
+ return ;
+ }
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (m_iValue - 1 >= m_iStart)
+ m_iValue--;
+ else if (m_iValue == m_iStart)
+ m_iValue = m_iEnd;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_PAGE:
+ ChangePage(-1);
+ break;
+
+ case SPIN_CONTROL_TYPE_FLOAT:
+ {
+ if (m_fValue - m_fInterval >= m_fStart)
+ m_fValue -= m_fInterval;
+ else
+ m_fValue = m_fEnd;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (m_iValue - 1 >= 0)
+ m_iValue--;
+ else if (m_iValue == 0)
+ m_iValue = (int)m_vecLabels.size() - 1;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+ }
+}
+
+void CGUISpinControl::MoveDown(bool bTestReverse)
+{
+ if (bTestReverse && m_bReverse)
+ { // actually should move up.
+ MoveUp(false);
+ return ;
+ }
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (m_iValue + 1 <= m_iEnd)
+ m_iValue++;
+ else if (m_iValue == m_iEnd)
+ m_iValue = m_iStart;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_PAGE:
+ ChangePage(1);
+ break;
+
+ case SPIN_CONTROL_TYPE_FLOAT:
+ {
+ if (m_fValue + m_fInterval <= m_fEnd)
+ m_fValue += m_fInterval;
+ else
+ m_fValue = m_fStart;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (m_iValue + 1 < (int)m_vecLabels.size() )
+ m_iValue++;
+ else if (m_iValue == (int)m_vecLabels.size() - 1)
+ m_iValue = 0;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+ }
+}
+void CGUISpinControl::SetReverse(bool bReverse)
+{
+ m_bReverse = bReverse;
+}
+
+void CGUISpinControl::SetFloatInterval(float fInterval)
+{
+ m_fInterval = fInterval;
+}
+
+void CGUISpinControl::SetShowRange(bool bOnoff)
+{
+ m_bShowRange = bOnoff;
+}
+
+int CGUISpinControl::GetMinimum() const
+{
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_PAGE:
+ return 0;
+ case SPIN_CONTROL_TYPE_INT:
+ return m_iStart;
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ return 1;
+ break;
+
+ case SPIN_CONTROL_TYPE_FLOAT:
+ return (int)(m_fStart*10.0f);
+ break;
+ }
+ return 0;
+}
+
+int CGUISpinControl::GetMaximum() const
+{
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_PAGE:
+ return m_numItems;
+ case SPIN_CONTROL_TYPE_INT:
+ return m_iEnd;
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ return (int)m_vecLabels.size();
+ break;
+
+ case SPIN_CONTROL_TYPE_FLOAT:
+ return (int)(m_fEnd*10.0f);
+ break;
+ }
+ return 100;
+}
+
+bool CGUISpinControl::HitTest(const CPoint &point) const
+{
+ if (m_imgspinUpFocus->HitTest(point) || m_imgspinDownFocus->HitTest(point))
+ return true;
+ return CGUIControl::HitTest(point);
+}
+
+bool CGUISpinControl::OnMouseOver(const CPoint &point)
+{
+ int select = m_iSelect;
+ if (m_imgspinDownFocus->HitTest(point))
+ m_iSelect = SPIN_BUTTON_DOWN;
+ else
+ m_iSelect = SPIN_BUTTON_UP;
+
+ if (select != m_iSelect)
+ MarkDirtyRegion();
+
+ return CGUIControl::OnMouseOver(point);
+}
+
+EVENT_RESULT CGUISpinControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
+{
+ if (event.m_id == ACTION_MOUSE_LEFT_CLICK)
+ {
+ if (m_imgspinUpFocus->HitTest(point))
+ MoveUp();
+ else if (m_imgspinDownFocus->HitTest(point))
+ MoveDown();
+ return EVENT_RESULT_HANDLED;
+ }
+ else if (event.m_id == ACTION_MOUSE_WHEEL_UP)
+ {
+ if (m_imgspinUpFocus->HitTest(point) || m_imgspinDownFocus->HitTest(point))
+ {
+ MoveUp();
+ return EVENT_RESULT_HANDLED;
+ }
+ }
+ else if (event.m_id == ACTION_MOUSE_WHEEL_DOWN)
+ {
+ if (m_imgspinUpFocus->HitTest(point) || m_imgspinDownFocus->HitTest(point))
+ {
+ MoveDown();
+ return EVENT_RESULT_HANDLED;
+ }
+ }
+ return EVENT_RESULT_UNHANDLED;
+}
+
+std::string CGUISpinControl::GetDescription() const
+{
+ return StringUtils::Format("{}/{}", 1 + GetValue(), GetMaximum());
+}
+
+bool CGUISpinControl::IsFocusedOnUp() const
+{
+ return (m_iSelect == SPIN_BUTTON_UP);
+}
+
+void CGUISpinControl::ChangePage(int amount)
+{
+ m_currentItem += amount * m_itemsPerPage;
+ if (m_currentItem > m_numItems - m_itemsPerPage)
+ m_currentItem = m_numItems - m_itemsPerPage;
+ if (m_currentItem < 0)
+ m_currentItem = 0;
+ CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_currentItem);
+ SendWindowMessage(message);
+}
+
+bool CGUISpinControl::UpdateColors(const CGUIListItem* item)
+{
+ bool changed = CGUIControl::UpdateColors(nullptr);
+ changed |= m_label.UpdateColors();
+ changed |= m_imgspinDownFocus->SetDiffuseColor(m_diffuseColor);
+ changed |= m_imgspinDown->SetDiffuseColor(m_diffuseColor);
+ changed |= m_imgspinUp->SetDiffuseColor(m_diffuseColor);
+ changed |= m_imgspinUpFocus->SetDiffuseColor(m_diffuseColor);
+ changed |= m_imgspinUpDisabled->SetDiffuseColor(m_diffuseColor);
+ changed |= m_imgspinDownDisabled->SetDiffuseColor(m_diffuseColor);
+
+ return changed;
+}
+
+bool CGUISpinControl::IsVisible() const
+{
+ // page controls can be optionally disabled if the number of pages is 1
+ if (m_iType == SPIN_CONTROL_TYPE_PAGE && m_numItems <= m_itemsPerPage && !m_showOnePage)
+ return false;
+ return CGUIControl::IsVisible();
+}