VTB: release CVBuffer after it actually has been rendered
[xbmc.git] / xbmc / input / MouseStat.cpp
blob846e0429eeea7e22f1097e691c32378d4063fd00
1 /*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
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.
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 "MouseStat.h"
22 #include "input/Key.h"
23 #include "utils/TimeUtils.h"
24 #include "windowing/WindowingFactory.h"
26 CMouseStat::CMouseStat()
28 m_pointerState = MOUSE_STATE_NORMAL;
29 SetEnabled();
30 m_speedX = m_speedY = 0;
31 m_maxX = m_maxY = 0;
32 memset(&m_mouseState, 0, sizeof(m_mouseState));
33 m_Key = KEY_MOUSE_NOOP;
36 CMouseStat::~CMouseStat()
40 void CMouseStat::Initialize()
42 // Set the default resolution (PAL)
43 SetResolution(720, 576, 1, 1);
46 void CMouseStat::HandleEvent(XBMC_Event& newEvent)
48 // Save the mouse position and the size of the last move
49 int dx, dy;
50 if (newEvent.type == XBMC_MOUSEMOTION)
52 dx = newEvent.motion.x - m_mouseState.x;
53 dy = newEvent.motion.y - m_mouseState.y;
55 else if (newEvent.type == XBMC_MOUSEBUTTONDOWN || newEvent.type == XBMC_MOUSEBUTTONUP)
57 dx = newEvent.button.x - m_mouseState.x;
58 dy = newEvent.button.y - m_mouseState.y;
60 else
62 return;
64 m_mouseState.dx = dx;
65 m_mouseState.dy = dy;
66 m_mouseState.x = std::max(0, std::min(m_maxX, m_mouseState.x + dx));
67 m_mouseState.y = std::max(0, std::min(m_maxY, m_mouseState.y + dy));
69 // Fill in the public members
70 if (newEvent.button.type == XBMC_MOUSEBUTTONDOWN)
72 if (newEvent.button.button == XBMC_BUTTON_LEFT) m_mouseState.button[MOUSE_LEFT_BUTTON] = true;
73 if (newEvent.button.button == XBMC_BUTTON_RIGHT) m_mouseState.button[MOUSE_RIGHT_BUTTON] = true;
74 if (newEvent.button.button == XBMC_BUTTON_MIDDLE) m_mouseState.button[MOUSE_MIDDLE_BUTTON] = true;
75 if (newEvent.button.button == XBMC_BUTTON_X1) m_mouseState.button[MOUSE_EXTRA_BUTTON1] = true;
76 if (newEvent.button.button == XBMC_BUTTON_X2) m_mouseState.button[MOUSE_EXTRA_BUTTON2] = true;
77 if (newEvent.button.button == XBMC_BUTTON_X3) m_mouseState.button[MOUSE_EXTRA_BUTTON3] = true;
78 if (newEvent.button.button == XBMC_BUTTON_X4) m_mouseState.button[MOUSE_EXTRA_BUTTON4] = true;
79 if (newEvent.button.button == XBMC_BUTTON_WHEELUP) m_mouseState.dz = 1;
80 if (newEvent.button.button == XBMC_BUTTON_WHEELDOWN) m_mouseState.dz = -1;
82 else if (newEvent.button.type == XBMC_MOUSEBUTTONUP)
84 if (newEvent.button.button == XBMC_BUTTON_LEFT) m_mouseState.button[MOUSE_LEFT_BUTTON] = false;
85 if (newEvent.button.button == XBMC_BUTTON_RIGHT) m_mouseState.button[MOUSE_RIGHT_BUTTON] = false;
86 if (newEvent.button.button == XBMC_BUTTON_MIDDLE) m_mouseState.button[MOUSE_MIDDLE_BUTTON] = false;
87 if (newEvent.button.button == XBMC_BUTTON_X1) m_mouseState.button[MOUSE_EXTRA_BUTTON1] = false;
88 if (newEvent.button.button == XBMC_BUTTON_X2) m_mouseState.button[MOUSE_EXTRA_BUTTON2] = false;
89 if (newEvent.button.button == XBMC_BUTTON_X3) m_mouseState.button[MOUSE_EXTRA_BUTTON3] = false;
90 if (newEvent.button.button == XBMC_BUTTON_X4) m_mouseState.button[MOUSE_EXTRA_BUTTON4] = false;
91 if (newEvent.button.button == XBMC_BUTTON_WHEELUP) m_mouseState.dz = 0;
92 if (newEvent.button.button == XBMC_BUTTON_WHEELDOWN) m_mouseState.dz = 0;
95 // Now check the current message and the previous state to find out if
96 // this is a click, doubleclick, drag etc
97 uint32_t now = CTimeUtils::GetFrameTime();
98 bool bNothingDown = true;
100 for (int i = 0; i < MOUSE_MAX_BUTTON; i++)
102 bClick[i] = false;
103 bLongClick[i] = false;
104 bDoubleClick[i] = false;
105 bHold[i] = 0;
107 // CButtonState::Update does the hard work of checking the button state
108 // and spotting drags, doubleclicks etc
109 CButtonState::BUTTON_ACTION action = m_buttonState[i].Update(now, m_mouseState.x, m_mouseState.y, m_mouseState.button[i]);
110 switch (action)
112 case CButtonState::MB_SHORT_CLICK:
113 bClick[i] = true;
114 bNothingDown = false;
115 break;
116 case CButtonState::MB_LONG_CLICK:
117 bLongClick[i] = true;
118 bNothingDown = false;
119 break;
120 case CButtonState::MB_DOUBLE_CLICK:
121 bDoubleClick[i] = true;
122 bNothingDown = false;
123 break;
124 case CButtonState::MB_DRAG_START:
125 bHold[i] = CButtonState::MB_DRAG_START;
126 bNothingDown = false;
127 break;
128 case CButtonState::MB_DRAG:
129 bHold[i] = CButtonState::MB_DRAG;
130 bNothingDown = false;
131 break;
132 case CButtonState::MB_DRAG_END:
133 bHold[i] = CButtonState::MB_DRAG_END;
134 bNothingDown = false;
135 break;
136 default:
137 break;
141 // Now work out what action ID to send to XBMC.
143 // ignore any mouse messages by default
144 m_Key = KEY_MOUSE_NOOP;
146 for (int button=0; button<MOUSE_MAX_BUTTON; ++button)
148 // The bClick array is set true if CButtonState::Update spots a click
149 // i.e. a button down followed by a button up.
150 if (bClick[button])
151 m_Key = KEY_MOUSE_CLICK + button;
152 // The bDoubleClick array is set true if CButtonState::Update spots a
153 // button down within double_click_time (500ms) of the last click
154 else if (bDoubleClick[button])
155 m_Key = KEY_MOUSE_DOUBLE_CLICK + button;
156 else if (bLongClick[button])
157 m_Key = KEY_MOUSE_LONG_CLICK + button;
159 if (m_Key != KEY_MOUSE_NOOP)
160 break;
163 if (m_Key == KEY_MOUSE_NOOP)
165 // The bHold array is set to the drag action
166 if (bHold[MOUSE_LEFT_BUTTON] != 0)
168 switch (bHold[MOUSE_LEFT_BUTTON])
170 case CButtonState::MB_DRAG:
171 m_Key = KEY_MOUSE_DRAG;
172 break;
173 case CButtonState::MB_DRAG_START:
174 m_Key = KEY_MOUSE_DRAG_START;
175 break;
176 case CButtonState::MB_DRAG_END:
177 m_Key = KEY_MOUSE_DRAG_END;
178 break;
181 else if (bHold[MOUSE_RIGHT_BUTTON] != 0)
183 switch (bHold[MOUSE_RIGHT_BUTTON])
185 case CButtonState::MB_DRAG:
186 m_Key = KEY_MOUSE_RDRAG;
187 break;
188 case CButtonState::MB_DRAG_START:
189 m_Key = KEY_MOUSE_RDRAG_START;
190 break;
191 case CButtonState::MB_DRAG_END:
192 m_Key = KEY_MOUSE_RDRAG_END;
193 break;
197 // dz is +1 on wheel up and -1 on wheel down
198 else if (m_mouseState.dz > 0)
199 m_Key = KEY_MOUSE_WHEEL_UP;
200 else if (m_mouseState.dz < 0)
201 m_Key = KEY_MOUSE_WHEEL_DOWN;
203 // Check for a mouse move that isn't a drag, ignoring messages with no movement at all
204 else if (newEvent.type == XBMC_MOUSEMOTION && (m_mouseState.dx || m_mouseState.dy))
205 m_Key = KEY_MOUSE_MOVE;
208 // activate the mouse pointer if we have an action or the mouse has moved far enough
209 if ((MovedPastThreshold() && m_Key == KEY_MOUSE_MOVE) ||
210 (m_Key != KEY_MOUSE_NOOP && m_Key != KEY_MOUSE_MOVE))
211 SetActive();
213 // reset the mouse state if nothing is held down
214 if (bNothingDown)
215 SetState(MOUSE_STATE_NORMAL);
218 void CMouseStat::SetResolution(int maxX, int maxY, float speedX, float speedY)
220 m_maxX = maxX;
221 m_maxY = maxY;
223 // speed is currently unused
224 m_speedX = speedX;
225 m_speedY = speedY;
228 void CMouseStat::SetActive(bool active /*=true*/)
230 m_lastActiveTime = CTimeUtils::GetFrameTime();
231 m_mouseState.active = active;
232 // we show the OS mouse if:
233 // 1. The mouse is active (it has been moved) AND
234 // 2. The XBMC mouse is disabled in settings AND
235 // 3. XBMC is not in fullscreen.
236 g_Windowing.ShowOSMouse(m_mouseState.active && !IsEnabled() && !g_Windowing.IsFullScreen());
239 // IsActive - returns true if we have been active in the last MOUSE_ACTIVE_LENGTH period
240 bool CMouseStat::IsActive()
242 if (m_mouseState.active && (CTimeUtils::GetFrameTime() - m_lastActiveTime > MOUSE_ACTIVE_LENGTH))
243 SetActive(false);
244 return (m_mouseState.active && IsEnabled());
247 void CMouseStat::SetEnabled(bool enabled)
249 m_mouseEnabled = enabled;
250 SetActive(enabled);
253 // IsEnabled - returns true if mouse is enabled
254 bool CMouseStat::IsEnabled() const
256 return m_mouseEnabled;
259 bool CMouseStat::MovedPastThreshold() const
261 return (m_mouseState.dx * m_mouseState.dx + m_mouseState.dy * m_mouseState.dy >= MOUSE_MINIMUM_MOVEMENT * MOUSE_MINIMUM_MOVEMENT);
264 uint32_t CMouseStat::GetKey() const
266 return m_Key;
269 int CMouseStat::GetHold(int ButtonID) const
271 switch (ButtonID)
272 { case MOUSE_LEFT_BUTTON:
273 return bHold[MOUSE_LEFT_BUTTON];
275 return false;
278 CMouseStat::CButtonState::CButtonState()
280 m_state = STATE_RELEASED;
281 m_time = 0;
282 m_x = 0;
283 m_y = 0;
286 bool CMouseStat::CButtonState::InClickRange(int x, int y) const
288 int dx = x - m_x;
289 int dy = y - m_y;
290 return (unsigned int)(dx*dx + dy*dy) <= click_confines*click_confines;
293 CMouseStat::CButtonState::BUTTON_ACTION CMouseStat::CButtonState::Update(unsigned int time, int x, int y, bool down)
295 if (m_state == STATE_IN_DRAG)
297 if (down)
298 return MB_DRAG;
299 m_state = STATE_RELEASED;
300 return MB_DRAG_END;
302 else if (m_state == STATE_RELEASED)
304 if (down)
306 m_state = STATE_IN_CLICK;
307 m_time = time;
308 m_x = x;
309 m_y = y;
312 else if (m_state == STATE_IN_CLICK)
314 if (down)
316 if (!InClickRange(x,y))
317 { // beginning a drag
318 m_state = STATE_IN_DRAG;
319 return MB_DRAG_START;
322 else
323 { // button up
324 if (time - m_time < short_click_time)
325 { // single click
326 m_state = STATE_IN_DOUBLE_CLICK;
327 m_time = time; // double click time and positioning is measured from the
328 m_x = x; // end of a single click
329 m_y = y;
330 return MB_SHORT_CLICK;
332 else
333 { // long click
334 m_state = STATE_RELEASED;
335 return MB_LONG_CLICK;
339 else if (m_state == STATE_IN_DOUBLE_CLICK)
341 if (time - m_time > double_click_time || !InClickRange(x,y))
342 { // too long, or moved to much - reset to released state and re-update, as we may be starting a new click
343 m_state = STATE_RELEASED;
344 return Update(time, x, y, down);
346 if (down)
348 m_state = STATE_IN_DOUBLE_IGNORE;
349 return MB_DOUBLE_CLICK;
352 else if (m_state == STATE_IN_DOUBLE_IGNORE)
354 if (!down)
355 m_state = STATE_RELEASED;
358 return MB_NONE;