diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/guilib/GUIListContainer.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/guilib/GUIListContainer.cpp')
-rw-r--r-- | xbmc/guilib/GUIListContainer.cpp | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/xbmc/guilib/GUIListContainer.cpp b/xbmc/guilib/GUIListContainer.cpp new file mode 100644 index 0000000..b078263 --- /dev/null +++ b/xbmc/guilib/GUIListContainer.cpp @@ -0,0 +1,299 @@ +/* + * 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 "GUIListContainer.h" + +#include "GUIListItemLayout.h" +#include "GUIMessage.h" +#include "input/Key.h" +#include "utils/StringUtils.h" + +CGUIListContainer::CGUIListContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, const CScroller& scroller, int preloadItems) + : CGUIBaseContainer(parentID, controlID, posX, posY, width, height, orientation, scroller, preloadItems) +{ + ControlType = GUICONTAINER_LIST; + m_type = VIEW_TYPE_LIST; +} + +CGUIListContainer::CGUIListContainer(const CGUIListContainer& other) : CGUIBaseContainer(other) +{ +} + +CGUIListContainer::~CGUIListContainer(void) = default; + +bool CGUIListContainer::OnAction(const CAction &action) +{ + switch (action.GetID()) + { + case ACTION_PAGE_UP: + { + if (GetOffset() == 0) + { // already on the first page, so move to the first item + SetCursor(0); + } + else + { // scroll up to the previous page + Scroll( -m_itemsPerPage); + } + return true; + } + break; + case ACTION_PAGE_DOWN: + { + if (GetOffset() == (int)m_items.size() - m_itemsPerPage || (int)m_items.size() < m_itemsPerPage) + { // already at the last page, so move to the last item. + SetCursor(m_items.size() - GetOffset() - 1); + } + else + { // scroll down to the next page + Scroll(m_itemsPerPage); + } + return true; + } + break; + // 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; + if (GetOffset() > 0 && GetCursor() <= m_itemsPerPage / 2) + { + Scroll(-1); + } + else if (GetCursor() > 0) + { + SetCursor(GetCursor() - 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; + if (GetOffset() + m_itemsPerPage < (int)m_items.size() && GetCursor() >= m_itemsPerPage / 2) + { + Scroll(1); + } + else if (GetCursor() < m_itemsPerPage - 1 && GetOffset() + GetCursor() < (int)m_items.size() - 1) + { + SetCursor(GetCursor() + 1); + } + } + return handled; + } + break; + } + return CGUIBaseContainer::OnAction(action); +} + +bool CGUIListContainer::OnMessage(CGUIMessage& message) +{ + if (message.GetControlId() == GetID() ) + { + if (message.GetMessage() == GUI_MSG_LABEL_RESET) + { + SetCursor(0); + SetOffset(0); + m_scroller.SetValue(0); + } + } + return CGUIBaseContainer::OnMessage(message); +} + +bool CGUIListContainer::MoveUp(bool wrapAround) +{ + if (GetCursor() > 0) + { + SetCursor(GetCursor() - 1); + } + else if (GetCursor() == 0 && GetOffset()) + { + ScrollToOffset(GetOffset() - 1); + } + else if (wrapAround) + { + if (!m_items.empty()) + { // move 2 last item in list, and set our container moving up + int offset = m_items.size() - m_itemsPerPage; + if (offset < 0) offset = 0; + SetCursor(m_items.size() - offset - 1); + ScrollToOffset(offset); + SetContainerMoving(-1); + } + } + else + return false; + return true; +} + +bool CGUIListContainer::MoveDown(bool wrapAround) +{ + if (GetOffset() + GetCursor() + 1 < (int)m_items.size()) + { + if (GetCursor() + 1 < m_itemsPerPage) + { + SetCursor(GetCursor() + 1); + } + else + { + ScrollToOffset(GetOffset() + 1); + } + } + else if(wrapAround) + { // move first item in list, and set our container moving in the "down" direction + SetCursor(0); + ScrollToOffset(0); + SetContainerMoving(1); + } + else + return false; + return true; +} + +// scrolls the said amount +void CGUIListContainer::Scroll(int amount) +{ + // increase or decrease the offset + int offset = GetOffset() + amount; + if (offset > (int)m_items.size() - m_itemsPerPage) + { + offset = m_items.size() - m_itemsPerPage; + } + if (offset < 0) offset = 0; + ScrollToOffset(offset); +} + +void CGUIListContainer::ValidateOffset() +{ + if (!m_layout) return; + // first thing is we check the range of our offset + // don't validate offset if we are scrolling in case the tween image exceed <0, 1> range + int minOffset, maxOffset; + GetOffsetRange(minOffset, maxOffset); + if (GetOffset() > maxOffset || (!m_scroller.IsScrolling() && m_scroller.GetValue() > maxOffset * m_layout->Size(m_orientation))) + { + SetOffset(std::max(0, maxOffset)); + m_scroller.SetValue(GetOffset() * m_layout->Size(m_orientation)); + } + if (GetOffset() < 0 || (!m_scroller.IsScrolling() && m_scroller.GetValue() < 0)) + { + SetOffset(0); + m_scroller.SetValue(0); + } +} + +void CGUIListContainer::SetCursor(int cursor) +{ + if (cursor > m_itemsPerPage - 1) cursor = m_itemsPerPage - 1; + if (cursor < 0) cursor = 0; + if (!m_wasReset) + SetContainerMoving(cursor - GetCursor()); + CGUIBaseContainer::SetCursor(cursor); +} + +void CGUIListContainer::SelectItem(int item) +{ + // Check that our offset is valid + ValidateOffset(); + // only select an item if it's in a valid range + if (item >= 0 && item < (int)m_items.size()) + { + // Select the item requested + if (item >= GetOffset() && item < GetOffset() + m_itemsPerPage) + { // the item is on the current page, so don't change it. + SetCursor(item - GetOffset()); + } + else if (item < GetOffset()) + { // item is on a previous page - make it the first item on the page + SetCursor(0); + ScrollToOffset(item); + } + else // (item >= GetOffset()+m_itemsPerPage) + { // item is on a later page - make it the last item on the page + SetCursor(m_itemsPerPage - 1); + ScrollToOffset(item - GetCursor()); + } + } +} + +int CGUIListContainer::GetCursorFromPoint(const CPoint &point, CPoint *itemPoint) const +{ + if (!m_focusedLayout || !m_layout) + return -1; + + int row = 0; + float pos = (m_orientation == VERTICAL) ? point.y : point.x; + while (row < m_itemsPerPage + 1) // 1 more to ensure we get the (possible) half item at the end. + { + const CGUIListItemLayout *layout = (row == GetCursor()) ? m_focusedLayout : m_layout; + if (pos < layout->Size(m_orientation) && row + GetOffset() < (int)m_items.size()) + { // found correct "row" -> check horizontal + if (!InsideLayout(layout, point)) + return -1; + + if (itemPoint) + *itemPoint = m_orientation == VERTICAL ? CPoint(point.x, pos) : CPoint(pos, point.y); + return row; + } + row++; + pos -= layout->Size(m_orientation); + } + return -1; +} + +bool CGUIListContainer::SelectItemFromPoint(const CPoint &point) +{ + CPoint itemPoint; + int row = GetCursorFromPoint(point, &itemPoint); + if (row < 0) + return false; + + SetCursor(row); + CGUIListItemLayout *focusedLayout = GetFocusedLayout(); + if (focusedLayout) + focusedLayout->SelectItemFromPoint(itemPoint); + return true; +} + +//#ifdef GUILIB_PYTHON_COMPATIBILITY +CGUIListContainer::CGUIListContainer(int parentID, int controlID, float posX, float posY, float width, float height, + const CLabelInfo& labelInfo, const CLabelInfo& labelInfo2, + const CTextureInfo& textureButton, const CTextureInfo& textureButtonFocus, + float textureHeight, float itemWidth, float itemHeight, float spaceBetweenItems) +: CGUIBaseContainer(parentID, controlID, posX, posY, width, height, VERTICAL, 200, 0) +{ + m_layouts.emplace_back(); + m_layouts.back().CreateListControlLayouts(width, textureHeight + spaceBetweenItems, false, labelInfo, labelInfo2, textureButton, textureButtonFocus, textureHeight, itemWidth, itemHeight, "", ""); + std::string condition = StringUtils::Format("control.hasfocus({})", controlID); + std::string condition2 = "!" + condition; + m_focusedLayouts.emplace_back(); + m_focusedLayouts.back().CreateListControlLayouts(width, textureHeight + spaceBetweenItems, true, labelInfo, labelInfo2, textureButton, textureButtonFocus, textureHeight, itemWidth, itemHeight, condition2, condition); + m_height = floor(m_height / (textureHeight + spaceBetweenItems)) * (textureHeight + spaceBetweenItems); + ControlType = GUICONTAINER_LIST; +} +//#endif + +bool CGUIListContainer::HasNextPage() const +{ + return (GetOffset() != (int)m_items.size() - m_itemsPerPage && (int)m_items.size() >= m_itemsPerPage); +} + +bool CGUIListContainer::HasPreviousPage() const +{ + return (GetOffset() > 0); +} |