1 module gfm.sdl2.mouse;
2 
3 import derelict.sdl2.sdl;
4 import gfm.sdl2.sdl;
5 import gfm.sdl2.surface;
6 
7 /// Holds SDL mouse state.
8 final class SDL2Mouse
9 {
10     public
11     {
12         /// Returns: true if a specific mouse button defined by mask is pressed
13         /// Example:
14         /// --------------------
15         /// // Check if the left mouse button is pressed
16         /// if(_sdl2.mouse.isButtonPressed(SDL_BUTTON_LMASK))
17         ///     ...
18         /// --------------------
19         bool isButtonPressed(int mask) pure const nothrow
20         {
21             return (_buttonState & mask) != 0;
22         }
23 
24         /// Returns: X coordinate of mouse pointer.
25         int x() pure const nothrow
26         {
27             return _x;
28         }
29 
30         /// Returns: Y coordinate of mouse pointer.
31         int y() pure const nothrow
32         {
33             return _y;
34         }
35 
36         /// Returns: X relative movement on last motion event.
37         int lastDeltaX() pure const nothrow
38         {
39             return _lastDeltaX;
40         }
41 
42         /// Returns: Y relative movement on last motion event.
43         int lastDeltaY() pure const nothrow
44         {
45             return _lastDeltaY;
46         }
47 
48         /// Returns: Coordinates of mouse pointer.
49         SDL_Point position() pure const nothrow
50         {
51             return SDL_Point(_x, _y);
52         }
53 
54         /// Returns: Previous coordinates of mouse pointer. Useful in onMouseMove event callback.
55         SDL_Point previousPosition() pure const nothrow
56         {
57             return SDL_Point(_x - _lastDeltaX, _y - _lastDeltaY);
58         }
59 
60         /// Returns: How much was scrolled by X coordinate since the last call.
61         int wheelDeltaX() nothrow
62         {
63             int value = _wheelX;
64             _wheelX = 0;
65             return value;
66         }
67 
68         /// Returns: How much was scrolled by Y coordinate since the last call.
69         int wheelDeltaY() nothrow
70         {
71             int value = _wheelY;
72             _wheelY = 0;
73             return value;
74         }
75 
76         /// Use this function to capture the mouse and to track input outside an SDL window.
77         /// See_also: $(LINK https://wiki.libsdl.org/SDL_CaptureMouse)
78         /// Throws: $(D SDL2Exception) on error.
79         void startCapture()
80         {
81             if (SDL_CaptureMouse(SDL_TRUE) != 0)
82                 _sdl2.throwSDL2Exception("SDL_CaptureMouse");
83         }
84 
85         /// Use this function to stop capturing the mouse.
86         /// See_also: $(LINK https://wiki.libsdl.org/SDL_CaptureMouse)
87         /// Throws: $(D SDL2Exception) on error.
88         void stopCapture()
89         {
90             if (SDL_CaptureMouse(SDL_FALSE) != 0)
91                 _sdl2.throwSDL2Exception("SDL_CaptureMouse");
92         }
93     }
94 
95     package
96     {
97         this(SDL2 sdl2)
98         {
99             _sdl2 = sdl2;
100         }
101 
102         void updateMotion(const(SDL_MouseMotionEvent)* event)
103         {
104             // Get mouse buttons state but ignore mouse coordinates
105             // because we get them from event data
106             _buttonState = SDL_GetMouseState(null, null);
107             _x = event.x;
108             _y = event.y;
109             _lastDeltaX = event.xrel;
110             _lastDeltaY = event.yrel;
111         }
112 
113         void updateButtons(const(SDL_MouseButtonEvent)* event)
114         {
115             // get mouse buttons state but ignore mouse coordinates
116             // because we get them from event data
117             _buttonState = SDL_GetMouseState(null, null);
118             _x = event.x;
119             _y = event.y;
120         }
121 
122         void updateWheel(const(SDL_MouseWheelEvent)* event)
123         {
124             _buttonState = SDL_GetMouseState(&_x, &_y);
125             _wheelX += event.x;
126             _wheelY += event.y;
127         }
128     }
129 
130     private
131     {
132         SDL2 _sdl2;
133 
134         // Last button state
135         int _buttonState;
136 
137         // Last mouse coordinates
138         int _x = 0,
139             _y = 0;
140 
141         // mouse wheel scrolled amounts
142         int _wheelX = 0,
143             _wheelY = 0;
144 
145         int _lastDeltaX = 0,
146             _lastDeltaY = 0;
147     }
148 }
149 
150 
151 /// Mouse cursor, can be created from custom bitmap or from system defaults.
152 final class SDL2Cursor
153 {
154     public
155     {
156         /// Creates a cursor from a SDL surface.
157         /// The surface should outlive this cursor, its ownership will not be taken.
158         /// See_also: $(LINK http://wiki.libsdl.org/SDL_CreateColorCursor)
159         /// Throws: $(D SDL2Exception) on error.
160         this(SDL2 sdl2, SDL2Surface surface, int hotspotX, int hotspotY)
161         {
162             _sdl2 = sdl2;
163             _handle = SDL_CreateColorCursor(surface.handle(), hotspotX, hotspotY);
164             if(_handle is null)
165                 _sdl2.throwSDL2Exception("SDL_CreateColorCursor");
166             _owned = true;
167         }
168 
169         /// Creates a system cursor.
170         /// See_also: $(LINK http://wiki.libsdl.org/SDL_CreateSystemCursor)
171         /// Throws: $(D SDL2Exception) on error.
172         this(SDL2 sdl2, SDL_SystemCursor id)
173         {
174             _sdl2 = sdl2;
175             _handle = SDL_CreateSystemCursor(id);
176             if(_handle is null)
177                 _sdl2.throwSDL2Exception("SDL_CreateSystemCursor");
178             _owned = true;
179         }
180 
181         /// Returns: Default cursor.
182         /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetDefaultCursor)
183         /// Throws: $(D SDL2Exception) on error.
184         static SDL2Cursor getDefault(SDL2 sdl2)
185         {
186             SDL_Cursor* handle = SDL_GetDefaultCursor();
187             if(handle is null)
188                 sdl2.throwSDL2Exception("SDL_GetDefaultCursor");
189 
190             return new SDL2Cursor(sdl2, handle);
191 
192         }
193 
194         /// Returns: Current cursor.
195         /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetCursor)
196         /// Throws: $(D SDL2Exception) on error.
197         static SDL2Cursor getCurrent(SDL2 sdl2)
198         {
199             SDL_Cursor* handle = SDL_GetCursor();
200             if(handle is null)
201                 sdl2.throwSDL2Exception("SDL_GetCursor");
202 
203             return new SDL2Cursor(sdl2, handle);
204         }
205 
206         ~this()
207         {
208             close();
209         }
210 
211         /// Returns: SDL handle.
212         SDL_Cursor* handle()
213         {
214             return _handle;
215         }
216 
217         void close()
218         {
219             if (_owned && _handle !is null)
220             {
221                 SDL_FreeCursor(_handle);
222                 _handle = null;
223             }
224         }
225 
226         void setCurrent()
227         {
228             SDL_SetCursor(_handle);
229         }
230     }
231 
232     private
233     {
234         SDL2 _sdl2;
235         SDL_Cursor* _handle;
236         SDL2Surface _surface;
237         bool _owned;
238 
239         // Create with specified handle.
240         this(SDL2 sdl2, SDL_Cursor* handle)
241         {
242             _sdl2 = sdl2;
243             _handle = handle;
244             _owned = false;
245         }
246     }
247 }