1 module nudsfml.window.window; 2 3 import bindbc.sfml.window; 4 import bindbc.sfml.system; 5 6 7 import nudsfml.window.event; 8 import nudsfml.window.keyboard; 9 import nudsfml.window.mouse; 10 import nudsfml.window.videomode; 11 import nudsfml.window.contextsettings; 12 import nudsfml.window.windowhandle; 13 import nudsfml.system.vector2; 14 //import nudsfml.system.err; 15 16 /** 17 * Window that serves as a target for OpenGL rendering. 18 */ 19 class Window { 20 /// Choices for window style 21 enum Style { 22 None = 0, 23 Titlebar = 1 << 0, 24 Resize = 1 << 1, 25 Close = 1 << 2, 26 Fullscreen = 1 << 3, 27 DefaultStyle = Titlebar | Resize | Close 28 } 29 30 package sfWindow* sfPtr; 31 32 //let's RenderWindow inherit from Window without trying to delete the null 33 //pointer 34 private bool m_needsToDelete = true; 35 36 /// Default constructor. 37 this() { 38 sfPtr = null; //sfWindow_construct(); 39 } 40 41 //Construct a window without calling sfWindow_construct 42 //This allows a RenderWindow to be created without creating a Window first 43 protected this(int){ 44 m_needsToDelete = false; 45 } 46 47 //allows RenderWindow to delete the Window pointer when it is created 48 //so that there are not both instances. 49 protected void deleteWindowPtr() { 50 sfWindow_destroy(sfPtr); 51 m_needsToDelete = false; 52 } 53 54 /** 55 * Construct a new window. 56 * 57 * This constructor creates the window with the size and pixel depth defined 58 * in mode. An optional style can be passed to customize the look and 59 * behaviour of the window (borders, title bar, resizable, closable, ...). 60 * If style contains Style::Fullscreen, then mode must be a valid video 61 * mode. 62 * 63 * The fourth parameter is an optional structure specifying advanced OpenGL 64 * context settings such as antialiasing, depth-buffer bits, etc. 65 * 66 * Params: 67 * mode = Video mode to use (defines the width, height and depth of the 68 * rendering area of the window) 69 * title = Title of the window 70 * style = Window style 71 * settings = Additional settings for the underlying OpenGL context 72 */ 73 this(T)(VideoMode mode, immutable(T)[] title, Style style = Style.DefaultStyle, ContextSettings settings = ContextSettings.init) 74 if (is(T == dchar)||is(T == wchar)||is(T == char)) 75 { 76 this(); 77 create(mode, title, style, settings); 78 } 79 80 /** 81 * Construct the window from an existing control. 82 * 83 * Use this constructor if you want to create an OpenGL rendering area into 84 * an already existing control. 85 * 86 * The second parameter is an optional structure specifying advanced OpenGL 87 * context settings such as antialiasing, depth-buffer bits, etc. 88 * 89 * Params: 90 * handle = Platform-specific handle of the control 91 * settings = Additional settings for the underlying OpenGL context 92 */ 93 this(WindowHandle handle, ContextSettings settings = ContextSettings.init){ 94 this(); 95 create(handle, settings); 96 } 97 98 /// Destructor. 99 ~this() { 100 import nudsfml.system.config; 101 //this takes care of not freeing a null pointer due to inheritance 102 //(RenderWindow does not create the inherited sfWindow) 103 if(m_needsToDelete) { 104 mixin(destructorOutput); 105 if(sfPtr !is null) 106 sfWindow_destroy(sfPtr); 107 } 108 } 109 110 @property { 111 /** 112 * Get's or set's the window's position. 113 * 114 * This function only works for top-level windows (i.e. it will be ignored 115 * for windows created from the handle of a child window/control). 116 */ 117 Vector2i position(Vector2i newPosition) { 118 sfVector2i pos = cast(sfVector2i)(newPosition); 119 sfWindow_setPosition(sfPtr,pos); 120 return newPosition; 121 } 122 123 /// ditto 124 Vector2i position() const{ 125 Vector2i temp = cast(Vector2i) sfWindow_getPosition(sfPtr); 126 return temp; 127 } 128 } 129 130 @property { 131 /// Get's or set's the window's size. 132 Vector2u size(Vector2u newSize) { 133 sfVector2u temp = cast(sfVector2u)(newSize); 134 sfWindow_setSize(sfPtr, temp); 135 return newSize; 136 } 137 138 // ditto 139 Vector2u size() const { 140 Vector2u temp = cast(Vector2u) sfWindow_getSize(sfPtr); 141 return temp; 142 } 143 } 144 145 /** 146 * Activate or deactivate the window as the current target for OpenGL 147 * rendering. 148 * 149 * A window is active only on the current thread, if you want to make it 150 * active on another thread you have to deactivate it on the previous thread 151 * first if it was active. Only one window can be active on a thread at a 152 * time, thus the window previously active (if any) automatically gets 153 * deactivated. 154 * 155 * Params: 156 * active = true to activate, false to deactivate 157 * 158 * Returns: true if operation was successful, false otherwise. 159 */ 160 bool setActive(bool active) { 161 int sfbool = active ? 1 : 0; 162 return sfWindow_setActive(sfPtr, cast(sfBool) sfbool) > 0; 163 } 164 165 ///Request the current window to be made the active foreground window. 166 void requestFocus() { 167 sfWindow_requestFocus(sfPtr); 168 } 169 170 /** 171 * Check whether the window has the input focus 172 * 173 * Returns: true if the window has focus, false otherwise 174 */ 175 bool hasFocus() const { 176 return sfWindow_hasFocus(sfPtr) > 0; 177 } 178 179 /** 180 * Limit the framerate to a maximum fixed frequency. 181 * 182 * If a limit is set, the window will use a small delay after each call to 183 * display() to ensure that the current frame lasted long enough to match 184 * the framerate limit. SFML will try to match the given limit as much as it 185 * can, but since it internally usesnudsfml.system.sleep, whose precision 186 * depends on the underlying OS, the results may be a little unprecise as 187 * well (for example, you can get 65 FPS when requesting 60). 188 * 189 * Params: 190 * limit = Framerate limit, in frames per seconds (use 0 to disable limit). 191 */ 192 void setFramerateLimit(uint limit) { 193 sfWindow_setFramerateLimit(sfPtr, limit); 194 } 195 196 /** 197 * Change the window's icon. 198 * 199 * pixels must be an array of width x height pixels in 32-bits RGBA format. 200 * 201 * The OS default icon is used by default. 202 * 203 * Params: 204 * width = Icon's width, in pixels 205 * height = Icon's height, in pixels 206 * pixels = Pointer to the array of pixels in memory 207 */ 208 void setIcon(uint width, uint height, const(ubyte[]) pixels) { 209 sfWindow_setIcon(sfPtr,width, height, pixels.ptr); 210 } 211 212 /** 213 * Change the joystick threshold. 214 * 215 * The joystick threshold is the value below which no JoystickMoved event 216 * will be generated. 217 * 218 * The threshold value is 0.1 by default. 219 * 220 * Params: 221 * threshold = New threshold, in the range [0, 100]. 222 */ 223 void setJoystickThreshold(float threshold) { 224 sfWindow_setJoystickThreshold(sfPtr, threshold); 225 } 226 227 /** 228 * Change the joystick threshold. 229 * 230 * The joystick threshold is the value below which no JoystickMoved event 231 * will be generated. 232 * 233 * The threshold value is 0.1 by default. 234 * 235 * Params: 236 * threshhold = New threshold, in the range [0, 100]. 237 * 238 * //deprecated: Use set `setJoystickThreshold` instead. 239 */ 240 //deprecated("Use setJoystickThreshold instead.") 241 void setJoystickThreshhold(float threshhold) { 242 sfWindow_setJoystickThreshold(sfPtr, threshhold); 243 } 244 245 /** 246 * Enable or disable automatic key-repeat. 247 * 248 * If key repeat is enabled, you will receive repeated KeyPressed events 249 * while keeping a key pressed. If it is disabled, you will only get a 250 * single event when the key is pressed. 251 * 252 * Key repeat is enabled by default. 253 * 254 * Params: 255 * enabled = true to enable, false to disable. 256 */ 257 void setKeyRepeatEnabled(bool enabled) { 258 sfWindow_setKeyRepeatEnabled(sfPtr, enabled); 259 } 260 261 /** 262 * Show or hide the mouse cursor. 263 * 264 * The mouse cursor is visible by default. 265 * 266 * Params: 267 * visible = true to show the mouse cursor, false to hide it. 268 */ 269 void setMouseCursorVisible(bool visible) { 270 sfWindow_setMouseCursorVisible(sfPtr, visible); 271 } 272 273 //Cannot use templates here as template member functions cannot be virtual. 274 275 /** 276 * Change the title of the window. 277 * 278 * Params: 279 * newTitle = New title 280 * 281 * //deprecated: Use the version of setTitle that takes a 'const(dchar)[]'. 282 */ 283 //deprecated("Use the version of setTitle that takes a 'const(dchar)[]'.") 284 void setTitle(const(char)[] newTitle) { 285 import std.string; 286 sfWindow_setTitle(sfPtr, newTitle.toStringz); 287 } 288 289 /// ditto 290 //deprecated("Use the version of setTitle that takes a 'const(dchar)[]'.") 291 void setTitle(const(wchar)[] newTitle) { 292 import std.utf; 293 sfWindow_setUnicodeTitle(sfPtr, cast(uint*) newTitle.toUTFz!(dchar*)); 294 } 295 296 /** 297 * Change the title of the window. 298 * 299 * Params: 300 * newTitle = New title 301 */ 302 void setTitle(const(dchar)[] newTitle) { 303 import std.utf; 304 sfWindow_setUnicodeTitle(sfPtr, cast(uint*) newTitle.toUTFz!(dchar*)); 305 } 306 307 /** 308 * Show or hide the window. 309 * 310 * The window is shown by default. 311 * 312 * Params: 313 * visible = true to show the window, false to hide it 314 */ 315 void setVisible(bool visible) 316 { 317 sfWindow_setVisible(sfPtr, visible); 318 } 319 320 /** 321 * Enable or disable vertical synchronization. 322 * 323 * Activating vertical synchronization will limit the number of frames 324 * displayed to the refresh rate of the monitor. This can avoid some visual 325 * artifacts, and limit the framerate to a good value (but not constant 326 * across different computers). 327 * 328 * Vertical synchronization is disabled by default. 329 * 330 * Params: 331 * enabled = true to enable v-sync, false to deactivate it 332 */ 333 void setVerticalSyncEnabled(bool enabled) 334 { 335 sfWindow_setVerticalSyncEnabled(sfPtr, enabled); 336 } 337 338 /** 339 * Get the settings of the OpenGL context of the window. 340 * 341 * Note that these settings may be different from what was passed to the 342 * constructor or the create() function, if one or more settings were not 343 * supported. In this case, SFML chose the closest match. 344 * 345 * Returns: Structure containing the OpenGL context settings. 346 */ 347 ContextSettings getSettings() const 348 { 349 sfContextSettings settings; 350 ContextSettings temp; 351 //sfWindow_getSettings(sfPtr,&temp.depthBits, &temp.stencilBits, &temp.antialiasingLevel, &temp.majorVersion, &temp.minorVersion); 352 settings = sfWindow_getSettings(sfPtr); 353 temp = cast(ContextSettings)settings; 354 return temp; 355 } 356 357 /** 358 * Get the OS-specific handle of the window. 359 * 360 * The type of the returned handle is sf::WindowHandle, which is a typedef 361 * to the handle type defined by the OS. You shouldn't need to use this 362 * function, unless you have very specific stuff to implement that SFML 363 * doesn't support, or implement a temporary workaround until a bug is 364 * fixed. 365 * 366 * Returns: System handle of the window. 367 */ 368 WindowHandle getSystemHandle() const 369 { 370 return cast(WindowHandle)sfWindow_getSystemHandle(sfPtr); 371 } 372 373 //TODO: Consider adding these methods. 374 //void onCreate 375 //void onResize 376 377 /** 378 * Close the window and destroy all the attached resources. 379 * 380 * After calling this function, the Window instance remains valid and you 381 * can call create() to recreate the window. All other functions such as 382 * pollEvent() or display() will still work (i.e. you don't have to test 383 * isOpen() every time), and will have no effect on closed windows. 384 */ 385 void close() 386 { 387 sfWindow_close(sfPtr); 388 } 389 390 //Cannot use templates here as template member functions cannot be virtual. 391 392 /** 393 * Create (or recreate) the window. 394 * 395 * If the window was already created, it closes it first. If style contains 396 * Style.Fullscreen, then mode must be a valid video mode. 397 * 398 * The fourth parameter is an optional structure specifying advanced OpenGL 399 * context settings such as antialiasing, depth-buffer bits, etc. 400 * 401 * //deprecated: Use the version of create that takes a 'const(dchar)[]'. 402 */ 403 //deprecated("Use the version of create that takes a 'const(dchar)[]'.") 404 void create(VideoMode mode, const(char)[] title, Style style = Style.DefaultStyle, ContextSettings settings = ContextSettings.init) 405 { 406 import std.utf: toUTF32; 407 import std.string; 408 //auto convertedTitle = toUTF32(title); 409 //sfWindow_createFromSettings(sfPtr, mode.width, mode.height, mode.bitsPerPixel, convertedTitle.ptr, convertedTitle.length, style, settings.depthBits, settings.stencilBits, settings.antialiasingLevel, settings.majorVersion, settings.minorVersion); 410 sfContextSettings sfSettings = cast(sfContextSettings)settings; 411 sfPtr = sfWindow_create(cast(sfVideoMode)mode, title.toStringz, cast(sfUint32)style, cast(sfContextSettings*)&sfSettings); 412 } 413 414 /// ditto 415 //deprecated("Use the version of create that takes a 'const(dchar)[]'.") 416 void create(VideoMode mode, const(wchar)[] title, Style style = Style.DefaultStyle, ContextSettings settings = ContextSettings.init) 417 { 418 import std.utf: toUTF32; 419 auto convertedTitle = toUTF32(title); 420 //sfWindow_createFromSettings(sfPtr, mode.width, mode.height, mode.bitsPerPixel, convertedTitle.ptr, convertedTitle.length, style, settings.depthBits, settings.stencilBits, settings.antialiasingLevel, settings.majorVersion, settings.minorVersion); 421 } 422 423 /** 424 * Create (or recreate) the window. 425 * 426 * If the window was already created, it closes it first. If style contains 427 * Style.Fullscreen, then mode must be a valid video mode. 428 * 429 * The fourth parameter is an optional structure specifying advanced OpenGL 430 * context settings such as antialiasing, depth-buffer bits, etc. 431 */ 432 void create(VideoMode mode, const(dchar)[] title, Style style = Style.DefaultStyle, ContextSettings settings = ContextSettings.init) 433 { 434 //sfWindow_createFromSettings(sfPtr, mode.width, mode.height, mode.bitsPerPixel, title.ptr, title.length, style, settings.depthBits, settings.stencilBits, settings.antialiasingLevel, settings.majorVersion, settings.minorVersion); 435 } 436 437 /// ditto 438 void create(WindowHandle handle, ContextSettings settings = ContextSettings.init) 439 { 440 sfWindowHandle sfHandle = cast(sfWindowHandle)handle; 441 sfContextSettings sfSettings = cast(sfContextSettings)settings; 442 sfPtr = sfWindow_createFromHandle(sfHandle, &sfSettings); 443 } 444 445 /** 446 * Display on screen what has been rendered to the window so far. 447 * 448 * This function is typically called after all OpenGL rendering has been 449 * done for the current frame, in order to show it on screen. 450 */ 451 void display() 452 { 453 sfWindow_display(sfPtr); 454 } 455 456 /** 457 * Tell whether or not the window is open. 458 * 459 * This function returns whether or not the window exists. Note that a 460 * hidden window (setVisible(false)) is open (therefore this function would 461 * return true). 462 * 463 * Returns: true if the window is open, false if it has been closed. 464 */ 465 bool isOpen() const 466 { 467 return (sfWindow_isOpen(sfPtr)) > 0; 468 } 469 470 /** 471 * Pop the event on top of the event queue, if any, and return it. 472 * 473 * This function is not blocking: if there's no pending event then it will 474 * return false and leave event unmodified. Note that more than one event 475 * may be present in the event queue, thus you should always call this 476 * function in a loop to make sure that you process every pending event. 477 * 478 * Params: 479 * event = Event to be returned. 480 * 481 * Returns: true if an event was returned, or false if the event queue was 482 * empty. 483 */ 484 bool pollEvent(ref Event event) 485 { 486 sfEvent sfevent; 487 bool retval = (sfWindow_pollEvent(sfPtr, &sfevent)) > 0; 488 event = fromSfEvent(sfevent); 489 return retval; 490 } 491 492 /** 493 * Wait for an event and return it. 494 * 495 * This function is blocking: if there's no pending event then it will wait 496 * until an event is received. After this function returns (and no error 497 * occured), the event object is always valid and filled properly. This 498 * function is typically used when you have a thread that is dedicated to 499 * events handling: you want to make this thread sleep as long as no new 500 * event is received. 501 * 502 * Params: 503 * event = Event to be returned 504 * 505 * Returns: False if any error occured. 506 */ 507 bool waitEvent(ref Event event) 508 { 509 sfEvent sfevent; 510 bool retval = (sfWindow_waitEvent(sfPtr, &sfevent)) > 0; 511 event = fromSfEvent(sfevent); 512 return retval; 513 } 514 515 //TODO: Clean this up. The names are so bad. :( 516 517 //Gives a way for RenderWindow to send its mouse position 518 protected Vector2i getMousePosition() const 519 { 520 Vector2i temp = cast(Vector2i)sfMouse_getPosition(sfPtr); 521 return temp; 522 } 523 524 //A method for the Mouse class to use in order to get the mouse position 525 //relative to the window 526 package Vector2i mouse_getPosition() const 527 { 528 return getMousePosition(); 529 } 530 531 //Gives a way for Render Window to set its mouse position 532 protected void setMousePosition(Vector2i pos) const 533 { 534 sfVector2i sfPos = cast(sfVector2i)pos; 535 sfMouse_setPosition(sfPos, sfPtr); 536 } 537 538 //A method for the mouse class to use 539 package void mouse_SetPosition(Vector2i pos) const 540 { 541 setMousePosition(pos); 542 } 543 544 //Circumvents the package restriction allowing Texture to get the internal 545 //pointer of a regular window (for texture.update) 546 protected static void* getWindowPointer(const(Window) window) 547 { 548 return cast(void*)window.sfPtr; 549 } 550 } 551 552 Event fromSfEvent(const(sfEvent) sfEvent) { 553 Event event; 554 event.type = cast(Event.Type)sfEvent.type; 555 switch(event.type){ 556 /// The window requested to be closed (no data) 557 case Event.Type.Closed: 558 break; 559 /// The window was resized (data in event.size) 560 case Event.Type.Resized: 561 event.size.width = sfEvent.size.width; 562 event.size.height = sfEvent.size.height; 563 break; 564 /// The window lost the focus (no data) 565 case Event.Type.LostFocus: 566 break; 567 /// The window gained the focus (no data) 568 case Event.Type.GainedFocus: 569 break; 570 /// A character was entered (data in event.text) 571 case Event.Type.TextEntered: 572 event.text.unicode = sfEvent.text.unicode; 573 break; 574 /// A key was pressed (data in event.key) 575 case Event.Type.KeyPressed: 576 event.key.code = cast(Keyboard.Key)sfEvent.key.code; 577 event.key.alt = sfEvent.key.alt > 0; 578 event.key.control = sfEvent.key.control > 0; 579 event.key.shift = sfEvent.key.shift > 0; 580 event.key.system = sfEvent.key.system > 0; 581 break; 582 /// A key was released (data in event.key) 583 case Event.Type.KeyReleased: 584 event.key.code = cast(Keyboard.Key)sfEvent.key.code; 585 event.key.alt = sfEvent.key.alt > 0; 586 event.key.control = sfEvent.key.control > 0; 587 event.key.shift = sfEvent.key.shift > 0; 588 event.key.system = sfEvent.key.system > 0; 589 break; 590 /// The mouse wheel was scrolled (data in event.mouseWheel) 591 case Event.Type.MouseWheelMoved: 592 event.mouseWheel.delta = sfEvent.mouseWheel.delta; 593 event.mouseWheel.x = sfEvent.mouseWheel.x; 594 event.mouseWheel.y = sfEvent.mouseWheel.y; 595 break; 596 /// The mouse cursor moved (data in event.mouseMove) 597 case Event.Type.MouseMoved: 598 event.mouseMove.x = sfEvent.mouseMove.x; 599 event.mouseMove.y = sfEvent.mouseMove.y; 600 break; 601 /// The mouse wheel was scrolled (data in event.mouseWheelScroll) 602 case Event.Type.MouseWheelScrolled: 603 event.mouseWheel.delta = sfEvent.mouseWheel.delta; 604 event.mouseWheel.x = sfEvent.mouseWheel.x; 605 event.mouseWheel.y = sfEvent.mouseWheel.y; 606 break; 607 /// A mouse button was pressed (data in event.mouseButton) 608 case Event.Type.MouseButtonPressed: 609 event.mouseButton.button = cast(Mouse.Button)sfEvent.mouseButton.button; 610 event.mouseButton.x = sfEvent.mouseButton.x; 611 event.mouseButton.y = sfEvent.mouseButton.y; 612 break; 613 /// A mouse button was released (data in event.mouseButton) 614 case Event.Type.MouseButtonReleased: 615 event.mouseButton.button = cast(Mouse.Button)sfEvent.mouseButton.button; 616 event.mouseButton.x = sfEvent.mouseButton.x; 617 event.mouseButton.y = sfEvent.mouseButton.y; 618 break; 619 /// The mouse cursor entered the area of the window (no data) 620 case Event.Type.MouseEntered: 621 break; 622 /// The mouse cursor left the area of the window (no data) 623 case Event.Type.MouseLeft: 624 break; 625 /// A joystick button was pressed (data in event.joystickButton) 626 case Event.Type.JoystickButtonPressed: 627 event.joystickButton.button = sfEvent.joystickButton.button; 628 event.joystickButton.joystickId = sfEvent.joystickButton.joystickId; 629 break; 630 /// A joystick button was released (data in event.joystickButton) 631 case Event.Type.JoystickButtonReleased: 632 event.joystickButton.button = sfEvent.joystickButton.button; 633 event.joystickButton.joystickId = sfEvent.joystickButton.joystickId; 634 break; 635 /// The joystick moved along an axis (data in event.joystickMove) 636 case Event.Type.JoystickMoved: 637 event.joystickMove.axis = sfEvent.joystickMove.axis; 638 event.joystickMove.joystickId = sfEvent.joystickMove.joystickId; 639 event.joystickMove.position = sfEvent.joystickMove.position; 640 break; 641 /// A joystick was connected (data in event.joystickConnect) 642 case Event.Type.JoystickConnected: 643 event.joystickConnect.joystickId = sfEvent.joystickConnect.joystickId; 644 break; 645 /// A joystick was disconnected (data in event.joystickConnect) 646 case Event.Type.JoystickDisconnected: 647 event.joystickConnect.joystickId = sfEvent.joystickConnect.joystickId; 648 break; 649 /// A touch event began (data in event.touch) 650 /*case Event.Type.TouchBegan: 651 event.touch.finger = sfEvent.touch.finger; 652 event.touch.x = sfEvent.touch.x; 653 event.touch.y = sfEvent.touch.y; 654 655 break; 656 /// A touch moved (data in event.touch) 657 case Event.Type.TouchMoved: 658 event.touch.finger = sfEvent.touch.finger; 659 event.touch.x = sfEvent.touch.x; 660 event.touch.y = sfEvent.touch.y; 661 662 break; 663 /// A touch ended (data in event.touch) 664 case Event.Type.TouchEnded: 665 event.touch.finger = sfEvent.touch.finger; 666 event.touch.x = sfEvent.touch.x; 667 event.touch.y = sfEvent.touch.y; 668 break; 669 /// A sensor value changed (data in event.sensor) 670 case Event.Type.SensorChanged: 671 event.sensor.type = sfEvent.sensor.type; 672 event.sensor.x = sfEvent.sensor.x; 673 event.sensor.y = sfEvent.sensor.y; 674 event.sensor.z = sfEvent.sensor.z; 675 break; 676 */ 677 default: 678 break; 679 } 680 681 682 683 return event; 684 }