[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / guilib / GUIWrappingListContainer.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "GUIWrappingListContainer.h"
22 #include "FileItem.h"
23 #include "Key.h"
24 #include "utils/log.h"
25
26 CGUIWrappingListContainer::CGUIWrappingListContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, const CScroller& scroller, int preloadItems, int fixedPosition)
27     : CGUIBaseContainer(parentID, controlID, posX, posY, width, height, orientation, scroller, preloadItems)
28 {
29   SetCursor(fixedPosition);
30   ControlType = GUICONTAINER_WRAPLIST;
31   m_type = VIEW_TYPE_LIST;
32   m_extraItems = 0;
33 }
34
35 CGUIWrappingListContainer::~CGUIWrappingListContainer(void)
36 {
37 }
38
39 void CGUIWrappingListContainer::UpdatePageControl(int offset)
40 {
41   if (m_pageControl)
42   { // tell our pagecontrol (scrollbar or whatever) to update (offset it by our cursor position)
43     CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), m_pageControl, GetNumItems() ? CorrectOffset(offset, GetCursor()) % GetNumItems() : 0);
44     SendWindowMessage(msg);
45   }
46 }
47
48 bool CGUIWrappingListContainer::OnAction(const CAction &action)
49 {
50   switch (action.GetID())
51   {
52   case ACTION_PAGE_UP:
53     Scroll(-m_itemsPerPage);
54     return true;
55   case ACTION_PAGE_DOWN:
56     Scroll(m_itemsPerPage);
57     return true;
58     // smooth scrolling (for analog controls)
59   case ACTION_SCROLL_UP:
60     {
61       m_analogScrollCount += action.GetAmount() * action.GetAmount();
62       bool handled = false;
63       while (m_analogScrollCount > 0.4)
64       {
65         handled = true;
66         m_analogScrollCount -= 0.4f;
67         Scroll(-1);
68       }
69       return handled;
70     }
71     break;
72   case ACTION_SCROLL_DOWN:
73     {
74       m_analogScrollCount += action.GetAmount() * action.GetAmount();
75       bool handled = false;
76       while (m_analogScrollCount > 0.4)
77       {
78         handled = true;
79         m_analogScrollCount -= 0.4f;
80         Scroll(1);
81       }
82       return handled;
83     }
84     break;
85   }
86   return CGUIBaseContainer::OnAction(action);
87 }
88
89 bool CGUIWrappingListContainer::OnMessage(CGUIMessage& message)
90 {
91   if (message.GetControlId() == GetID() )
92   {
93     if (message.GetMessage() == GUI_MSG_PAGE_CHANGE)
94     {
95       if (message.GetSenderId() == m_pageControl && IsVisible())
96       { // offset by our cursor position
97         message.SetParam1(message.GetParam1() - GetCursor());
98       }
99     }
100   }
101   return CGUIBaseContainer::OnMessage(message);
102 }
103
104 bool CGUIWrappingListContainer::MoveUp(bool wrapAround)
105 {
106   Scroll(-1);
107   return true;
108 }
109
110 bool CGUIWrappingListContainer::MoveDown(bool wrapAround)
111 {
112   Scroll(+1);
113   return true;
114 }
115
116 // scrolls the said amount
117 void CGUIWrappingListContainer::Scroll(int amount)
118 {
119   ScrollToOffset(GetOffset() + amount);
120 }
121
122 bool CGUIWrappingListContainer::GetOffsetRange(int &minOffset, int &maxOffset) const
123 {
124   return false;
125 }
126
127 void CGUIWrappingListContainer::ValidateOffset()
128 {
129   // our minimal amount of items - we need to take into acount extra items to display wrapped items when scrolling
130   unsigned int minItems = (unsigned int)m_itemsPerPage + ScrollCorrectionRange() + GetCacheCount() / 2;
131   if (minItems <= m_items.size())
132     return;
133
134   // no need to check the range here, but we need to check we have
135   // more items than slots.
136   ResetExtraItems();
137   if (m_items.size())
138   {
139     unsigned int numItems = m_items.size();
140     while (m_items.size() < minItems)
141     {
142       // add additional copies of items, as we require extras at render time
143       for (unsigned int i = 0; i < numItems; i++)
144       {
145         m_items.push_back(CGUIListItemPtr(m_items[i]->Clone()));
146         m_extraItems++;
147       }
148     }
149   }
150 }
151
152 int CGUIWrappingListContainer::CorrectOffset(int offset, int cursor) const
153 {
154   if (m_items.size())
155   {
156     int correctOffset = (offset + cursor) % (int)m_items.size();
157     if (correctOffset < 0) correctOffset += m_items.size();
158     return correctOffset;
159   }
160   return 0;
161 }
162
163 int CGUIWrappingListContainer::GetSelectedItem() const
164 {
165   if (m_items.size() > m_extraItems)
166   {
167     int numItems = (int)(m_items.size() - m_extraItems);
168     int correctOffset = (GetOffset() + GetCursor()) % numItems;
169     if (correctOffset < 0) correctOffset += numItems;
170     return correctOffset;
171   }
172   return 0;
173 }
174
175 bool CGUIWrappingListContainer::SelectItemFromPoint(const CPoint &point)
176 {
177   if (!m_focusedLayout || !m_layout)
178     return false;
179
180   const float mouse_scroll_speed = 0.05f;
181   const float mouse_max_amount = 1.0f;   // max speed: 1 item per frame
182   float sizeOfItem = m_layout->Size(m_orientation);
183   // see if the point is either side of our focused item
184   float start = GetCursor() * sizeOfItem;
185   float end = start + m_focusedLayout->Size(m_orientation);
186   float pos = (m_orientation == VERTICAL) ? point.y : point.x;
187   if (pos < start - 0.5f * sizeOfItem)
188   { // scroll backward
189     if (!InsideLayout(m_layout, point))
190       return false;
191     float amount = std::min((start - pos) / sizeOfItem, mouse_max_amount);
192     m_analogScrollCount += amount * amount * mouse_scroll_speed;
193     if (m_analogScrollCount > 1)
194     {
195       Scroll(-1);
196       m_analogScrollCount-=1.0f;
197     }
198     return true;
199   }
200   else if (pos > end + 0.5f * sizeOfItem)
201   { // scroll forward
202     if (!InsideLayout(m_layout, point))
203       return false;
204
205     float amount = std::min((pos - end) / sizeOfItem, mouse_max_amount);
206     m_analogScrollCount += amount * amount * mouse_scroll_speed;
207     if (m_analogScrollCount > 1)
208     {
209       Scroll(1);
210       m_analogScrollCount-=1.0f;
211     }
212     return true;
213   }
214   return InsideLayout(m_focusedLayout, point);
215 }
216
217 void CGUIWrappingListContainer::SelectItem(int item)
218 {
219   if (item >= 0 && item < (int)m_items.size())
220     ScrollToOffset(item - GetCursor());
221 }
222
223 void CGUIWrappingListContainer::ResetExtraItems()
224 {
225   // delete any extra items
226   if (m_extraItems)
227     m_items.erase(m_items.begin() + m_items.size() - m_extraItems, m_items.end());
228   m_extraItems = 0;
229 }
230
231 void CGUIWrappingListContainer::Reset()
232 {
233   ResetExtraItems();
234   CGUIBaseContainer::Reset();
235 }
236
237 int CGUIWrappingListContainer::GetCurrentPage() const
238 {
239   int offset = CorrectOffset(GetOffset(), GetCursor());
240   if (offset + m_itemsPerPage - GetCursor() >= (int)GetRows())  // last page
241     return (GetRows() + m_itemsPerPage - 1) / m_itemsPerPage;
242   return offset / m_itemsPerPage + 1;
243 }
244
245 void CGUIWrappingListContainer::SetPageControlRange()
246 {
247   if (m_pageControl)
248   {
249     CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), m_pageControl, m_itemsPerPage, GetNumItems());
250     SendWindowMessage(msg);
251   }
252 }