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