2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "GUIWrappingListContainer.h"
12 #include "GUIListItemLayout.h"
13 #include "GUIMessage.h"
14 #include "input/Key.h"
16 CGUIWrappingListContainer::CGUIWrappingListContainer(int parentID
, int controlID
, float posX
, float posY
, float width
, float height
, ORIENTATION orientation
, const CScroller
& scroller
, int preloadItems
, int fixedPosition
)
17 : CGUIBaseContainer(parentID
, controlID
, posX
, posY
, width
, height
, orientation
, scroller
, preloadItems
)
19 SetCursor(fixedPosition
);
20 ControlType
= GUICONTAINER_WRAPLIST
;
21 m_type
= VIEW_TYPE_LIST
;
25 CGUIWrappingListContainer::~CGUIWrappingListContainer(void) = default;
27 void CGUIWrappingListContainer::UpdatePageControl(int offset
)
30 { // tell our pagecontrol (scrollbar or whatever) to update (offset it by our cursor position)
31 CGUIMessage
msg(GUI_MSG_ITEM_SELECT
, GetID(), m_pageControl
, GetNumItems() ? CorrectOffset(offset
, GetCursor()) % GetNumItems() : 0);
32 SendWindowMessage(msg
);
36 bool CGUIWrappingListContainer::OnAction(const CAction
&action
)
38 switch (action
.GetID())
41 Scroll(-m_itemsPerPage
);
43 case ACTION_PAGE_DOWN
:
44 Scroll(m_itemsPerPage
);
46 // smooth scrolling (for analog controls)
47 case ACTION_SCROLL_UP
:
49 m_analogScrollCount
+= action
.GetAmount() * action
.GetAmount();
51 while (m_analogScrollCount
> 0.4f
)
54 m_analogScrollCount
-= 0.4f
;
60 case ACTION_SCROLL_DOWN
:
62 m_analogScrollCount
+= action
.GetAmount() * action
.GetAmount();
64 while (m_analogScrollCount
> 0.4f
)
67 m_analogScrollCount
-= 0.4f
;
74 return CGUIBaseContainer::OnAction(action
);
77 bool CGUIWrappingListContainer::OnMessage(CGUIMessage
& message
)
79 if (message
.GetControlId() == GetID() )
81 if (message
.GetMessage() == GUI_MSG_PAGE_CHANGE
)
83 if (message
.GetSenderId() == m_pageControl
&& IsVisible())
84 { // offset by our cursor position
85 message
.SetParam1(message
.GetParam1() - GetCursor());
89 return CGUIBaseContainer::OnMessage(message
);
92 bool CGUIWrappingListContainer::MoveUp(bool wrapAround
)
98 bool CGUIWrappingListContainer::MoveDown(bool wrapAround
)
104 // scrolls the said amount
105 void CGUIWrappingListContainer::Scroll(int amount
)
107 ScrollToOffset(GetOffset() + amount
);
110 bool CGUIWrappingListContainer::GetOffsetRange(int &minOffset
, int &maxOffset
) const
115 void CGUIWrappingListContainer::ValidateOffset()
117 // our minimal amount of items - we need to take into account extra items to display wrapped items when scrolling
118 unsigned int minItems
= (unsigned int)m_itemsPerPage
+ ScrollCorrectionRange() + GetCacheCount() / 2;
119 if (minItems
<= m_items
.size())
122 // no need to check the range here, but we need to check we have
123 // more items than slots.
127 size_t numItems
= m_items
.size();
128 while (m_items
.size() < minItems
)
130 // add additional copies of items, as we require extras at render time
131 for (unsigned int i
= 0; i
< numItems
; i
++)
133 m_items
.push_back(CGUIListItemPtr(m_items
[i
]->Clone()));
140 int CGUIWrappingListContainer::CorrectOffset(int offset
, int cursor
) const
144 int correctOffset
= (offset
+ cursor
) % (int)m_items
.size();
145 if (correctOffset
< 0) correctOffset
+= m_items
.size();
146 return correctOffset
;
151 int CGUIWrappingListContainer::GetSelectedItem() const
153 if (m_items
.size() > m_extraItems
)
155 int numItems
= (int)(m_items
.size() - m_extraItems
);
156 int correctOffset
= (GetOffset() + GetCursor()) % numItems
;
157 if (correctOffset
< 0) correctOffset
+= numItems
;
158 return correctOffset
;
163 bool CGUIWrappingListContainer::SelectItemFromPoint(const CPoint
&point
)
165 if (!m_focusedLayout
|| !m_layout
)
168 const float mouse_scroll_speed
= 0.05f
;
169 const float mouse_max_amount
= 1.0f
; // max speed: 1 item per frame
170 float sizeOfItem
= m_layout
->Size(m_orientation
);
171 // see if the point is either side of our focused item
172 float start
= GetCursor() * sizeOfItem
;
173 float end
= start
+ m_focusedLayout
->Size(m_orientation
);
174 float pos
= (m_orientation
== VERTICAL
) ? point
.y
: point
.x
;
175 if (pos
< start
- 0.5f
* sizeOfItem
)
177 if (!InsideLayout(m_layout
, point
))
179 float amount
= std::min((start
- pos
) / sizeOfItem
, mouse_max_amount
);
180 m_analogScrollCount
+= amount
* amount
* mouse_scroll_speed
;
181 if (m_analogScrollCount
> 1)
184 m_analogScrollCount
-=1.0f
;
188 else if (pos
> end
+ 0.5f
* sizeOfItem
)
190 if (!InsideLayout(m_layout
, point
))
193 float amount
= std::min((pos
- end
) / sizeOfItem
, mouse_max_amount
);
194 m_analogScrollCount
+= amount
* amount
* mouse_scroll_speed
;
195 if (m_analogScrollCount
> 1)
198 m_analogScrollCount
-=1.0f
;
202 return InsideLayout(m_focusedLayout
, point
);
205 void CGUIWrappingListContainer::SelectItem(int item
)
207 if (item
>= 0 && item
< (int)m_items
.size())
208 ScrollToOffset(item
- GetCursor());
211 void CGUIWrappingListContainer::ResetExtraItems()
213 // delete any extra items
215 m_items
.erase(m_items
.begin() + m_items
.size() - m_extraItems
, m_items
.end());
219 void CGUIWrappingListContainer::Reset()
222 CGUIBaseContainer::Reset();
225 int CGUIWrappingListContainer::GetCurrentPage() const
227 int offset
= CorrectOffset(GetOffset(), GetCursor());
228 if (offset
+ m_itemsPerPage
- GetCursor() >= (int)GetRows()) // last page
229 return (GetRows() + m_itemsPerPage
- 1) / m_itemsPerPage
;
230 return offset
/ m_itemsPerPage
+ 1;
233 void CGUIWrappingListContainer::SetPageControlRange()
237 CGUIMessage
msg(GUI_MSG_LABEL_RESET
, GetID(), m_pageControl
, m_itemsPerPage
, GetNumItems());
238 SendWindowMessage(msg
);