misc/vim: inform the user when no results are found
[nit.git] / lib / sdl.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2011-2013 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # SDL display support (used in Linux for windows and inputes only)
18 module sdl is
19 cflags exec("sdl-config", "--cflags")
20 ldflags(exec("sdl-config", "--libs"), "-lSDL_image -lSDL_ttf")
21 end
22
23 import mnit_display
24 import c
25
26 in "C header" `{
27 #include <unistd.h>
28 #include <SDL/SDL.h>
29 #include <SDL/SDL_syswm.h>
30 #include <SDL/SDL_image.h>
31 #include <SDL/SDL_ttf.h>
32 `}
33
34 # Represent a screen surface
35 extern class SDLDisplay `{SDL_Surface *`}
36 super Display
37
38 redef type I: SDLImage
39
40 # Initialize a surface with width and height
41 new (w, h: Int) import enable_mouse_motion_events `{
42 SDL_Init(SDL_INIT_VIDEO);
43
44 if(TTF_Init()==-1) {
45 printf("TTF_Init: %s\n", TTF_GetError());
46 exit(2);
47 }
48
49 SDL_Surface *self = SDL_SetVideoMode(w, h, 24, SDL_HWSURFACE);
50
51 if (!SDLDisplay_enable_mouse_motion_events(self)) {
52 /* ignores mousemotion for performance reasons */
53 SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
54 }
55
56 return self;
57 `}
58
59 # Indicates wether we want the SDL mouse motion event (or only clicks).
60 # Disabled by defaut for performance reason. To activate, redef this method
61 # andd return true
62 fun enable_mouse_motion_events: Bool do return false
63
64 # Destroy the surface
65 fun destroy `{
66 if (SDL_WasInit(SDL_INIT_VIDEO))
67 SDL_Quit();
68
69 if (TTF_WasInit())
70 TTF_Quit();
71 `}
72
73 redef fun finish `{ SDL_Flip(recv); `}
74
75 # Clear the entire window with given RGB color (integer values)
76 fun clear_int(r, g, b: Int) `{
77 SDL_FillRect(recv, NULL, SDL_MapRGB(recv->format,r,g,b));
78 `}
79
80 redef fun width: Int `{ return recv->w; `}
81 redef fun height: Int `{ return recv->h; `}
82
83 # Fill a rectangle with given color
84 fun fill_rect(rect: SDLRectangle, r, g, b: Int) `{
85 SDL_FillRect(recv, rect, SDL_MapRGB(recv->format,r,g,b));
86 `}
87
88 redef fun clear(r, g, b: Float) `{
89 Uint8 ri, gi, bi;
90 ri = (Uint8)r*255;
91 gi = (Uint8)g*255;
92 bi = (Uint8)b*255;
93 SDL_FillRect(recv, NULL, SDL_MapRGB(recv->format,ri,gi,bi));
94 `}
95
96 # SDL events since the last call to this method
97 fun events: Sequence[SDLInputEvent]
98 do
99 var events = new Array[SDLInputEvent]
100 loop
101 var new_event = poll_event
102 if new_event == null then break
103 events.add new_event
104 end
105 return events
106 end
107
108 private fun poll_event: nullable SDLInputEvent import SDLKeyEvent, SDLMouseButtonEvent, SDLMouseMotionEvent, SDLQuitEvent, NativeString.to_s, SDLMouseButtonEvent.as(nullable SDLInputEvent), SDLMouseMotionEvent.as(nullable SDLInputEvent), SDLKeyEvent.as(nullable SDLInputEvent), SDLQuitEvent.as(nullable SDLInputEvent) `{
109 SDL_Event event;
110
111 SDL_PumpEvents();
112
113 if (SDL_PollEvent(&event))
114 {
115 switch (event.type) {
116 case SDL_KEYDOWN:
117 case SDL_KEYUP:
118 #ifdef DEBUG
119 printf("The \"%s\" key was pressed!\n",
120 SDL_GetKeyName(event.key.keysym.sym));
121 #endif
122
123 return SDLKeyEvent_as_nullable_SDLInputEvent(
124 new_SDLKeyEvent(NativeString_to_s(
125 SDL_GetKeyName(event.key.keysym.sym)),
126 event.type==SDL_KEYDOWN));
127
128 case SDL_MOUSEMOTION:
129 #ifdef DEBUG
130 printf("Mouse moved by %d,%d to (%d,%d)\n",
131 event.motion.xrel, event.motion.yrel,
132 event.motion.x, event.motion.y);
133 #endif
134
135 return SDLMouseMotionEvent_as_nullable_SDLInputEvent(
136 new_SDLMouseMotionEvent(event.motion.x, event.motion.y,
137 event.motion.xrel, event.motion.yrel, SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(1)));
138
139 case SDL_MOUSEBUTTONDOWN:
140 case SDL_MOUSEBUTTONUP:
141 #ifdef DEBUG
142 printf("Mouse button \"%d\" pressed at (%d,%d)\n",
143 event.button.button, event.button.x, event.button.y);
144 #endif
145 return SDLMouseButtonEvent_as_nullable_SDLInputEvent(
146 new_SDLMouseButtonEvent(event.button.x, event.button.y,
147 event.button.button, event.type == SDL_MOUSEBUTTONDOWN));
148
149 case SDL_QUIT:
150 #ifdef DEBUG
151 printf("Quit event\n");
152 #endif
153 return SDLQuitEvent_as_nullable_SDLInputEvent(new_SDLQuitEvent());
154 }
155 }
156
157 return null_SDLInputEvent();
158 `}
159
160 # Set the position of the cursor to x,y
161 fun warp_mouse(x,y: Int) `{ SDL_WarpMouse(x, y); `}
162
163 # Show or hide the cursor
164 fun show_cursor=(val: Bool) `{ SDL_ShowCursor(val? SDL_ENABLE: SDL_DISABLE); `}
165
166 # Is the cursor visible?
167 fun show_cursor: Bool `{ SDL_ShowCursor(SDL_QUERY); `}
168
169 # Grab or release the input
170 fun grab_input=(val: Bool) `{ SDL_WM_GrabInput(val? SDL_GRAB_ON: SDL_GRAB_OFF); `}
171
172 # Is the input grabbed?
173 fun grab_input: Bool `{ SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON; `}
174
175 # Are instances of `SDLMouseMotionEvent` ignored?
176 fun ignore_mouse_motion_events: Bool `{
177 return SDL_EventState(SDL_MOUSEMOTION, SDL_QUERY);
178 `}
179
180 # Do not raise instances of `SDLMouseMotionEvent` if `val`
181 fun ignore_mouse_motion_events=(val: Bool) `{
182 SDL_EventState(SDL_MOUSEMOTION, val? SDL_IGNORE: SDL_ENABLE);
183 `}
184
185 # Does `self` has the mouse focus?
186 fun mouse_focus: Bool `{ return SDL_GetAppState() & SDL_APPMOUSEFOCUS; `}
187
188 # Does `self` has the input focus?
189 fun input_focus: Bool `{ return SDL_GetAppState() & SDL_APPINPUTFOCUS; `}
190 end
191
192 # Basic Drawing figures
193 extern class SDLDrawable `{SDL_Surface*`}
194 super Drawable
195
196 redef type I: SDLImage
197
198 redef fun blit(img, x, y) do native_blit(img, x.to_i, y.to_i)
199 private fun native_blit(img: I, x, y: Int) `{
200 SDL_Rect dst;
201 dst.x = x;
202 dst.y = y;
203 dst.w = 0;
204 dst.h = 0;
205
206 SDL_BlitSurface(img, NULL, recv, &dst);
207 `}
208
209 redef fun blit_centered(img, x, y)
210 do
211 x = x - img.width / 2
212 y = y - img.height / 2
213 blit(img, x, y)
214 end
215 end
216
217 # A drawable Image
218 extern class SDLImage
219 super DrawableImage
220 super SDLDrawable
221
222 # Import image from a file
223 new from_file(path: String) import String.to_cstring `{
224 SDL_Surface *image = IMG_Load(String_to_cstring(path));
225 return image;
226 `}
227
228 # Copy of an existing SDLImage
229 new copy_of(image: SDLImage) `{
230 SDL_Surface *new_image = SDL_CreateRGBSurface(
231 image->flags, image->w, image->h, 24,
232 0, 0, 0, 0);
233
234 SDL_Rect dst;
235 dst.x = 0;
236 dst.y = 0;
237 dst.w = image->w;
238 dst.h = image->h;
239 SDL_BlitSurface(image, NULL, new_image, &dst);
240
241 return new_image;
242 `}
243
244 # Save the image into the specified file
245 fun save_to_file(path: String) import String.to_cstring `{ `}
246
247 # Destroy the image and free the memory
248 redef fun destroy `{ SDL_FreeSurface(recv); `}
249
250 redef fun width: Int `{ return recv->w; `}
251 redef fun height: Int `{ return recv->h; `}
252
253 fun is_ok: Bool do return not address_is_null
254
255 # Returns a reference to the pixels of the texture
256 fun pixels: NativeCByteArray `{ return recv->pixels; `}
257
258 # Does this texture has an alpha mask?
259 fun amask: Bool `{ return recv->format->Amask; `}
260 end
261
262 # A simple rectangle
263 extern class SDLRectangle `{SDL_Rect*`}
264 # Constructor with x,y positions width and height of the rectangle
265 new (x: Int, y: Int, w: Int, h: Int) `{
266 SDL_Rect *rect = malloc(sizeof(SDL_Rect));
267 rect->x = (Sint16)x;
268 rect->y = (Sint16)y;
269 rect->w = (Uint16)w;
270 rect->h = (Uint16)h;
271 return rect;
272 `}
273
274 fun x=(v: Int) `{ recv->x = (Sint16)v; `}
275 fun x: Int `{ return recv->x; `}
276
277 fun y=(v: Int) `{ recv->y = (Sint16)v; `}
278 fun y: Int `{ return recv->y; `}
279
280 fun w=(v: Int) `{ recv->w = (Uint16)v; `}
281 fun w: Int `{ return recv->w; `}
282
283 fun h=(v: Int) `{ recv->h = (Uint16)v; `}
284 fun h: Int `{ return recv->h; `}
285 end
286
287 interface SDLInputEvent
288 super InputEvent
289 end
290
291 # MouseEvent class containing the cursor position
292 class SDLMouseEvent
293 super PointerEvent
294 super SDLInputEvent
295
296 redef var x: Float
297 redef var y: Float
298
299 private init (x, y: Float)
300 do
301 self.x = x
302 self.y = y
303 end
304 end
305
306 # MouseButtonEvent used to get information when a button is pressed/depressed
307 class SDLMouseButtonEvent
308 super SDLMouseEvent
309
310 var button: Int
311
312 redef var pressed: Bool
313 redef fun depressed: Bool do return not pressed
314
315 # Is this event raised by the left button?
316 fun is_left_button: Bool do return button == 1
317
318 # Is this event raised by the right button?
319 fun is_right_button: Bool do return button == 3
320
321 # Is this event raised by the middle button?
322 fun is_middle_button: Bool do return button == 2
323
324 # Is this event raised by the wheel going down?
325 fun is_down_wheel: Bool do return button == 4
326
327 # Is this event raised by the wheel going up?
328 fun is_up_wheel: Bool do return button == 5
329
330 # Is this event raised by the wheel?
331 fun is_wheel: Bool do return is_down_wheel or is_up_wheel
332
333 init (x, y: Float, button: Int, pressed: Bool)
334 do
335 super(x, y)
336
337 self.button = button
338 self.pressed = pressed
339 end
340
341 redef fun to_s
342 do
343 if pressed then
344 return "MouseButtonEvent button {button} down at {x}, {y}"
345 else
346 return "MouseButtonEvent button {button} up at {x}, {y}"
347 end
348 end
349 end
350
351 # MouseMotionEvent to get the cursor position when the mouse is moved
352 class SDLMouseMotionEvent
353 super SDLMouseEvent
354
355 var rel_x: Float
356 var rel_y: Float
357
358 redef var pressed: Bool
359 redef fun depressed: Bool do return not pressed
360
361 init (x, y, rel_x, rel_y: Float, pressed: Bool)
362 do
363 super(x, y)
364
365 self.rel_x = rel_x
366 self.rel_y = rel_y
367 self.pressed = pressed
368 end
369
370 redef fun to_s do return "MouseMotionEvent at {x}, {y}"
371 end
372
373 # SDLKeyEvent for when a key is pressed
374 class SDLKeyEvent
375 super KeyEvent
376 super SDLInputEvent
377
378 redef var name
379 var down: Bool
380
381 init (key_name: String, down: Bool)
382 do
383 self.name = key_name
384 self.down = down
385 end
386
387 redef fun to_c: nullable Char
388 do
389 if name.length == 1 then return name.chars.first
390 return null
391 end
392
393 redef fun to_s
394 do
395 if down then
396 return "KeyboardEvent key {name} down"
397 else
398 return "KeyboardEvent key {name} up"
399 end
400 end
401
402 # Return true if the key is down, false otherwise
403 redef fun is_down do return down
404
405 # Return true if the key is the up arrow
406 redef fun is_arrow_up do return name == "up"
407 # Return true if the key is the left arrow
408 redef fun is_arrow_left do return name == "left"
409 # Return true if the key is the down arrow
410 redef fun is_arrow_down do return name == "down"
411 # Return true if the key is the right arrow
412 redef fun is_arrow_right do return name == "right"
413 end
414
415 class SDLQuitEvent
416 super SDLInputEvent
417 super QuitEvent
418 end
419
420 redef class Int
421 fun delay `{ SDL_Delay(recv); `}
422 end
423
424 # Class to load and use TTF_Font
425 extern class SDLFont `{TTF_Font *`}
426 # Load a font with a specified name and size
427 new (name: String, points: Int) import String.to_cstring `{
428 char * cname = String_to_cstring(name);
429
430 TTF_Font *font = TTF_OpenFont(cname, (int)points);
431 if(!font) {
432 printf("TTF_OpenFont: %s\n", TTF_GetError());
433 exit(1);
434 }
435
436 return font;
437 `}
438
439 fun destroy `{ TTF_CloseFont(recv); `}
440
441 # Create a String with the specified color, return an SDLImage
442 fun render(text: String, r, g, b: Int): SDLImage import String.to_cstring `{
443 SDL_Color color;
444 SDL_Surface *text_surface;
445 char *ctext;
446
447 color.r = r;
448 color.g = g;
449 color.b = b;
450
451 ctext = String_to_cstring(text);
452 if(!(text_surface=TTF_RenderText_Blended(recv, ctext, color)))
453 {
454 fprintf(stderr, "SDL TFF error: %s\n", TTF_GetError());
455 exit(1);
456 }
457 else
458 return text_surface;
459 `}
460
461 # TODO reactivate fun below when updating libsdl_ttf to 2.0.10 or above
462 #fun outline: Int # TODO check to make inline/nitside only
463 #fun outline=(v: Int) is extern
464
465 #fun kerning: Bool is extern
466 #fun kerning=(v: Bool) is extern
467
468 # Maximum pixel height of all glyphs of this font.
469 fun height: Int `{
470 return TTF_FontHeight(recv);
471 `}
472
473 fun ascent: Int `{
474 return TTF_FontAscent(recv);
475 `}
476
477 fun descent: Int `{
478 return TTF_FontDescent(recv);
479 `}
480
481 # Get the recommended pixel height of a rendered line of text of the loaded font. This is usually larger than the Font.height.
482 fun line_skip: Int `{
483 return TTF_FontLineSkip(recv);
484 `}
485
486 # Return true is the font used fixed width for each char
487 fun is_fixed_width: Bool `{
488 return TTF_FontFaceIsFixedWidth(recv);
489 `}
490
491 # Return the family name of the font
492 fun family_name: nullable String import String.to_cstring, String.as nullable `{
493 char *fn = TTF_FontFaceFamilyName(recv);
494
495 if (fn == NULL)
496 return null_String();
497 else
498 return String_as_nullable(NativeString_to_s(fn));
499 `}
500
501 # Return the style name of the font
502 fun style_name: nullable String import String.to_cstring, String.as nullable `{
503 char *sn = TTF_FontFaceStyleName(recv);
504
505 if (sn == NULL)
506 return null_String();
507 else
508 return String_as_nullable(NativeString_to_s(sn));
509 `}
510
511 # Return the estimated width of a String if used with the current font
512 fun width_of(text: String): Int import NativeString.to_s `{
513 char *ctext = String_to_cstring(text);
514 int w;
515 if (TTF_SizeText(recv, ctext, &w, NULL))
516 {
517 fprintf(stderr, "SDL TFF error: %s\n", TTF_GetError());
518 exit(1);
519 }
520 else
521 return w;
522 `}
523 end
524
525 # Information on the SDL window
526 # Used in other modules to get window handle
527 extern class SDLSystemWindowManagerInfo `{SDL_SysWMinfo *`}
528
529 new `{
530 SDL_SysWMinfo *val = malloc(sizeof(SDL_SysWMinfo));
531
532 SDL_VERSION(&val->version);
533
534 if(SDL_GetWMInfo(val) <= 0) {
535 printf("Unable to get window handle");
536 return 0;
537 }
538
539 return val;
540 `}
541
542 # Returns the handle of this window on a X11 window system
543 fun x11_window_handle: Pointer `{
544 return (void*)recv->info.x11.window;
545 `}
546 end