diff options
Diffstat (limited to 'xbmc/guilib/GUIScrollBarControl.cpp')
-rw-r--r-- | xbmc/guilib/GUIScrollBarControl.cpp | 397 |
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(); +} |