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