diff options
Diffstat (limited to 'xbmc/guilib/GUIWrappingListContainer.cpp')
-rw-r--r-- | xbmc/guilib/GUIWrappingListContainer.cpp | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/xbmc/guilib/GUIWrappingListContainer.cpp b/xbmc/guilib/GUIWrappingListContainer.cpp new file mode 100644 index 0000000..e1bc3c0 --- /dev/null +++ b/xbmc/guilib/GUIWrappingListContainer.cpp @@ -0,0 +1,240 @@ +/* + * 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 "GUIWrappingListContainer.h" + +#include "FileItem.h" +#include "GUIListItemLayout.h" +#include "GUIMessage.h" +#include "input/Key.h" + +CGUIWrappingListContainer::CGUIWrappingListContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, const CScroller& scroller, int preloadItems, int fixedPosition) + : CGUIBaseContainer(parentID, controlID, posX, posY, width, height, orientation, scroller, preloadItems) +{ + SetCursor(fixedPosition); + ControlType = GUICONTAINER_WRAPLIST; + m_type = VIEW_TYPE_LIST; + m_extraItems = 0; +} + +CGUIWrappingListContainer::~CGUIWrappingListContainer(void) = default; + +void CGUIWrappingListContainer::UpdatePageControl(int offset) +{ + if (m_pageControl) + { // tell our pagecontrol (scrollbar or whatever) to update (offset it by our cursor position) + CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), m_pageControl, GetNumItems() ? CorrectOffset(offset, GetCursor()) % GetNumItems() : 0); + SendWindowMessage(msg); + } +} + +bool CGUIWrappingListContainer::OnAction(const CAction &action) +{ + switch (action.GetID()) + { + case ACTION_PAGE_UP: + Scroll(-m_itemsPerPage); + return true; + case ACTION_PAGE_DOWN: + Scroll(m_itemsPerPage); + return true; + // smooth scrolling (for analog controls) + case ACTION_SCROLL_UP: + { + m_analogScrollCount += action.GetAmount() * action.GetAmount(); + bool handled = false; + while (m_analogScrollCount > 0.4f) + { + handled = true; + m_analogScrollCount -= 0.4f; + Scroll(-1); + } + return handled; + } + break; + case ACTION_SCROLL_DOWN: + { + m_analogScrollCount += action.GetAmount() * action.GetAmount(); + bool handled = false; + while (m_analogScrollCount > 0.4f) + { + handled = true; + m_analogScrollCount -= 0.4f; + Scroll(1); + } + return handled; + } + break; + } + return CGUIBaseContainer::OnAction(action); +} + +bool CGUIWrappingListContainer::OnMessage(CGUIMessage& message) +{ + if (message.GetControlId() == GetID() ) + { + if (message.GetMessage() == GUI_MSG_PAGE_CHANGE) + { + if (message.GetSenderId() == m_pageControl && IsVisible()) + { // offset by our cursor position + message.SetParam1(message.GetParam1() - GetCursor()); + } + } + } + return CGUIBaseContainer::OnMessage(message); +} + +bool CGUIWrappingListContainer::MoveUp(bool wrapAround) +{ + Scroll(-1); + return true; +} + +bool CGUIWrappingListContainer::MoveDown(bool wrapAround) +{ + Scroll(+1); + return true; +} + +// scrolls the said amount +void CGUIWrappingListContainer::Scroll(int amount) +{ + ScrollToOffset(GetOffset() + amount); +} + +bool CGUIWrappingListContainer::GetOffsetRange(int &minOffset, int &maxOffset) const +{ + return false; +} + +void CGUIWrappingListContainer::ValidateOffset() +{ + // our minimal amount of items - we need to take into account extra items to display wrapped items when scrolling + unsigned int minItems = (unsigned int)m_itemsPerPage + ScrollCorrectionRange() + GetCacheCount() / 2; + if (minItems <= m_items.size()) + return; + + // no need to check the range here, but we need to check we have + // more items than slots. + ResetExtraItems(); + if (m_items.size()) + { + size_t numItems = m_items.size(); + while (m_items.size() < minItems) + { + // add additional copies of items, as we require extras at render time + for (unsigned int i = 0; i < numItems; i++) + { + m_items.push_back(CGUIListItemPtr(m_items[i]->Clone())); + m_extraItems++; + } + } + } +} + +int CGUIWrappingListContainer::CorrectOffset(int offset, int cursor) const +{ + if (m_items.size()) + { + int correctOffset = (offset + cursor) % (int)m_items.size(); + if (correctOffset < 0) correctOffset += m_items.size(); + return correctOffset; + } + return 0; +} + +int CGUIWrappingListContainer::GetSelectedItem() const +{ + if (m_items.size() > m_extraItems) + { + int numItems = (int)(m_items.size() - m_extraItems); + int correctOffset = (GetOffset() + GetCursor()) % numItems; + if (correctOffset < 0) correctOffset += numItems; + return correctOffset; + } + return 0; +} + +bool CGUIWrappingListContainer::SelectItemFromPoint(const CPoint &point) +{ + if (!m_focusedLayout || !m_layout) + return false; + + const float mouse_scroll_speed = 0.05f; + const float mouse_max_amount = 1.0f; // max speed: 1 item per frame + float sizeOfItem = m_layout->Size(m_orientation); + // see if the point is either side of our focused item + float start = GetCursor() * sizeOfItem; + float end = start + m_focusedLayout->Size(m_orientation); + float pos = (m_orientation == VERTICAL) ? point.y : point.x; + if (pos < start - 0.5f * sizeOfItem) + { // scroll backward + if (!InsideLayout(m_layout, point)) + return false; + float amount = std::min((start - pos) / sizeOfItem, mouse_max_amount); + m_analogScrollCount += amount * amount * mouse_scroll_speed; + if (m_analogScrollCount > 1) + { + Scroll(-1); + m_analogScrollCount-=1.0f; + } + return true; + } + else if (pos > end + 0.5f * sizeOfItem) + { // scroll forward + if (!InsideLayout(m_layout, point)) + return false; + + float amount = std::min((pos - end) / sizeOfItem, mouse_max_amount); + m_analogScrollCount += amount * amount * mouse_scroll_speed; + if (m_analogScrollCount > 1) + { + Scroll(1); + m_analogScrollCount-=1.0f; + } + return true; + } + return InsideLayout(m_focusedLayout, point); +} + +void CGUIWrappingListContainer::SelectItem(int item) +{ + if (item >= 0 && item < (int)m_items.size()) + ScrollToOffset(item - GetCursor()); +} + +void CGUIWrappingListContainer::ResetExtraItems() +{ + // delete any extra items + if (m_extraItems) + m_items.erase(m_items.begin() + m_items.size() - m_extraItems, m_items.end()); + m_extraItems = 0; +} + +void CGUIWrappingListContainer::Reset() +{ + ResetExtraItems(); + CGUIBaseContainer::Reset(); +} + +int CGUIWrappingListContainer::GetCurrentPage() const +{ + int offset = CorrectOffset(GetOffset(), GetCursor()); + if (offset + m_itemsPerPage - GetCursor() >= (int)GetRows()) // last page + return (GetRows() + m_itemsPerPage - 1) / m_itemsPerPage; + return offset / m_itemsPerPage + 1; +} + +void CGUIWrappingListContainer::SetPageControlRange() +{ + if (m_pageControl) + { + CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), m_pageControl, m_itemsPerPage, GetNumItems()); + SendWindowMessage(msg); + } +} |