FIFE  6e1afdbeda11afe9ac53e6023a4be96ef88f1dc6
cursor.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2017 by the FIFE team *
3  * http://www.fifengine.net *
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 
24 // 3rd party library includes
25 #include <SDL.h>
26 
27 // FIFE includes
28 // These includes are split up in two parts, separated by one empty line
29 // First block: files included from the FIFE root src directory
30 // Second block: files included from the same folder
31 #include "util/structures/rect.h"
32 #include "util/time/timemanager.h"
33 #include "util/log/logger.h"
34 #include "video/imagemanager.h"
35 
36 #include "animation.h"
37 #include "image.h"
38 #include "renderbackend.h"
39 #include "cursor.h"
40 
41 namespace FIFE {
45  static Logger _log(LM_CURSOR);
46 
47  Cursor::Cursor(RenderBackend* renderbackend):
48  m_cursor_id(NC_ARROW),
49  m_cursor_type(CURSOR_NATIVE),
50  m_drag_type(CURSOR_NONE),
51  m_native_cursor(NULL),
52  m_renderbackend(renderbackend),
53  m_animtime(0),
54  m_drag_animtime(0),
55  m_drag_offset_x(0),
56  m_drag_offset_y(0),
57  m_mx(0),
58  m_my(0),
59  m_timemanager(TimeManager::instance()),
60  m_invalidated(false),
61  m_native_image_cursor_enabled(false) {
62  assert(m_timemanager);
63  set(m_cursor_id);
64  }
65 
66  void Cursor::set(uint32_t cursor_id) {
68 
69  if (!SDL_ShowCursor(1)) {
70  SDL_PumpEvents();
71  }
72  setNativeCursor(cursor_id);
73 
76  }
77 
78  void Cursor::set(ImagePtr image) {
79  assert(image != 0);
80 
81  m_cursor_image = image;
83 
85  if (!setNativeImageCursor(image)) {
86  return;
87  }
88  if (!SDL_ShowCursor(1)) {
89  SDL_PumpEvents();
90  }
91  }
92  else if (SDL_ShowCursor(0)) {
93  SDL_PumpEvents();
94  }
95 
98  }
99 
101  assert(anim != 0);
102 
103  m_cursor_animation = anim;
105 
107  if (!setNativeImageCursor(anim->getFrameByTimestamp(0))) {
108  return;
109  }
110  if (!SDL_ShowCursor(1)) {
111  SDL_PumpEvents();
112  }
113  }
114  else if (SDL_ShowCursor(0)) {
115  SDL_PumpEvents();
116  }
118 
121  }
122 
123  void Cursor::setDrag(ImagePtr image, int32_t drag_offset_x, int32_t drag_offset_y) {
124  assert(image != 0);
125 
126  m_cursor_drag_image = image;
128  m_drag_offset_x = drag_offset_x;
129  m_drag_offset_y = drag_offset_y;
130 
132  }
133 
134  void Cursor::setDrag(AnimationPtr anim, int32_t drag_offset_x, int32_t drag_offset_y) {
135  assert(anim != 0);
136 
139  m_drag_offset_x = drag_offset_x;
140  m_drag_offset_y = drag_offset_y;
141 
143 
145  }
146 
149 
150  m_drag_animtime = 0;
151  m_drag_offset_x = 0;
152  m_drag_offset_y = 0;
153 
156  }
157 
159  m_mx = x;
160  m_my = y;
161  SDL_WarpMouseInWindow(RenderBackend::instance()->getWindow(), m_mx, m_my);
162  }
163 
164  void Cursor::getPosition(int32_t* x, int32_t* y) {
165  *x = m_mx;
166  *y = m_my;
167  }
168 
170  if (m_native_cursor != NULL) {
171  SDL_FreeCursor(m_native_cursor);
172  m_native_cursor = NULL;
174 
175  m_invalidated = true;
176  }
177  }
178 
179  void Cursor::draw() {
180  if (m_invalidated) {
181  if (m_cursor_type == CURSOR_NATIVE ) {
182  set(m_cursor_id);
183  }
185  if (m_cursor_type == CURSOR_IMAGE ) {
186  set(m_cursor_image);
187  }
188  else if (m_cursor_type == CURSOR_ANIMATION ) {
189  set(m_cursor_animation);
190  }
191  }
192 
193  m_invalidated = false;
194  }
195 
196  SDL_GetMouseState(&m_mx, &m_my);
198  return;
199  }
200 
201  // render possible drag image
202  ImagePtr img;
203  if (m_drag_type == CURSOR_IMAGE) {
204  img = m_cursor_drag_image;
205  }
206  else if (m_drag_type == CURSOR_ANIMATION) {
209  }
210 
211  if (img != 0) {
212  Rect area(m_mx + m_drag_offset_x + img->getXShift(), m_my + m_drag_offset_y + img->getYShift(), img->getWidth(), img->getHeight());
213  m_renderbackend->pushClipArea(area, false);
214  img->render(area);
217  }
218 
219  ImagePtr img2;
220  // render possible cursor image
221  if (m_cursor_type == CURSOR_IMAGE) {
222  img2 = m_cursor_image;
223  }
224  else if (m_cursor_type == CURSOR_ANIMATION) {
225  int32_t animtime = (m_timemanager->getTime() - m_animtime) % m_cursor_animation->getDuration();
226  img2 = m_cursor_animation->getFrameByTimestamp(animtime);
227  }
228 
229  if (img2 != 0) {
231  setNativeImageCursor(img2);
232  } else {
233  Rect area(m_mx + img2->getXShift(), m_my + img2->getYShift(), img2->getWidth(), img2->getHeight());
234  m_renderbackend->pushClipArea(area, false);
235  img2->render(area);
238  }
239  }
240  }
241 
243  switch (cursor_id) {
244  case NC_ARROW:
245  return SDL_SYSTEM_CURSOR_ARROW;
246  case NC_IBEAM:
247  return SDL_SYSTEM_CURSOR_IBEAM;
248  case NC_WAIT:
249  return SDL_SYSTEM_CURSOR_WAIT;
250  case NC_CROSS:
251  return SDL_SYSTEM_CURSOR_CROSSHAIR;
252  case NC_WAITARROW:
253  return SDL_SYSTEM_CURSOR_WAITARROW;
254  case NC_RESIZENWSE:
255  return SDL_SYSTEM_CURSOR_SIZENWSE;
256  case NC_RESIZENESW:
257  return SDL_SYSTEM_CURSOR_SIZENESW;
258  case NC_RESIZEWE:
259  return SDL_SYSTEM_CURSOR_SIZEWE;
260  case NC_RESIZENS:
261  return SDL_SYSTEM_CURSOR_SIZENS;
262  case NC_RESIZEALL:
263  return SDL_SYSTEM_CURSOR_SIZEALL;
264  case NC_NO:
265  return SDL_SYSTEM_CURSOR_NO;
266  case NC_HAND:
267  return SDL_SYSTEM_CURSOR_HAND;
268  }
269  return cursor_id;
270  }
271 
273  cursor_id = getNativeId(cursor_id);
274  SDL_Cursor* cursor = SDL_CreateSystemCursor(static_cast<SDL_SystemCursor>(cursor_id));
275  if (!cursor) {
276  FL_WARN(_log, "No cursor matching cursor_id was found.");
277  return;
278  }
279  SDL_SetCursor(cursor);
280  if (m_native_cursor != NULL) {
281  SDL_FreeCursor(m_native_cursor);
282  }
283  m_native_cursor = cursor;
284  }
285 
287  if (image == m_native_cursor_image) {
288  // we're already using this image
289  return true;
290  }
291  if (image->getState() == IResource::RES_NOT_LOADED) {
292  image->load();
293  }
294 
295  // SDL only accepts whole surfaces here so if this image uses a shared surface
296  // we need to prepare a temporary surface with just the relevant part
297  ImagePtr temp_image = image;
298  if (image->isSharedImage()) {
299  temp_image = ImageManager::instance()->create();
300  temp_image->copySubimage(0, 0, image);
301  }
302 
303  SDL_Cursor* cursor = SDL_CreateColorCursor(
304  temp_image->getSurface(),
305  -image->getXShift(),
306  -image->getYShift());
307  if (cursor == NULL) {
308  FL_WARN(_log, LMsg("SDL_CreateColorCursor: \"") << SDL_GetError() <<
309  "\". Falling back to software cursor.");
310  if (image->isSharedImage()) {
311  ImageManager::instance()->remove(temp_image);
312  }
314  return false;
315  }
316  SDL_SetCursor(cursor);
317  m_native_cursor_image = image;
318 
319  if (image->isSharedImage()) {
320  ImageManager::instance()->remove(temp_image);
321  }
322  if (m_native_cursor != NULL) {
323  SDL_FreeCursor(m_native_cursor);
324  }
325  m_native_cursor = cursor;
326  return true;
327  }
328 
329  void Cursor::setNativeImageCursorEnabled(bool native_image_cursor_enabled) {
330  if (m_native_image_cursor_enabled != native_image_cursor_enabled) {
331  m_native_image_cursor_enabled = native_image_cursor_enabled;
332  if (m_cursor_type == CURSOR_IMAGE ) {
333  set(m_cursor_image);
334  }
335  else if (m_cursor_type == CURSOR_ANIMATION ) {
336  set(m_cursor_animation);
337  }
338  }
339  }
340 
343  }
344 }
virtual ImagePtr create(IResourceLoader *loader=0)
Creates a blank Image but does not load it immediately.
#define FL_WARN(logger, msg)
Definition: logger.h:72
uint32_t m_animtime
Definition: cursor.h:218
Abstract interface for all the renderbackends.
MouseCursorType m_cursor_type
Definition: cursor.h:205
virtual ResourceState getState()
Definition: resource.h:70
MouseCursorType m_drag_type
Definition: cursor.h:206
virtual void load()
Definition: image.cpp:124
TimeManager * m_timemanager
Definition: cursor.h:225
Helper class to create log strings out from separate parts Usage: LMsg("some text") << variable << "...
Definition: logger.h:82
int32_t m_drag_offset_x
Definition: cursor.h:221
int32_t getXShift() const
Definition: image.h:122
void reset(T *ptr=0)
reset this pointer to a null shared pointer this can be used to lower the reference count of the shar...
Definition: sharedptr.h:164
bool isNativeImageCursorEnabled() const
Returns whether cursors set to an image or an animation are drawn natively.
Definition: cursor.cpp:341
ImagePtr m_cursor_image
Definition: cursor.h:210
uint32_t getDuration() const
Gets the total duration for the whole animation.
Definition: animation.h:138
virtual void remove(ImagePtr &resource)
Removes an Image from the manager.
int32_t getYShift() const
Definition: image.h:128
static Logger _log(LM_AUDIO)
int32_t m_my
Definition: cursor.h:224
bool m_native_image_cursor_enabled
Definition: cursor.h:228
static RenderBackend * instance()
Definition: singleton.h:84
ImagePtr m_cursor_drag_image
Definition: cursor.h:211
void setDrag(ImagePtr image, int32_t drag_offset_x=0, int32_t drag_offset_y=0)
Sets the current drag image cursor.
Definition: cursor.cpp:123
uint32_t getHeight() const
Definition: image.cpp:160
AnimationPtr m_cursor_animation
Definition: cursor.h:213
bool m_invalidated
Definition: cursor.h:227
void setNativeCursor(uint32_t cursor_id)
Sets the cursor to a native type.
Definition: cursor.cpp:272
void invalidate()
Definition: cursor.cpp:169
uint32_t getTime() const
Get the time.
ImagePtr getFrameByTimestamp(uint32_t timestamp)
Gets the frame image that matches the given timestamp.
Definition: animation.cpp:150
SDL_Surface * getSurface()
Definition: image.h:96
virtual void copySubimage(uint32_t xoffset, uint32_t yoffset, const ImagePtr &img)
Copies given image into this one with respect to given offsets.
Definition: image.cpp:315
void setNativeImageCursorEnabled(bool native_image_cursor_enabled)
Enables or disables the native image cursor feature.
Definition: cursor.cpp:329
virtual void draw()
draws cursor on screen
Definition: cursor.cpp:179
void pushClipArea(const Rect &cliparea, bool clear=true)
Pushes clip area to clip stack Clip areas define which area is drawn on screen.
int32_t m_drag_offset_y
Definition: cursor.h:222
uint32_t m_drag_animtime
Definition: cursor.h:219
void popClipArea()
Pops clip area from clip stack.
uint32_t getWidth() const
Definition: image.cpp:151
uint32_t m_cursor_id
Definition: cursor.h:204
Time Manager.
Definition: timemanager.h:50
void set(uint32_t cursor_id=0)
Sets the current mouse cursor.
Definition: cursor.cpp:66
void resetDrag()
Resets the cursor drag type to CURSOR_NONE.
Definition: cursor.cpp:147
uint32_t getNativeId(uint32_t cursor_id)
To get some consistancy between platforms, this function checks if cursor_id matches any of the value...
Definition: cursor.cpp:242
bool isSharedImage() const
Returns true if this image shares data with another one.
Definition: image.h:148
ImagePtr m_native_cursor_image
Definition: cursor.h:229
AnimationPtr m_cursor_drag_animation
Definition: cursor.h:214
virtual void render(const Rect &rect, uint8_t alpha=255, uint8_t const *rgb=0)=0
Renders itself to the current render target (main screen or attached destination image) at the rectan...
Cursor(RenderBackend *renderbackend)
Constructor.
Definition: cursor.cpp:47
bool setNativeImageCursor(ImagePtr image)
Sets the SDL cursor to the specified image.
Definition: cursor.cpp:286
void getPosition(int32_t *x, int32_t *y)
Get the current mouse position.
Definition: cursor.cpp:164
virtual void renderVertexArrays()=0
Render the Vertex Arrays, only for primitives (points, lines,...)
int32_t m_mx
Definition: cursor.h:223
RenderBackend * m_renderbackend
Definition: cursor.h:216
unsigned int uint32_t
Definition: core.h:40
SDL_Cursor * m_native_cursor
Definition: cursor.h:208
void setPosition(uint32_t x, uint32_t y)
Set the mouse position.
Definition: cursor.cpp:158