1 /*
2 DSFML - The Simple and Fast Multimedia Library for D
3 
4 Copyright (c) 2013 - 2015 Jeremy DeHaan (dehaan.jeremiah@gmail.com)
5 
6 This software is provided 'as-is', without any express or implied warranty.
7 In no event will the authors be held liable for any damages arising from the use of this software.
8 
9 Permission is granted to anyone to use this software for any purpose, including commercial applications,
10 and to alter it and redistribute it freely, subject to the following restrictions:
11 
12 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
13 If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
14 
15 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
16 
17 3. This notice may not be removed or altered from any source distribution
18 */
19 
20 module dsfml.window.window;
21 
22 import dsfml.window.event;
23 import dsfml.window.videomode;
24 import dsfml.window.contextsettings;
25 import dsfml.window.windowhandle;
26 import dsfml.system.vector2;
27 import dsfml.system.err;
28 
29 /**
30  *Window that serves as a target for OpenGL rendering.
31  *
32  *Window is the main class of the Window module.
33  *
34  *It defines an OS window that is able to receive an OpenGL rendering.
35  *
36  *A Window can create its own new window, or be embedded into an already existing control using the create(handle) function. This can be useful for embedding an OpenGL rendering area into a view which is part of a bigger GUI with existing windows, controls, etc. It can also serve as embedding an OpenGL rendering area into a window created by another (probably richer) GUI library like Qt or wxWidgets.
37  *
38  *The Window class provides a simple interface for manipulating the window: move, resize, show/hide, control mouse cursor, etc. It also provides event handling through its pollEvent() and waitEvent() functions.
39  *
40  *Note that OpenGL experts can pass their own parameters (antialiasing level, bits for the depth and stencil buffers, etc.) to the OpenGL context attached to the window, with the ContextSettings structure which is passed as an optional argument when creating the window.
41  */
42 class Window
43 {
44 	//Choices for window style
45 	enum Style
46 	{
47 		None = 0,
48 		Titlebar = 1 << 0,
49 		Resize = 1 << 1,
50 		Close = 1 << 2,
51 		Fullscreen = 1 << 3,
52 		DefaultStyle = Titlebar | Resize | Close
53 	}
54 
55 	package sfWindow* sfPtr;
56 
57 	private bool m_needsToDelete = true;
58 
59 	//Default constructor
60 	this()
61 	{
62 		sfPtr = sfWindow_construct();
63 	}
64 
65 	//Construct a window without calling sfWindow_construct
66 	//This allows a RenderWindow to be created without creating a Window first
67 	protected this(int)
68 	{
69 		m_needsToDelete = false;
70 	}
71 
72 	//allows RenderWindow to delete the Window pointer when it is created
73 	//so that there are not both instances.
74 	protected void deleteWindowPtr()
75 	{
76 		sfWindow_destroy(sfPtr);
77 		m_needsToDelete = false;
78 	}
79 	
80 	//TODO: Reduce to one constructor with a template parameter for the string types. Use sfWindow_createUnicode in case it has unicode in the title.
81 
82 	//in order to envoke this constructor when using string literals, be sure to use the d suffix, i.e. "素晴らしい !"d
83 
84 	///Construct a new window.
85 	///
86 	///This constructor creates the window with the size and pixel depth defined in mode. An optional style can be passed to customize the look and behaviour of the window (borders, title bar, resizable, closable, ...). If style contains Style::Fullscreen, then mode must be a valid video mode.
87 	///
88 	///The fourth parameter is an optional structure specifying advanced OpenGL context settings such as antialiasing, depth-buffer bits, etc.
89 	///
90 	///Params:
91 	///   	mode = Video mode to use (defines the width, height and depth of the rendering area of the window).
92 	///  	title = Title of the window.
93 	///   	style = Window style.
94 	///    	settings = Additional settings for the underlying OpenGL context.
95 	this(T)(VideoMode mode, immutable(T)[] title, Style style = Style.DefaultStyle, ref const(ContextSettings) settings = ContextSettings.Default)
96 		if (is(T == dchar)||is(T == wchar)||is(T == char))
97 	{
98 		import dsfml.system.string;
99 
100 		this();
101 		create(mode, title, style, settings);
102 	}
103 
104 	///Construct the window from an existing control.
105 	///
106 	///Use this constructor if you want to create an OpenGL rendering area into an already existing control.
107 	///
108 	///The second parameter is an optional structure specifying advanced OpenGL context settings such as antialiasing, depth-buffer bits, etc.
109 	///
110 	///Params:
111     ///		handle = Platform-specific handle of the control.
112     ///		settings = Additional settings for the underlying OpenGL context.
113 	this(WindowHandle handle, ref const(ContextSettings) settings = ContextSettings.Default)
114 	{
115 		this();
116 		create(handle, settings);
117 	}
118 	
119 	~this()
120 	{
121 		import dsfml.system.config;
122 		//this takes care of not freeing a null pointer due to inheritance
123 		//(RenderWindow does not create the inherited sfWindow)
124 		if(m_needsToDelete)
125 		{
126 			mixin(destructorOutput);
127 			sfWindow_destroy(sfPtr);
128 		}
129 	}
130 
131 	///Get's or set's the window's position.
132 	///
133 	///This function only works for top-level windows (i.e. it will be ignored for windows created from the handle of a child window/control).
134 	@property
135 	{
136 		Vector2i position(Vector2i newPosition)
137 		{
138 			sfWindow_setPosition(sfPtr,newPosition.x, newPosition.y);
139 			return newPosition;
140 		}
141 		
142 		Vector2i position()
143 		{
144 			Vector2i temp;
145 			sfWindow_getPosition(sfPtr,&temp.x, &temp.y);
146 			return temp;
147 		}
148 	}
149 	
150 	///Get's or set's the window's size.
151 	@property
152 	{
153 		Vector2u size(Vector2u newSize)
154 		{
155 			sfWindow_setSize(sfPtr, newSize.x, newSize.y);
156 			return newSize;
157 		}
158 		Vector2u size()
159 		{
160 			Vector2u temp;
161 			sfWindow_getSize(sfPtr,&temp.x, &temp.y);
162 			return temp;
163 		}
164 	}
165 
166 	///Activate or deactivate the window as the current target for OpenGL rendering.
167 	///
168 	///A window is active only on the current thread, if you want to make it active on another thread you have to deactivate it on the previous thread first if it was active. Only one window can be active on a thread at a time, thus the window previously active (if any) automatically gets deactivated.
169 	///
170 	///Params:
171     ///		active = True to activate, false to deactivate.
172     ///
173 	///Returns: True if operation was successful, false otherwise.
174 	bool setActive(bool active)
175 	{
176 		import dsfml.system.string;
177 		bool toReturn = sfWindow_setActive(sfPtr, active);
178 		err.write(dsfml.system..string.toString(sfErr_getOutput()));
179 		return toReturn;
180 	}
181 
182 	///Limit the framerate to a maximum fixed frequency.
183 	///
184 	///If a limit is set, the window will use a small delay after each call to display() to ensure that the current frame lasted long enough to match the framerate limit. SFML will try to match the given limit as much as it can, but since it internally uses sf::sleep, whose precision depends on the underlying OS, the results may be a little unprecise as well (for example, you can get 65 FPS when requesting 60).
185 	///
186 	///Params:
187     ///		limit = Framerate limit, in frames per seconds (use 0 to disable limit).
188 	void setFramerateLimit(uint limit)
189 	{
190 		sfWindow_setFramerateLimit(sfPtr, limit);
191 	}
192 
193 	///Change the window's icon.
194 	///
195 	///pixels must be an array of width x height pixels in 32-bits RGBA format.
196 	///
197 	///The OS default icon is used by default.
198 	///
199 	///Params:
200 	///    width = Icon's width, in pixels.
201 	///    height = Icon's height, in pixels.
202 	///    pixels = Pointer to the array of pixels in memory.
203 	void setIcon(uint width, uint height, const(ubyte[]) pixels)
204 	{
205 		sfWindow_setIcon(sfPtr,width, height, pixels.ptr);
206 	}
207 
208 	///Change the joystick threshold.
209 	///
210 	///The joystick threshold is the value below which no JoystickMoved event will be generated.
211 	///
212 	///The threshold value is 0.1 by default.
213 	///
214 	///Params:
215 	///    threshold = New threshold, in the range [0, 100].
216 	void setJoystickThreshhold(float threshhold)
217 	{
218 		sfWindow_setJoystickThreshold(sfPtr, threshhold);
219 	}
220 
221 	///Enable or disable automatic key-repeat.
222 	///
223 	///If key repeat is enabled, you will receive repeated KeyPressed events while keeping a key pressed. If it is disabled, you will only get a single event when the key is pressed.
224 	///
225 	///Key repeat is enabled by default.
226 	///
227 	///Params:
228 	///    enabled = True to enable, false to disable.
229 	void setKeyRepeatEnabled(bool enabled)
230 	{
231 		enabled ? sfWindow_setKeyRepeatEnabled(sfPtr,true):sfWindow_setKeyRepeatEnabled(sfPtr,false);
232 	}
233 
234 	///Show or hide the mouse cursor.
235 	///
236 	///The mouse cursor is visible by default.
237 	///
238 	///Params:
239     ///		visible = True to show the mouse cursor, false to hide it.
240 	void setMouseCursorVisible(bool visible)
241 	{
242 		visible ? sfWindow_setMouseCursorVisible(sfPtr,true): sfWindow_setMouseCursorVisible(sfPtr,false);
243 	}
244 
245 	//Cannot use templates here as template member functions cannot be virtual.
246 
247 	///Change the title of the window.
248 	///
249 	///Params:
250     ///		title = New title.
251 	void setTitle(string newTitle)
252 	{
253 		import dsfml.system.string;
254 		sfWindow_setUnicodeTitle(sfPtr, toStringz(stringConvert!(char, dchar)(newTitle)));
255 	}
256 	///Change the title of the window.
257 	///
258 	///Params:
259     ///		title = New title.
260 	void setTitle(wstring newTitle)
261 	{
262 		import dsfml.system.string;
263 		sfWindow_setUnicodeTitle(sfPtr, toStringz(stringConvert!(wchar, dchar)(newTitle)));
264 	}
265 	///Change the title of the window.
266 	///
267 	///Params:
268     ///		title = New title.
269 	void setTitle(dstring newTitle)
270 	{
271 		import dsfml.system.string;
272 		sfWindow_setUnicodeTitle(sfPtr, toStringz(newTitle));
273 	}
274 
275 	///Show or hide the window.
276 	///
277 	///The window is shown by default.
278 	///
279 	///Params:
280 	///    visible = True to show the window, false to hide it.
281 	void setVisible(bool visible)
282 	{
283 		sfWindow_setVisible(sfPtr,visible);
284 	}
285 	
286 	///Enable or disable vertical synchronization.
287 	///
288 	///Activating vertical synchronization will limit the number of frames displayed to the refresh rate of the monitor. This can avoid some visual artifacts, and limit the framerate to a good value (but not constant across different computers).
289 	///
290 	///Vertical synchronization is disabled by default.
291 	///
292 	///Params:
293 	///    enabled = True to enable v-sync, false to deactivate it.
294 	void setVerticalSyncEnabled(bool enabled)
295 	{
296 		enabled ? sfWindow_setVerticalSyncEnabled(sfPtr, true): sfWindow_setVerticalSyncEnabled(sfPtr, false);
297 	}
298 
299 	///Get the settings of the OpenGL context of the window.
300 	///
301 	///Note that these settings may be different from what was passed to the constructor or the create() function, if one or more settings were not supported. In this case, SFML chose the closest match.
302 	///
303 	///Returns: Structure containing the OpenGL context settings.
304 	ContextSettings getSettings() const
305 	{
306 		ContextSettings temp;
307 		sfWindow_getSettings(sfPtr,&temp.depthBits, &temp.stencilBits, &temp.antialiasingLevel, &temp.majorVersion, &temp.minorVersion);
308 		return temp;
309 	}
310 
311 	///Get the OS-specific handle of the window.
312 	///
313 	///The type of the returned handle is sf::WindowHandle, which is a typedef to the handle type defined by the OS. You shouldn't need to use this function, unless you have very specific stuff to implement that SFML doesn't support, or implement a temporary workaround until a bug is fixed.
314 	///
315 	///Returns: System handle of the window.
316 	WindowHandle getSystemHandle() const
317 	{
318 		return sfWindow_getSystemHandle(sfPtr);
319 	}
320 
321 	//TODO: Consider adding these methods.
322 	//void onCreate
323 	//void onResize
324 
325 	///Close the window and destroy all the attached resources.
326 	///
327 	///After calling this function, the Window instance remains valid and you can call create() to recreate the window. All other functions such as pollEvent() or display() will still work (i.e. you don't have to test isOpen() every time), and will have no effect on closed windows.
328 	void close()
329 	{
330 		sfWindow_close(sfPtr);
331 	}
332 
333 	//Cannot use templates here as template member functions cannot be virtual.
334 
335 	///Create (or recreate) the window.
336 	///
337 	///If the window was already created, it closes it first. If style contains Style::Fullscreen, then mode must be a valid video mode.
338 	///
339 	///The fourth parameter is an optional structure specifying advanced OpenGL context settings such as antialiasing, depth-buffer bits, etc.
340 	void create(VideoMode mode, string title, Style style = Style.DefaultStyle, ref const(ContextSettings) settings = ContextSettings.Default)
341 	{
342 		import dsfml.system.string;
343 		sfWindow_createFromSettings(sfPtr, mode.width, mode.height, mode.bitsPerPixel, toStringz(stringConvert!(char,dchar)(title)), style, settings.depthBits, settings.stencilBits, settings.antialiasingLevel, settings.majorVersion, settings.minorVersion);
344 		err.write(dsfml.system..string.toString(sfErr_getOutput()));
345 	}
346 	///Create (or recreate) the window.
347 	///
348 	///If the window was already created, it closes it first. If style contains Style::Fullscreen, then mode must be a valid video mode.
349 	///
350 	///The fourth parameter is an optional structure specifying advanced OpenGL context settings such as antialiasing, depth-buffer bits, etc.
351 	void create(VideoMode mode, wstring title, Style style = Style.DefaultStyle, ref const(ContextSettings) settings = ContextSettings.Default)
352 	{
353 		import dsfml.system.string;
354 		sfWindow_createFromSettings(sfPtr, mode.width, mode.height, mode.bitsPerPixel, toStringz(stringConvert!(wchar,dchar)(title)), style, settings.depthBits, settings.stencilBits, settings.antialiasingLevel, settings.majorVersion, settings.minorVersion);
355 		err.write(dsfml.system..string.toString(sfErr_getOutput()));
356 	}
357 	///Create (or recreate) the window.
358 	///
359 	///If the window was already created, it closes it first. If style contains Style::Fullscreen, then mode must be a valid video mode.
360 	///
361 	///The fourth parameter is an optional structure specifying advanced OpenGL context settings such as antialiasing, depth-buffer bits, etc.
362 	void create(VideoMode mode, dstring title, Style style = Style.DefaultStyle, ref const(ContextSettings) settings = ContextSettings.Default)
363 	{
364 		import dsfml.system.string;
365 		sfWindow_createFromSettings(sfPtr, mode.width, mode.height, mode.bitsPerPixel, toStringz(title), style, settings.depthBits, settings.stencilBits, settings.antialiasingLevel, settings.majorVersion, settings.minorVersion);
366 		err.write(dsfml.system..string.toString(sfErr_getOutput()));
367 	}
368 
369 	///Create (or recreate) the window from an existing control.
370 	///
371 	///Use this function if you want to create an OpenGL rendering area into an already existing control. If the window was already created, it closes it first.
372 	///
373 	///The second parameter is an optional structure specifying advanced OpenGL context settings such as antialiasing, depth-buffer bits, etc.
374 	void create(WindowHandle handle, ref const(ContextSettings) settings = ContextSettings.Default)
375 	{
376 		import dsfml.system.string;
377 		sfWindow_createFromHandle(sfPtr, handle, settings.depthBits,settings.stencilBits, settings.antialiasingLevel, settings.majorVersion, settings.minorVersion);
378 		err.write(dsfml.system..string.toString(sfErr_getOutput()));
379 	}
380 
381 	///Display on screen what has been rendered to the window so far.
382 	///
383 	///This function is typically called after all OpenGL rendering has been done for the current frame, in order to show it on screen.
384 	void display()
385 	{
386 		sfWindow_display(sfPtr);
387 	}
388 
389 	///Tell whether or not the window is open.
390 	///
391 	///This function returns whether or not the window exists. Note that a hidden window (setVisible(false)) is open (therefore this function would return true).
392 	///
393 	///Returns: True if the window is open, false if it has been closed.
394 	bool isOpen()
395 	{
396 		return (sfWindow_isOpen(sfPtr));
397 	}
398 
399 	///Pop the event on top of the event queue, if any, and return it.
400 	///
401 	///This function is not blocking: if there's no pending event then it will return false and leave event unmodified. Note that more than one event may be present in the event queue, thus you should always call this function in a loop to make sure that you process every pending event. 
402 	///
403 	///Params:
404     ///		event = Event to be returned.
405     ///
406 	///Returns: True if an event was returned, or false if the event queue was empty.
407 	bool pollEvent(ref Event event)
408 	{
409 		return (sfWindow_pollEvent(sfPtr, &event));
410 	}
411 	
412 	///Wait for an event and return it.
413 	///
414 	///This function is blocking: if there's no pending event then it will wait until an event is received. After this function returns (and no error occured), the event object is always valid and filled properly. This function is typically used when you have a thread that is dedicated to events handling: you want to make this thread sleep as long as no new event is received. 
415 	///
416 	///Params:
417     ///		event = Event to be returned.
418     ///
419 	///Returns: False if any error occured.
420 	bool waitEvent(ref Event event)
421 	{
422 		return (sfWindow_waitEvent(sfPtr, &event));
423 	}
424 
425 	//TODO: Clean this shit up. The names are so bad. :(
426 
427 	//Gives a way for RenderWindow to send its mouse position 
428 	protected Vector2i getMousePosition()const
429 	{
430 		Vector2i temp;
431 		sfMouse_getPosition(sfPtr,&temp.x, &temp.y);
432 		return temp;
433 	}
434 
435 	//A method for the Mouse class to use in order to get the mouse position relative to the window
436 	package Vector2i mouse_getPosition()const
437 	{
438 		return getMousePosition();
439 	}
440 
441 	//Gives a way for Render Window to set its mouse position
442 	protected void setMousePosition(Vector2i pos) const
443 	{
444 		sfMouse_setPosition(pos.x, pos.y, sfPtr);
445 	}
446 
447 	//A method for the mouse class to use
448 	package void mouse_SetPosition(Vector2i pos) const
449 	{
450 		setMousePosition(pos);
451 	}
452 
453 	//Circumvents the package restriction allowing Texture to get the internal pointer
454 	protected static void* getWindowPointer(Window window)
455 	{
456 		return window.sfPtr;
457 	}
458 
459 	
460 }
461 
462 unittest
463 {
464 	version(DSFML_Unittest_Window)
465 	{
466 		import std.stdio;
467 		import dsfml.graphics.image;
468 
469 		writeln("Unit test for Window class.");
470 
471 
472 		//constructor
473 		auto window = new Window(VideoMode(800,600),"Test Window");
474 
475 		//perform each window call
476 		Vector2u windowSize = window.size;
477 
478 		windowSize.x = 1000;
479 		windowSize.y = 1000;
480 
481 		window.size = windowSize;
482 
483 		Vector2i windowPosition = window.position;
484 
485 		windowPosition.x = 100;
486 		windowPosition.y = 100;
487 
488 		window.position = windowPosition;
489 
490 		window.setTitle("thing");//uses the first set title
491 
492 		window.setTitle("素晴らしい !");//forces the dstring override and uses unicode
493 
494 		window.setActive(true);
495 
496 		window.setJoystickThreshhold(1);
497 
498 		window.setVisible(true);
499 
500 		window.setFramerateLimit(60);
501 
502 		window.setMouseCursorVisible(true);
503 
504 		window.setVerticalSyncEnabled(true);
505 
506 		auto settings = window.getSettings();
507 
508 		auto image = new Image();
509 		image.loadFromFile("res/TestImage.png");
510 
511 		window.setIcon(image.getSize().x,image.getSize().x,image.getPixelArray());
512 
513 		if(window.isOpen())
514 		{
515 			Event event;
516 			if(window.pollEvent(event))
517 			{
518 
519 			}
520 			//requires users input
521 			if(window.waitEvent(event))
522 			{
523 
524 			}
525 
526 			window.display();
527 		}
528 
529 		window.close();
530 
531 	}
532 }
533 
534 
535 package extern(C) struct sfWindow;
536 
537 private extern(C):
538 
539 	//Construct a new window
540 	sfWindow* sfWindow_construct();
541 
542 	//Construct a new window (with a UTF-32 title)
543 	void sfWindow_createFromSettings(sfWindow* window, uint width, uint height, uint bitsPerPixel, const(dchar)* title, int style, uint depthBits, uint stencilBits, uint antialiasingLevel, uint majorVersion, uint minorVersion);
544 
545 	//Construct a window from an existing control
546 	void sfWindow_createFromHandle(sfWindow* window, WindowHandle handle, uint depthBits, uint stencilBits, uint antialiasingLevel, uint majorVersion, uint minorVersion);
547 
548 	// Destroy a window
549 	void sfWindow_destroy(sfWindow* window);
550 
551 	//Close a window and destroy all the attached resources
552 	void sfWindow_close(sfWindow* window);
553 
554 	//Tell whether or not a window is opened
555 	bool sfWindow_isOpen(const(sfWindow)* window);
556 
557 	//Get the settings of the OpenGL context of a window
558 	void sfWindow_getSettings(const(sfWindow)* window, uint* depthBits, uint* stencilBits, uint* antialiasingLevel, uint* majorVersion, uint* minorVersion);
559 
560 	//Pop the event on top of event queue, if any, and return it
561 	bool sfWindow_pollEvent(sfWindow* window, Event* event);
562 
563 	//Wait for an event and return it
564 	bool sfWindow_waitEvent(sfWindow* window, Event* event);
565 
566 	//Get the position of a window
567 	void sfWindow_getPosition(const(sfWindow)* window, int* x, int* y);
568 
569 	//Change the position of a window on screen
570 	void sfWindow_setPosition(sfWindow* window, int x, int y);
571 
572 	//Get the size of the rendering region of a window
573 	void sfWindow_getSize(const(sfWindow)* window, uint* width, uint* height);
574 
575 	//Change the size of the rendering region of a window
576 	void sfWindow_setSize(sfWindow* window, uint width, uint height);
577 
578 	//Change the title of a window
579 	void sfWindow_setTitle(sfWindow* window, const(char)* title);
580 
581 	//Change the title of a window (with a UTF-32 string)
582 	void sfWindow_setUnicodeTitle(sfWindow* window, const(dchar)* title);
583 
584 	//Change a window's icon
585 	void sfWindow_setIcon(sfWindow* window, uint width, uint height, const(ubyte)* pixels);
586 
587 	//Show or hide a window
588 	void sfWindow_setVisible(sfWindow* window, bool visible);
589 
590 	//Show or hide the mouse cursor
591 	void sfWindow_setMouseCursorVisible(sfWindow* window, bool visible);
592 
593 	//Enable or disable vertical synchronization
594 	 void sfWindow_setVerticalSyncEnabled(sfWindow* window, bool enabled);
595 
596 	//Enable or disable automatic key-repeat
597 	 void sfWindow_setKeyRepeatEnabled(sfWindow* window, bool enabled);
598 
599 	//Activate or deactivate a window as the current target for OpenGL rendering
600 	 bool sfWindow_setActive(sfWindow* window, bool active);
601 
602 	//Display on screen what has been rendered to the window so far
603 	 void sfWindow_display(sfWindow* window);
604 
605 	//Limit the framerate to a maximum fixed frequency
606 	 void sfWindow_setFramerateLimit(sfWindow* window, uint limit);
607 
608 	//Change the joystick threshold
609 	 void sfWindow_setJoystickThreshold(sfWindow* window, float threshold);
610 	
611 	
612 	//Get the OS-specific handle of the window
613 	 WindowHandle sfWindow_getSystemHandle(const(sfWindow)* window);
614 
615 	void sfMouse_getPosition(const(sfWindow)* relativeTo, int* x, int* y);
616 	void sfMouse_setPosition(int x, int y, const(sfWindow)* relativeTo);
617 
618 	const(char)* sfErr_getOutput();
619 
620 
621