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 
96     package
97     {
98         this(SDL2 sdl2)
99         {
100             _sdl2 = sdl2;
101         }
102 
103         void updateMotion(const(SDL_MouseMotionEvent)* event)
104         {
105             // Get mouse buttons state but ignore mouse coordinates
106             // because we get them from event data
107             _buttonState = SDL_GetMouseState(null, null);
108             _x = event.x;
109             _y = event.y;
110             _lastDeltaX = event.xrel;
111             _lastDeltaY = event.yrel;
112         }
113 
114         void updateButtons(const(SDL_MouseButtonEvent)* event)
115         {
116             // get mouse buttons state but ignore mouse coordinates
117             // because we get them from event data
118             _buttonState = SDL_GetMouseState(null, null);
119             _x = event.x;
120             _y = event.y;
121         }
122 
123         void updateWheel(const(SDL_MouseWheelEvent)* event)
124         {
125             _buttonState = SDL_GetMouseState(&_x, &_y);
126             _wheelX += event.x;
127             _wheelY += event.y;
128         }
129     }
130 
131     private
132     {
133         SDL2 _sdl2;
134 
135         // Last button state
136         int _buttonState;
137 
138         // Last mouse coordinates
139         int _x = 0,
140             _y = 0;
141 
142         // mouse wheel scrolled amounts
143         int _wheelX = 0,
144             _wheelY = 0;
145 
146         int _lastDeltaX = 0,
147             _lastDeltaY = 0;
148     }
149 }
150 
151 
152 /// Mouse cursor, can be created from custom bitmap or from system defaults.
153 final class SDL2Cursor
154 {
155     public
156     {
157         /// Creates a cursor from a SDL surface.
158         /// The surface should outlive this cursor, its ownership will not be taken.
159         /// See_also: $(LINK http://wiki.libsdl.org/SDL_CreateColorCursor)
160         /// Throws: $(D SDL2Exception) on error.
161         this(SDL2 sdl2, SDL2Surface surface, int hotspotX, int hotspotY)
162         {
163             _sdl2 = sdl2;
164             _handle = SDL_CreateColorCursor(surface.handle(), hotspotX, hotspotY);
165             if(_handle is null)
166                 _sdl2.throwSDL2Exception("SDL_CreateColorCursor");
167             _owned = true;
168         }
169 
170         /// Creates a system cursor.
171         /// See_also: $(LINK http://wiki.libsdl.org/SDL_CreateSystemCursor)
172         /// Throws: $(D SDL2Exception) on error.
173         this(SDL2 sdl2, SDL_SystemCursor id)
174         {
175             _sdl2 = sdl2;
176             _handle = SDL_CreateSystemCursor(id);
177             if(_handle is null)
178                 _sdl2.throwSDL2Exception("SDL_CreateSystemCursor");
179             _owned = true;
180         }
181 
182         /// Returns: Default cursor.
183         /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetDefaultCursor)
184         /// Throws: $(D SDL2Exception) on error.
185         static SDL2Cursor getDefault(SDL2 sdl2)
186         {
187             SDL_Cursor* handle = SDL_GetDefaultCursor();
188             if(handle is null)
189                 sdl2.throwSDL2Exception("SDL_GetDefaultCursor");
190 
191             return new SDL2Cursor(sdl2, handle);
192 
193         }
194 
195         /// Returns: Current cursor.
196         /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetCursor)
197         /// Throws: $(D SDL2Exception) on error.
198         static SDL2Cursor getCurrent(SDL2 sdl2)
199         {
200             SDL_Cursor* handle = SDL_GetCursor();
201             if(handle is null)
202                 sdl2.throwSDL2Exception("SDL_GetCursor");
203 
204             return new SDL2Cursor(sdl2, handle);
205         }
206 
207         ~this()
208         {
209             close();
210         }
211 
212         /// Returns: SDL handle.
213         SDL_Cursor* handle()
214         {
215             return _handle;
216         }
217 
218         void close()
219         {
220             if (_owned && _handle !is null)
221             {
222                 SDL_FreeCursor(_handle);
223                 _handle = null;
224             }
225         }
226 
227         void setCurrent()
228         {
229             SDL_SetCursor(_handle);
230         }
231     }
232 
233     private
234     {
235         SDL2 _sdl2;
236         SDL_Cursor* _handle;
237         SDL2Surface _surface;
238         bool _owned;
239 
240         // Create with specified handle.
241         this(SDL2 sdl2, SDL_Cursor* handle)
242         {
243             _sdl2 = sdl2;
244             _handle = handle;
245             _owned = false;
246         }
247     }
248 }