From c04dcc2e7d834218ef2d4194331e383402495ae1 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 20:07:22 +0200 Subject: Adding upstream version 2:20.4+dfsg. Signed-off-by: Daniel Baumann --- xbmc/guilib/GUIFixedListContainer.cpp | 308 ++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100644 xbmc/guilib/GUIFixedListContainer.cpp (limited to 'xbmc/guilib/GUIFixedListContainer.cpp') diff --git a/xbmc/guilib/GUIFixedListContainer.cpp b/xbmc/guilib/GUIFixedListContainer.cpp new file mode 100644 index 0000000..0295736 --- /dev/null +++ b/xbmc/guilib/GUIFixedListContainer.cpp @@ -0,0 +1,308 @@ +/* + * 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 "GUIFixedListContainer.h" + +#include "GUIListItemLayout.h" +#include "input/Key.h" + +CGUIFixedListContainer::CGUIFixedListContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, const CScroller& scroller, int preloadItems, int fixedPosition, int cursorRange) + : CGUIBaseContainer(parentID, controlID, posX, posY, width, height, orientation, scroller, preloadItems) +{ + ControlType = GUICONTAINER_FIXEDLIST; + m_type = VIEW_TYPE_LIST; + m_fixedCursor = fixedPosition; + m_cursorRange = std::max(0, cursorRange); + SetCursor(m_fixedCursor); +} + +CGUIFixedListContainer::~CGUIFixedListContainer(void) = default; + +bool CGUIFixedListContainer::OnAction(const CAction &action) +{ + switch (action.GetID()) + { + case ACTION_PAGE_UP: + { + Scroll(-m_itemsPerPage); + return true; + } + break; + case ACTION_PAGE_DOWN: + { + 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; + 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 CGUIFixedListContainer::MoveUp(bool wrapAround) +{ + int item = GetSelectedItem(); + if (item > 0) + SelectItem(item - 1); + else if (wrapAround) + { + SelectItem((int)m_items.size() - 1); + SetContainerMoving(-1); + } + else + return false; + return true; +} + +bool CGUIFixedListContainer::MoveDown(bool wrapAround) +{ + int item = GetSelectedItem(); + if (item < (int)m_items.size() - 1) + SelectItem(item + 1); + else if (wrapAround) + { // move first item in list + SelectItem(0); + SetContainerMoving(1); + } + else + return false; + return true; +} + +void CGUIFixedListContainer::Scroll(int amount) +{ + // increase or decrease the offset within [-minCursor, m_items.size() - maxCursor] + int minCursor, maxCursor; + GetCursorRange(minCursor, maxCursor); + const int nextCursor = GetCursor() + amount; + int offset = GetOffset() + amount; + if (offset < -minCursor) + { + offset = -minCursor; + SetCursor(nextCursor < minCursor ? minCursor : nextCursor); + } + if (offset > (int)m_items.size() - 1 - maxCursor) + { + offset = m_items.size() - 1 - maxCursor; + SetCursor(nextCursor > maxCursor ? maxCursor : nextCursor); + } + ScrollToOffset(offset); +} + +bool CGUIFixedListContainer::GetOffsetRange(int &minOffset, int &maxOffset) const +{ + GetCursorRange(minOffset, maxOffset); + minOffset = -minOffset; + maxOffset = m_items.size() - maxOffset - 1; + return true; +} + +void CGUIFixedListContainer::ValidateOffset() +{ + if (!m_layout) return; + // ensure our fixed cursor position is valid + if (m_fixedCursor >= m_itemsPerPage) + m_fixedCursor = m_itemsPerPage - 1; + if (m_fixedCursor < 0) + m_fixedCursor = 0; + // compute our minimum and maximum cursor positions + int minCursor, maxCursor; + GetCursorRange(minCursor, maxCursor); + // assure our cursor is between these limits + SetCursor(std::max(GetCursor(), minCursor)); + SetCursor(std::min(GetCursor(), maxCursor)); + int minOffset, maxOffset; + GetOffsetRange(minOffset, maxOffset); + // and finally ensure our offset is valid + // don't validate offset if we are scrolling in case the tween image exceed <0, 1> range + if (GetOffset() > maxOffset || (!m_scroller.IsScrolling() && m_scroller.GetValue() > maxOffset * m_layout->Size(m_orientation))) + { + SetOffset(std::max(-minCursor, maxOffset)); + m_scroller.SetValue(GetOffset() * m_layout->Size(m_orientation)); + } + if (GetOffset() < minOffset || (!m_scroller.IsScrolling() && m_scroller.GetValue() < minOffset * m_layout->Size(m_orientation))) + { + SetOffset(minOffset); + m_scroller.SetValue(GetOffset() * m_layout->Size(m_orientation)); + } +} + +int CGUIFixedListContainer::GetCursorFromPoint(const CPoint &point, CPoint *itemPoint) const +{ + if (!m_focusedLayout || !m_layout) + return -1; + int minCursor, maxCursor; + GetCursorRange(minCursor, maxCursor); + // see if the point is either side of our focus range + float start = (minCursor + 0.2f) * m_layout->Size(m_orientation); + float end = (maxCursor - 0.2f) * m_layout->Size(m_orientation) + m_focusedLayout->Size(m_orientation); + float pos = (m_orientation == VERTICAL) ? point.y : point.x; + if (pos >= start && pos <= end) + { // select the appropriate item + pos -= minCursor * m_layout->Size(m_orientation); + for (int row = minCursor; row <= maxCursor; row++) + { + const CGUIListItemLayout *layout = (row == GetCursor()) ? m_focusedLayout : m_layout; + if (pos < layout->Size(m_orientation)) + { + if (!InsideLayout(layout, point)) + return -1; + return row; + } + pos -= layout->Size(m_orientation); + } + } + return -1; +} + +bool CGUIFixedListContainer::SelectItemFromPoint(const CPoint &point) +{ + if (!m_focusedLayout || !m_layout) + return false; + + MarkDirtyRegion(); + + const float mouse_scroll_speed = 0.25f; + const float mouse_max_amount = 1.5f; + float sizeOfItem = m_layout->Size(m_orientation); + int minCursor, maxCursor; + GetCursorRange(minCursor, maxCursor); + // see if the point is either side of our focus range + float start = (minCursor + 0.2f) * sizeOfItem; + float end = (maxCursor - 0.2f) * sizeOfItem + m_focusedLayout->Size(m_orientation); + float pos = (m_orientation == VERTICAL) ? point.y : point.x; + if (pos < start && GetOffset() > -minCursor) + { // 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) + { + ScrollToOffset(GetOffset() - 1); + m_analogScrollCount = 0; + } + return true; + } + else if (pos > end && GetOffset() + maxCursor < (int)m_items.size() - 1) + { + if (!InsideLayout(m_layout, point)) + return false; + // scroll forward + float amount = std::min((pos - end) / sizeOfItem, mouse_max_amount); + m_analogScrollCount += amount * amount * mouse_scroll_speed; + if (m_analogScrollCount > 1) + { + ScrollToOffset(GetOffset() + 1); + m_analogScrollCount = 0; + } + return true; + } + else + { // select the appropriate item + int cursor = GetCursorFromPoint(point); + if (cursor < 0) + return false; + // calling SelectItem() here will focus the item and scroll, which isn't really what we're after + SetCursor(cursor); + return true; + } +} + +void CGUIFixedListContainer::SelectItem(int item) +{ + // Check that GetOffset() 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 - we first set the cursor position + // which may be different at either end of the list, then the offset + int minCursor, maxCursor; + GetCursorRange(minCursor, maxCursor); + + int cursor; + if ((int)m_items.size() - 1 - item <= maxCursor - m_fixedCursor) + cursor = std::max(m_fixedCursor, maxCursor + item - (int)m_items.size() + 1); + else if (item <= m_fixedCursor - minCursor) + cursor = std::min(m_fixedCursor, minCursor + item); + else + cursor = m_fixedCursor; + if (cursor != GetCursor()) + SetContainerMoving(cursor - GetCursor()); + SetCursor(cursor); + ScrollToOffset(item - GetCursor()); + MarkDirtyRegion(); + } +} + +bool CGUIFixedListContainer::HasPreviousPage() const +{ + return (GetOffset() > 0); +} + +bool CGUIFixedListContainer::HasNextPage() const +{ + return (GetOffset() < (int)m_items.size() - m_itemsPerPage && (int)m_items.size() >= m_itemsPerPage); +} + +int CGUIFixedListContainer::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 CGUIFixedListContainer::GetCursorRange(int &minCursor, int &maxCursor) const +{ + minCursor = std::max(m_fixedCursor - m_cursorRange, 0); + maxCursor = std::min(m_fixedCursor + m_cursorRange, m_itemsPerPage); + + if (!m_items.size()) + { + minCursor = m_fixedCursor; + maxCursor = m_fixedCursor; + return; + } + + while (maxCursor - minCursor > (int)m_items.size() - 1) + { + if (maxCursor - m_fixedCursor > m_fixedCursor - minCursor) + maxCursor--; + else + minCursor++; + } +} + -- cgit v1.2.3