summaryrefslogtreecommitdiffstats
path: root/xbmc/guilib/GUIScrollBarControl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/guilib/GUIScrollBarControl.cpp')
-rw-r--r--xbmc/guilib/GUIScrollBarControl.cpp397
1 files changed, 397 insertions, 0 deletions
diff --git a/xbmc/guilib/GUIScrollBarControl.cpp b/xbmc/guilib/GUIScrollBarControl.cpp
new file mode 100644
index 0000000..bcb2101
--- /dev/null
+++ b/xbmc/guilib/GUIScrollBarControl.cpp
@@ -0,0 +1,397 @@
+/*
+ * 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 "GUIScrollBarControl.h"
+
+#include "GUIMessage.h"
+#include "input/Key.h"
+#include "input/mouse/MouseStat.h"
+#include "utils/StringUtils.h"
+
+#define MIN_NIB_SIZE 4.0f
+
+GUIScrollBarControl::GUIScrollBarControl(int parentID,
+ int controlID,
+ float posX,
+ float posY,
+ float width,
+ float height,
+ const CTextureInfo& backGroundTexture,
+ const CTextureInfo& barTexture,
+ const CTextureInfo& barTextureFocus,
+ const CTextureInfo& nibTexture,
+ const CTextureInfo& nibTextureFocus,
+ ORIENTATION orientation,
+ bool showOnePage)
+ : CGUIControl(parentID, controlID, posX, posY, width, height),
+ m_guiBackground(CGUITexture::CreateTexture(posX, posY, width, height, backGroundTexture)),
+ m_guiBarNoFocus(CGUITexture::CreateTexture(posX, posY, width, height, barTexture)),
+ m_guiBarFocus(CGUITexture::CreateTexture(posX, posY, width, height, barTextureFocus)),
+ m_guiNibNoFocus(CGUITexture::CreateTexture(posX, posY, width, height, nibTexture)),
+ m_guiNibFocus(CGUITexture::CreateTexture(posX, posY, width, height, nibTextureFocus))
+{
+ m_guiNibNoFocus->SetAspectRatio(CAspectRatio::AR_CENTER);
+ m_guiNibFocus->SetAspectRatio(CAspectRatio::AR_CENTER);
+ m_numItems = 100;
+ m_offset = 0;
+ m_pageSize = 10;
+ ControlType = GUICONTROL_SCROLLBAR;
+ m_orientation = orientation;
+ m_showOnePage = showOnePage;
+}
+
+GUIScrollBarControl::GUIScrollBarControl(const GUIScrollBarControl& control)
+ : CGUIControl(control),
+ m_guiBackground(control.m_guiBackground->Clone()),
+ m_guiBarNoFocus(control.m_guiBarNoFocus->Clone()),
+ m_guiBarFocus(control.m_guiBarFocus->Clone()),
+ m_guiNibNoFocus(control.m_guiNibNoFocus->Clone()),
+ m_guiNibFocus(control.m_guiNibFocus->Clone()),
+ m_numItems(control.m_numItems),
+ m_pageSize(control.m_pageSize),
+ m_offset(control.m_offset),
+ m_showOnePage(control.m_showOnePage),
+ m_orientation(control.m_orientation)
+{
+}
+
+void GUIScrollBarControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
+{
+ bool changed = false;
+
+ if (m_bInvalidated)
+ changed |= UpdateBarSize();
+
+ changed |= m_guiBackground->Process(currentTime);
+ changed |= m_guiBarNoFocus->Process(currentTime);
+ changed |= m_guiBarFocus->Process(currentTime);
+ changed |= m_guiNibNoFocus->Process(currentTime);
+ changed |= m_guiNibFocus->Process(currentTime);
+
+ if (changed)
+ MarkDirtyRegion();
+
+ CGUIControl::Process(currentTime, dirtyregions);
+}
+
+void GUIScrollBarControl::Render()
+{
+ m_guiBackground->Render();
+ if (m_bHasFocus)
+ {
+ m_guiBarFocus->Render();
+ m_guiNibFocus->Render();
+ }
+ else
+ {
+ m_guiBarNoFocus->Render();
+ m_guiNibNoFocus->Render();
+ }
+
+ CGUIControl::Render();
+}
+
+bool GUIScrollBarControl::OnMessage(CGUIMessage& message)
+{
+ switch (message.GetMessage())
+ {
+ case GUI_MSG_ITEM_SELECT:
+ SetValue(message.GetParam1());
+ return true;
+ case GUI_MSG_LABEL_RESET:
+ SetRange(message.GetParam1(), message.GetParam2());
+ return true;
+ case GUI_MSG_PAGE_UP:
+ Move(-1);
+ return true;
+ case GUI_MSG_PAGE_DOWN:
+ Move(1);
+ return true;
+ }
+ return CGUIControl::OnMessage(message);
+}
+
+bool GUIScrollBarControl::OnAction(const CAction &action)
+{
+ switch ( action.GetID() )
+ {
+ case ACTION_MOVE_LEFT:
+ if (m_orientation == HORIZONTAL)
+ {
+ if(Move( -1))
+ return true;
+ }
+ break;
+
+ case ACTION_MOVE_RIGHT:
+ if (m_orientation == HORIZONTAL)
+ {
+ if(Move(1))
+ return true;
+ }
+ break;
+ case ACTION_MOVE_UP:
+ if (m_orientation == VERTICAL)
+ {
+ if(Move(-1))
+ return true;
+ }
+ break;
+
+ case ACTION_MOVE_DOWN:
+ if (m_orientation == VERTICAL)
+ {
+ if(Move(1))
+ return true;
+ }
+ break;
+ }
+ return CGUIControl::OnAction(action);
+}
+
+bool GUIScrollBarControl::Move(int numSteps)
+{
+ if (numSteps < 0 && m_offset == 0) // we are at the beginning - can't scroll up/left anymore
+ return false;
+ if (numSteps > 0 && m_offset == std::max(m_numItems - m_pageSize, 0)) // we are at the end - we can't scroll down/right anymore
+ return false;
+
+ m_offset += numSteps * m_pageSize;
+ if (m_offset > m_numItems - m_pageSize) m_offset = m_numItems - m_pageSize;
+ if (m_offset < 0) m_offset = 0;
+ CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_offset);
+ SendWindowMessage(message);
+ SetInvalid();
+ return true;
+}
+
+void GUIScrollBarControl::SetRange(int pageSize, int numItems)
+{
+ if (m_pageSize != pageSize || m_numItems != numItems)
+ {
+ m_pageSize = pageSize;
+ m_numItems = numItems;
+ m_offset = 0;
+ SetInvalid();
+ }
+}
+
+void GUIScrollBarControl::SetValue(int value)
+{
+ if (m_offset != value)
+ {
+ m_offset = value;
+ SetInvalid();
+ }
+}
+
+void GUIScrollBarControl::FreeResources(bool immediately)
+{
+ CGUIControl::FreeResources(immediately);
+ m_guiBackground->FreeResources(immediately);
+ m_guiBarNoFocus->FreeResources(immediately);
+ m_guiBarFocus->FreeResources(immediately);
+ m_guiNibNoFocus->FreeResources(immediately);
+ m_guiNibFocus->FreeResources(immediately);
+}
+
+void GUIScrollBarControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_guiBackground->DynamicResourceAlloc(bOnOff);
+ m_guiBarNoFocus->DynamicResourceAlloc(bOnOff);
+ m_guiBarFocus->DynamicResourceAlloc(bOnOff);
+ m_guiNibNoFocus->DynamicResourceAlloc(bOnOff);
+ m_guiNibFocus->DynamicResourceAlloc(bOnOff);
+}
+
+void GUIScrollBarControl::AllocResources()
+{
+ CGUIControl::AllocResources();
+ m_guiBackground->AllocResources();
+ m_guiBarNoFocus->AllocResources();
+ m_guiBarFocus->AllocResources();
+ m_guiNibNoFocus->AllocResources();
+ m_guiNibFocus->AllocResources();
+}
+
+void GUIScrollBarControl::SetInvalid()
+{
+ CGUIControl::SetInvalid();
+ m_guiBackground->SetInvalid();
+ m_guiBarFocus->SetInvalid();
+ m_guiBarFocus->SetInvalid();
+ m_guiNibNoFocus->SetInvalid();
+ m_guiNibFocus->SetInvalid();
+}
+
+bool GUIScrollBarControl::UpdateBarSize()
+{
+ bool changed = false;
+
+ // scale our textures to suit
+ if (m_orientation == VERTICAL)
+ {
+ // calculate the height to display the nib at
+ float percent = (m_numItems == 0) ? 0 : (float)m_pageSize / m_numItems;
+ float nibSize = GetHeight() * percent;
+ if (nibSize < m_guiNibFocus->GetTextureHeight() + 2 * MIN_NIB_SIZE)
+ nibSize = m_guiNibFocus->GetTextureHeight() + 2 * MIN_NIB_SIZE;
+ if (nibSize > GetHeight()) nibSize = GetHeight();
+
+ changed |= m_guiBarNoFocus->SetHeight(nibSize);
+ changed |= m_guiBarFocus->SetHeight(nibSize);
+ changed |= m_guiNibNoFocus->SetHeight(nibSize);
+ changed |= m_guiNibFocus->SetHeight(nibSize);
+ // nibSize may be altered by the border size of the nib (and bar).
+ nibSize = std::max(m_guiBarFocus->GetHeight(), m_guiNibFocus->GetHeight());
+
+ // and the position
+ percent = (m_numItems == m_pageSize) ? 0 : (float)m_offset / (m_numItems - m_pageSize);
+ float nibPos = (GetHeight() - nibSize) * percent;
+ if (nibPos < 0) nibPos = 0;
+ if (nibPos > GetHeight() - nibSize) nibPos = GetHeight() - nibSize;
+
+ changed |= m_guiBarNoFocus->SetPosition(GetXPosition(), GetYPosition() + nibPos);
+ changed |= m_guiBarFocus->SetPosition(GetXPosition(), GetYPosition() + nibPos);
+ changed |= m_guiNibNoFocus->SetPosition(GetXPosition(), GetYPosition() + nibPos);
+ changed |= m_guiNibFocus->SetPosition(GetXPosition(), GetYPosition() + nibPos);
+ }
+ else
+ {
+ // calculate the height to display the nib at
+ float percent = (m_numItems == 0) ? 0 : (float)m_pageSize / m_numItems;
+ float nibSize = GetWidth() * percent + 0.5f;
+ if (nibSize < m_guiNibFocus->GetTextureWidth() + 2 * MIN_NIB_SIZE)
+ nibSize = m_guiNibFocus->GetTextureWidth() + 2 * MIN_NIB_SIZE;
+ if (nibSize > GetWidth()) nibSize = GetWidth();
+
+ changed |= m_guiBarNoFocus->SetWidth(nibSize);
+ changed |= m_guiBarFocus->SetWidth(nibSize);
+ changed |= m_guiNibNoFocus->SetWidth(nibSize);
+ changed |= m_guiNibFocus->SetWidth(nibSize);
+
+ // and the position
+ percent = (m_numItems == m_pageSize) ? 0 : (float)m_offset / (m_numItems - m_pageSize);
+ float nibPos = (GetWidth() - nibSize) * percent;
+ if (nibPos < 0) nibPos = 0;
+ if (nibPos > GetWidth() - nibSize) nibPos = GetWidth() - nibSize;
+
+ changed |= m_guiBarNoFocus->SetPosition(GetXPosition() + nibPos, GetYPosition());
+ changed |= m_guiBarFocus->SetPosition(GetXPosition() + nibPos, GetYPosition());
+ changed |= m_guiNibNoFocus->SetPosition(GetXPosition() + nibPos, GetYPosition());
+ changed |= m_guiNibFocus->SetPosition(GetXPosition() + nibPos, GetYPosition());
+ }
+
+ return changed;
+}
+
+void GUIScrollBarControl::SetFromPosition(const CPoint &point)
+{
+ float fPercent;
+ if (m_orientation == VERTICAL)
+ fPercent = (point.y - m_guiBackground->GetYPosition() - 0.5f * m_guiBarFocus->GetHeight()) /
+ (m_guiBackground->GetHeight() - m_guiBarFocus->GetHeight());
+ else
+ fPercent = (point.x - m_guiBackground->GetXPosition() - 0.5f * m_guiBarFocus->GetWidth()) /
+ (m_guiBackground->GetWidth() - m_guiBarFocus->GetWidth());
+ if (fPercent < 0) fPercent = 0;
+ if (fPercent > 1) fPercent = 1;
+
+ int offset = (int)(floor(fPercent * (m_numItems - m_pageSize) + 0.5f));
+
+ if (m_offset != offset)
+ {
+ m_offset = offset;
+ CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_offset);
+ SendWindowMessage(message);
+ SetInvalid();
+ }
+}
+
+EVENT_RESULT GUIScrollBarControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
+{
+ if (event.m_id == ACTION_MOUSE_DRAG || event.m_id == ACTION_MOUSE_DRAG_END)
+ {
+ if (static_cast<HoldAction>(event.m_state) == HoldAction::DRAG)
+ { // we want exclusive access
+ CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ }
+ else if (static_cast<HoldAction>(event.m_state) == HoldAction::DRAG_END)
+ { // we're done with exclusive access
+ CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
+ SendWindowMessage(msg);
+ }
+ SetFromPosition(point);
+ return EVENT_RESULT_HANDLED;
+ }
+ else if (event.m_id == ACTION_MOUSE_LEFT_CLICK && m_guiBackground->HitTest(point))
+ {
+ SetFromPosition(point);
+ return EVENT_RESULT_HANDLED;
+ }
+ else if (event.m_id == ACTION_MOUSE_WHEEL_UP)
+ {
+ Move(-1);
+ return EVENT_RESULT_HANDLED;
+ }
+ else if (event.m_id == ACTION_MOUSE_WHEEL_DOWN)
+ {
+ Move(1);
+ return EVENT_RESULT_HANDLED;
+ }
+ else if (event.m_id == ACTION_GESTURE_NOTIFY)
+ {
+ return (m_orientation == HORIZONTAL) ? EVENT_RESULT_PAN_HORIZONTAL_WITHOUT_INERTIA : EVENT_RESULT_PAN_VERTICAL_WITHOUT_INERTIA;
+ }
+ else if (event.m_id == ACTION_GESTURE_BEGIN)
+ { // grab exclusive access
+ CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return EVENT_RESULT_HANDLED;
+ }
+ else if (event.m_id == ACTION_GESTURE_PAN)
+ { // do the drag
+ SetFromPosition(point);
+ return EVENT_RESULT_HANDLED;
+ }
+ else if (event.m_id == ACTION_GESTURE_END || event.m_id == ACTION_GESTURE_ABORT)
+ { // release exclusive access
+ CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
+ SendWindowMessage(msg);
+ return EVENT_RESULT_HANDLED;
+ }
+
+ return EVENT_RESULT_UNHANDLED;
+}
+
+std::string GUIScrollBarControl::GetDescription() const
+{
+ return StringUtils::Format("{}/{}", m_offset, m_numItems);
+}
+
+bool GUIScrollBarControl::UpdateColors(const CGUIListItem* item)
+{
+ bool changed = CGUIControl::UpdateColors(nullptr);
+ changed |= m_guiBackground->SetDiffuseColor(m_diffuseColor);
+ changed |= m_guiBarNoFocus->SetDiffuseColor(m_diffuseColor);
+ changed |= m_guiBarFocus->SetDiffuseColor(m_diffuseColor);
+ changed |= m_guiNibNoFocus->SetDiffuseColor(m_diffuseColor);
+ changed |= m_guiNibFocus->SetDiffuseColor(m_diffuseColor);
+
+ return changed;
+}
+
+bool GUIScrollBarControl::IsVisible() const
+{
+ // page controls can be optionally disabled if the number of pages is 1
+ if (m_numItems <= m_pageSize && !m_showOnePage)
+ return false;
+ return CGUIControl::IsVisible();
+}