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 #include "video/imagemanager.h"
42 
43 #include "animation.h"
44 #include "image.h"
45 #include "renderbackend.h"
46 #include "cursor.h"
47 
48 #if defined( WIN32 )
49 
50 // From SDL_sysmouse.c
51 struct WMcursor {
52  HCURSOR curs;
53 #ifndef _WIN32_WCE
54  Uint8 *ands;
55  Uint8 *xors;
56 #endif
57 };
58 
59 #endif
60 
61 #if defined( __unix__ )
62 
63 // Stops the compiler from confusing it with FIFE:Cursor
64 typedef Cursor XCursor;
65 
66 // From SDL_x11mouse.c
67 struct WMcursor {
68  Cursor x_cursor;
69 };
70 
71 #endif
72 
73 namespace FIFE {
74  static Logger _log(LM_GUI); //@todo We should have a log module for cursor
75 
76  Cursor::Cursor(RenderBackend* renderbackend):
77  m_cursor_id(NC_ARROW),
78  m_drag_id(0),
79  m_cursor_type(CURSOR_NATIVE),
80  m_drag_type(CURSOR_NONE),
81  m_native_cursor(NULL),
82  m_renderbackend(renderbackend),
83  m_animtime(0),
84  m_drag_animtime(0),
85  m_drag_offset_x(0),
86  m_drag_offset_y(0),
87  m_mx(0),
88  m_my(0),
89  m_timemanager(TimeManager::instance()),
90  m_invalidated(false) {
91  assert(m_timemanager);
92  set(m_cursor_id);
93  }
94 
95  void Cursor::set(uint32_t cursor_id) {
96  m_cursor_type = CURSOR_NATIVE;
97 
98  if (!SDL_ShowCursor(1)) {
99  SDL_PumpEvents();
100  }
101  setNativeCursor(cursor_id);
102 
103  m_cursor_image.reset();
104  m_cursor_animation.reset();
105  }
106 
107  void Cursor::set(ImagePtr image) {
108  assert(image != 0);
109 
110  m_cursor_image = image;
111  m_cursor_type = CURSOR_IMAGE;
112 
113  if (SDL_ShowCursor(0)) {
114  SDL_PumpEvents();
115  }
116 
117  m_cursor_id = NC_ARROW;
118  m_cursor_animation.reset();
119  }
120 
122  assert(anim != 0);
123 
124  m_cursor_animation = anim;
125  m_cursor_type = CURSOR_ANIMATION;
126 
127  if (SDL_ShowCursor(0)) {
128  SDL_PumpEvents();
129  }
130  m_animtime = m_timemanager->getTime();
131 
132  m_cursor_id = NC_ARROW;
133  m_cursor_image.reset();
134  }
135 
136  void Cursor::setDrag(ImagePtr image, int32_t drag_offset_x, int32_t drag_offset_y) {
137  assert(image != 0);
138 
139  m_cursor_drag_image = image;
140  m_drag_type = CURSOR_IMAGE;
141  m_drag_offset_x = drag_offset_x;
142  m_drag_offset_y = drag_offset_y;
143 
144  m_cursor_drag_animation.reset();
145  }
146 
147  void Cursor::setDrag(AnimationPtr anim, int32_t drag_offset_x, int32_t drag_offset_y) {
148  assert(anim != 0);
149 
150  m_cursor_drag_animation = anim;
151  m_drag_type = CURSOR_ANIMATION;
152  m_drag_offset_x = drag_offset_x;
153  m_drag_offset_y = drag_offset_y;
154 
155  m_drag_animtime = m_timemanager->getTime();
156 
157  m_cursor_drag_image.reset();
158  }
159 
161  m_drag_type = CURSOR_NONE;
162 
163  m_drag_animtime = 0;
164  m_drag_offset_x = 0;
165  m_drag_offset_y = 0;
166 
167  m_cursor_drag_animation.reset();
168  m_cursor_drag_image.reset();
169  }
170 
171  void Cursor::setPosition(uint32_t x, uint32_t y) {
172  m_mx = x;
173  m_my = y;
174  SDL_WarpMouse(m_mx, m_my);
175  }
176 
177  void Cursor::getPosition(int32_t* x, int32_t* y) {
178  *x = m_mx;
179  *y = m_my;
180  }
181 
182  void Cursor::invalidate() {
183  if (m_native_cursor != NULL) {
184  SDL_free(m_native_cursor->wm_cursor);
185  m_native_cursor->wm_cursor = NULL;
186  SDL_FreeCursor(m_native_cursor);
187  m_native_cursor = NULL;
188 
189  m_invalidated = true;
190  }
191  }
192 
193  void Cursor::draw() {
194  if (m_invalidated) {
195  if (m_cursor_type != CURSOR_ANIMATION || m_cursor_type == CURSOR_IMAGE ) {
196  set(m_cursor_id);
197  }
198 
199  m_invalidated = false;
200  }
201 
202  SDL_GetMouseState(&m_mx, &m_my);
203  if ((m_cursor_type == CURSOR_NATIVE) && (m_drag_type == CURSOR_NONE)) {
204  return;
205  }
206 
207  // render possible drag image
208  ImagePtr img;
209  if (m_drag_type == CURSOR_IMAGE) {
210  img = m_cursor_drag_image;
211  }
212  else if (m_drag_type == CURSOR_ANIMATION) {
213  int32_t animtime = (m_timemanager->getTime() - m_drag_animtime) % m_cursor_drag_animation->getDuration();
214  img = m_cursor_drag_animation->getFrameByTimestamp(animtime);
215  }
216 
217  if (img != 0) {
218  Rect area(m_mx + m_drag_offset_x + img->getXShift(), m_my + m_drag_offset_y + img->getYShift(), img->getWidth(), img->getHeight());
219  m_renderbackend->pushClipArea(area, false);
220  img->render(area);
221  m_renderbackend->renderVertexArrays();
222  m_renderbackend->popClipArea();
223  }
224 
225  ImagePtr img2;
226  // render possible cursor image
227  if (m_cursor_type == CURSOR_IMAGE) {
228  img2 = m_cursor_image;
229  }
230  else if (m_cursor_type == CURSOR_ANIMATION) {
231  int32_t animtime = (m_timemanager->getTime() - m_animtime) % m_cursor_animation->getDuration();
232  img2 = m_cursor_animation->getFrameByTimestamp(animtime);
233  }
234 
235  if (img2 != 0) {
236  Rect area(m_mx + img2->getXShift(), m_my + img2->getYShift(), img2->getWidth(), img2->getHeight());
237  m_renderbackend->pushClipArea(area, false);
238  img2->render(area);
239  m_renderbackend->renderVertexArrays();
240  m_renderbackend->popClipArea();
241  }
242  }
243 
244  uint32_t Cursor::getNativeId(uint32_t cursor_id) {
245 #if defined( WIN32 )
246  switch (cursor_id) {
247  case NC_ARROW:
248  return 32512; // IDC_ARROW;
249  case NC_IBEAM:
250  return 32513; // IDC_IBEAM;
251  case NC_WAIT:
252  return 32514; // IDC_WAIT;
253  case NC_CROSS:
254  return 32515; // IDC_CROSS;
255  case NC_UPARROW:
256  return 32516; // IDC_UPARROW;
257  case NC_RESIZESE:
258  return 32642; // IDC_SIZENWSE;
259  case NC_RESIZESW:
260  return 32643; // IDC_SIZENESW;
261  case NC_RESIZEE:
262  return 32644; // IDC_SIZEWE;
263  case NC_RESIZES:
264  return 32645; // IDC_SIZENS;
265  case NC_RESIZENW:
266  return 32642; // IDC_SIZENWSE;
267  case NC_RESIZENE:
268  return 32643; // IDC_SIZENESW;
269  case NC_RESIZEW:
270  return 32644; // IDC_SIZEWE;
271  case NC_RESIZEN:
272  return 32645; // IDC_SIZENS;
273  case NC_RESIZEALL:
274  return 32646; // IDC_SIZEALL;
275  case NC_NO:
276  return 32648; // IDC_NO;
277  case NC_HAND:
278  return 32649; // IDC_HAND;
279  case NC_APPSTARTING:
280  return 32650; // IDC_APPSTARTING;
281  case NC_HELP:
282  return 32651; // IDC_HELP;
283  default:
284  break;
285  }
286 
287 #elif defined( __unix__ )
288  switch (cursor_id) {
289  case NC_ARROW:
290  return 68;
291  case NC_IBEAM:
292  return 152;
293  case NC_WAIT:
294  return 150;
295  case NC_CROSS:
296  return 130;
297  case NC_UPARROW:
298  return 22;
299  case NC_RESIZESE:
300  return 14;
301  case NC_RESIZESW:
302  return 12;
303  case NC_RESIZEE:
304  return 96;
305  case NC_RESIZES:
306  return 16;
307  case NC_RESIZENW:
308  return 134;
309  case NC_RESIZENE:
310  return 136;
311  case NC_RESIZEW:
312  return 70;
313  case NC_RESIZEN:
314  return 138;
315  case NC_RESIZEALL:
316  return 52;
317  case NC_NO:
318  return 0;
319  case NC_HAND:
320  return 60;
321  case NC_APPSTARTING:
322  return 150;
323  case NC_HELP:
324  return 92;
325  default:
326  break;
327  }
328 #endif
329  return cursor_id;
330  }
331 
332  void Cursor::setNativeCursor(uint32_t cursor_id) {
333 #if defined( WIN32 ) || defined(__unix__)
334  // Check if a value in NativeCursors is requested
335  cursor_id = getNativeId(cursor_id);
336 
337  // Load cursor
338 #if defined( __unix__ )
339  static Display* dsp = XOpenDisplay(NULL);
340  XCursor xCursor = XcursorShapeLoadCursor(dsp, cursor_id);
341  if (xCursor == 0) {
342  if (m_native_cursor != NULL) {
343  SDL_FreeCursor(m_native_cursor);
344  m_native_cursor = NULL;
345  }
346  FL_WARN(_log, "Cursor: No cursor matching cursor_id was found.");
347  return;
348  }
349 #elif defined( WIN32 )
350  // Load native cursor
351  HCURSOR hIcon = LoadCursor(NULL, MAKEINTRESOURCE(cursor_id));
352  if (hIcon == static_cast<HCURSOR>(0)) {
353  if (m_native_cursor != NULL) {
354  SDL_FreeCursor(m_native_cursor);
355  m_native_cursor = NULL;
356  }
357  FL_WARN(_log, "Cursor: No cursor matching cursor_id was found.");
358  return;
359  }
360 #endif
361 
362  WMcursor *cursor;
363  SDL_Cursor *curs2;
364 
365  // Allocate memory. Use SDL_FreeCursor to free cursor memory
366  cursor = (WMcursor *)SDL_malloc(sizeof(*cursor));
367  curs2 = (SDL_Cursor *)SDL_malloc(sizeof *curs2);
368 
369  //-- Set up some default values --
370  curs2->wm_cursor = cursor;
371  curs2->data = NULL;
372  curs2->mask = NULL;
373  curs2->save[0] = NULL;
374  curs2->save[1] = NULL;
375  curs2->area.x = 0;
376  curs2->area.y = 0;
377  curs2->area.w = 32;
378  curs2->area.h = 32;
379  curs2->hot_x = 0;
380  curs2->hot_y = 0;
381 
382 #if defined(WIN32)
383  cursor->curs = hIcon;
384 #ifndef _WIN32_WCE
385  cursor->ands = NULL;
386  cursor->xors = NULL;
387 #endif
388 
389  // Get hot spot
390  ICONINFO iconinfo;
391  if (GetIconInfo(hIcon, &iconinfo)) {
392  curs2->hot_x = static_cast<Sint16>(iconinfo.xHotspot);
393  curs2->hot_y = static_cast<Sint16>(iconinfo.yHotspot);
394  }
395 
396 #elif defined(__unix__)
397  cursor->x_cursor = xCursor;
398  XSync(dsp, false);
399 #endif
400 
401  m_native_cursor = curs2;
402  SDL_SetCursor(curs2);
403 
404 #endif // WIN32 || __unix__
405  }
406 }
void reset(T *ptr=0)
Definition: sharedptr.h:164
uint32_t getDuration() const
Definition: animation.h:129
void setDrag(ImagePtr image, int32_t drag_offset_x=0, int32_t drag_offset_y=0)
Definition: cursor.cpp:136
void setNativeCursor(uint32_t cursor_id)
Definition: cursor.cpp:332
uint32_t getTime() const
ImagePtr getFrameByTimestamp(uint32_t timestamp)
Definition: animation.cpp:99
virtual void draw()
Definition: cursor.cpp:193
void pushClipArea(const Rect &cliparea, bool clear=true)
void set(uint32_t cursor_id=0)
Definition: cursor.cpp:95
void resetDrag()
Definition: cursor.cpp:160
uint32_t getNativeId(uint32_t cursor_id)
Definition: cursor.cpp:244
virtual void render(const Rect &rect, uint8_t alpha=255, uint8_t const *rgb=0)=0
Cursor(RenderBackend *renderbackend)
Definition: cursor.cpp:76
void getPosition(int32_t *x, int32_t *y)
Definition: cursor.cpp:177
virtual void renderVertexArrays()=0
void setPosition(uint32_t x, uint32_t y)
Definition: cursor.cpp:171