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