From b0f1edf297981e036ec91b79d49fe9f27aa12310 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 2 Jan 2024 00:37:24 +0100 Subject: [PATCH] Add SDL2 backend --- libraries/ZWidget/CMakeLists.txt | 2 + .../src/window/sdl2/sdl2displaywindow.cpp | 606 ++++++++++++++++++ .../src/window/sdl2/sdl2displaywindow.h | 85 +++ libraries/ZWidget/src/window/window.cpp | 41 +- 4 files changed, 733 insertions(+), 1 deletion(-) create mode 100644 libraries/ZWidget/src/window/sdl2/sdl2displaywindow.cpp create mode 100644 libraries/ZWidget/src/window/sdl2/sdl2displaywindow.h diff --git a/libraries/ZWidget/CMakeLists.txt b/libraries/ZWidget/CMakeLists.txt index b548bc0cfa..548af0c460 100644 --- a/libraries/ZWidget/CMakeLists.txt +++ b/libraries/ZWidget/CMakeLists.txt @@ -65,6 +65,8 @@ set(ZWIDGET_WIN32_SOURCES ) set(ZWIDGET_UNIX_SOURCES + src/window/sdl2/sdl2displaywindow.cpp + src/window/sdl2/sdl2displaywindow.h ) source_group("src" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/.+") diff --git a/libraries/ZWidget/src/window/sdl2/sdl2displaywindow.cpp b/libraries/ZWidget/src/window/sdl2/sdl2displaywindow.cpp new file mode 100644 index 0000000000..a715a0cb91 --- /dev/null +++ b/libraries/ZWidget/src/window/sdl2/sdl2displaywindow.cpp @@ -0,0 +1,606 @@ + +#include "sdl2displaywindow.h" + +Uint32 SDL2DisplayWindow::PaintEventNumber = 0xffffffff; +bool SDL2DisplayWindow::ExitRunLoop; +std::unordered_map SDL2DisplayWindow::WindowList; + +class InitSDL +{ +public: + InitSDL() + { + int result = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); + if (result != 0) + throw std::runtime_error(std::string("Unable to initialize SDL:") + SDL_GetError()); + + SDL2DisplayWindow::PaintEventNumber = SDL_RegisterEvents(1); + } +}; + +SDL2DisplayWindow::SDL2DisplayWindow(DisplayWindowHost* windowHost) : WindowHost(windowHost) +{ + static InitSDL initsdl; + + int result = SDL_CreateWindowAndRenderer(320, 200, SDL_WINDOW_HIDDEN /*| SDL_WINDOW_ALLOW_HIGHDPI*/, &WindowHandle, &RendererHandle); + if (result != 0) + throw std::runtime_error(std::string("Unable to create SDL window:") + SDL_GetError()); + + WindowList[SDL_GetWindowID(WindowHandle)] = this; +} + +SDL2DisplayWindow::~SDL2DisplayWindow() +{ + WindowList.erase(WindowList.find(SDL_GetWindowID(WindowHandle))); + SDL_DestroyRenderer(RendererHandle); + SDL_DestroyWindow(WindowHandle); + RendererHandle = nullptr; + WindowHandle = nullptr; +} + +void SDL2DisplayWindow::SetWindowTitle(const std::string& text) +{ + SDL_SetWindowTitle(WindowHandle, text.c_str()); +} + +void SDL2DisplayWindow::SetWindowFrame(const Rect& box) +{ + // SDL2 doesn't really seem to have an API for this. + // The docs aren't clear what you're setting when calling SDL_SetWindowSize. + SetClientFrame(box); +} + +void SDL2DisplayWindow::SetClientFrame(const Rect& box) +{ + // Is there a way to set both in one call? + + double uiscale = GetDpiScale(); + int x = (int)std::round(box.x * uiscale); + int y = (int)std::round(box.y * uiscale); + int w = (int)std::round(box.width * uiscale); + int h = (int)std::round(box.height * uiscale); + + SDL_SetWindowPosition(WindowHandle, x, y); + SDL_SetWindowSize(WindowHandle, w, h); +} + +void SDL2DisplayWindow::Show() +{ + SDL_ShowWindow(WindowHandle); +} + +void SDL2DisplayWindow::ShowFullscreen() +{ + SDL_SetWindowFullscreen(WindowHandle, SDL_WINDOW_FULLSCREEN_DESKTOP); +} + +void SDL2DisplayWindow::ShowMaximized() +{ + SDL_ShowWindow(WindowHandle); + SDL_MaximizeWindow(WindowHandle); +} + +void SDL2DisplayWindow::ShowMinimized() +{ + SDL_ShowWindow(WindowHandle); + SDL_MinimizeWindow(WindowHandle); +} + +void SDL2DisplayWindow::ShowNormal() +{ + SDL_ShowWindow(WindowHandle); + SDL_SetWindowFullscreen(WindowHandle, 0); +} + +void SDL2DisplayWindow::Hide() +{ + SDL_HideWindow(WindowHandle); +} + +void SDL2DisplayWindow::Activate() +{ + SDL_RaiseWindow(WindowHandle); +} + +void SDL2DisplayWindow::ShowCursor(bool enable) +{ + SDL_ShowCursor(enable); +} + +void SDL2DisplayWindow::LockCursor() +{ + SDL_SetWindowGrab(WindowHandle, SDL_TRUE); + SDL_ShowCursor(0); +} + +void SDL2DisplayWindow::UnlockCursor() +{ + SDL_SetWindowGrab(WindowHandle, SDL_FALSE); + SDL_ShowCursor(1); +} + +void SDL2DisplayWindow::Update() +{ + SDL_Event event = {}; + event.type = PaintEventNumber; + event.user.windowID = SDL_GetWindowID(WindowHandle); + SDL_PushEvent(&event); +} + +bool SDL2DisplayWindow::GetKeyState(EInputKey key) +{ + int numkeys = 0; + const Uint8* state = SDL_GetKeyboardState(&numkeys); + if (!state) return false; + + SDL_Scancode index = InputKeyToScancode(key); + return (index < numkeys) ? state[index] != 0 : false; +} + +Rect SDL2DisplayWindow::GetWindowFrame() const +{ + int x = 0; + int y = 0; + int w = 0; + int h = 0; + double uiscale = GetDpiScale(); + SDL_GetWindowPosition(WindowHandle, &x, &y); + SDL_GetWindowSize(WindowHandle, &w, &h); + return Rect::xywh(x / uiscale, y / uiscale, w / uiscale, h / uiscale); +} + +Size SDL2DisplayWindow::GetClientSize() const +{ + int w = 0; + int h = 0; + double uiscale = GetDpiScale(); + SDL_GetWindowSize(WindowHandle, &w, &h); + return Size(w / uiscale, h / uiscale); +} + +int SDL2DisplayWindow::GetPixelWidth() const +{ + int w = 0; + int h = 0; + int result = SDL_GetRendererOutputSize(RendererHandle, &w, &h); + return w; +} + +int SDL2DisplayWindow::GetPixelHeight() const +{ + int w = 0; + int h = 0; + int result = SDL_GetRendererOutputSize(RendererHandle, &w, &h); + return h; +} + +double SDL2DisplayWindow::GetDpiScale() const +{ + // SDL2 doesn't really support this properly. SDL_GetDisplayDPI returns the wrong information according to the docs. + return 1.0; +} + +void SDL2DisplayWindow::PresentBitmap(int width, int height, const uint32_t* pixels) +{ +} + +void SDL2DisplayWindow::SetBorderColor(uint32_t bgra8) +{ + // SDL doesn't have this +} + +void SDL2DisplayWindow::SetCaptionColor(uint32_t bgra8) +{ + // SDL doesn't have this +} + +void SDL2DisplayWindow::SetCaptionTextColor(uint32_t bgra8) +{ + // SDL doesn't have this +} + +std::string SDL2DisplayWindow::GetClipboardText() +{ + char* buffer = SDL_GetClipboardText(); + if (!buffer) + return {}; + std::string text = buffer; + SDL_free(buffer); + return text; +} + +void SDL2DisplayWindow::SetClipboardText(const std::string& text) +{ + SDL_SetClipboardText(text.c_str()); +} + +void SDL2DisplayWindow::ProcessEvents() +{ + SDL_Event event; + while (SDL_PollEvent(&event) != 0) + { + DispatchEvent(event); + } +} + +void SDL2DisplayWindow::RunLoop() +{ + while (!ExitRunLoop) + { + SDL_Event event; + int result = SDL_WaitEvent(&event); + if (result == 0) + throw std::runtime_error(std::string("SDL_WaitEvent failed:") + SDL_GetError()); + DispatchEvent(event); + } +} + +void SDL2DisplayWindow::ExitLoop() +{ + ExitRunLoop = true; +} + +Size SDL2DisplayWindow::GetScreenSize() +{ + SDL_Rect rect = {}; + int result = SDL_GetDisplayBounds(0, &rect); + if (result != 0) + throw std::runtime_error(std::string("Unable to get screen size:") + SDL_GetError()); + + double uiscale = 1.0; // SDL2 doesn't really support this properly. SDL_GetDisplayDPI returns the wrong information according to the docs. + return Size(rect.w / uiscale, rect.h / uiscale); +} + +void* SDL2DisplayWindow::StartTimer(int timeoutMilliseconds, std::function onTimer) +{ + return nullptr; +} + +void SDL2DisplayWindow::StopTimer(void* timerID) +{ +} + +SDL2DisplayWindow* SDL2DisplayWindow::FindEventWindow(const SDL_Event& event) +{ + int windowID; + switch (event.type) + { + case SDL_WINDOWEVENT: windowID = event.window.windowID; break; + case SDL_TEXTINPUT: windowID = event.text.windowID; break; + case SDL_KEYUP: windowID = event.key.windowID; break; + case SDL_KEYDOWN: windowID = event.key.windowID; break; + case SDL_MOUSEBUTTONUP: windowID = event.button.windowID; break; + case SDL_MOUSEBUTTONDOWN: windowID = event.button.windowID; break; + case SDL_MOUSEWHEEL: windowID = event.wheel.windowID; break; + case SDL_MOUSEMOTION: windowID = event.motion.windowID; break; + default: + if (event.type == PaintEventNumber) windowID = event.user.windowID; + else return nullptr; + } + + auto it = WindowList.find(windowID); + return it != WindowList.end() ? it->second : nullptr; +} + +void SDL2DisplayWindow::DispatchEvent(const SDL_Event& event) +{ + SDL2DisplayWindow* window = FindEventWindow(event); + if (!window) return; + + switch (event.type) + { + case SDL_WINDOWEVENT: window->OnWindowEvent(event.window); break; + case SDL_TEXTINPUT: window->OnTextInput(event.text); break; + case SDL_KEYUP: window->OnKeyUp(event.key); break; + case SDL_KEYDOWN: window->OnKeyDown(event.key); break; + case SDL_MOUSEBUTTONUP: window->OnMouseButtonUp(event.button); break; + case SDL_MOUSEBUTTONDOWN: window->OnMouseButtonDown(event.button); break; + case SDL_MOUSEWHEEL: window->OnMouseWheel(event.wheel); break; + case SDL_MOUSEMOTION: window->OnMouseMotion(event.motion); break; + default: + if (event.type == PaintEventNumber) window->OnPaintEvent(); + } +} + +void SDL2DisplayWindow::OnWindowEvent(const SDL_WindowEvent& event) +{ + switch (event.event) + { + case SDL_WINDOWEVENT_CLOSE: WindowHost->OnWindowClose(); break; + case SDL_WINDOWEVENT_MOVED: WindowHost->OnWindowGeometryChanged(); break; + case SDL_WINDOWEVENT_RESIZED: WindowHost->OnWindowGeometryChanged(); break; + case SDL_WINDOWEVENT_SHOWN: WindowHost->OnWindowPaint(); break; + case SDL_WINDOWEVENT_EXPOSED: WindowHost->OnWindowPaint(); break; + case SDL_WINDOWEVENT_FOCUS_GAINED: WindowHost->OnWindowActivated(); break; + case SDL_WINDOWEVENT_FOCUS_LOST: WindowHost->OnWindowDeactivated(); break; + } +} + +void SDL2DisplayWindow::OnTextInput(const SDL_TextInputEvent& event) +{ + WindowHost->OnWindowKeyChar(event.text); +} + +void SDL2DisplayWindow::OnKeyUp(const SDL_KeyboardEvent& event) +{ + WindowHost->OnWindowKeyUp(ScancodeToInputKey(event.keysym.scancode)); +} + +void SDL2DisplayWindow::OnKeyDown(const SDL_KeyboardEvent& event) +{ + WindowHost->OnWindowKeyDown(ScancodeToInputKey(event.keysym.scancode)); +} + +EInputKey SDL2DisplayWindow::GetMouseButtonKey(const SDL_MouseButtonEvent& event) +{ + switch (event.button) + { + case SDL_BUTTON_LEFT: return IK_LeftMouse; + case SDL_BUTTON_MIDDLE: return IK_MiddleMouse; + case SDL_BUTTON_RIGHT: return IK_RightMouse; + // case SDL_BUTTON_X1: return IK_XButton1; + // case SDL_BUTTON_X2: return IK_XButton2; + default: return IK_None; + } +} + +void SDL2DisplayWindow::OnMouseButtonUp(const SDL_MouseButtonEvent& event) +{ + EInputKey key = GetMouseButtonKey(event); + if (key != IK_None) + { + WindowHost->OnWindowMouseUp(GetMousePos(event), key); + } +} + +void SDL2DisplayWindow::OnMouseButtonDown(const SDL_MouseButtonEvent& event) +{ + EInputKey key = GetMouseButtonKey(event); + if (key != IK_None) + { + WindowHost->OnWindowMouseDown(GetMousePos(event), key); + } +} + +void SDL2DisplayWindow::OnMouseWheel(const SDL_MouseWheelEvent& event) +{ + EInputKey key = (event.y > 0) ? IK_MouseWheelUp : (event.y < 0) ? IK_MouseWheelDown : IK_None; + if (key != IK_None) + { + WindowHost->OnWindowMouseWheel(GetMousePos(event), key); + } +} + +void SDL2DisplayWindow::OnMouseMotion(const SDL_MouseMotionEvent& event) +{ + WindowHost->OnWindowMouseMove(GetMousePos(event)); +} + +void SDL2DisplayWindow::OnPaintEvent() +{ + WindowHost->OnWindowPaint(); +} + +EInputKey SDL2DisplayWindow::ScancodeToInputKey(SDL_Scancode keycode) +{ + switch (keycode) + { + case SDL_SCANCODE_BACKSPACE: return IK_Backspace; + case SDL_SCANCODE_TAB: return IK_Tab; + case SDL_SCANCODE_CLEAR: return IK_OEMClear; + case SDL_SCANCODE_RETURN: return IK_Enter; + case SDL_SCANCODE_MENU: return IK_Alt; + case SDL_SCANCODE_PAUSE: return IK_Pause; + case SDL_SCANCODE_ESCAPE: return IK_Escape; + case SDL_SCANCODE_SPACE: return IK_Space; + case SDL_SCANCODE_END: return IK_End; + case SDL_SCANCODE_HOME: return IK_Home; + case SDL_SCANCODE_LEFT: return IK_Left; + case SDL_SCANCODE_UP: return IK_Up; + case SDL_SCANCODE_RIGHT: return IK_Right; + case SDL_SCANCODE_DOWN: return IK_Down; + case SDL_SCANCODE_SELECT: return IK_Select; + case SDL_SCANCODE_PRINTSCREEN: return IK_Print; + case SDL_SCANCODE_EXECUTE: return IK_Execute; + case SDL_SCANCODE_INSERT: return IK_Insert; + case SDL_SCANCODE_DELETE: return IK_Delete; + case SDL_SCANCODE_HELP: return IK_Help; + case SDL_SCANCODE_0: return IK_0; + case SDL_SCANCODE_1: return IK_1; + case SDL_SCANCODE_2: return IK_2; + case SDL_SCANCODE_3: return IK_3; + case SDL_SCANCODE_4: return IK_4; + case SDL_SCANCODE_5: return IK_5; + case SDL_SCANCODE_6: return IK_6; + case SDL_SCANCODE_7: return IK_7; + case SDL_SCANCODE_8: return IK_8; + case SDL_SCANCODE_9: return IK_9; + case SDL_SCANCODE_A: return IK_A; + case SDL_SCANCODE_B: return IK_B; + case SDL_SCANCODE_C: return IK_C; + case SDL_SCANCODE_D: return IK_D; + case SDL_SCANCODE_E: return IK_E; + case SDL_SCANCODE_F: return IK_F; + case SDL_SCANCODE_G: return IK_G; + case SDL_SCANCODE_H: return IK_H; + case SDL_SCANCODE_I: return IK_I; + case SDL_SCANCODE_J: return IK_J; + case SDL_SCANCODE_K: return IK_K; + case SDL_SCANCODE_L: return IK_L; + case SDL_SCANCODE_M: return IK_M; + case SDL_SCANCODE_N: return IK_N; + case SDL_SCANCODE_O: return IK_O; + case SDL_SCANCODE_P: return IK_P; + case SDL_SCANCODE_Q: return IK_Q; + case SDL_SCANCODE_R: return IK_R; + case SDL_SCANCODE_S: return IK_S; + case SDL_SCANCODE_T: return IK_T; + case SDL_SCANCODE_U: return IK_U; + case SDL_SCANCODE_V: return IK_V; + case SDL_SCANCODE_W: return IK_W; + case SDL_SCANCODE_X: return IK_X; + case SDL_SCANCODE_Y: return IK_Y; + case SDL_SCANCODE_Z: return IK_Z; + case SDL_SCANCODE_KP_0: return IK_NumPad0; + case SDL_SCANCODE_KP_1: return IK_NumPad1; + case SDL_SCANCODE_KP_2: return IK_NumPad2; + case SDL_SCANCODE_KP_3: return IK_NumPad3; + case SDL_SCANCODE_KP_4: return IK_NumPad4; + case SDL_SCANCODE_KP_5: return IK_NumPad5; + case SDL_SCANCODE_KP_6: return IK_NumPad6; + case SDL_SCANCODE_KP_7: return IK_NumPad7; + case SDL_SCANCODE_KP_8: return IK_NumPad8; + case SDL_SCANCODE_KP_9: return IK_NumPad9; + // case SDL_SCANCODE_KP_ENTER: return IK_NumPadEnter; + // case SDL_SCANCODE_KP_MULTIPLY: return IK_Multiply; + // case SDL_SCANCODE_KP_PLUS: return IK_Add; + case SDL_SCANCODE_SEPARATOR: return IK_Separator; + // case SDL_SCANCODE_KP_MINUS: return IK_Subtract; + case SDL_SCANCODE_KP_PERIOD: return IK_NumPadPeriod; + // case SDL_SCANCODE_KP_DIVIDE: return IK_Divide; + case SDL_SCANCODE_F1: return IK_F1; + case SDL_SCANCODE_F2: return IK_F2; + case SDL_SCANCODE_F3: return IK_F3; + case SDL_SCANCODE_F4: return IK_F4; + case SDL_SCANCODE_F5: return IK_F5; + case SDL_SCANCODE_F6: return IK_F6; + case SDL_SCANCODE_F7: return IK_F7; + case SDL_SCANCODE_F8: return IK_F8; + case SDL_SCANCODE_F9: return IK_F9; + case SDL_SCANCODE_F10: return IK_F10; + case SDL_SCANCODE_F11: return IK_F11; + case SDL_SCANCODE_F12: return IK_F12; + case SDL_SCANCODE_F13: return IK_F13; + case SDL_SCANCODE_F14: return IK_F14; + case SDL_SCANCODE_F15: return IK_F15; + case SDL_SCANCODE_F16: return IK_F16; + case SDL_SCANCODE_F17: return IK_F17; + case SDL_SCANCODE_F18: return IK_F18; + case SDL_SCANCODE_F19: return IK_F19; + case SDL_SCANCODE_F20: return IK_F20; + case SDL_SCANCODE_F21: return IK_F21; + case SDL_SCANCODE_F22: return IK_F22; + case SDL_SCANCODE_F23: return IK_F23; + case SDL_SCANCODE_F24: return IK_F24; + case SDL_SCANCODE_NUMLOCKCLEAR: return IK_NumLock; + case SDL_SCANCODE_SCROLLLOCK: return IK_ScrollLock; + case SDL_SCANCODE_LSHIFT: return IK_LShift; + case SDL_SCANCODE_RSHIFT: return IK_RShift; + case SDL_SCANCODE_LCTRL: return IK_LControl; + case SDL_SCANCODE_RCTRL: return IK_RControl; + case SDL_SCANCODE_GRAVE: return IK_Tilde; + default: return IK_None; + } +} + +SDL_Scancode SDL2DisplayWindow::InputKeyToScancode(EInputKey inputkey) +{ + switch (inputkey) + { + case IK_Backspace: return SDL_SCANCODE_BACKSPACE; + case IK_Tab: return SDL_SCANCODE_TAB; + case IK_OEMClear: return SDL_SCANCODE_CLEAR; + case IK_Enter: return SDL_SCANCODE_RETURN; + case IK_Alt: return SDL_SCANCODE_MENU; + case IK_Pause: return SDL_SCANCODE_PAUSE; + case IK_Escape: return SDL_SCANCODE_ESCAPE; + case IK_Space: return SDL_SCANCODE_SPACE; + case IK_End: return SDL_SCANCODE_END; + case IK_Home: return SDL_SCANCODE_HOME; + case IK_Left: return SDL_SCANCODE_LEFT; + case IK_Up: return SDL_SCANCODE_UP; + case IK_Right: return SDL_SCANCODE_RIGHT; + case IK_Down: return SDL_SCANCODE_DOWN; + case IK_Select: return SDL_SCANCODE_SELECT; + case IK_Print: return SDL_SCANCODE_PRINTSCREEN; + case IK_Execute: return SDL_SCANCODE_EXECUTE; + case IK_Insert: return SDL_SCANCODE_INSERT; + case IK_Delete: return SDL_SCANCODE_DELETE; + case IK_Help: return SDL_SCANCODE_HELP; + case IK_0: return SDL_SCANCODE_0; + case IK_1: return SDL_SCANCODE_1; + case IK_2: return SDL_SCANCODE_2; + case IK_3: return SDL_SCANCODE_3; + case IK_4: return SDL_SCANCODE_4; + case IK_5: return SDL_SCANCODE_5; + case IK_6: return SDL_SCANCODE_6; + case IK_7: return SDL_SCANCODE_7; + case IK_8: return SDL_SCANCODE_8; + case IK_9: return SDL_SCANCODE_9; + case IK_A: return SDL_SCANCODE_A; + case IK_B: return SDL_SCANCODE_B; + case IK_C: return SDL_SCANCODE_C; + case IK_D: return SDL_SCANCODE_D; + case IK_E: return SDL_SCANCODE_E; + case IK_F: return SDL_SCANCODE_F; + case IK_G: return SDL_SCANCODE_G; + case IK_H: return SDL_SCANCODE_H; + case IK_I: return SDL_SCANCODE_I; + case IK_J: return SDL_SCANCODE_J; + case IK_K: return SDL_SCANCODE_K; + case IK_L: return SDL_SCANCODE_L; + case IK_M: return SDL_SCANCODE_M; + case IK_N: return SDL_SCANCODE_N; + case IK_O: return SDL_SCANCODE_O; + case IK_P: return SDL_SCANCODE_P; + case IK_Q: return SDL_SCANCODE_Q; + case IK_R: return SDL_SCANCODE_R; + case IK_S: return SDL_SCANCODE_S; + case IK_T: return SDL_SCANCODE_T; + case IK_U: return SDL_SCANCODE_U; + case IK_V: return SDL_SCANCODE_V; + case IK_W: return SDL_SCANCODE_W; + case IK_X: return SDL_SCANCODE_X; + case IK_Y: return SDL_SCANCODE_Y; + case IK_Z: return SDL_SCANCODE_Z; + case IK_NumPad0: return SDL_SCANCODE_KP_0; + case IK_NumPad1: return SDL_SCANCODE_KP_1; + case IK_NumPad2: return SDL_SCANCODE_KP_2; + case IK_NumPad3: return SDL_SCANCODE_KP_3; + case IK_NumPad4: return SDL_SCANCODE_KP_4; + case IK_NumPad5: return SDL_SCANCODE_KP_5; + case IK_NumPad6: return SDL_SCANCODE_KP_6; + case IK_NumPad7: return SDL_SCANCODE_KP_7; + case IK_NumPad8: return SDL_SCANCODE_KP_8; + case IK_NumPad9: return SDL_SCANCODE_KP_9; + // case IK_NumPadEnter: return SDL_SCANCODE_KP_ENTER; + // case IK_Multiply return SDL_SCANCODE_KP_MULTIPLY:; + // case IK_Add: return SDL_SCANCODE_KP_PLUS; + case IK_Separator: return SDL_SCANCODE_SEPARATOR; + // case IK_Subtract: return SDL_SCANCODE_KP_MINUS; + case IK_NumPadPeriod: return SDL_SCANCODE_KP_PERIOD; + // case IK_Divide: return SDL_SCANCODE_KP_DIVIDE; + case IK_F1: return SDL_SCANCODE_F1; + case IK_F2: return SDL_SCANCODE_F2; + case IK_F3: return SDL_SCANCODE_F3; + case IK_F4: return SDL_SCANCODE_F4; + case IK_F5: return SDL_SCANCODE_F5; + case IK_F6: return SDL_SCANCODE_F6; + case IK_F7: return SDL_SCANCODE_F7; + case IK_F8: return SDL_SCANCODE_F8; + case IK_F9: return SDL_SCANCODE_F9; + case IK_F10: return SDL_SCANCODE_F10; + case IK_F11: return SDL_SCANCODE_F11; + case IK_F12: return SDL_SCANCODE_F12; + case IK_F13: return SDL_SCANCODE_F13; + case IK_F14: return SDL_SCANCODE_F14; + case IK_F15: return SDL_SCANCODE_F15; + case IK_F16: return SDL_SCANCODE_F16; + case IK_F17: return SDL_SCANCODE_F17; + case IK_F18: return SDL_SCANCODE_F18; + case IK_F19: return SDL_SCANCODE_F19; + case IK_F20: return SDL_SCANCODE_F20; + case IK_F21: return SDL_SCANCODE_F21; + case IK_F22: return SDL_SCANCODE_F22; + case IK_F23: return SDL_SCANCODE_F23; + case IK_F24: return SDL_SCANCODE_F24; + case IK_NumLock: return SDL_SCANCODE_NUMLOCKCLEAR; + case IK_ScrollLock: return SDL_SCANCODE_SCROLLLOCK; + case IK_LShift: return SDL_SCANCODE_LSHIFT; + case IK_RShift: return SDL_SCANCODE_RSHIFT; + case IK_LControl: return SDL_SCANCODE_LCTRL; + case IK_RControl: return SDL_SCANCODE_RCTRL; + case IK_Tilde: return SDL_SCANCODE_GRAVE; + default: return (SDL_Scancode)0; + } +} diff --git a/libraries/ZWidget/src/window/sdl2/sdl2displaywindow.h b/libraries/ZWidget/src/window/sdl2/sdl2displaywindow.h new file mode 100644 index 0000000000..f825303c9c --- /dev/null +++ b/libraries/ZWidget/src/window/sdl2/sdl2displaywindow.h @@ -0,0 +1,85 @@ +#pragma once + +#include +#include +#include +#include + +class SDL2DisplayWindow : public DisplayWindow +{ +public: + SDL2DisplayWindow(DisplayWindowHost* windowHost); + ~SDL2DisplayWindow(); + + void SetWindowTitle(const std::string& text) override; + void SetWindowFrame(const Rect& box) override; + void SetClientFrame(const Rect& box) override; + void Show() override; + void ShowFullscreen() override; + void ShowMaximized() override; + void ShowMinimized() override; + void ShowNormal() override; + void Hide() override; + void Activate() override; + void ShowCursor(bool enable) override; + void LockCursor() override; + void UnlockCursor() override; + void Update() override; + bool GetKeyState(EInputKey key) override; + + Rect GetWindowFrame() const override; + Size GetClientSize() const override; + int GetPixelWidth() const override; + int GetPixelHeight() const override; + double GetDpiScale() const override; + + void PresentBitmap(int width, int height, const uint32_t* pixels) override; + + void SetBorderColor(uint32_t bgra8) override; + void SetCaptionColor(uint32_t bgra8) override; + void SetCaptionTextColor(uint32_t bgra8) override; + + std::string GetClipboardText() override; + void SetClipboardText(const std::string& text) override; + + static void DispatchEvent(const SDL_Event& event); + static SDL2DisplayWindow* FindEventWindow(const SDL_Event& event); + + void OnWindowEvent(const SDL_WindowEvent& event); + void OnTextInput(const SDL_TextInputEvent& event); + void OnKeyUp(const SDL_KeyboardEvent& event); + void OnKeyDown(const SDL_KeyboardEvent& event); + void OnMouseButtonUp(const SDL_MouseButtonEvent& event); + void OnMouseButtonDown(const SDL_MouseButtonEvent& event); + void OnMouseWheel(const SDL_MouseWheelEvent& event); + void OnMouseMotion(const SDL_MouseMotionEvent& event); + void OnPaintEvent(); + + EInputKey GetMouseButtonKey(const SDL_MouseButtonEvent& event); + + static EInputKey ScancodeToInputKey(SDL_Scancode keycode); + static SDL_Scancode InputKeyToScancode(EInputKey inputkey); + + template + Point GetMousePos(const T& event) + { + double uiscale = GetDpiScale(); + return Point(event.x / uiscale, event.y / uiscale); + } + + static void ProcessEvents(); + static void RunLoop(); + static void ExitLoop(); + static Size GetScreenSize(); + + static void* StartTimer(int timeoutMilliseconds, std::function onTimer); + static void StopTimer(void* timerID); + + DisplayWindowHost* WindowHost = nullptr; + SDL_Window* WindowHandle = nullptr; + SDL_Renderer* RendererHandle = nullptr; + + static bool ExitRunLoop; + static Uint32 PaintEventNumber; + static std::unordered_map WindowList; +}; diff --git a/libraries/ZWidget/src/window/window.cpp b/libraries/ZWidget/src/window/window.cpp index 909a2e309e..234be61e43 100644 --- a/libraries/ZWidget/src/window/window.cpp +++ b/libraries/ZWidget/src/window/window.cpp @@ -41,7 +41,7 @@ void DisplayWindow::StopTimer(void* timerID) Win32Window::StopTimer(timerID); } -#else +#elif defined(__APPLE__) std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost) { @@ -78,4 +78,43 @@ void DisplayWindow::StopTimer(void* timerID) throw std::runtime_error("DisplayWindow::StopTimer not implemented"); } +#else + +#include "sdl2/sdl2displaywindow.h" + +std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost) +{ + return std::make_unique(windowHost); +} + +void DisplayWindow::ProcessEvents() +{ + SDL2DisplayWindow::ProcessEvents(); +} + +void DisplayWindow::RunLoop() +{ + SDL2DisplayWindow::RunLoop(); +} + +void DisplayWindow::ExitLoop() +{ + SDL2DisplayWindow::ExitLoop(); +} + +Size DisplayWindow::GetScreenSize() +{ + return SDL2DisplayWindow::GetScreenSize(); +} + +void* DisplayWindow::StartTimer(int timeoutMilliseconds, std::function onTimer) +{ + return SDL2DisplayWindow::StartTimer(timeoutMilliseconds, std::move(onTimer)); +} + +void DisplayWindow::StopTimer(void* timerID) +{ + SDL2DisplayWindow::StopTimer(timerID); +} + #endif