1 module framed; 2 import framed.win32; 3 import core.stdc.stdlib; 4 5 version (Windows) { 6 import core.sys.windows.windows; 7 8 enum FramedWindowSupport = true; 9 } 10 else { 11 enum FramedWindowSupport = false; 12 } 13 14 nothrow: 15 16 package enum FramebufferType { 17 Null, 18 Window, 19 } 20 21 package struct WindowData { 22 nothrow: 23 24 void* udata; 25 int function(void*) getWidth; 26 int function(void*) getHeight; 27 Cursors function(void*) getCursor; 28 void function(void*, Cursors) setCursor; 29 void function(void*) close; 30 void function(void*, uint[]) update; 31 void function(void*) yield; 32 bool function(void*) evqEmpty; 33 Event function(void*) evqFront; 34 void function(void*) evqPopFront; 35 version (Windows) { 36 HWND function(void*) getHwnd; 37 } 38 } 39 40 enum Cursors { 41 None, 42 Arrow, 43 } 44 45 enum EventType { 46 CloseRequest, 47 Resize, 48 KeyDown, 49 KeyRepeat, 50 KeyUp, 51 MouseMove, 52 MouseDown, 53 MouseUp, 54 MouseEnter, 55 MouseLeave, 56 } 57 58 enum MouseButton { 59 Left, 60 Middle, 61 Right, 62 } 63 64 // dfmt off 65 enum KeyCode { 66 Space, 67 Quote, 68 Comma, 69 Minus, 70 Period, 71 Slash, 72 D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, 73 Semicolon, 74 Equal, 75 A, B, C, D, E, F, G, H, I, J, K, L, M, 76 N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 77 LeftBracket, 78 Backslash, 79 RightBracket, 80 Backtick, 81 Escape, 82 Enter, 83 Tab, 84 Backspace, 85 Insert, 86 Delete, 87 Right, 88 Left, 89 Down, 90 Up, 91 PageUp, 92 PageDown, 93 Home, 94 End, 95 CapsLock, 96 ScrollLock, 97 NumLock, 98 PrintScreen, 99 Pause, 100 F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, 101 F11, F12, F13, F14, F15, F16, F17, F18, 102 F19, F20, F21, F22, F23, F24, F25, 103 Numpad0, Numpad1, Numpad2, 104 Numpad3, Numpad4, Numpad5, 105 Numpad6, Numpad7, Numpad8, 106 Numpad9, NumpadPeriod, NumpadSlash, NumpadMultiply, 107 NumpadMinus, NumpadPlus, NumpadEnter, NumpadEqual, 108 LeftShift, LeftCtrl, LeftAlt, LeftSuper, 109 RightShift, RightCtrl, RightAlt, RightSuper, 110 Menu, 111 } 112 // dfmt on 113 114 struct Event { 115 nothrow: 116 EventType type; 117 long a; 118 long b; 119 120 int width() const @property { 121 return cast(int) a; 122 } 123 124 void width(int value) @property { 125 a = (cast(ulong) height << 32UL) | cast(uint) value; 126 } 127 128 int height() const @property { 129 return cast(int)(a >> 32UL); 130 } 131 132 void height(int value) @property { 133 a = (cast(ulong) value << 32UL) | cast(uint) width; 134 } 135 136 int x() const @property { 137 return width; 138 } 139 140 void x(int value) @property { 141 width = value; 142 } 143 144 int y() const @property { 145 return height; 146 } 147 148 void y(int value) @property { 149 height = value; 150 } 151 152 MouseButton button() const @property { 153 return cast(MouseButton) b; 154 } 155 156 void button(MouseButton value) @property { 157 b = cast(long) value; 158 } 159 160 KeyCode key() const @property { 161 return cast(KeyCode) b; 162 } 163 164 void key(KeyCode value) @property { 165 b = cast(long) value; 166 } 167 } 168 169 package struct EventRange { 170 nothrow: 171 172 Framebuffer buffer; 173 174 bool empty() { 175 final switch (buffer.type) { 176 case FramebufferType.Null: 177 return true; 178 case FramebufferType.Window: 179 return buffer.window.evqEmpty(buffer.window.udata); 180 } 181 } 182 183 Event front() { 184 switch (buffer.type) { 185 case FramebufferType.Window: 186 return buffer.window.evqFront(buffer.window.udata); 187 default: 188 assert(0); 189 } 190 } 191 192 void popFront() { 193 final switch (buffer.type) { 194 case FramebufferType.Null: 195 break; 196 case FramebufferType.Window: 197 buffer.window.evqPopFront(buffer.window.udata); 198 break; 199 } 200 } 201 202 } 203 204 struct Framebuffer { 205 nothrow: 206 207 private FramebufferType type = FramebufferType.Null; 208 private void* data; 209 private int* count; 210 211 package this(FramebufferType type, void* data) { 212 this.type = type; 213 this.data = data; 214 count = cast(int*) malloc(int.sizeof); 215 *count = 1; 216 } 217 218 this(ref return scope inout(Framebuffer) rhs) inout { 219 type = rhs.type; 220 data = rhs.data; 221 count = rhs.count; 222 *cast(int*) count += 1; 223 } 224 225 ~this() { 226 if (count == null) 227 return; 228 *count -= 1; 229 if (*count == 0) { 230 final switch (type) { 231 case FramebufferType.Null: 232 break; 233 case FramebufferType.Window: 234 window.close(window.udata); 235 } 236 free(data); 237 free(count); 238 } 239 } 240 241 private WindowData* window() inout { 242 return cast(WindowData*) data; 243 } 244 245 int width() { 246 final switch (type) { 247 case FramebufferType.Null: 248 return 0; 249 case FramebufferType.Window: 250 return window.getWidth(window.udata); 251 } 252 } 253 254 int height() { 255 final switch (type) { 256 case FramebufferType.Null: 257 return 0; 258 case FramebufferType.Window: 259 return window.getHeight(window.udata); 260 } 261 } 262 263 void update(uint[] buffer) { 264 assert(buffer.length == width * cast(size_t) height, "Wrong buffer size"); 265 final switch (type) { 266 case FramebufferType.Null: 267 break; 268 case FramebufferType.Window: 269 window.update(window.udata, buffer); 270 break; 271 } 272 } 273 274 void yield() { 275 final switch (type) { 276 case FramebufferType.Null: 277 break; 278 case FramebufferType.Window: 279 window.yield(window.udata); 280 break; 281 } 282 } 283 284 Cursors cursor() const @property { 285 final switch (type) { 286 case FramebufferType.Null: 287 return Cursors.None; 288 case FramebufferType.Window: 289 return window.getCursor(window.udata); 290 } 291 } 292 293 void cursor(Cursors value) @property { 294 final switch (type) { 295 case FramebufferType.Null: 296 break; 297 case FramebufferType.Window: 298 window.setCursor(window.udata, value); 299 break; 300 } 301 } 302 303 EventRange eventQueue() { 304 return EventRange(this); 305 } 306 307 } 308 309 struct WindowOptions { 310 nothrow: 311 312 int initialWidth = 640; 313 int initialHeight = 480; 314 bool resizable = true; 315 string title = "Untitled window"; 316 317 this(string title) { 318 this.title = title; 319 } 320 321 this(int initialWidth, int initialHeight) { 322 this.initialWidth = initialWidth; 323 this.initialHeight = initialHeight; 324 } 325 326 this(string title, int initialWidth, int initialHeight) { 327 this.title = title; 328 this.initialWidth = initialWidth; 329 this.initialHeight = initialHeight; 330 } 331 } 332 333 static if (FramedWindowSupport) { 334 version (Windows) { 335 Framebuffer openWindow(WindowOptions options) { 336 return win32OpenWindow(options); 337 } 338 339 HWND getWin32Hwnd(Framebuffer buffer) { 340 return buffer.window.getHwnd(buffer.window.udata); 341 } 342 } 343 else { 344 static assert(0); 345 } 346 347 Framebuffer openWindow(Args...)(Args args) { 348 return openWindow(WindowOptions(args)); 349 } 350 }