FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
cursor.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2008 by the FIFE team *
3  * http://www.fifengine.de *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 #if defined( WIN32 )
24 #include <windows.h>
25 #include <sdl.h>
26 #endif
27 
28 #if defined( __unix__ )
29 #include <X11/Xcursor/Xcursor.h>
30 #endif
31 
32 // 3rd party library includes
33 
34 // FIFE includes
35 // These includes are split up in two parts, separated by one empty line
36 // First block: files included from the FIFE root src directory
37 // Second block: files included from the same folder
38 #include "util/structures/rect.h"
39 #include "util/time/timemanager.h"
40 #include "util/log/logger.h"
41 
42 #include "imagepool.h"
43 #include "animationpool.h"
44 #include "animation.h"
45 #include "image.h"
46 #include "renderbackend.h"
47 #include "cursor.h"
48 
49 #if defined( WIN32 )
50 
51 // From SDL_sysmouse.c
52 struct WMcursor {
53  HCURSOR curs;
54 #ifndef _WIN32_WCE
55  Uint8 *ands;
56  Uint8 *xors;
57 #endif
58 };
59 
60 #endif
61 
62 #if defined( __unix__ )
63 
64 // Stops the compiler from confusing it with FIFE:Cursor
65 typedef Cursor XCursor;
66 
67 // From SDL_x11mouse.c
68 struct WMcursor {
69  Cursor x_cursor;
70 };
71 
72 #endif
73 
74 namespace FIFE {
75  static Logger _log(LM_GUI); // We should have a log module for cursor
76 
77  Cursor::Cursor(ImagePool* imgpool, AnimationPool* animpool, RenderBackend* renderbackend):
78  m_cursor_id(NC_ARROW),
79  m_drag_id(0),
80  m_cursor_type(CURSOR_NATIVE),
81  m_drag_type(CURSOR_NONE),
82  m_native_cursor(NULL),
83  m_renderbackend(renderbackend),
84  m_imgpool(imgpool),
85  m_animpool(animpool),
86  m_animtime(0),
87  m_drag_animtime(0),
88  m_drag_offset_x(0),
89  m_drag_offset_y(0),
90  m_mx(0),
91  m_my(0),
92  m_timemanager(TimeManager::instance()),
93  m_invalidated(false) {
94  assert(m_timemanager);
95  set(m_cursor_type, m_cursor_id);
96  }
97 
98  void Cursor::set(MouseCursorType ctype, unsigned int cursor_id) {
99  m_cursor_id = cursor_id;
100  m_cursor_type = ctype;
101  int mx, my;
102  SDL_GetMouseState(&mx, &my);
103 
104  if (ctype == CURSOR_NATIVE) {
105  if (!SDL_ShowCursor(1)) {
106  SDL_PumpEvents();
107  SDL_WarpMouse(mx, my);
108  }
109  setNativeCursor(cursor_id);
110  } else {
111  if (SDL_ShowCursor(0)) {
112  SDL_PumpEvents();
113  SDL_WarpMouse(mx, my);
114  }
115  if (ctype == CURSOR_ANIMATION) {
116  m_animtime = m_timemanager->getTime();
117  }
118  }
119  m_invalidated = false;
120  }
121 
122  void Cursor::setDrag(MouseCursorType ctype, unsigned int drag_id, int drag_offset_x, int drag_offset_y) {
123  m_drag_type = ctype;
124  m_drag_id = drag_id;
125  m_drag_offset_x = drag_offset_x;
126  m_drag_offset_y = drag_offset_y;
127  if (ctype != CURSOR_NONE) {
128  if (ctype == CURSOR_ANIMATION) {
129  m_drag_animtime = m_timemanager->getTime();
130  }
131  }
132  }
133 
134  void Cursor::invalidate() {
135  if (m_native_cursor != NULL) {
136  SDL_free(m_native_cursor->wm_cursor);
137  m_native_cursor->wm_cursor = NULL;
138  SDL_FreeCursor(m_native_cursor);
139  m_native_cursor = NULL;
140 
141  m_invalidated = true;
142  }
143  }
144 
145  void Cursor::draw() {
146  if (m_invalidated) {
147  set(m_cursor_type, m_cursor_id);
148  }
149 
150  SDL_GetMouseState(&m_mx, &m_my);
151  if ((m_cursor_type == CURSOR_NATIVE) && (m_drag_type == CURSOR_NONE)) {
152  return;
153  }
154 
155  // render possible drag image
156  Image* img = NULL;
157  if (m_drag_type == CURSOR_IMAGE) {
158  img = &m_imgpool->getImage(m_drag_id);
159  } else if (m_drag_type == CURSOR_ANIMATION) {
160  Animation& anim = m_animpool->getAnimation(m_drag_id);
161  int animtime = (m_timemanager->getTime() - m_drag_animtime) % anim.getDuration();
162  img = anim.getFrameByTimestamp(animtime);
163  }
164  if (img) {
165  Rect area(m_mx + m_drag_offset_x + img->getXShift(), m_my + m_drag_offset_y + img->getYShift(), img->getWidth(), img->getHeight());
166  m_renderbackend->pushClipArea(area, false);
167  img->render(area);
168  m_renderbackend->popClipArea();
169  }
170 
171  // render possible cursor image
172  img = NULL;
173  if (m_cursor_type == CURSOR_IMAGE) {
174  img = &m_imgpool->getImage(m_cursor_id);
175  } else if (m_cursor_type == CURSOR_ANIMATION) {
176  Animation& anim = m_animpool->getAnimation(m_cursor_id);
177  int animtime = (m_timemanager->getTime() - m_animtime) % anim.getDuration();
178  img = anim.getFrameByTimestamp(animtime);
179  }
180  if (img) {
181  Rect area(m_mx + img->getXShift(), m_my + img->getYShift(), img->getWidth(), img->getHeight());
182  m_renderbackend->pushClipArea(area, false);
183  img->render(area);
184  m_renderbackend->popClipArea();
185  }
186  }
187 
188  unsigned int Cursor::getNativeId(unsigned int cursor_id) {
189 #if defined( WIN32 )
190  switch (cursor_id) {
191  case NC_ARROW:
192  return 32512; // IDC_ARROW;
193  case NC_IBEAM:
194  return 32513; // IDC_IBEAM;
195  case NC_WAIT:
196  return 32514; // IDC_WAIT;
197  case NC_CROSS:
198  return 32515; // IDC_CROSS;
199  case NC_UPARROW:
200  return 32516; // IDC_UPARROW;
201  case NC_RESIZESE:
202  return 32642; // IDC_SIZENWSE;
203  case NC_RESIZESW:
204  return 32643; // IDC_SIZENESW;
205  case NC_RESIZEE:
206  return 32644; // IDC_SIZEWE;
207  case NC_RESIZES:
208  return 32645; // IDC_SIZENS;
209  case NC_RESIZENW:
210  return 32642; // IDC_SIZENWSE;
211  case NC_RESIZENE:
212  return 32643; // IDC_SIZENESW;
213  case NC_RESIZEW:
214  return 32644; // IDC_SIZEWE;
215  case NC_RESIZEN:
216  return 32645; // IDC_SIZENS;
217  case NC_RESIZEALL:
218  return 32646; // IDC_SIZEALL;
219  case NC_NO:
220  return 32648; // IDC_NO;
221  case NC_HAND:
222  return 32649; // IDC_HAND;
223  case NC_APPSTARTING:
224  return 32650; // IDC_APPSTARTING;
225  case NC_HELP:
226  return 32651; // IDC_HELP;
227  default:
228  break;
229  }
230 
231 #elif defined( __unix__ )
232  switch (cursor_id) {
233  case NC_ARROW:
234  return 68;
235  case NC_IBEAM:
236  return 152;
237  case NC_WAIT:
238  return 150;
239  case NC_CROSS:
240  return 130;
241  case NC_UPARROW:
242  return 22;
243  case NC_RESIZESE:
244  return 14;
245  case NC_RESIZESW:
246  return 12;
247  case NC_RESIZEE:
248  return 96;
249  case NC_RESIZES:
250  return 16;
251  case NC_RESIZENW:
252  return 134;
253  case NC_RESIZENE:
254  return 136;
255  case NC_RESIZEW:
256  return 70;
257  case NC_RESIZEN:
258  return 138;
259  case NC_RESIZEALL:
260  return 52;
261  case NC_NO:
262  return 0;
263  case NC_HAND:
264  return 60;
265  case NC_APPSTARTING:
266  return 150;
267  case NC_HELP:
268  return 92;
269  default:
270  break;
271  }
272 #endif
273  return cursor_id;
274  }
275 
276  void Cursor::setNativeCursor(unsigned int cursor_id) {
277 #if defined( WIN32 ) || defined(__unix__)
278  // Check if a value in NativeCursors is requested
279  cursor_id = getNativeId(cursor_id);
280 
281  // Load cursor
282 #if defined( __unix__ )
283  static Display* dsp = XOpenDisplay(NULL);
284  XCursor xCursor = XcursorShapeLoadCursor(dsp, cursor_id);
285  if (xCursor == 0) {
286  if (m_native_cursor != NULL) {
287  SDL_FreeCursor(m_native_cursor);
288  m_native_cursor = NULL;
289  }
290  FL_WARN(_log, "Cursor: No cursor matching cursor_id was found.");
291  return;
292  }
293 #elif defined( WIN32 )
294  // Load native cursor
295  HCURSOR hIcon = LoadCursor(NULL, MAKEINTRESOURCE(cursor_id));
296  if (hIcon == static_cast<HCURSOR>(0)) {
297  if (m_native_cursor != NULL) {
298  SDL_FreeCursor(m_native_cursor);
299  m_native_cursor = NULL;
300  }
301  FL_WARN(_log, "Cursor: No cursor matching cursor_id was found.");
302  return;
303  }
304 #endif
305 
306  WMcursor *cursor;
307  SDL_Cursor *curs2;
308 
309  // Allocate memory. Use SDL_FreeCursor to free cursor memory
310  cursor = (WMcursor *)SDL_malloc(sizeof(*cursor));
311  curs2 = (SDL_Cursor *)SDL_malloc(sizeof *curs2);
312 
313  //-- Set up some default values --
314  curs2->wm_cursor = cursor;
315  curs2->data = NULL;
316  curs2->mask = NULL;
317  curs2->save[0] = NULL;
318  curs2->save[1] = NULL;
319  curs2->area.x = 0;
320  curs2->area.y = 0;
321  curs2->area.w = 32;
322  curs2->area.h = 32;
323  curs2->hot_x = 0;
324  curs2->hot_y = 0;
325 
326 #if defined(WIN32)
327  cursor->curs = hIcon;
328 #ifndef _WIN32_WCE
329  cursor->ands = NULL;
330  cursor->xors = NULL;
331 #endif
332 
333  // Get hot spot
334  ICONINFO iconinfo;
335  if (GetIconInfo(hIcon, &iconinfo)) {
336  curs2->hot_x = static_cast<Sint16>(iconinfo.xHotspot);
337  curs2->hot_y = static_cast<Sint16>(iconinfo.yHotspot);
338  }
339 
340 #elif defined(__unix__)
341  cursor->x_cursor = xCursor;
342  XSync(dsp, false);
343 #endif
344 
345  m_native_cursor = curs2;
346  SDL_SetCursor(curs2);
347 
348 #endif // WIN32 || __unix__
349  }
350 }