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/actions/Action.h"
15 #include "input/actions/ActionIDs.h"
17 CGUIWrappingListContainer::CGUIWrappingListContainer(int parentID
, int controlID
, float posX
, float posY
, float width
, float height
, ORIENTATION orientation
, const CScroller
& scroller
, int preloadItems
, int fixedPosition
)
18 : CGUIBaseContainer(parentID
, controlID
, posX
, posY
, width
, height
, orientation
, scroller
, preloadItems
)
20 SetCursor(fixedPosition
);
21 ControlType
= GUICONTAINER_WRAPLIST
;
22 m_type
= VIEW_TYPE_LIST
;
26 CGUIWrappingListContainer::~CGUIWrappingListContainer(void) = default;
28 void CGUIWrappingListContainer::UpdatePageControl(int offset
)
31 { // tell our pagecontrol (scrollbar or whatever) to update (offset it by our cursor position)
32 CGUIMessage
msg(GUI_MSG_ITEM_SELECT
, GetID(), m_pageControl
, GetNumItems() ? CorrectOffset(offset
, GetCursor()) % GetNumItems() : 0);
33 SendWindowMessage(msg
);
37 bool CGUIWrappingListContainer::OnAction(const CAction
&action
)
39 switch (action
.GetID())
42 Scroll(-m_itemsPerPage
);
44 case ACTION_PAGE_DOWN
:
45 Scroll(m_itemsPerPage
);
47 // smooth scrolling (for analog controls)
48 case ACTION_SCROLL_UP
:
50 m_analogScrollCount
+= action
.GetAmount() * action
.GetAmount();
52 while (m_analogScrollCount
> 0.4f
)
55 m_analogScrollCount
-= 0.4f
;
61 case ACTION_SCROLL_DOWN
:
63 m_analogScrollCount
+= action
.GetAmount() * action
.GetAmount();
65 while (m_analogScrollCount
> 0.4f
)
68 m_analogScrollCount
-= 0.4f
;
75 return CGUIBaseContainer::OnAction(action
);
78 bool CGUIWrappingListContainer::OnMessage(CGUIMessage
& message
)
80 if (message
.GetControlId() == GetID() )
82 if (message
.GetMessage() == GUI_MSG_PAGE_CHANGE
)
84 if (message
.GetSenderId() == m_pageControl
&& IsVisible())
85 { // offset by our cursor position
86 message
.SetParam1(message
.GetParam1() - GetCursor());
90 return CGUIBaseContainer::OnMessage(message
);
93 bool CGUIWrappingListContainer::MoveUp(bool wrapAround
)
99 bool CGUIWrappingListContainer::MoveDown(bool wrapAround
)
105 // scrolls the said amount
106 void CGUIWrappingListContainer::Scroll(int amount
)
108 ScrollToOffset(GetOffset() + amount
);
111 bool CGUIWrappingListContainer::GetOffsetRange(int &minOffset
, int &maxOffset
) const
116 void CGUIWrappingListContainer::ValidateOffset()
118 // our minimal amount of items - we need to take into account extra items to display wrapped items when scrolling
119 unsigned int minItems
= (unsigned int)m_itemsPerPage
+ ScrollCorrectionRange() + GetCacheCount() / 2;
120 if (minItems
<= m_items
.size())
123 // no need to check the range here, but we need to check we have
124 // more items than slots.
128 size_t numItems
= m_items
.size();
129 while (m_items
.size() < minItems
)
131 // add additional copies of items, as we require extras at render time
132 for (unsigned int i
= 0; i
< numItems
; i
++)
134 m_items
.push_back(std::shared_ptr
<CGUIListItem
>(m_items
[i
]->Clone()));
141 int CGUIWrappingListContainer::CorrectOffset(int offset
, int cursor
) const
145 int correctOffset
= (offset
+ cursor
) % (int)m_items
.size();
146 if (correctOffset
< 0) correctOffset
+= m_items
.size();
147 return correctOffset
;
152 int CGUIWrappingListContainer::GetSelectedItem() const
154 if (m_items
.size() > m_extraItems
)
156 int numItems
= (int)(m_items
.size() - m_extraItems
);
157 int correctOffset
= (GetOffset() + GetCursor()) % numItems
;
158 if (correctOffset
< 0) correctOffset
+= numItems
;
159 return correctOffset
;
164 bool CGUIWrappingListContainer::SelectItemFromPoint(const CPoint
&point
)
166 if (!m_focusedLayout
|| !m_layout
)
169 const float mouse_scroll_speed
= 0.05f
;
170 const float mouse_max_amount
= 1.0f
; // max speed: 1 item per frame
171 float sizeOfItem
= m_layout
->Size(m_orientation
);
172 // see if the point is either side of our focused item
173 float start
= GetCursor() * sizeOfItem
;
174 float end
= start
+ m_focusedLayout
->Size(m_orientation
);
175 float pos
= (m_orientation
== VERTICAL
) ? point
.y
: point
.x
;
176 if (pos
< start
- 0.5f
* sizeOfItem
)
178 if (!InsideLayout(m_layout
, point
))
180 float amount
= std::min((start
- pos
) / sizeOfItem
, mouse_max_amount
);
181 m_analogScrollCount
+= amount
* amount
* mouse_scroll_speed
;
182 if (m_analogScrollCount
> 1)
185 m_analogScrollCount
-=1.0f
;
189 else if (pos
> end
+ 0.5f
* sizeOfItem
)
191 if (!InsideLayout(m_layout
, point
))
194 float amount
= std::min((pos
- end
) / sizeOfItem
, mouse_max_amount
);
195 m_analogScrollCount
+= amount
* amount
* mouse_scroll_speed
;
196 if (m_analogScrollCount
> 1)
199 m_analogScrollCount
-=1.0f
;
203 return InsideLayout(m_focusedLayout
, point
);
206 void CGUIWrappingListContainer::SelectItem(int item
)
208 if (item
>= 0 && item
< (int)m_items
.size())
209 ScrollToOffset(item
- GetCursor());
212 void CGUIWrappingListContainer::ResetExtraItems()
214 // delete any extra items
216 m_items
.erase(m_items
.begin() + m_items
.size() - m_extraItems
, m_items
.end());
220 void CGUIWrappingListContainer::Reset()
223 CGUIBaseContainer::Reset();
226 int CGUIWrappingListContainer::GetCurrentPage() const
228 int offset
= CorrectOffset(GetOffset(), GetCursor());
229 if (offset
+ m_itemsPerPage
- GetCursor() >= (int)GetRows()) // last page
230 return (GetRows() + m_itemsPerPage
- 1) / m_itemsPerPage
;
231 return offset
/ m_itemsPerPage
+ 1;
234 void CGUIWrappingListContainer::SetPageControlRange()
238 CGUIMessage
msg(GUI_MSG_LABEL_RESET
, GetID(), m_pageControl
, m_itemsPerPage
, GetNumItems());
239 SendWindowMessage(msg
);