├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── docs ├── CrystGLFW.html ├── CrystGLFW │ ├── Error.html │ ├── Error │ │ ├── APIUnavailable.html │ │ ├── Any.html │ │ ├── FormatUnavailable.html │ │ ├── InvalidEnum.html │ │ ├── InvalidValue.html │ │ ├── JoystickNotConnected.html │ │ ├── KeyNotPrintable.html │ │ ├── NoCurrentContext.html │ │ ├── NoWindowContext.html │ │ ├── NotFullScreen.html │ │ ├── NotInitialized.html │ │ ├── OutOfMemory.html │ │ ├── PlatformError.html │ │ └── VersionUnavailable.html │ ├── ErrorCallback.html │ ├── Event.html │ ├── Event │ │ ├── Any.html │ │ ├── JoystickToggleConnection.html │ │ ├── Modifiers.html │ │ ├── MonitorToggleConnection.html │ │ ├── WindowChar.html │ │ ├── WindowClose.html │ │ ├── WindowCursorCrossThreshold.html │ │ ├── WindowCursorMove.html │ │ ├── WindowFileDrop.html │ │ ├── WindowFramebufferResize.html │ │ ├── WindowKey.html │ │ ├── WindowMouseButton.html │ │ ├── WindowMove.html │ │ ├── WindowRefresh.html │ │ ├── WindowResize.html │ │ ├── WindowScroll.html │ │ ├── WindowToggleFocus.html │ │ └── WindowToggleIconification.html │ ├── Joystick.html │ ├── Joystick │ │ ├── JoystickCallback.html │ │ └── ToggleConnectionCallback.html │ ├── Key.html │ ├── Monitor.html │ ├── Monitor │ │ ├── GammaRamp.html │ │ ├── MonitorCallback.html │ │ ├── ToggleConnectionCallback.html │ │ └── VideoMode.html │ ├── MouseButton.html │ ├── Window.html │ └── Window │ │ ├── CharCallback.html │ │ ├── CloseCallback.html │ │ ├── Cursor.html │ │ ├── CursorCrossThresholdCallback.html │ │ ├── CursorMoveCallback.html │ │ ├── FileDropCallback.html │ │ ├── FramebufferResizeCallback.html │ │ ├── Image.html │ │ ├── KeyCallback.html │ │ ├── MouseButtonCallback.html │ │ ├── MoveCallback.html │ │ ├── RefreshCallback.html │ │ ├── ResizeCallback.html │ │ ├── ScrollCallback.html │ │ ├── ToggleFocusCallback.html │ │ ├── ToggleIconificationCallback.html │ │ └── WindowCallback.html ├── css │ └── style.css ├── index.html └── js │ └── doc.js ├── shard.yml ├── spec ├── CrystGLFW_spec.cr └── spec_helper.cr └── src ├── crystglfw.cr └── crystglfw ├── action.cr ├── client_api.cr ├── connection_status.cr ├── context_api.cr ├── context_robustness.cr ├── error.cr ├── events ├── any.cr ├── event.cr ├── joystick_toggle_connection.cr ├── modifiers.cr ├── monitor_toggle_connection.cr ├── window_char.cr ├── window_close.cr ├── window_cursor_cross_threshold.cr ├── window_cursor_move.cr ├── window_file_drop.cr ├── window_framebuffer_resize.cr ├── window_key.cr ├── window_mouse_button.cr ├── window_move.cr ├── window_refresh.cr ├── window_resize.cr ├── window_scroll.cr ├── window_toggle_focus.cr └── window_toggle_iconification.cr ├── joystick.cr ├── key.cr ├── monitors ├── gamma_ramp.cr ├── monitor.cr └── video_mode.cr ├── mouse_button.cr ├── opengl_profile.cr ├── release_behavior.cr ├── sticky.cr ├── version.cr └── windows ├── cursor.cr ├── hint_label.cr ├── image.cr ├── state.cr └── window.cr /.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | 6 | # Libraries don't need dependency lock 7 | # Dependencies will be locked in application that uses them 8 | /shard.lock 9 | 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: crystal 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Caleb Uriah Harrison 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CrystGLFW 2 | 3 | An object-oriented API for GLFW in Crystal. 4 | 5 | [GLFW](https://glfw.org) is a razor-thin, cross-platform library for spinning up OpenGL contexts via windows as well as 6 | receiving user input and platform events. CrystGLFW provides an object-oriented API for the full GLFW specification, including 7 | window creation, working with multiple monitors, keyboard and joystick/controller input, idiomatic callbacks, and more. 8 | 9 | The flexibility and portability of GLFW meets the speed and ease-of-use of Crystal. What a time to be alive! 10 | 11 | CrystGLFW uses [LibGLFW](https://github.com/calebuharrison/LibGLFW) behind the scenes. 12 | 13 | [Read the guides!](https://calebuharrison.gitbooks.io/crystglfw-guide/content/) 14 | 15 | ## Installation 16 | 17 | First, you'll want to make sure you've got GLFW3: 18 | 19 | ```sh 20 | brew install glfw3 21 | ``` 22 | 23 | Add this to your application's `shard.yml`: 24 | 25 | ```yaml 26 | dependencies: 27 | crystglfw: 28 | github: calebuharrison/CrystGLFW 29 | branch: master 30 | ``` 31 | 32 | Install your dependencies: 33 | 34 | ```sh 35 | shards install 36 | ``` 37 | 38 | ## Quick Start 39 | 40 | ```crystal 41 | require "crystglfw" 42 | include CrystGLFW 43 | 44 | # Initialize GLFW 45 | CrystGLFW.run do 46 | # Create a new window. 47 | window = Window.new(title: "My First Window") 48 | 49 | # Configure the window to print its dimensions each time it is resized. 50 | window.on_resize do |event| 51 | puts "Window resized to #{event.size}" 52 | end 53 | 54 | # Make this window's OpenGL context the current drawing context. 55 | window.make_context_current 56 | 57 | # Listen for callbacks and draw the window until it has been marked for closing. 58 | until window.should_close? 59 | CrystGLFW.wait_events 60 | window.swap_buffers 61 | end 62 | 63 | # Destroy the window. 64 | window.destroy 65 | 66 | # Shut down and clean up GLFW. 67 | end 68 | ``` 69 | 70 | CrystGLFW has much more to offer - check out the [guides](https://calebuharrison.gitbooks.io/crystglfw-guide/content/)! 71 | 72 | ## Contributing 73 | 74 | 1. Fork it ( https://github.com/calebuharrison/CrystGLFW/fork ) 75 | 2. Create your feature branch (git checkout -b my-new-feature) 76 | 3. Commit your changes (git commit -am 'Add some feature') 77 | 4. Push to the branch (git push origin my-new-feature) 78 | 5. Create a new Pull Request 79 | 80 | ## Contributors 81 | 82 | - [calebuharrison](https://github.com/calebuharrison) Caleb Uriah Harrison - creator, maintainer -------------------------------------------------------------------------------- /docs/CrystGLFW/ErrorCallback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | CrystGLFW::ErrorCallback - github.com/calebuharrison/CrystGLFW 9 | 10 | 11 | 12 |
13 | 16 | 17 | 20 | 21 | 374 | 375 |
376 | 377 |
378 |

379 | 380 | alias CrystGLFW::ErrorCallback 381 | 382 |

383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 |

Alias Definition

391 | Int32 -> Nil 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 |

Defined in:

405 | 406 | 407 | crystglfw.cr 408 | 409 |
410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 |
425 | 426 |
427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 |
437 | 438 | 439 | 440 | -------------------------------------------------------------------------------- /docs/CrystGLFW/Window/CharCallback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | CrystGLFW::Window::CharCallback - github.com/calebuharrison/CrystGLFW 9 | 10 | 11 | 12 |
13 | 16 | 17 | 20 | 21 | 374 | 375 |
376 | 377 |
378 |

379 | 380 | alias CrystGLFW::Window::CharCallback 381 | 382 |

383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 |

Alias Definition

391 | CrystGLFW::Event::WindowChar -> Nil 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 |

Defined in:

405 | 406 | 407 | crystglfw/windows/window.cr 408 | 409 |
410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 |
425 | 426 |
427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 |
437 | 438 | 439 | 440 | -------------------------------------------------------------------------------- /docs/CrystGLFW/Window/CloseCallback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | CrystGLFW::Window::CloseCallback - github.com/calebuharrison/CrystGLFW 9 | 10 | 11 | 12 |
13 | 16 | 17 | 20 | 21 | 374 | 375 |
376 | 377 |
378 |

379 | 380 | alias CrystGLFW::Window::CloseCallback 381 | 382 |

383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 |

Alias Definition

391 | CrystGLFW::Event::WindowClose -> Nil 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 |

Defined in:

405 | 406 | 407 | crystglfw/windows/window.cr 408 | 409 |
410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 |
425 | 426 |
427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 |
437 | 438 | 439 | 440 | -------------------------------------------------------------------------------- /docs/CrystGLFW/Window/KeyCallback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | CrystGLFW::Window::KeyCallback - github.com/calebuharrison/CrystGLFW 9 | 10 | 11 | 12 |
13 | 16 | 17 | 20 | 21 | 374 | 375 |
376 | 377 |
378 |

379 | 380 | alias CrystGLFW::Window::KeyCallback 381 | 382 |

383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 |

Alias Definition

391 | CrystGLFW::Event::WindowKey -> Nil 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 |

Defined in:

405 | 406 | 407 | crystglfw/windows/window.cr 408 | 409 |
410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 |
425 | 426 |
427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 |
437 | 438 | 439 | 440 | -------------------------------------------------------------------------------- /docs/CrystGLFW/Window/MoveCallback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | CrystGLFW::Window::MoveCallback - github.com/calebuharrison/CrystGLFW 9 | 10 | 11 | 12 |
13 | 16 | 17 | 20 | 21 | 374 | 375 |
376 | 377 |
378 |

379 | 380 | alias CrystGLFW::Window::MoveCallback 381 | 382 |

383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 |

Alias Definition

391 | CrystGLFW::Event::WindowMove -> Nil 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 |

Defined in:

405 | 406 | 407 | crystglfw/windows/window.cr 408 | 409 |
410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 |
425 | 426 |
427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 |
437 | 438 | 439 | 440 | -------------------------------------------------------------------------------- /docs/CrystGLFW/Window/RefreshCallback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | CrystGLFW::Window::RefreshCallback - github.com/calebuharrison/CrystGLFW 9 | 10 | 11 | 12 |
13 | 16 | 17 | 20 | 21 | 374 | 375 |
376 | 377 |
378 |

379 | 380 | alias CrystGLFW::Window::RefreshCallback 381 | 382 |

383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 |

Alias Definition

391 | CrystGLFW::Event::WindowRefresh -> Nil 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 |

Defined in:

405 | 406 | 407 | crystglfw/windows/window.cr 408 | 409 |
410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 |
425 | 426 |
427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 |
437 | 438 | 439 | 440 | -------------------------------------------------------------------------------- /docs/CrystGLFW/Window/ResizeCallback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | CrystGLFW::Window::ResizeCallback - github.com/calebuharrison/CrystGLFW 9 | 10 | 11 | 12 |
13 | 16 | 17 | 20 | 21 | 374 | 375 |
376 | 377 |
378 |

379 | 380 | alias CrystGLFW::Window::ResizeCallback 381 | 382 |

383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 |

Alias Definition

391 | CrystGLFW::Event::WindowResize -> Nil 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 |

Defined in:

405 | 406 | 407 | crystglfw/windows/window.cr 408 | 409 |
410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 |
425 | 426 |
427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 |
437 | 438 | 439 | 440 | -------------------------------------------------------------------------------- /docs/CrystGLFW/Window/ScrollCallback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | CrystGLFW::Window::ScrollCallback - github.com/calebuharrison/CrystGLFW 9 | 10 | 11 | 12 |
13 | 16 | 17 | 20 | 21 | 374 | 375 |
376 | 377 |
378 |

379 | 380 | alias CrystGLFW::Window::ScrollCallback 381 | 382 |

383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 |

Alias Definition

391 | CrystGLFW::Event::WindowScroll -> Nil 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 |

Defined in:

405 | 406 | 407 | crystglfw/windows/window.cr 408 | 409 |
410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 |
425 | 426 |
427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 |
437 | 438 | 439 | 440 | -------------------------------------------------------------------------------- /docs/css/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | position: relative; 3 | margin: 0; 4 | padding: 0; 5 | width: 100%; 6 | height: 100%; 7 | overflow: hidden; 8 | } 9 | 10 | body { 11 | font-family: "Avenir", "Tahoma", "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; 12 | color: #333; 13 | } 14 | 15 | a { 16 | color: #263F6C; 17 | } 18 | 19 | a:visited { 20 | color: #112750; 21 | } 22 | 23 | h1, h2, h3, h4, h5, h6 { 24 | margin: 35px 0 25px; 25 | color: #444444; 26 | } 27 | 28 | h1.type-name { 29 | color: #47266E; 30 | margin: 20px 0 30px; 31 | background-color: #F8F8F8; 32 | padding: 10px 12px; 33 | border: 1px solid #EBEBEB; 34 | border-radius: 2px; 35 | } 36 | 37 | h2 { 38 | border-bottom: 1px solid #E6E6E6; 39 | padding-bottom: 5px; 40 | } 41 | 42 | #types-list, #main-content { 43 | position: absolute; 44 | top: 0; 45 | bottom: 0; 46 | overflow: auto; 47 | } 48 | 49 | #types-list { 50 | left: 0; 51 | width: 20%; 52 | background-color: #2E1052; 53 | padding: 0 0 30px; 54 | box-shadow: inset -3px 0 4px rgba(0,0,0,.35); 55 | } 56 | 57 | #types-list #search-box { 58 | padding: 8px 9px; 59 | } 60 | 61 | #types-list input { 62 | display: block; 63 | box-sizing: border-box; 64 | margin: 0; 65 | padding: 5px; 66 | font: inherit; 67 | font-family: inherit; 68 | line-height: 1.2; 69 | width: 100%; 70 | border: 0; 71 | outline: 0; 72 | border-radius: 2px; 73 | box-shadow: 0px 3px 5px rgba(0,0,0,.25); 74 | transition: box-shadow .12s; 75 | } 76 | 77 | #types-list input:focus { 78 | box-shadow: 0px 5px 6px rgba(0,0,0,.5); 79 | } 80 | 81 | #types-list input::-webkit-input-placeholder { /* Chrome/Opera/Safari */ 82 | color: #C8C8C8; 83 | font-size: 14px; 84 | text-indent: 2px; 85 | } 86 | 87 | #types-list input::-moz-placeholder { /* Firefox 19+ */ 88 | color: #C8C8C8; 89 | font-size: 14px; 90 | text-indent: 2px; 91 | } 92 | 93 | #types-list input:-ms-input-placeholder { /* IE 10+ */ 94 | color: #C8C8C8; 95 | font-size: 14px; 96 | text-indent: 2px; 97 | } 98 | 99 | #types-list input:-moz-placeholder { /* Firefox 18- */ 100 | color: #C8C8C8; 101 | font-size: 14px; 102 | text-indent: 2px; 103 | } 104 | 105 | #types-list ul { 106 | margin: 0; 107 | padding: 0; 108 | list-style: none outside; 109 | } 110 | 111 | #types-list li { 112 | display: block; 113 | position: relative; 114 | } 115 | 116 | #types-list li.hide { 117 | display: none; 118 | } 119 | 120 | #types-list a { 121 | display: block; 122 | padding: 5px 15px 5px 30px; 123 | text-decoration: none; 124 | color: #F8F4FD; 125 | transition: color .14s; 126 | } 127 | 128 | #types-list a:focus { 129 | outline: 1px solid #D1B7F1; 130 | } 131 | 132 | #types-list .current > a, 133 | #types-list a:hover { 134 | color: #866BA6; 135 | } 136 | 137 | #types-list li ul { 138 | overflow: hidden; 139 | height: 0; 140 | max-height: 0; 141 | transition: 1s ease-in-out; 142 | } 143 | 144 | 145 | #types-list li.parent { 146 | padding-left: 30px; 147 | } 148 | 149 | #types-list li.parent::before { 150 | box-sizing: border-box; 151 | content: "▼"; 152 | display: block; 153 | width: 30px; 154 | height: 30px; 155 | position: absolute; 156 | top: 0; 157 | left: 0; 158 | text-align: center; 159 | color: white; 160 | font-size: 8px; 161 | line-height: 30px; 162 | transform: rotateZ(-90deg); 163 | cursor: pointer; 164 | transition: .2s linear; 165 | } 166 | 167 | 168 | #types-list li.parent > a { 169 | padding-left: 0; 170 | } 171 | 172 | #types-list li.parent.open::before { 173 | transform: rotateZ(0); 174 | } 175 | 176 | #types-list li.open > ul { 177 | height: auto; 178 | max-height: 1000em; 179 | } 180 | 181 | #main-content { 182 | padding: 0 30px 30px 30px; 183 | left: 20%; 184 | right: 0; 185 | } 186 | 187 | .kind { 188 | font-size: 60%; 189 | color: #866BA6; 190 | } 191 | 192 | .superclass-hierarchy { 193 | margin: -15px 0 30px 0; 194 | padding: 0; 195 | list-style: none outside; 196 | font-size: 80%; 197 | } 198 | 199 | .superclass-hierarchy .superclass { 200 | display: inline-block; 201 | margin: 0 7px 0 0; 202 | padding: 0; 203 | } 204 | 205 | .superclass-hierarchy .superclass + .superclass::before { 206 | content: "<"; 207 | margin-right: 7px; 208 | } 209 | 210 | .other-types-list li { 211 | display: inline-block; 212 | } 213 | 214 | .other-types-list, 215 | .list-summary { 216 | margin: 0 0 30px 0; 217 | padding: 0; 218 | list-style: none outside; 219 | } 220 | 221 | .entry-const { 222 | font-family: Consolas, 'Courier New', Courier, Monaco, monospace; 223 | } 224 | 225 | .entry-summary { 226 | padding-bottom: 4px; 227 | } 228 | 229 | .superclass-hierarchy .superclass a, 230 | .other-type a, 231 | .entry-summary .signature { 232 | padding: 4px 8px; 233 | margin-bottom: 4px; 234 | display: inline-block; 235 | background-color: #f8f8f8; 236 | color: #47266E; 237 | border: 1px solid #f0f0f0; 238 | text-decoration: none; 239 | border-radius: 3px; 240 | font-family: Consolas, 'Courier New', Courier, Monaco, monospace; 241 | transition: background .15s, border-color .15s; 242 | } 243 | 244 | .superclass-hierarchy .superclass a:hover, 245 | .other-type a:hover, 246 | .entry-summary .signature:hover { 247 | background: #D5CAE3; 248 | border-color: #624288; 249 | } 250 | 251 | .entry-summary .summary { 252 | padding-left: 32px; 253 | } 254 | 255 | .entry-summary .summary p { 256 | margin: 12px 0 16px; 257 | } 258 | 259 | .entry-summary a { 260 | text-decoration: none; 261 | } 262 | 263 | .entry-detail { 264 | padding: 30px 0; 265 | } 266 | 267 | .entry-detail .signature { 268 | position: relative; 269 | padding: 5px 15px; 270 | margin-bottom: 10px; 271 | display: block; 272 | border-radius: 5px; 273 | background-color: #f8f8f8; 274 | color: #47266E; 275 | border: 1px solid #f0f0f0; 276 | font-family: Consolas, 'Courier New', Courier, Monaco, monospace; 277 | transition: .2s ease-in-out; 278 | } 279 | 280 | .entry-detail:target .signature { 281 | background-color: #D5CAE3; 282 | border: 1px solid #624288; 283 | } 284 | 285 | .entry-detail .signature .method-permalink { 286 | position: absolute; 287 | top: 0; 288 | left: -35px; 289 | padding: 5px 15px; 290 | text-decoration: none; 291 | font-weight: bold; 292 | color: #624288; 293 | opacity: .4; 294 | transition: opacity .2s; 295 | } 296 | 297 | .entry-detail .signature .method-permalink:hover { 298 | opacity: 1; 299 | } 300 | 301 | .entry-detail:target .signature .method-permalink { 302 | opacity: 1; 303 | } 304 | 305 | .methods-inherited { 306 | padding-right: 10%; 307 | line-height: 1.5em; 308 | } 309 | 310 | .methods-inherited h3 { 311 | margin-bottom: 4px; 312 | } 313 | 314 | .methods-inherited a { 315 | display: inline-block; 316 | text-decoration: none; 317 | color: #47266E; 318 | } 319 | 320 | .methods-inherited a:hover { 321 | text-decoration: underline; 322 | color: #6C518B; 323 | } 324 | 325 | .methods-inherited .tooltip>span { 326 | background: #D5CAE3; 327 | padding: 4px 8px; 328 | border-radius: 3px; 329 | margin: -4px -8px; 330 | } 331 | 332 | .methods-inherited .tooltip * { 333 | color: #47266E; 334 | } 335 | 336 | pre { 337 | padding: 10px 20px; 338 | margin-top: 4px; 339 | border-radius: 3px; 340 | line-height: 1.45; 341 | overflow: auto; 342 | color: #333; 343 | background: #fdfdfd; 344 | font-size: 14px; 345 | border: 1px solid #eee; 346 | } 347 | 348 | code { 349 | font-family: Consolas, 'Courier New', Courier, Monaco, monospace; 350 | } 351 | 352 | span.flag { 353 | padding: 2px 4px 1px; 354 | border-radius: 3px; 355 | margin-right: 3px; 356 | font-size: 11px; 357 | border: 1px solid transparent; 358 | } 359 | 360 | span.flag.orange { 361 | background-color: #EE8737; 362 | color: #FCEBDD; 363 | border-color: #EB7317; 364 | } 365 | 366 | span.flag.yellow { 367 | background-color: #E4B91C; 368 | color: #FCF8E8; 369 | border-color: #B69115; 370 | } 371 | 372 | span.flag.green { 373 | background-color: #469C14; 374 | color: #E2F9D3; 375 | border-color: #34700E; 376 | } 377 | 378 | span.flag.red { 379 | background-color: #BF1919; 380 | color: #F9ECEC; 381 | border-color: #822C2C; 382 | } 383 | 384 | span.flag.purple { 385 | background-color: #2E1052; 386 | color: #ECE1F9; 387 | border-color: #1F0B37; 388 | } 389 | 390 | .tooltip>span { 391 | position: absolute; 392 | opacity: 0; 393 | display: none; 394 | pointer-events: none; 395 | } 396 | 397 | .tooltip:hover>span { 398 | display: inline-block; 399 | opacity: 1; 400 | } 401 | 402 | .c { 403 | color: #969896; 404 | } 405 | 406 | .n { 407 | color: #0086b3; 408 | } 409 | 410 | .t { 411 | color: #0086b3; 412 | } 413 | 414 | .s { 415 | color: #183691; 416 | } 417 | 418 | .i { 419 | color: #7f5030; 420 | } 421 | 422 | .k { 423 | color: #a71d5d; 424 | } 425 | 426 | .o { 427 | color: #a71d5d; 428 | } 429 | 430 | .m { 431 | color: #795da3; 432 | } 433 | -------------------------------------------------------------------------------- /docs/js/doc.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | var sessionStorage; 3 | try { 4 | sessionStorage = window.sessionStorage; 5 | } catch (e) { } 6 | if(!sessionStorage) { 7 | sessionStorage = { 8 | setItem: function() {}, 9 | getItem: function() {}, 10 | removeItem: function() {} 11 | }; 12 | } 13 | 14 | var repositoryName = document.getElementById('repository-name').getAttribute('content'); 15 | var typesList = document.getElementById('types-list'); 16 | var searchInput = document.getElementById('search-input'); 17 | var parents = document.querySelectorAll('#types-list li.parent'); 18 | 19 | for(var i = 0; i < parents.length; i++) { 20 | var _parent = parents[i]; 21 | _parent.addEventListener('click', function(e) { 22 | e.stopPropagation(); 23 | 24 | if(e.target.tagName.toLowerCase() == 'li') { 25 | if(e.target.className.match(/open/)) { 26 | sessionStorage.removeItem(e.target.getAttribute('data-id')); 27 | e.target.className = e.target.className.replace(/ +open/g, ''); 28 | } else { 29 | sessionStorage.setItem(e.target.getAttribute('data-id'), '1'); 30 | if(e.target.className.indexOf('open') == -1) { 31 | e.target.className += ' open'; 32 | } 33 | } 34 | } 35 | }); 36 | 37 | if(sessionStorage.getItem(_parent.getAttribute('data-id')) == '1') { 38 | _parent.className += ' open'; 39 | } 40 | }; 41 | 42 | var childMatch = function(type, regexp){ 43 | var types = type.querySelectorAll("ul li"); 44 | for (var j = 0; j < types.length; j ++) { 45 | var t = types[j]; 46 | if(regexp.exec(t.getAttribute('data-name'))){ return true; }; 47 | }; 48 | return false; 49 | }; 50 | 51 | var searchTimeout; 52 | var performSearch = function() { 53 | clearTimeout(searchTimeout); 54 | searchTimeout = setTimeout(function() { 55 | var text = searchInput.value; 56 | var types = document.querySelectorAll('#types-list li'); 57 | var words = text.toLowerCase().split(/\s+/).filter(function(word) { 58 | return word.length > 0; 59 | }); 60 | var regexp = new RegExp(words.join('|')); 61 | 62 | for(var i = 0; i < types.length; i++) { 63 | var type = types[i]; 64 | if(words.length == 0 || regexp.exec(type.getAttribute('data-name')) || childMatch(type, regexp)) { 65 | type.className = type.className.replace(/ +hide/g, ''); 66 | var is_parent = new RegExp("parent").exec(type.className); 67 | var is_not_opened = !(new RegExp("open").exec(type.className)); 68 | if(childMatch(type,regexp) && is_parent && is_not_opened){ 69 | type.className += " open"; 70 | }; 71 | } else { 72 | if(type.className.indexOf('hide') == -1) { 73 | type.className += ' hide'; 74 | }; 75 | }; 76 | if(words.length == 0){ 77 | type.className = type.className.replace(/ +open/g, ''); 78 | }; 79 | } 80 | }, 200); 81 | }; 82 | if (searchInput.value.length > 0) { 83 | performSearch(); 84 | } 85 | searchInput.addEventListener('keyup', performSearch); 86 | searchInput.addEventListener('input', performSearch); 87 | 88 | typesList.onscroll = function() { 89 | var y = typesList.scrollTop; 90 | sessionStorage.setItem(repositoryName + '::types-list:scrollTop', y); 91 | }; 92 | 93 | var initialY = parseInt(sessionStorage.getItem(repositoryName + '::types-list:scrollTop') + "", 10); 94 | if(initialY > 0) { 95 | typesList.scrollTop = initialY; 96 | } 97 | 98 | var scrollToEntryFromLocationHash = function() { 99 | var hash = window.location.hash; 100 | if (hash) { 101 | var targetAnchor = unescape(hash.substr(1)); 102 | var targetEl = document.querySelectorAll('.entry-detail[id="' + targetAnchor + '"]'); 103 | 104 | if (targetEl && targetEl.length > 0) { 105 | targetEl[0].offsetParent.scrollTop = targetEl[0].offsetTop; 106 | } 107 | } 108 | }; 109 | window.addEventListener("hashchange", scrollToEntryFromLocationHash, false); 110 | scrollToEntryFromLocationHash(); 111 | }); 112 | -------------------------------------------------------------------------------- /shard.yml: -------------------------------------------------------------------------------- 1 | name: crystglfw 2 | version: 0.3.0 3 | 4 | authors: 5 | - Caleb Uriah Harrison 6 | 7 | dependencies: 8 | lib_glfw: 9 | github: calebuharrison/LibGLFW 10 | branch: master 11 | 12 | crystal: 1.0.0 13 | 14 | license: MIT 15 | -------------------------------------------------------------------------------- /spec/CrystGLFW_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe CrystGLFW do 4 | 5 | describe "#version" do 6 | it "returns a NamedTuple(major: Int32, minor: Int32, rev: Int32)" do 7 | CrystGLFW.version.should be_a(NamedTuple(major: Int32, minor: Int32, rev: Int32)) 8 | end 9 | 10 | it "can be called outside of a run block" do 11 | CrystGLFW.version.should be_a(NamedTuple(major: Int32, minor: Int32, rev: Int32)) 12 | end 13 | end 14 | 15 | describe "#version_string" do 16 | it "returns a String" do 17 | CrystGLFW.version_string.should be_a(String) 18 | end 19 | 20 | it "can be called outside of a run block" do 21 | CrystGLFW.version_string.should be_a(String) 22 | end 23 | end 24 | 25 | describe "#time" do 26 | context "when GLFW is initialized" do 27 | it "returns a Float64" do 28 | CrystGLFW.run do 29 | CrystGLFW.time.should be_a(Float64) 30 | end 31 | end 32 | end 33 | context "when GLFW is not initialized" do 34 | it "raises an exception" do 35 | expect_raises(Exception) do 36 | CrystGLFW.time 37 | end 38 | end 39 | end 40 | end 41 | 42 | end 43 | -------------------------------------------------------------------------------- /spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/CrystGLFW" 3 | -------------------------------------------------------------------------------- /src/crystglfw.cr: -------------------------------------------------------------------------------- 1 | require "./crystglfw/**" 2 | require "lib_glfw" 3 | 4 | module CrystGLFW 5 | extend self 6 | 7 | DONT_CARE = LibGLFW::DONT_CARE 8 | 9 | alias ErrorCallback = Proc(Int32, Nil) 10 | 11 | @@error_callback = ErrorCallback.new do |error_code| 12 | Error.new(error_code).raise 13 | end 14 | 15 | # Sets the error callback that is called when an error occurs in LibGLFW. 16 | # 17 | # When an error occurs in LibGLFW, an error code is yielded to the block 18 | # defined by this method. The error code identifies the type of error that 19 | # occurred and can be validated by checking it against the constants defined 20 | # in CrystGLFW: 21 | # 22 | # ``` 23 | # CrystGLFW.on_error do |error_code| 24 | # case error_code 25 | # when CrystGLFW[:not_initialized] 26 | # puts "CrystGLFW has not been initialized." 27 | # when CrystGLFW[:invalid_enum] 28 | # puts "An invalid enum was passed to CrystGLFW." 29 | # else 30 | # puts "An error occurred" 31 | # end 32 | # end 33 | # ``` 34 | # 35 | # NOTE: This method may be called outside a `#run` block definition without 36 | # triggering an error. 37 | # NOTE: Defining custom behavior will bypass the `Error` module entirely. It 38 | # is recommended that this method not be used. 39 | def self.on_error(&callback : ErrorCallback) 40 | @@error_callback = callback 41 | end 42 | 43 | # Sets up GLFW to execute the block and terminates GLFW afterwards. 44 | # 45 | # ``` 46 | # include CrystGLFW 47 | # 48 | # CrystGLFW.run do 49 | # window = Window.new(title: "My Window") 50 | # until window.should_close? 51 | # window.wait_events 52 | # window.swap_buffers 53 | # end 54 | # end 55 | # ``` 56 | # 57 | # With few exceptions, all CrystGLFW methods must be called within the block 58 | # passed to this method. This method initializes the underlying GLFW library 59 | # for use and cleans up the library after the block has returned. 60 | def self.run(&block) 61 | LibGLFW.init 62 | yield 63 | LibGLFW.terminate 64 | end 65 | 66 | # Returns the major, minor, and revision version numbers of GLFW. 67 | # 68 | # ``` 69 | # CrystGLFW.version # => {major: 3, minor: 2, rev: 1} 70 | # ``` 71 | # 72 | # NOTE: This method may be called outside a `#run` block definition without 73 | # triggering an error. 74 | def self.version : NamedTuple(major: Int32, minor: Int32, rev: Int32) 75 | LibGLFW.get_version(out major, out minor, out rev) 76 | { major: major, minor: minor, rev: rev } 77 | end 78 | 79 | # Returns the compile-time generated version string of GLFW. 80 | # 81 | # ``` 82 | # CrystGLFW.version_string # => "3.2.1 Cocoa NSGL chdir menubar retina dynamic" 83 | # ``` 84 | # 85 | # NOTE: This method may be called outside a `#run` block definition without 86 | # triggering an error. 87 | def self.version_string : String 88 | String.new(LibGLFW.get_version_string) 89 | end 90 | 91 | # Returns the current value, in seconds, of the GLFW timer. 92 | # 93 | # ``` 94 | # CrystGLFW.time # => 0.13899576 95 | # ``` 96 | # 97 | # NOTE: This method must be called inside a `#run` block definition. 98 | def self.time : Float64 99 | LibGLFW.get_time 100 | end 101 | 102 | # Sets the GLFW timer to a new time, in seconds. 103 | # 104 | # This method accepts the following arguments: 105 | # - *t*, the new time. 106 | # 107 | # ``` 108 | # CrystGLFW.set_time 1.0 109 | # CrystGLFW.time # => 1.0 110 | # ``` 111 | # 112 | # NOTE: This method must be called inside a `#run` block definition. 113 | def self.set_time(t : Number) 114 | LibGLFW.set_time t 115 | end 116 | 117 | # Alternate syntax for `#set_time`. 118 | # 119 | # This method accepts the following arguments: 120 | # - *t*, the new time. 121 | # 122 | # ``` 123 | # CrystGLFW.time = 1.0 124 | # CrystGLFW.time # => 1.0 125 | # ``` 126 | # 127 | # NOTE: This method must be called from within a `#run` block definition. 128 | def self.time=(t : Number) 129 | self.set_time t 130 | end 131 | 132 | # Returns the current value of the raw timer, measured in 1 / `#timer_frequency` seconds. 133 | # 134 | # ``` 135 | # CrystGLFW.timer_value # => 754_104_002_009_408 136 | # ``` 137 | # 138 | # NOTE: This method must be called inside a `#run` block definition. 139 | def self.timer_value : UInt64 140 | LibGLFW.get_timer_value 141 | end 142 | 143 | # Returns the frequency, in Hz, of the raw timer. 144 | # 145 | # ``` 146 | # CrystGLFW.timer_frequency # => 1_000_000_000 147 | # ``` 148 | # 149 | # NOTE: This method must be called inside a `#run` block definition. 150 | def self.timer_frequency : UInt64 151 | LibGLFW.get_timer_frequency 152 | end 153 | 154 | # Processes all events in the event queue and then returns immediately. 155 | # 156 | # ``` 157 | # include CrystGLFW 158 | # 159 | # CrystGLFW.run do 160 | # window = Window.new 161 | # until window.should_close? 162 | # CrystGLFW.poll_events # Process all events, even if queue is empty. 163 | # window.swap_buffers 164 | # end 165 | # end 166 | # ``` 167 | # 168 | # NOTE: This method must be called inside a `#run` block definition. 169 | # NOTE: This method must not be called from within a callback. 170 | def self.poll_events 171 | LibGLFW.poll_events 172 | end 173 | 174 | # Puts the calling thread to sleep until at least one event is queued. 175 | # 176 | # ``` 177 | # include CrystGLFW 178 | # 179 | # CrystGLFW.run do 180 | # window = Window.new 181 | # until window.should_close? 182 | # CrystGLFW.wait_events # Wait for events to queue, then process them. 183 | # window.swap_buffers 184 | # end 185 | # end 186 | # 187 | # NOTE: This method must be called inside a `#run` block definition. 188 | # NOTE: This method must not be called from within a callback. 189 | def self.wait_events 190 | LibGLFW.wait_events 191 | end 192 | 193 | # Puts the calling thread to sleep until at least one event is queued or the specified timeout is reached. 194 | # 195 | # ``` 196 | # include CrystGLFW 197 | # 198 | # CrystGLFW.run do 199 | # window = Window.new 200 | # until window.should_close? 201 | # CrystGLFW.wait_events(1.5) 202 | # window.swap_buffers 203 | # end 204 | # end 205 | # 206 | # This method accepts the following arguments: 207 | # - *timeout*, the maximum amount of time, in seconds, to wait. 208 | # 209 | # NOTE: This method must be called inside a `#run` block definition. 210 | # NOTE: This method must not be called from within a callback. 211 | def self.wait_events(timeout : Number) 212 | LibGLFW.wait_events_timeout(timeout) 213 | end 214 | 215 | # Posts an empty event to the event queue, forcing `#wait_events` to return. 216 | # 217 | # ``` 218 | # CrystGLFW.post_empty_event 219 | # ``` 220 | # 221 | # NOTE: This method must be called inside a `#run` block definition. 222 | def self.post_empty_event 223 | LibGLFW.post_empty_event 224 | end 225 | 226 | # Sets the immutable error callback shim. 227 | private def self.set_error_callback 228 | callback = LibGLFW::Errorfun.new do |error_code, description| 229 | @@error_callback.call error_code 230 | end 231 | LibGLFW.set_error_callback callback 232 | end 233 | 234 | set_error_callback 235 | end -------------------------------------------------------------------------------- /src/crystglfw/action.cr: -------------------------------------------------------------------------------- 1 | require "lib_glfw" 2 | 3 | module CrystGLFW 4 | enum Action 5 | Press = LibGLFW::PRESS 6 | Release = LibGLFW::RELEASE 7 | Repeat = LibGLFW::REPEAT 8 | end 9 | end -------------------------------------------------------------------------------- /src/crystglfw/client_api.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | enum ClientAPI 3 | OpenGL = LibGLFW::OPENGL_API 4 | OpenGLES = LibGLFW::OPENGL_ES_API 5 | None = LibGLFW::NO_API 6 | end 7 | end -------------------------------------------------------------------------------- /src/crystglfw/connection_status.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | enum ConnectionStatus 3 | Connected = LibGLFW::CONNECTED 4 | Disconnected = LibGLFW::DISCONNECTED 5 | end 6 | end -------------------------------------------------------------------------------- /src/crystglfw/context_api.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | enum ContextAPI 3 | Native = LibGLFW::NATIVE_CONTEXT_API 4 | EGL = LibGLFW::EGL_CONTEXT_API 5 | end 6 | end -------------------------------------------------------------------------------- /src/crystglfw/context_robustness.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | enum ContextRobustness 3 | None = LibGLFW::NO_ROBUSTNESS 4 | NoResetNotification = LibGLFW::NO_RESET_NOTIFICATION 5 | LoseContextOnReset = LibGLFW::LOSE_CONTEXT_ON_RESET 6 | end 7 | end -------------------------------------------------------------------------------- /src/crystglfw/error.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | enum Error 3 | NotInitialized = LibGLFW::NOT_INITIALIZED 4 | NoCurrentContext = LibGLFW::NO_CURRENT_CONTEXT 5 | InvalidEnum = LibGLFW::INVALID_ENUM 6 | InvalidValue = LibGLFW::INVALID_VALUE 7 | OutOfMemory = LibGLFW::OUT_OF_MEMORY 8 | APIUnavailable = LibGLFW::API_UNAVAILABLE 9 | VersionUnavailable = LibGLFW::VERSION_UNAVAILABLE 10 | PlatformError = LibGLFW::PLATFORM_ERROR 11 | FormatUnavailable = LibGLFW::FORMAT_UNAVAILABLE 12 | NoWindowContext = LibGLFW::NO_WINDOW_CONTEXT 13 | NotFullScreen 14 | KeyNotPrintable 15 | JoystickNotConnected 16 | 17 | def raise 18 | raise "CrystGLFW Error: " + self.to_s 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /src/crystglfw/events/any.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Event::Any is the abstract superclass of the different CrystGLFW events. 4 | abstract struct Any 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /src/crystglfw/events/event.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | # The Event module encapsulates the handful of GLFW callback events and provides an interface for them. 3 | module Event 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /src/crystglfw/events/joystick_toggle_connection.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein a joystick is either connected or disconnected from the system. 4 | struct JoystickToggleConnection < Any 5 | getter joystick : Joystick 6 | 7 | # :nodoc: 8 | def initialize(joystick : Joystick, connection_status : ConnectionStatus) 9 | @joystick = joystick 10 | @connection_status = connection_status 11 | end 12 | 13 | def connected? 14 | @connection_status.connected? 15 | end 16 | end 17 | end 18 | end -------------------------------------------------------------------------------- /src/crystglfw/events/modifiers.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # The Modifiers module encapsulates the instance variables and interfaces for Events that support modifier keys. 4 | module Modifiers 5 | @mod_shift : Bool = false 6 | @mod_control : Bool = false 7 | @mod_alt : Bool = false 8 | @mod_super : Bool = false 9 | 10 | private def set_modifiers(modifiers : Int32) 11 | @mod_shift = modifiers.bit(0) == 1 12 | @mod_control = modifiers.bit(1) == 1 13 | @mod_alt = modifiers.bit(2) == 1 14 | @mod_super = modifiers.bit(3) == 1 15 | end 16 | 17 | # Returns true if the shift key was held down as a modifier. False otherwise. 18 | # 19 | # ``` 20 | # window.on_key do |key_event| 21 | # puts "The shift key was held down as a modifier." if key_event.shift? 22 | # end 23 | # ``` 24 | def shift? 25 | @mod_shift 26 | end 27 | 28 | # Returns true if the control key was held down as a modifier. False otherwise. 29 | # 30 | # ``` 31 | # window.on_key do |key_event| 32 | # puts "The control key was held down as a modifier." if key_event.control? 33 | # end 34 | # ``` 35 | def control? 36 | @mod_control 37 | end 38 | 39 | # Returns true if the alt key was held down as a modifier. False otherwise. 40 | # 41 | # ``` 42 | # window.on_key do |key_event| 43 | # puts "The alt key was held down as a modifier." if key_event.alt? 44 | # end 45 | # ``` 46 | def alt? 47 | @mod_alt 48 | end 49 | 50 | # Returns true if the super key was held down as a modifier. False otherwise. 51 | # 52 | # ``` 53 | # window.on_key do |key_event| 54 | # puts "The super key was held down as a modifier." if key_event.super? 55 | # end 56 | # ``` 57 | def super? 58 | @mod_super 59 | end 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /src/crystglfw/events/monitor_toggle_connection.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein a monitor is either connected or disconnected from the system. 4 | struct MonitorToggleConnection < Any 5 | getter monitor : Monitor 6 | 7 | # :nodoc: 8 | def initialize(@monitor : Monitor, @connection_status : ConnectionStatus) 9 | end 10 | 11 | def connected? 12 | @connection_status.connected? 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_char.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # A WindowCharEvent represents a user-input unicode character along with the modifier keys that were held during its input. 4 | # 5 | # ``` 6 | # window = CrystGLFW::Window.new 7 | # window.on_char do |char_event| 8 | # puts char_event.char if char_event.shift? # Prints the char if the shift key is held down. 9 | # end 10 | # ``` 11 | # 12 | # WindowCharEvents are generated by `Window#on_char` and are not intended to be 13 | # created in any other context. As such, CharEvents should be used when 14 | # generated by the callback, but should never be created. 15 | struct WindowChar < Any 16 | include Modifiers 17 | 18 | getter window : Window 19 | getter char : Char 20 | 21 | # :nodoc: 22 | def initialize(window : Window, char : Char, modifiers : Int32) 23 | @window = window 24 | @char = char 25 | set_modifiers modifiers 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_close.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein a window is closed. 4 | struct WindowClose < Any 5 | getter window : Window 6 | 7 | # :nodoc: 8 | def initialize(window : Window) 9 | @window = window 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_cursor_cross_threshold.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein a window's cursor crosses the threshold of the window. 4 | struct WindowCursorCrossThreshold < Any 5 | getter window : Window 6 | getter cursor : Window::Cursor 7 | 8 | # :nodoc: 9 | def initialize(@window : Window, @cursor : Window::Cursor, @entered : Bool) 10 | end 11 | 12 | def entered? 13 | @entered 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_cursor_move.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein a window's cursor is moved to a new location. 4 | struct WindowCursorMove < Any 5 | getter window : Window 6 | getter cursor : Window::Cursor 7 | 8 | # :nodoc: 9 | def initialize(@window : Window, @cursor : Window::Cursor, @x : Float64, @y : Float64) 10 | end 11 | 12 | def position : NamedTuple(x: Float64, y: Float64) 13 | { x: @x, y: @y } 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_file_drop.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein one or more files are drag-and-dropped onto the window. 4 | struct WindowFileDrop < Any 5 | getter window : Window 6 | getter paths : Array(String) 7 | 8 | # :nodoc: 9 | def initialize(window : Window, paths : Array(String)) 10 | @window = window 11 | @paths = paths 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_framebuffer_resize.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein a window's framebuffer is resized. 4 | struct WindowFramebufferResize < Any 5 | getter window : CrystGLFW::Window 6 | 7 | # :nodoc: 8 | def initialize(@window : Window, @width : Int32, @height : Int32) 9 | end 10 | 11 | def size : NamedTuple(width: Int32, height: Int32) 12 | { width: @width, height: @height } 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_key.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # A WindowKeyEvent is generated by the `Window#on_key` callback and contains a `Key` along with 4 | # an interface to determine what action occurred with the key. 5 | struct WindowKey < Any 6 | include Modifiers 7 | 8 | getter window : Window 9 | getter key : Key 10 | getter action : Action 11 | 12 | # :nodoc: 13 | def initialize(window : Window, key : Key, action : Action, modifiers : Int32) 14 | @window = window 15 | @key = key 16 | @action = action 17 | set_modifiers modifiers 18 | end 19 | 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_mouse_button.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # A WindowMouseButtonEvent is generated by the `Window#on_mouse_button` callback and contains a `MouseButton` along with 4 | # an interface to determine what action occurred with the key. 5 | struct WindowMouseButton < Any 6 | include Modifiers 7 | 8 | getter window : Window 9 | getter mouse_button : MouseButton 10 | getter action : Action 11 | 12 | # :nodoc: 13 | def initialize(window : Window, mouse_button : MouseButton, action : Action, modifiers : Int32) 14 | @window = window 15 | @mouse_button = mouse_button 16 | @action = action 17 | set_modifiers modifiers 18 | end 19 | 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_move.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein a window is moved to a new location. 4 | struct WindowMove < Any 5 | getter window : Window 6 | 7 | # :nodoc: 8 | def initialize(@window : Window, @x : Int32, @y : Int32) 9 | end 10 | 11 | def position : NamedTuple(x: Int32, y: Int32) 12 | { x: @x, y: @y } 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_refresh.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein a window is refreshed. 4 | struct WindowRefresh < Any 5 | getter window : Window 6 | 7 | # :nodoc: 8 | def initialize(window : Window) 9 | @window = window 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_resize.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein a window is resized. 4 | struct WindowResize < Any 5 | getter window : Window 6 | 7 | # :nodoc: 8 | def initialize(@window : Window, @width : Int32, @height : Int32) 9 | end 10 | 11 | def size : NamedTuple(width: Int32, height: Int32) 12 | { width: @width, height: @height } 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_scroll.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein a window receives scroll input. 4 | struct WindowScroll < Any 5 | getter window : Window 6 | 7 | # :nodoc: 8 | def initialize(@window : Window, @x : Float64, @y : Float64) 9 | end 10 | 11 | def offset : NamedTuple(x: Float64, y: Float64) 12 | { x: @x, y: @y } 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_toggle_focus.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein a window's focus is toggled on or off. 4 | struct WindowToggleFocus < Any 5 | getter window : Window 6 | 7 | # :nodoc: 8 | def initialize(@window : Window, @focused : Bool) 9 | end 10 | 11 | def focused? 12 | @focused 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /src/crystglfw/events/window_toggle_iconification.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | module Event 3 | # Represents an event wherein a window's iconification is toggled on or off. 4 | struct WindowToggleIconification < Any 5 | getter window : Window 6 | 7 | # :nodoc: 8 | def initialize(@window : Window, @iconified : Bool) 9 | end 10 | 11 | def iconified? 12 | @iconified 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /src/crystglfw/joystick.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | 3 | enum Joystick 4 | One = LibGLFW::JOYSTICK_1 5 | Two = LibGLFW::JOYSTICK_2 6 | Three = LibGLFW::JOYSTICK_3 7 | Four = LibGLFW::JOYSTICK_4 8 | Five = LibGLFW::JOYSTICK_5 9 | Six = LibGLFW::JOYSTICK_6 10 | Seven = LibGLFW::JOYSTICK_7 11 | Eight = LibGLFW::JOYSTICK_8 12 | Nine = LibGLFW::JOYSTICK_9 13 | Ten = LibGLFW::JOYSTICK_10 14 | Eleven = LibGLFW::JOYSTICK_11 15 | Twelve = LibGLFW::JOYSTICK_12 16 | Thirteen = LibGLFW::JOYSTICK_13 17 | Fourteen = LibGLFW::JOYSTICK_14 18 | Fifteen = LibGLFW::JOYSTICK_15 19 | Sixteen = LibGLFW::JOYSTICK_16 20 | Last = LibGLFW::JOYSTICK_LAST 21 | 22 | def self.on_toggle_connection(&callback : Proc(Event::JoystickToggleConnection, Nil)) 23 | @@callback = callback 24 | end 25 | 26 | protected def self.set_joystick_callback 27 | callback = LibGLFW::Joystickfun.new do |code, connection_code| 28 | joystick = Joystick.new(code) 29 | connection_status = ConnectionStatus.new(connection_code) 30 | event = Event::JoystickToggleConnection.new(joystick, connection_status) 31 | @@callback.try &.call(event) 32 | end 33 | end 34 | 35 | def name : String 36 | candidate = LibGLFW.get_joystick_name(@code) 37 | if candidate.null? 38 | Error::JoystickNotConnected.raise 39 | else 40 | String.new(candidate) 41 | end 42 | end 43 | 44 | def connected? : Bool 45 | LibGLFW.joystick_present(self) == 1 46 | end 47 | 48 | def buttons : Array(Bool) 49 | btns = LibGLFW.get_joystick_buttons(self, out count) 50 | Slice.new(btns, count).map { |b| Action.new(b).press? } 51 | end 52 | 53 | def axes : Slice(Float32) 54 | ptr = LibGLFW.get_joystick_axes(self, out count) 55 | Slice.new(ptr, count) 56 | end 57 | 58 | end 59 | 60 | Joystick.set_joystick_callback 61 | end 62 | -------------------------------------------------------------------------------- /src/crystglfw/key.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | enum Key 3 | Unknown = LibGLFW::KEY_UNKNOWN 4 | Space = LibGLFW::KEY_SPACE 5 | Apostrophe = LibGLFW::KEY_APOSTROPHE 6 | Comma = LibGLFW::KEY_COMMA 7 | Minus = LibGLFW::KEY_MINUS 8 | Period = LibGLFW::KEY_PERIOD 9 | Slash = LibGLFW::KEY_SLASH 10 | Zero = LibGLFW::KEY_0 11 | One = LibGLFW::KEY_1 12 | Two = LibGLFW::KEY_2 13 | Three = LibGLFW::KEY_3 14 | Four = LibGLFW::KEY_4 15 | Five = LibGLFW::KEY_5 16 | Six = LibGLFW::KEY_6 17 | Seven = LibGLFW::KEY_7 18 | Eight = LibGLFW::KEY_8 19 | Nine = LibGLFW::KEY_9 20 | Semicolon = LibGLFW::KEY_SEMICOLON 21 | Equal = LibGLFW::KEY_EQUAL 22 | A = LibGLFW::KEY_A 23 | B = LibGLFW::KEY_B 24 | C = LibGLFW::KEY_C 25 | D = LibGLFW::KEY_D 26 | E = LibGLFW::KEY_E 27 | F = LibGLFW::KEY_F 28 | G = LibGLFW::KEY_G 29 | H = LibGLFW::KEY_H 30 | I = LibGLFW::KEY_I 31 | J = LibGLFW::KEY_J 32 | K = LibGLFW::KEY_K 33 | L = LibGLFW::KEY_L 34 | M = LibGLFW::KEY_M 35 | N = LibGLFW::KEY_N 36 | O = LibGLFW::KEY_O 37 | P = LibGLFW::KEY_P 38 | Q = LibGLFW::KEY_Q 39 | R = LibGLFW::KEY_R 40 | S = LibGLFW::KEY_S 41 | T = LibGLFW::KEY_T 42 | U = LibGLFW::KEY_U 43 | V = LibGLFW::KEY_V 44 | W = LibGLFW::KEY_W 45 | X = LibGLFW::KEY_X 46 | Y = LibGLFW::KEY_Y 47 | Z = LibGLFW::KEY_Z 48 | LeftBracket = LibGLFW::KEY_LEFT_BRACKET 49 | Backslash = LibGLFW::KEY_BACKSLASH 50 | RightBracket = LibGLFW::KEY_RIGHT_BRACKET 51 | GraveAccent = LibGLFW::KEY_GRAVE_ACCENT 52 | World1 = LibGLFW::KEY_WORLD_1 53 | World2 = LibGLFW::KEY_WORLD_2 54 | Escape = LibGLFW::KEY_ESCAPE 55 | Enter = LibGLFW::KEY_ENTER 56 | Tab = LibGLFW::KEY_TAB 57 | Backspace = LibGLFW::KEY_BACKSPACE 58 | Insert = LibGLFW::KEY_INSERT 59 | Delete = LibGLFW::KEY_DELETE 60 | Right = LibGLFW::KEY_RIGHT 61 | Left = LibGLFW::KEY_LEFT 62 | Down = LibGLFW::KEY_DOWN 63 | Up = LibGLFW::KEY_UP 64 | PageUp = LibGLFW::KEY_PAGE_UP 65 | PageDown = LibGLFW::KEY_PAGE_DOWN 66 | Home = LibGLFW::KEY_HOME 67 | End = LibGLFW::KEY_END 68 | CapsLock = LibGLFW::KEY_CAPS_LOCK 69 | ScrollLock = LibGLFW::KEY_SCROLL_LOCK 70 | NumLock = LibGLFW::KEY_NUM_LOCK 71 | PrintScreen = LibGLFW::KEY_PRINT_SCREEN 72 | Pause = LibGLFW::KEY_PAUSE 73 | F1 = LibGLFW::KEY_F1 74 | F2 = LibGLFW::KEY_F2 75 | F3 = LibGLFW::KEY_F3 76 | F4 = LibGLFW::KEY_F4 77 | F5 = LibGLFW::KEY_F5 78 | F6 = LibGLFW::KEY_F6 79 | F7 = LibGLFW::KEY_F7 80 | F8 = LibGLFW::KEY_F8 81 | F9 = LibGLFW::KEY_F9 82 | F10 = LibGLFW::KEY_F10 83 | F11 = LibGLFW::KEY_F11 84 | F12 = LibGLFW::KEY_F12 85 | F13 = LibGLFW::KEY_F13 86 | F14 = LibGLFW::KEY_F14 87 | F15 = LibGLFW::KEY_F15 88 | F16 = LibGLFW::KEY_F16 89 | F17 = LibGLFW::KEY_F17 90 | F18 = LibGLFW::KEY_F18 91 | F19 = LibGLFW::KEY_F19 92 | F20 = LibGLFW::KEY_F20 93 | F21 = LibGLFW::KEY_F21 94 | F22 = LibGLFW::KEY_F22 95 | F23 = LibGLFW::KEY_F23 96 | F24 = LibGLFW::KEY_F24 97 | F25 = LibGLFW::KEY_F25 98 | KP0 = LibGLFW::KEY_KP_0 99 | KP1 = LibGLFW::KEY_KP_1 100 | KP2 = LibGLFW::KEY_KP_2 101 | KP3 = LibGLFW::KEY_KP_3 102 | KP4 = LibGLFW::KEY_KP_4 103 | KP5 = LibGLFW::KEY_KP_5 104 | KP6 = LibGLFW::KEY_KP_6 105 | KP7 = LibGLFW::KEY_KP_7 106 | KP8 = LibGLFW::KEY_KP_8 107 | KP9 = LibGLFW::KEY_KP_9 108 | KPDecimal = LibGLFW::KEY_KP_DECIMAL 109 | KPDivide = LibGLFW::KEY_KP_DIVIDE 110 | KPMultiply = LibGLFW::KEY_KP_MULTIPLY 111 | KPSubtract = LibGLFW::KEY_KP_SUBTRACT 112 | KPAdd = LibGLFW::KEY_KP_ADD 113 | KPEnter = LibGLFW::KEY_KP_ENTER 114 | KPEqual = LibGLFW::KEY_KP_EQUAL 115 | LeftShift = LibGLFW::KEY_LEFT_SHIFT 116 | LeftControl = LibGLFW::KEY_LEFT_CONTROL 117 | LeftAlt = LibGLFW::KEY_LEFT_ALT 118 | LeftSuper = LibGLFW::KEY_LEFT_SUPER 119 | RightShift = LibGLFW::KEY_RIGHT_SHIFT 120 | RightControl = LibGLFW::KEY_RIGHT_CONTROL 121 | RightAlt = LibGLFW::KEY_RIGHT_ALT 122 | RightSuper = LibGLFW::KEY_RIGHT_SUPER 123 | Menu = LibGLFW::KEY_MENU 124 | Last = LibGLFW::KEY_LAST 125 | ModShift = LibGLFW::MOD_SHIFT 126 | ModAlt = LibGLFW::MOD_ALT 127 | ModControl = LibGLFW::MOD_CONTROL 128 | ModSuper = LibGLFW::MOD_SUPER 129 | 130 | @@printable_keys = [ 131 | Apostrophe, Comma, Minus, Period, Slash, Semicolon, Equal, 132 | LeftBracket, RightBracket, Backslash, World1, World2, 133 | Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine, 134 | A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, 135 | U, V, W, X, Y, Z, KP0, KP1, KP2, KP3, KP4, KP5, KP6, KP7, 136 | KP8, KP9, KPDecimal, KPDivide, KPMultiply, KPSubtract, KPAdd, 137 | KPEqual 138 | ] 139 | 140 | @@scancodes = Hash(Key, Int32).new 141 | 142 | def self.from(code : Int32, scancode : Int32) : Key 143 | Key.new(code).tap { |k| @@scancodes[k] = scancode } 144 | end 145 | 146 | def name : String 147 | return "invalid-key" unless scancode = @@scancodes[self]? 148 | candidate = LibGLFW.get_key_name(self.value, scancode) 149 | if candidate.null? 150 | Error::KeyNotPrintable.raise 151 | else 152 | String.new(candidate) 153 | end 154 | end 155 | 156 | def printable? : Bool 157 | @@printable_keys.includes? self 158 | end 159 | end 160 | end 161 | -------------------------------------------------------------------------------- /src/crystglfw/monitors/gamma_ramp.cr: -------------------------------------------------------------------------------- 1 | require "lib_glfw" 2 | 3 | module CrystGLFW 4 | struct Monitor 5 | # A GammaRamp object wraps an underlying GLFW Gammaramp and exposes its attributes. 6 | struct GammaRamp 7 | # :nodoc: 8 | def initialize(handle : Pointer(LibGLFW::Gammaramp)) 9 | @handle = handle 10 | end 11 | 12 | # Returns a slice of values that describes the response of the red channel. 13 | # 14 | # ``` 15 | # monitor = Monitor.primary 16 | # gamma_ramp = monitor.gamma_ramp 17 | # gamma_ramp.red 18 | # ``` 19 | def red : Slice(UInt16) 20 | Slice.new(gamma_ramp.red, size) 21 | end 22 | 23 | # Returns an array of values that describes the resposne of the green channel. 24 | # 25 | # ``` 26 | # monitor = Monitor.primary 27 | # gamma_ramp = monitor.gamma_ramp 28 | # gamma_ramp.green 29 | # ``` 30 | def green : Slice(UInt16) 31 | Slice.new(gamma_ramp.green, size) 32 | end 33 | 34 | # Returns an array of values that describes the response of the blue channel. 35 | # 36 | # ``` 37 | # monitor = Monitor.primary 38 | # gamma_ramp = monitor.gamma_ramp 39 | # gamma_ramp.blue 40 | # ``` 41 | def blue : Slice(UInt16) 42 | Slice.new(gamma_ramp.blue, size) 43 | end 44 | 45 | # Returns the number of elements in each color array. 46 | # 47 | # ``` 48 | # monitor = Monitor.primary 49 | # gamma_ramp = monitor.gamma_ramp 50 | # gamma_ramp.size 51 | # ``` 52 | def size : UInt32 53 | gamma_ramp.size 54 | end 55 | 56 | # :nodoc: 57 | def ==(other : GammaRamp) 58 | @handle == other.to_unsafe 59 | end 60 | 61 | # :nodoc: 62 | def to_unsafe 63 | @handle 64 | end 65 | 66 | # Dereferences the underlying Gammaramp pointer. 67 | private def gamma_ramp 68 | @handle.value 69 | end 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /src/crystglfw/monitors/monitor.cr: -------------------------------------------------------------------------------- 1 | require "lib_glfw" 2 | 3 | module CrystGLFW 4 | # A Monitor represents a physical monitor connected to the system. 5 | struct Monitor 6 | alias ToggleConnectionCallback = Proc(Event::MonitorToggleConnection, Nil) 7 | alias MonitorCallback = ToggleConnectionCallback | Nil 8 | 9 | @@monitor_callback : MonitorCallback 10 | 11 | # Sets the immutable monitor connection callback shim. 12 | private def self.set_toggle_connection_callback 13 | callback = LibGLFW::Monitorfun.new do |handle, connection_code| 14 | monitor = new(handle) 15 | connection_status = ConnectionStatus.new(connection_code) 16 | event = Event::MonitorToggleConnection.new(monitor, connection_status) 17 | @@monitor_callback.try &.call(event) 18 | end 19 | LibGLFW.set_monitor_callback callback 20 | end 21 | 22 | # Defines the behavior that gets triggered when a monitor is either connected or disconnected. 23 | # 24 | # ``` 25 | # monitor = CrystGLFW::Monitor.primary 26 | # monitor.on_toggle_connection do |event| 27 | # if event.connected? 28 | # puts "Welcome back, #{event.monitor.name}!" 29 | # else 30 | # puts "Farewell, #{event.monitor.name}." 31 | # end 32 | # end 33 | # ``` 34 | def self.on_toggle_connection(&callback : ToggleConnectionCallback) 35 | @@monitor_callback = callback 36 | end 37 | 38 | # Returns all monitors currently connected to the system as an Array. 39 | # 40 | # ``` 41 | # monitors = CrystGLFW::Monitor.all 42 | # monitors.each { |m| puts m.name } # Prints out the name of each connected monitor. 43 | # ``` 44 | # 45 | # NOTE: This method must be called from within a `CrystGLFW#run` block definition. 46 | def self.all : Array(Monitor) 47 | handles = LibGLFW.get_monitors(out count) 48 | count.times.map { |i| Monitor.new(handles[i]) } 49 | end 50 | 51 | # Returns the primary monitor, which is inferred by GLFW as the window that includes the task bar. 52 | # 53 | # ``` 54 | # monitor = CrystGLFW::Monitor.primary 55 | # puts "Monitor #{monitor.name} is the primary monitor." 56 | # ``` 57 | # 58 | # NOTE: This method must be called from within a `CrystGLFW#run` block definition. 59 | def self.primary : Monitor 60 | new(LibGLFW.get_primary_monitor) 61 | end 62 | 63 | private def initialize(handle : Pointer(LibGLFW::Monitor)) 64 | @handle = handle 65 | end 66 | 67 | # Returns the position of the upper-left corner of the monitor in screen coordinates relative to the virtual screen. 68 | # 69 | # ``` 70 | # # Retrieve all monitors. 71 | # monitors = CrystGLFW::Monitors.all 72 | # 73 | # # Find the monitor that is furthest to the left. 74 | # leftmost_monitor = monitors.min_by { |monitor| monitor.position[:x] } 75 | # ``` 76 | # 77 | # NOTE: This method must be called from within a `CrystGLFW#run` block definition. 78 | def position : NamedTuple(x: Int32, y: Int32) 79 | LibGLFW.get_monitor_pos(@handle, out x, out y) 80 | { x: x, y: y } 81 | end 82 | 83 | # Returns the physical size of the monitor in millimeters. 84 | # 85 | # ``` 86 | # # Retrieve the primary monitor. 87 | # monitor = CrystGLFW::Monitor.primary 88 | # 89 | # # Calculate the area of the monitor using its physical size. 90 | # monitor_area = monitor.physical_size[:width] * monitor.physical_size[:height] 91 | # 92 | # # Print the area of the monitor in millimeters. 93 | # puts "The area of the monitor is #{monitor_area} millimeters squared." 94 | # ``` 95 | # 96 | # NOTE: This method must be called from within a `CrystGLFW#run` block definition. 97 | def physical_size : NamedTuple(width: Int32, height: Int32) 98 | LibGLFW.get_monitor_physical_size(@handle, out width, out height) 99 | { width: width, height: height } 100 | end 101 | 102 | # Returns the monitor's name, as set by the manufacturer. 103 | # 104 | # ``` 105 | # # Retrieve the primary monitor. 106 | # monitor = CrystGLFW::Monitor.primary 107 | # 108 | # # Print out the name of the monitor. 109 | # puts "The name of the primary monitor is #{monitor.name}" 110 | # ``` 111 | # 112 | # NOTE: This method must be called from within a `CrystGLFW#run` block definition. 113 | def name : String 114 | String.new LibGLFW.get_monitor_name(@handle) 115 | end 116 | 117 | # Returns the monitor's supported video modes. 118 | # 119 | # TODO: Add an example here. 120 | # 121 | # NOTE: This method must be called from within a `CrystGLFW#run` block definition. 122 | def video_modes : Array(VideoMode) 123 | vid_modes = LibGLFW.get_video_modes(@handle, out count) 124 | count.times.map { |i| VideoMode.new(vid_modes + i) } 125 | end 126 | 127 | # Returns the monitor's current video mode. 128 | # 129 | # ``` 130 | # # Retrieve the primary monitor. 131 | # monitor = CrystGLFW::Monitor.primary 132 | # 133 | # current_video_mode = monitor.video_mode 134 | # ``` 135 | # 136 | # TODO: Improve this example with something useful. 137 | # 138 | # NOTE: This method must be called inside a `CrystGLFW#run` block definition. 139 | def video_mode : VideoMode 140 | VideoMode.new LibGLFW.get_video_mode(@handle) 141 | end 142 | 143 | # Generates a gamma ramp from the given exponent and sets it as the monitor's gamma ramp. 144 | # 145 | # This method accepts the following arguments: 146 | # - *gamma*, the exponent used to generate the new gamma ramp. 147 | # 148 | # NOTE: This method must be called inside a `CrystGLFW#run` block definition. 149 | def set_gamma(gamma : Number) 150 | LibGLFW.set_gamma @handle, gamma 151 | end 152 | 153 | # Alternate syntax for `#set_gamma`. 154 | # 155 | # This method accepts the following arguments: 156 | # - *gamma*, the exponent used to generate the new gamma ramp. 157 | # 158 | # NOTE: This method must be called inside a `CrystGLFW#run` block definition. 159 | def gamma=(gamma : Number) 160 | LibGLFW.set_gamma @handle, gamma 161 | end 162 | 163 | # Returns the monitor's current gamma ramp. 164 | # 165 | # NOTE: This method must be called inside a `CrystGLFW#run` block definition. 166 | def gamma_ramp : GammaRamp 167 | GammaRamp.new LibGLFW.get_gamma_ramp(@handle) 168 | end 169 | 170 | # Sets the monitor's gamma ramp to the given gamma ramp. 171 | def set_gamma_ramp(gamma_ramp : GammaRamp) 172 | LibGLFW.set_gamma_ramp @handle, gamma_ramp 173 | end 174 | 175 | # Alternate syntax for `#set_gamma_ramp`. 176 | def gamma_ramp=(gamma_ramp : GammaRamp) 177 | LibGLFW.set_gamma_ramp @handle, gamma_ramp 178 | end 179 | 180 | # :nodoc: 181 | def ==(other : Monitor) 182 | @handle == other.to_unsafe 183 | end 184 | 185 | # :nodoc: 186 | def to_unsafe : Pointer(LibGLFW::Monitor) 187 | @handle 188 | end 189 | 190 | set_toggle_connection_callback 191 | end 192 | end 193 | -------------------------------------------------------------------------------- /src/crystglfw/monitors/video_mode.cr: -------------------------------------------------------------------------------- 1 | require "lib_glfw" 2 | 3 | module CrystGLFW 4 | struct Monitor 5 | # A VideoMode object wraps an underlying GLFW Vidmode and exposes its attributes. 6 | struct VideoMode 7 | # :nodoc: 8 | def initialize(handle : Pointer(LibGLFW::Vidmode)) 9 | @handle = handle 10 | end 11 | 12 | # Returns the bit depth of the red channel. 13 | def red_bits : Int32 14 | vid_mode.redBits 15 | end 16 | 17 | # Returns the bit depth of the green channel. 18 | def green_bits : Int32 19 | vid_mode.greenBits 20 | end 21 | 22 | # Returns the bit depth of the blue channel. 23 | def blue_bits : Int32 24 | vid_mode.blueBits 25 | end 26 | 27 | # Returns the size, in screen coordinates, of the video mode. 28 | def size : NamedTuple(width: Int32, height: Int32) 29 | { width: vid_mode.width, height: vid_mode.height } 30 | end 31 | 32 | # Returns the refresh rate, in Hz, of the video mode. 33 | def refresh_rate : Int32 34 | vid_mode.refreshRate 35 | end 36 | 37 | # :nodoc: 38 | def ==(other : VideoMode) : Bool 39 | @handle == other.to_unsafe 40 | end 41 | 42 | # :nodoc: 43 | def to_unsafe : Pointer(LibGLFW::Vidmode) 44 | @handle 45 | end 46 | 47 | # Dereferences the pointer to the GLFW Vidmode. 48 | private def vid_mode : LibGLFW::Vidmode 49 | @handle.value 50 | end 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /src/crystglfw/mouse_button.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | enum MouseButton 3 | One = LibGLFW::MOUSE_BUTTON_1 4 | Two = LibGLFW::MOUSE_BUTTON_2 5 | Three = LibGLFW::MOUSE_BUTTON_3 6 | Four = LibGLFW::MOUSE_BUTTON_4 7 | Five = LibGLFW::MOUSE_BUTTON_5 8 | Six = LibGLFW::MOUSE_BUTTON_6 9 | Seven = LibGLFW::MOUSE_BUTTON_7 10 | Eight = LibGLFW::MOUSE_BUTTON_8 11 | Last = LibGLFW::MOUSE_BUTTON_LAST 12 | Left = LibGLFW::MOUSE_BUTTON_LEFT 13 | Right = LibGLFW::MOUSE_BUTTON_RIGHT 14 | Middle = LibGLFW::MOUSE_BUTTON_MIDDLE 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /src/crystglfw/opengl_profile.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | enum OpenGLProfile 3 | Any = LibGLFW::OPENGL_ANY_PROFILE 4 | Compat = LibGLFW::OPENGL_COMPAT_PROFILE 5 | Core = LibGLFW::OPENGL_CORE_PROFILE 6 | end 7 | end -------------------------------------------------------------------------------- /src/crystglfw/release_behavior.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | enum ReleaseBehavior 3 | Any = LibGLFW::ANY_RELEASE_BEHAVIOR 4 | Flush = LibGLFW::RELEASE_BEHAVIOR_FLUSH 5 | None = LibGLFW::RELEASE_BEHAVIOR_NONE 6 | end 7 | end -------------------------------------------------------------------------------- /src/crystglfw/sticky.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | enum Sticky 3 | Keys = LibGLFW::STICKY_KEYS 4 | MouseButtons = LibGLFW::STICKY_MOUSE_BUTTONS 5 | end 6 | end -------------------------------------------------------------------------------- /src/crystglfw/version.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | enum Version 3 | Major = LibGLFW::VERSION_MAJOR 4 | Minor = LibGLFW::VERSION_MINOR 5 | Revision = LibGLFW::VERSION_REVISION 6 | end 7 | end -------------------------------------------------------------------------------- /src/crystglfw/windows/cursor.cr: -------------------------------------------------------------------------------- 1 | require "lib_glfw" 2 | 3 | module CrystGLFW 4 | class Window 5 | # A Cursor represents a GLFW cursor and can either use a custom image or a system-default shape as its likeness. 6 | # 7 | # Cursors are created indirectly through windows, and are therefore always associated with a `Window`. 8 | struct Cursor 9 | 10 | enum Shape 11 | Arrow = LibGLFW::ARROW_CURSOR 12 | IBeam = LibGLFW::IBEAM_CURSOR 13 | Crosshair = LibGLFW::CROSSHAIR_CURSOR 14 | Hand = LibGLFW::HAND_CURSOR 15 | HResize = LibGLFW::HRESIZE_CURSOR 16 | VResize = LibGLFW::VRESIZE_CURSOR 17 | end 18 | 19 | enum Mode 20 | Normal = LibGLFW::CURSOR_NORMAL 21 | Hidden = LibGLFW::CURSOR_HIDDEN 22 | Disabled = LibGLFW::CURSOR_DISABLED 23 | end 24 | 25 | # :nodoc: 26 | def initialize(cursor_shape : Shape, window : Window) 27 | @handle = LibGLFW.create_standard_cursor(cursor_shape) 28 | @window = window 29 | LibGLFW.set_cursor @window, @handle 30 | end 31 | 32 | # :nodoc: 33 | def initialize(image : Image, x : Number, y : Number, window : Window) 34 | @handle = LibGLFW.create_cursor(image, x, y) 35 | @window = window 36 | LibGLFW.set_cursor @window, @handle 37 | end 38 | 39 | # Returns the cursor's window. 40 | # 41 | # ``` 42 | # # Get the cursor's associated window. 43 | # window = cursor.window 44 | # ``` 45 | def window : Window 46 | @window 47 | end 48 | 49 | # Returns the position of the cursor relative to its window. 50 | # 51 | # ``` 52 | # cp = cursor.position 53 | # puts "The cursor position is located at (#{cp[:x]}, #{cp[:y]}) relative to its window." 54 | # ``` 55 | # 56 | # NOTE: This method must be called from within a `CrystGLFW#run` block definition. 57 | def position : NamedTuple(x: Float64, y: Float64) 58 | LibGLFW.get_cursor_pos @window.to_unsafe, out x, out y 59 | { x: x, y: y } 60 | end 61 | 62 | # Sets the cursor's position relative to its window. 63 | # 64 | # ``` 65 | # # Set the cursor position to the top-left corner of its window. 66 | # cursor.set_position 0, 0 67 | # ``` 68 | # 69 | # This method accepts the following arguments: 70 | # - *x*, the desired x coordinate of the cursor. 71 | # - *y*, the desired y coordinate of the cursor. 72 | # 73 | # NOTE: This method must be called from within a `CrystGLFW#run` block definition. 74 | def set_position(x : Number, y : Number) 75 | LibGLFW.set_cursor_pos @window.to_unsafe, x, y 76 | end 77 | 78 | # Alternate syntax for `#set_position`. 79 | # 80 | # ``` 81 | # # Set the cursor position to the top-left corner of its window. 82 | # cursor.position = {x: 0, y: 0} 83 | # ``` 84 | # 85 | # This method accepts the following arguments: 86 | # - *pos*, the desired coordinates of the cursor's position. 87 | # 88 | # NOTE: This method must be called from within a `CrystGLFW#run` block definition. 89 | def position=(pos : NamedTuple(x: Number, y: Number)) 90 | set_position pos[:x], pos[:y] 91 | end 92 | 93 | # Returns true if the cursor is in its window. False otherwise. 94 | # 95 | # ``` 96 | # if window.cursor.in_window? 97 | # puts "The cursor is in its window!" 98 | # else 99 | # puts "The cursor is somewhere else" 100 | # end 101 | # ``` 102 | # 103 | # NOTE: This method must be called from within a `CrystGLFW#run` block definition. 104 | def in_window? 105 | wp = @window.position 106 | @window.contains? position[:x] + wp[:x], position[:y] + wp[:y] 107 | end 108 | 109 | def normal? 110 | Mode.new(LibGLFW.get_input_mode(@window, LibGLFW::CURSOR)).normal? 111 | end 112 | 113 | def hidden? 114 | Mode.new(LibGLFW.get_input_mode(@window, LibGLFW::CURSOR)).hidden? 115 | end 116 | 117 | def disabled? 118 | Mode.new(LibGLFW.get_input_mode(@window, LibGLFW::CURSOR)).disabled? 119 | end 120 | 121 | def normalize 122 | LibGLFW.set_input_mode(@window, LibGLFW::CURSOR, Mode::Normal) 123 | end 124 | 125 | def hide 126 | LibGLFW.set_input_mode(@window, LibGLFW::CURSOR, Mode::Hidden) 127 | end 128 | 129 | def disable 130 | LibGLFW.set_input_mode(@window, LibGLFW::CURSOR, Mode::Disabled) 131 | end 132 | 133 | # :nodoc: 134 | def destroy 135 | LibGLFW.destroy_cursor @handle 136 | end 137 | 138 | # :nodoc: 139 | def ==(other : Cursor) 140 | @handle == other.to_unsafe 141 | end 142 | 143 | # :nodoc: 144 | def to_unsafe 145 | @handle 146 | end 147 | end 148 | end 149 | end 150 | -------------------------------------------------------------------------------- /src/crystglfw/windows/hint_label.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | class Window 3 | enum HintLabel 4 | Resizable = LibGLFW::RESIZABLE 5 | Visible = LibGLFW::VISIBLE 6 | Decorated = LibGLFW::DECORATED 7 | Focused = LibGLFW::FOCUSED 8 | AutoIconify = LibGLFW::AUTO_ICONIFY 9 | Floating = LibGLFW::FLOATING 10 | Maximized = LibGLFW::MAXIMIZED 11 | RedBits = LibGLFW::RED_BITS 12 | GreenBits = LibGLFW::GREEN_BITS 13 | BlueBits = LibGLFW::BLUE_BITS 14 | AlphaBits = LibGLFW::ALPHA_BITS 15 | DepthBits = LibGLFW::DEPTH_BITS 16 | StencilBits = LibGLFW::STENCIL_BITS 17 | AccumRedBits = LibGLFW::ACCUM_RED_BITS 18 | AccumGreenBits = LibGLFW::ACCUM_GREEN_BITS 19 | AccumBlueBits = LibGLFW::ACCUM_BLUE_BITS 20 | AccumAlphaBits = LibGLFW::ACCUM_ALPHA_BITS 21 | AuxBuffers = LibGLFW::AUX_BUFFERS 22 | Samples = LibGLFW::SAMPLES 23 | RefreshRate = LibGLFW::REFRESH_RATE 24 | Stereo = LibGLFW::STEREO 25 | SRGBCapable = LibGLFW::SRGB_CAPABLE 26 | Doublebuffer = LibGLFW::DOUBLEBUFFER 27 | ClientAPI = LibGLFW::CLIENT_API 28 | ContextCreationAPI = LibGLFW::CONTEXT_CREATION_API 29 | ContextVersionMajor = LibGLFW::CONTEXT_VERSION_MAJOR 30 | ContextVersionMinor = LibGLFW::CONTEXT_VERSION_MINOR 31 | ContextRobustness = LibGLFW::CONTEXT_ROBUSTNESS 32 | ContextReleaseBehavior = LibGLFW::CONTEXT_RELEASE_BEHAVIOR 33 | OpenGLForwardCompat = LibGLFW::OPENGL_FORWARD_COMPAT 34 | OpenGLDebugContext = LibGLFW::OPENGL_DEBUG_CONTEXT 35 | OpenGLProfile = LibGLFW::OPENGL_PROFILE 36 | end 37 | end 38 | end -------------------------------------------------------------------------------- /src/crystglfw/windows/image.cr: -------------------------------------------------------------------------------- 1 | require "lib_glfw" 2 | 3 | module CrystGLFW 4 | class Window 5 | # An Image object wraps an underlying GLFW Image and exposes its attributes. 6 | struct Image 7 | @image : LibGLFW::Image 8 | 9 | # Create a new image for use as a Cursor image or a Window icon. 10 | # 11 | # ``` 12 | # width, height = 16, 32 13 | # pixels = Array(UInt8).new(width * height, 255_u8) 14 | # image = CrystGLFW::Image.new(width, height, pixels) 15 | # ``` 16 | # 17 | # This method accepts the following arguments: 18 | # - *width*, the width of the image, in pixels. 19 | # - *height*, the height of the image, in pixels. 20 | # - *pixels*, the pixel data, given left-to-right, top-to-bottom. 21 | # 22 | # NOTE: This method may be called outside a `CrystGLFW#run` block defintion without triggering an error. 23 | def initialize(width : Int32, height : Int32, pixels : Array(UInt8)) 24 | @image = LibGLFW::Image.new 25 | @image.width = width 26 | @image.height = height 27 | @image.pixels = pixels 28 | end 29 | 30 | def size : NamedTuple(width: Int32, height: Int32) 31 | { width: @image.width, height: @image.height } 32 | end 33 | 34 | # Returns the pixel data of the image, arranged left-to-right, top-to-bottom. 35 | def pixels : Slice(UInt8) 36 | Slice.new(@image.pixels, width * height) 37 | end 38 | 39 | # :nodoc: 40 | def to_unsafe 41 | pointerof(@image) 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /src/crystglfw/windows/state.cr: -------------------------------------------------------------------------------- 1 | module CrystGLFW 2 | class Window 3 | enum State 4 | Focused = LibGLFW::FOCUSED 5 | Iconified = LibGLFW::ICONIFIED 6 | Resizable = LibGLFW::RESIZABLE 7 | Visible = LibGLFW::VISIBLE 8 | Decorated = LibGLFW::DECORATED 9 | Floating = LibGLFW::FLOATING 10 | Maximized = LibGLFW::MAXIMIZED 11 | end 12 | end 13 | end --------------------------------------------------------------------------------