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