1 module rpui.platform_sdl; 2 3 version(rpuiSdl2): 4 5 import std.conv; 6 import std.array; 7 import std.string; 8 9 import derelict.sdl2.sdl; 10 import derelict.sdl2.ttf; 11 import derelict.sdl2.image; 12 13 import gapi.opengl; 14 15 import rpui.events; 16 import rpui.events_observer; 17 import rpui.input; 18 import rpui.platform; 19 20 extern(C) void platformShowSystemCursor() { 21 SDL_ShowCursor(SDL_ENABLE); 22 } 23 24 extern(C) void platformHideSystemCursor() { 25 SDL_ShowCursor(SDL_DISABLE); 26 } 27 28 extern(C) void platformSetMousePosition(void* window, in int x, in int y) { 29 SDL_WarpMouseInWindow(cast(SDL_Window*) window, x, y); 30 } 31 32 extern(C) float platformGetTicks() { 33 return SDL_GetTicks(); 34 } 35 36 extern(C) bool platformEventLoop(void* window, EventsObserver events) { 37 SDL_Event event; 38 39 while (SDL_PollEvent(&event)) { 40 if (event.type == SDL_QUIT) { 41 return false; 42 } 43 else if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { 44 events.notify(WindowResizeEvent(event.window.data1, event.window.data2)); 45 } 46 else if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_EXPOSED) { 47 events.notify(WindowExposedEvent()); 48 } 49 else if (event.type == SDL_MOUSEMOTION) { 50 const button = createMouseButtonFromSdlState(event.motion.state); 51 events.notify(MouseMoveEvent(event.motion.x, event.motion.y, button)); 52 } 53 else if (event.type == SDL_MOUSEBUTTONDOWN) { 54 const button = createMouseButtonFromButtonSdlEvent(event); 55 events.notify(MouseDownEvent(event.button.x, event.button.y, button)); 56 57 switch (event.button.clicks) { 58 case 2: 59 events.notify(DblClickEvent(event.button.x, event.button.y, button)); 60 break; 61 62 case 3: 63 events.notify(TripleClickEvent(event.button.x, event.button.y, button)); 64 break; 65 66 default: 67 // Ignore 68 } 69 } 70 else if (event.type == SDL_MOUSEBUTTONUP) { 71 const button = createMouseButtonFromButtonSdlEvent(event); 72 events.notify(MouseUpEvent(event.button.x, event.button.y, button)); 73 } 74 else if (event.type == SDL_MOUSEWHEEL) { 75 events.notify(MouseWheelEvent(event.wheel.x, event.wheel.y)); 76 } 77 else if (event.type == SDL_TEXTINPUT) { 78 const ch = fromStringz(dtext(event.text.text[0..4]).ptr)[0]; 79 events.notify(TextEnteredEvent(ch)); 80 } 81 else if (event.type == SDL_KEYDOWN) { 82 try { 83 const key = to!(KeyCode)(to!(int)(event.key.keysym.sym)); 84 setKeyPressed(key, true); 85 events.notify(KeyPressedEvent(key)); 86 } catch (Exception e) { 87 } 88 } 89 else if (event.type == SDL_KEYUP) { 90 try { 91 const key = to!(KeyCode)(to!(int)(event.key.keysym.sym)); 92 events.notify(KeyReleasedEvent(key)); 93 setKeyPressed(key, false); 94 } catch (Exception e) { 95 } 96 } 97 } 98 99 return true; 100 } 101 102 extern(C) void platformSwapWindow(void* window) { 103 SDL_GL_SwapWindow(cast(SDL_Window*) window); 104 } 105 106 extern(C) void platformGapiDeleteContext(void* context) { 107 SDL_GL_DeleteContext(context); 108 } 109 110 extern(C) void platformDestroyWindow(void* window) { 111 SDL_DestroyWindow(cast(SDL_Window*) window); 112 } 113 114 extern(C) void platformShutdown() { 115 SDL_Quit(); 116 TTF_Quit(); 117 } 118 119 extern(C) void platformInit() { 120 // Load shared libraries 121 DerelictGL3.load(); 122 DerelictSDL2.load(); 123 DerelictSDL2Image.load(); 124 DerelictSDL2TTF.load(); 125 126 // Init 127 if (SDL_Init(SDL_INIT_VIDEO) < 0) 128 throw new Error("Failed to init SDL"); 129 130 if (TTF_Init() < 0) 131 throw new Error("Failed to init SDL TTF"); 132 133 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); 134 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); 135 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 136 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 137 SDL_GL_SetSwapInterval(2); 138 } 139 140 extern(C) Window platformCreateWindow(in string title, uint width, uint height) { 141 auto window = SDL_CreateWindow( 142 toStringz(title), 143 SDL_WINDOWPOS_CENTERED, 144 SDL_WINDOWPOS_CENTERED, 145 width, 146 height, 147 SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE 148 ); 149 150 if (window == null) 151 throw new Error("SDL Error: " ~ to!string(SDL_GetError())); 152 153 auto glContext = SDL_GL_CreateContext(window); 154 155 if (glContext == null) 156 throw new Error("SDL Error: " ~ to!string(SDL_GetError())); 157 158 SDL_GL_SwapWindow(window); 159 DerelictGL3.reload(); 160 161 return Window(window, glContext); 162 } 163 164 extern(C) void platformSetClipboardTextUtf8(in string text) { 165 SDL_SetClipboardText(toStringz(text)); 166 } 167 168 extern(C) void platformSetClipboardTextUtf32(in dstring text) { 169 // writeln("PLATFORM COPY: ", data.charString); 170 171 SDL_SetClipboardText(toStringz(to!string(text))); 172 } 173 174 extern(C) string platformGetClipboardTextUtf8() { 175 return to!string(fromStringz(SDL_GetClipboardText())); 176 } 177 178 extern(C) dstring platformGetClipboardTextUtf32() { 179 return to!dstring(fromStringz(SDL_GetClipboardText())); 180 } 181 182 extern(C) bool hasClipboardText() { 183 return cast(bool) SDL_HasClipboardText(); 184 }