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/>.
21 #include "GUIScrollBarControl.h"
23 #include "utils/StringUtils.h"
25 #define MIN_NIB_SIZE 4.0f
27 CGUIScrollBar::CGUIScrollBar(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& backGroundTexture, const CTextureInfo& barTexture, const CTextureInfo& barTextureFocus, const CTextureInfo& nibTexture, const CTextureInfo& nibTextureFocus, ORIENTATION orientation, bool showOnePage)
28 : CGUIControl(parentID, controlID, posX, posY, width, height)
29 , m_guiBackground(posX, posY, width, height, backGroundTexture)
30 , m_guiBarNoFocus(posX, posY, width, height, barTexture)
31 , m_guiBarFocus(posX, posY, width, height, barTextureFocus)
32 , m_guiNibNoFocus(posX, posY, width, height, nibTexture)
33 , m_guiNibFocus(posX, posY, width, height, nibTextureFocus)
35 m_guiNibNoFocus.SetAspectRatio(CAspectRatio::AR_CENTER);
36 m_guiNibFocus.SetAspectRatio(CAspectRatio::AR_CENTER);
40 ControlType = GUICONTROL_SCROLLBAR;
41 m_orientation = orientation;
42 m_showOnePage = showOnePage;
45 CGUIScrollBar::~CGUIScrollBar(void)
49 void CGUIScrollBar::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
54 changed |= UpdateBarSize();
56 changed |= m_guiBackground.Process(currentTime);
57 changed |= m_guiBarNoFocus.Process(currentTime);
58 changed |= m_guiBarFocus.Process(currentTime);
59 changed |= m_guiNibNoFocus.Process(currentTime);
60 changed |= m_guiNibFocus.Process(currentTime);
65 CGUIControl::Process(currentTime, dirtyregions);
68 void CGUIScrollBar::Render()
70 m_guiBackground.Render();
73 m_guiBarFocus.Render();
74 m_guiNibFocus.Render();
78 m_guiBarNoFocus.Render();
79 m_guiNibNoFocus.Render();
82 CGUIControl::Render();
85 bool CGUIScrollBar::OnMessage(CGUIMessage& message)
87 switch (message.GetMessage())
89 case GUI_MSG_ITEM_SELECT:
90 SetValue(message.GetParam1());
92 case GUI_MSG_LABEL_RESET:
93 SetRange(message.GetParam1(), message.GetParam2());
98 case GUI_MSG_PAGE_DOWN:
102 return CGUIControl::OnMessage(message);
105 bool CGUIScrollBar::OnAction(const CAction &action)
107 switch ( action.GetID() )
109 case ACTION_MOVE_LEFT:
110 if (m_orientation == HORIZONTAL)
117 case ACTION_MOVE_RIGHT:
118 if (m_orientation == HORIZONTAL)
125 if (m_orientation == VERTICAL)
132 case ACTION_MOVE_DOWN:
133 if (m_orientation == VERTICAL)
140 return CGUIControl::OnAction(action);
143 bool CGUIScrollBar::Move(int numSteps)
145 if (numSteps < 0 && m_offset == 0) // we are at the beginning - can't scroll up/left anymore
147 if (numSteps > 0 && m_offset == std::max(m_numItems - m_pageSize, 0)) // we are at the end - we can't scroll down/right anymore
150 m_offset += numSteps * m_pageSize;
151 if (m_offset > m_numItems - m_pageSize) m_offset = m_numItems - m_pageSize;
152 if (m_offset < 0) m_offset = 0;
153 CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_offset);
154 SendWindowMessage(message);
159 void CGUIScrollBar::SetRange(int pageSize, int numItems)
161 if (m_pageSize != pageSize || m_numItems != numItems)
163 m_pageSize = pageSize;
164 m_numItems = numItems;
170 void CGUIScrollBar::SetValue(int value)
172 if (m_offset != value)
179 void CGUIScrollBar::FreeResources(bool immediately)
181 CGUIControl::FreeResources(immediately);
182 m_guiBackground.FreeResources(immediately);
183 m_guiBarNoFocus.FreeResources(immediately);
184 m_guiBarFocus.FreeResources(immediately);
185 m_guiNibNoFocus.FreeResources(immediately);
186 m_guiNibFocus.FreeResources(immediately);
189 void CGUIScrollBar::DynamicResourceAlloc(bool bOnOff)
191 CGUIControl::DynamicResourceAlloc(bOnOff);
192 m_guiBackground.DynamicResourceAlloc(bOnOff);
193 m_guiBarNoFocus.DynamicResourceAlloc(bOnOff);
194 m_guiBarFocus.DynamicResourceAlloc(bOnOff);
195 m_guiNibNoFocus.DynamicResourceAlloc(bOnOff);
196 m_guiNibFocus.DynamicResourceAlloc(bOnOff);
199 void CGUIScrollBar::AllocResources()
201 CGUIControl::AllocResources();
202 m_guiBackground.AllocResources();
203 m_guiBarNoFocus.AllocResources();
204 m_guiBarFocus.AllocResources();
205 m_guiNibNoFocus.AllocResources();
206 m_guiNibFocus.AllocResources();
209 void CGUIScrollBar::SetInvalid()
211 CGUIControl::SetInvalid();
212 m_guiBackground.SetInvalid();
213 m_guiBarFocus.SetInvalid();
214 m_guiBarFocus.SetInvalid();
215 m_guiNibNoFocus.SetInvalid();
216 m_guiNibFocus.SetInvalid();
219 bool CGUIScrollBar::UpdateBarSize()
221 bool changed = false;
223 // scale our textures to suit
224 if (m_orientation == VERTICAL)
226 // calculate the height to display the nib at
227 float percent = (m_numItems == 0) ? 0 : (float)m_pageSize / m_numItems;
228 float nibSize = GetHeight() * percent;
229 if (nibSize < m_guiNibFocus.GetTextureHeight() + 2 * MIN_NIB_SIZE) nibSize = m_guiNibFocus.GetTextureHeight() + 2 * MIN_NIB_SIZE;
230 if (nibSize > GetHeight()) nibSize = GetHeight();
232 changed |= m_guiBarNoFocus.SetHeight(nibSize);
233 changed |= m_guiBarFocus.SetHeight(nibSize);
234 changed |= m_guiNibNoFocus.SetHeight(nibSize);
235 changed |= m_guiNibFocus.SetHeight(nibSize);
236 // nibSize may be altered by the border size of the nib (and bar).
237 nibSize = std::max(m_guiBarFocus.GetHeight(), m_guiNibFocus.GetHeight());
240 percent = (m_numItems == m_pageSize) ? 0 : (float)m_offset / (m_numItems - m_pageSize);
241 float nibPos = (GetHeight() - nibSize) * percent;
242 if (nibPos < 0) nibPos = 0;
243 if (nibPos > GetHeight() - nibSize) nibPos = GetHeight() - nibSize;
245 changed |= m_guiBarNoFocus.SetPosition(GetXPosition(), GetYPosition() + nibPos);
246 changed |= m_guiBarFocus.SetPosition(GetXPosition(), GetYPosition() + nibPos);
247 changed |= m_guiNibNoFocus.SetPosition(GetXPosition(), GetYPosition() + nibPos);
248 changed |= m_guiNibFocus.SetPosition(GetXPosition(), GetYPosition() + nibPos);
252 // calculate the height to display the nib at
253 float percent = (m_numItems == 0) ? 0 : (float)m_pageSize / m_numItems;
254 float nibSize = GetWidth() * percent + 0.5f;
255 if (nibSize < m_guiNibFocus.GetTextureWidth() + 2 * MIN_NIB_SIZE) nibSize = m_guiNibFocus.GetTextureWidth() + 2 * MIN_NIB_SIZE;
256 if (nibSize > GetWidth()) nibSize = GetWidth();
258 changed |= m_guiBarNoFocus.SetWidth(nibSize);
259 changed |= m_guiBarFocus.SetWidth(nibSize);
260 changed |= m_guiNibNoFocus.SetWidth(nibSize);
261 changed |= m_guiNibFocus.SetWidth(nibSize);
264 percent = (m_numItems == m_pageSize) ? 0 : (float)m_offset / (m_numItems - m_pageSize);
265 float nibPos = (GetWidth() - nibSize) * percent;
266 if (nibPos < 0) nibPos = 0;
267 if (nibPos > GetWidth() - nibSize) nibPos = GetWidth() - nibSize;
269 changed |= m_guiBarNoFocus.SetPosition(GetXPosition() + nibPos, GetYPosition());
270 changed |= m_guiBarFocus.SetPosition(GetXPosition() + nibPos, GetYPosition());
271 changed |= m_guiNibNoFocus.SetPosition(GetXPosition() + nibPos, GetYPosition());
272 changed |= m_guiNibFocus.SetPosition(GetXPosition() + nibPos, GetYPosition());
278 bool CGUIScrollBar::HitTest(const CPoint &point) const
280 if (m_guiBackground.HitTest(point)) return true;
281 if (m_guiBarNoFocus.HitTest(point)) return true;
285 void CGUIScrollBar::SetFromPosition(const CPoint &point)
288 if (m_orientation == VERTICAL)
289 fPercent = (point.y - m_guiBackground.GetYPosition() - 0.5f*m_guiBarFocus.GetHeight()) / m_guiBackground.GetHeight();
291 fPercent = (point.x - m_guiBackground.GetXPosition() - 0.5f*m_guiBarFocus.GetWidth()) / m_guiBackground.GetWidth();
292 if (fPercent < 0) fPercent = 0;
293 if (fPercent > 1) fPercent = 1;
295 int offset = (int)(floor(fPercent * m_numItems + 0.5f));
297 if (m_offset != offset)
300 CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_offset);
301 SendWindowMessage(message);
306 EVENT_RESULT CGUIScrollBar::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
308 if (event.m_id == ACTION_MOUSE_DRAG)
310 if (event.m_state == 1)
311 { // we want exclusive access
312 CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
313 SendWindowMessage(msg);
315 else if (event.m_state == 3)
316 { // we're done with exclusive access
317 CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
318 SendWindowMessage(msg);
320 SetFromPosition(point);
321 return EVENT_RESULT_HANDLED;
323 else if (event.m_id == ACTION_MOUSE_LEFT_CLICK && m_guiBackground.HitTest(point))
325 SetFromPosition(point);
326 return EVENT_RESULT_HANDLED;
328 else if (event.m_id == ACTION_MOUSE_WHEEL_UP)
331 return EVENT_RESULT_HANDLED;
333 else if (event.m_id == ACTION_MOUSE_WHEEL_DOWN)
336 return EVENT_RESULT_HANDLED;
338 else if (event.m_id == ACTION_GESTURE_NOTIFY)
340 return (m_orientation == HORIZONTAL) ? EVENT_RESULT_PAN_HORIZONTAL_WITHOUT_INERTIA : EVENT_RESULT_PAN_VERTICAL_WITHOUT_INERTIA;
342 else if (event.m_id == ACTION_GESTURE_BEGIN)
343 { // grab exclusive access
344 CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
345 SendWindowMessage(msg);
346 return EVENT_RESULT_HANDLED;
348 else if (event.m_id == ACTION_GESTURE_PAN)
350 SetFromPosition(point);
351 return EVENT_RESULT_HANDLED;
353 else if (event.m_id == ACTION_GESTURE_END)
354 { // release exclusive access
355 CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
356 SendWindowMessage(msg);
357 return EVENT_RESULT_HANDLED;
360 return EVENT_RESULT_UNHANDLED;
363 CStdString CGUIScrollBar::GetDescription() const
365 return StringUtils::Format("%i/%i", m_offset, m_numItems);
368 bool CGUIScrollBar::UpdateColors()
370 bool changed = CGUIControl::UpdateColors();
371 changed |= m_guiBackground.SetDiffuseColor(m_diffuseColor);
372 changed |= m_guiBarNoFocus.SetDiffuseColor(m_diffuseColor);
373 changed |= m_guiBarFocus.SetDiffuseColor(m_diffuseColor);
374 changed |= m_guiNibNoFocus.SetDiffuseColor(m_diffuseColor);
375 changed |= m_guiNibFocus.SetDiffuseColor(m_diffuseColor);
380 bool CGUIScrollBar::IsVisible() const
382 // page controls can be optionally disabled if the number of pages is 1
383 if (m_numItems <= m_pageSize && !m_showOnePage)
385 return CGUIControl::IsVisible();