2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 #include "GUIListContainer.h"
23 #include "GUIListItem.h"
25 #include "utils/StringUtils.h"
27 CGUIListContainer::CGUIListContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, const CScroller& scroller, int preloadItems)
28 : CGUIBaseContainer(parentID, controlID, posX, posY, width, height, orientation, scroller, preloadItems)
30 ControlType = GUICONTAINER_LIST;
31 m_type = VIEW_TYPE_LIST;
34 CGUIListContainer::~CGUIListContainer(void)
38 bool CGUIListContainer::OnAction(const CAction &action)
40 switch (action.GetID())
45 { // already on the first page, so move to the first item
49 { // scroll up to the previous page
50 Scroll( -m_itemsPerPage);
55 case ACTION_PAGE_DOWN:
57 if (GetOffset() == (int)m_items.size() - m_itemsPerPage || (int)m_items.size() < m_itemsPerPage)
58 { // already at the last page, so move to the last item.
59 SetCursor(m_items.size() - GetOffset() - 1);
62 { // scroll down to the next page
63 Scroll(m_itemsPerPage);
68 // smooth scrolling (for analog controls)
69 case ACTION_SCROLL_UP:
71 m_analogScrollCount += action.GetAmount() * action.GetAmount();
73 while (m_analogScrollCount > 0.4)
76 m_analogScrollCount -= 0.4f;
77 if (GetOffset() > 0 && GetCursor() <= m_itemsPerPage / 2)
81 else if (GetCursor() > 0)
83 SetCursor(GetCursor() - 1);
89 case ACTION_SCROLL_DOWN:
91 m_analogScrollCount += action.GetAmount() * action.GetAmount();
93 while (m_analogScrollCount > 0.4)
96 m_analogScrollCount -= 0.4f;
97 if (GetOffset() + m_itemsPerPage < (int)m_items.size() && GetCursor() >= m_itemsPerPage / 2)
101 else if (GetCursor() < m_itemsPerPage - 1 && GetOffset() + GetCursor() < (int)m_items.size() - 1)
103 SetCursor(GetCursor() + 1);
110 return CGUIBaseContainer::OnAction(action);
113 bool CGUIListContainer::OnMessage(CGUIMessage& message)
115 if (message.GetControlId() == GetID() )
117 if (message.GetMessage() == GUI_MSG_LABEL_RESET)
121 else if (message.GetMessage() == GUI_MSG_SETFOCUS)
123 if (message.GetParam1()) // subfocus item is specified, so set the offset appropriately
125 int item = std::min(GetOffset() + (int)message.GetParam1() - 1, (int)m_items.size() - 1);
130 return CGUIBaseContainer::OnMessage(message);
133 bool CGUIListContainer::MoveUp(bool wrapAround)
137 SetCursor(GetCursor() - 1);
139 else if (GetCursor() == 0 && GetOffset())
141 ScrollToOffset(GetOffset() - 1);
145 if (m_items.size() > 0)
146 { // move 2 last item in list, and set our container moving up
147 int offset = m_items.size() - m_itemsPerPage;
148 if (offset < 0) offset = 0;
149 SetCursor(m_items.size() - offset - 1);
150 ScrollToOffset(offset);
151 SetContainerMoving(-1);
159 bool CGUIListContainer::MoveDown(bool wrapAround)
161 if (GetOffset() + GetCursor() + 1 < (int)m_items.size())
163 if (GetCursor() + 1 < m_itemsPerPage)
165 SetCursor(GetCursor() + 1);
169 ScrollToOffset(GetOffset() + 1);
173 { // move first item in list, and set our container moving in the "down" direction
176 SetContainerMoving(1);
183 // scrolls the said amount
184 void CGUIListContainer::Scroll(int amount)
186 // increase or decrease the offset
187 int offset = GetOffset() + amount;
188 if (offset > (int)m_items.size() - m_itemsPerPage)
190 offset = m_items.size() - m_itemsPerPage;
192 if (offset < 0) offset = 0;
193 ScrollToOffset(offset);
196 void CGUIListContainer::ValidateOffset()
198 if (!m_layout) return;
199 // first thing is we check the range of our offset
200 // don't validate offset if we are scrolling in case the tween image exceed <0, 1> range
201 int minOffset, maxOffset;
202 GetOffsetRange(minOffset, maxOffset);
203 if (GetOffset() > maxOffset || (!m_scroller.IsScrolling() && m_scroller.GetValue() > maxOffset * m_layout->Size(m_orientation)))
205 SetOffset(std::max(0, maxOffset));
206 m_scroller.SetValue(GetOffset() * m_layout->Size(m_orientation));
208 if (GetOffset() < 0 || (!m_scroller.IsScrolling() && m_scroller.GetValue() < 0))
211 m_scroller.SetValue(0);
215 void CGUIListContainer::SetCursor(int cursor)
217 if (cursor > m_itemsPerPage - 1) cursor = m_itemsPerPage - 1;
218 if (cursor < 0) cursor = 0;
220 SetContainerMoving(cursor - GetCursor());
221 CGUIBaseContainer::SetCursor(cursor);
224 void CGUIListContainer::SelectItem(int item)
226 // Check that our offset is valid
228 // only select an item if it's in a valid range
229 if (item >= 0 && item < (int)m_items.size())
231 // Select the item requested
232 if (item >= GetOffset() && item < GetOffset() + m_itemsPerPage)
233 { // the item is on the current page, so don't change it.
234 SetCursor(item - GetOffset());
236 else if (item < GetOffset())
237 { // item is on a previous page - make it the first item on the page
239 ScrollToOffset(item);
241 else // (item >= GetOffset()+m_itemsPerPage)
242 { // item is on a later page - make it the last item on the page
243 SetCursor(m_itemsPerPage - 1);
244 ScrollToOffset(item - GetCursor());
249 int CGUIListContainer::GetCursorFromPoint(const CPoint &point, CPoint *itemPoint) const
251 if (!m_focusedLayout || !m_layout)
255 float pos = (m_orientation == VERTICAL) ? point.y : point.x;
256 while (row < m_itemsPerPage + 1) // 1 more to ensure we get the (possible) half item at the end.
258 const CGUIListItemLayout *layout = (row == GetCursor()) ? m_focusedLayout : m_layout;
259 if (pos < layout->Size(m_orientation) && row + GetOffset() < (int)m_items.size())
260 { // found correct "row" -> check horizontal
261 if (!InsideLayout(layout, point))
265 *itemPoint = m_orientation == VERTICAL ? CPoint(point.x, pos) : CPoint(pos, point.y);
269 pos -= layout->Size(m_orientation);
274 bool CGUIListContainer::SelectItemFromPoint(const CPoint &point)
277 int row = GetCursorFromPoint(point, &itemPoint);
282 CGUIListItemLayout *focusedLayout = GetFocusedLayout();
284 focusedLayout->SelectItemFromPoint(itemPoint);
288 //#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
289 CGUIListContainer::CGUIListContainer(int parentID, int controlID, float posX, float posY, float width, float height,
290 const CLabelInfo& labelInfo, const CLabelInfo& labelInfo2,
291 const CTextureInfo& textureButton, const CTextureInfo& textureButtonFocus,
292 float textureHeight, float itemWidth, float itemHeight, float spaceBetweenItems)
293 : CGUIBaseContainer(parentID, controlID, posX, posY, width, height, VERTICAL, 200, 0)
295 CGUIListItemLayout layout;
296 layout.CreateListControlLayouts(width, textureHeight + spaceBetweenItems, false, labelInfo, labelInfo2, textureButton, textureButtonFocus, textureHeight, itemWidth, itemHeight, "", "");
297 m_layouts.push_back(layout);
298 CStdString condition = StringUtils::Format("control.hasfocus(%i)", controlID);
299 CStdString condition2 = "!" + condition;
300 CGUIListItemLayout focusLayout;
301 focusLayout.CreateListControlLayouts(width, textureHeight + spaceBetweenItems, true, labelInfo, labelInfo2, textureButton, textureButtonFocus, textureHeight, itemWidth, itemHeight, condition2, condition);
302 m_focusedLayouts.push_back(focusLayout);
303 m_height = floor(m_height / (textureHeight + spaceBetweenItems)) * (textureHeight + spaceBetweenItems);
304 ControlType = GUICONTAINER_LIST;
308 bool CGUIListContainer::HasNextPage() const
310 return (GetOffset() != (int)m_items.size() - m_itemsPerPage && (int)m_items.size() >= m_itemsPerPage);
313 bool CGUIListContainer::HasPreviousPage() const
315 return (GetOffset() > 0);