diff options
author | Yuqian Yang <crupest@crupest.life> | 2025-10-16 23:57:23 +0800 |
---|---|---|
committer | Yuqian Yang <crupest@crupest.life> | 2025-10-16 23:57:23 +0800 |
commit | 2a9118d137b411b3871073bb6ab18ba98c225d34 (patch) | |
tree | b5fbcf4d6ca1023efd1f3a9383ae8b242b9aadf6 | |
parent | 0b0a8a4087bd3843d4aa9140a9f302423ad5fde8 (diff) | |
download | cru-2a9118d137b411b3871073bb6ab18ba98c225d34.tar.gz cru-2a9118d137b411b3871073bb6ab18ba98c225d34.tar.bz2 cru-2a9118d137b411b3871073bb6ab18ba98c225d34.zip |
Bootstrap sdl.
-rw-r--r-- | include/cru/platform/gui/sdl/Base.h | 24 | ||||
-rw-r--r-- | include/cru/platform/gui/sdl/UiApplication.h | 69 | ||||
-rw-r--r-- | include/cru/platform/gui/sdl/Window.h | 104 | ||||
-rw-r--r-- | src/platform/gui/sdl/CMakeLists.txt | 8 | ||||
-rw-r--r-- | src/platform/gui/sdl/UiApplication.cpp | 102 | ||||
-rw-r--r-- | src/platform/gui/sdl/Window.cpp | 170 |
6 files changed, 477 insertions, 0 deletions
diff --git a/include/cru/platform/gui/sdl/Base.h b/include/cru/platform/gui/sdl/Base.h new file mode 100644 index 00000000..9dd2eff6 --- /dev/null +++ b/include/cru/platform/gui/sdl/Base.h @@ -0,0 +1,24 @@ + +#pragma once + +#include <cru/base/Exception.h> + +#include "../../Resource.h" + +namespace cru::platform::gui::sdl { +class SdlResource : public Object, public virtual IPlatformResource { + public: + static constexpr const char16_t* kPlatformId = u"SDL"; + + protected: + SdlResource() = default; + + public: + String GetPlatformId() const final { return String(kPlatformId); } +}; + +class SdlException : public PlatformException { + public: + using PlatformException::PlatformException; +}; +} // namespace cru::platform::gui::xcb diff --git a/include/cru/platform/gui/sdl/UiApplication.h b/include/cru/platform/gui/sdl/UiApplication.h new file mode 100644 index 00000000..f47e26bb --- /dev/null +++ b/include/cru/platform/gui/sdl/UiApplication.h @@ -0,0 +1,69 @@ + +#pragma once +#include "../UiApplication.h" +#include "Base.h" + +#include <cru/base/platform/unix/EventLoop.h> +#include <cru/platform/graphics/cairo/CairoGraphicsFactory.h> + +#include <functional> + +namespace cru::platform::gui::sdl { +class SdlWindow; + +class SdlUiApplication : public SdlResource, public virtual IUiApplication { + friend SdlWindow; + + public: + explicit SdlUiApplication( + graphics::cairo::CairoGraphicsFactory* cairo_factory = nullptr); + ~SdlUiApplication(); + + public: + graphics::cairo::CairoGraphicsFactory* GetCairoFactory(); + + public: + int Run() override; + + void RequestQuit(int quit_code) override; + + void AddOnQuitHandler(std::function<void()> handler) override; + + bool IsQuitOnAllWindowClosed() override; + void SetQuitOnAllWindowClosed(bool quit_on_all_window_closed) override; + + long long SetImmediate(std::function<void()> action) override; + long long SetTimeout(std::chrono::milliseconds milliseconds, + std::function<void()> action) override; + long long SetInterval(std::chrono::milliseconds milliseconds, + std::function<void()> action) override; + void CancelTimer(long long id) override; + + std::vector<INativeWindow*> GetAllWindow() override; + + INativeWindow* CreateWindow() override; + + cru::platform::graphics::IGraphicsFactory* GetGraphicsFactory() override; + + ICursorManager* GetCursorManager() override; + + IClipboard* GetClipboard() override; + + // If return nullptr, it means the menu is not supported. + IMenu* GetApplicationMenu() override; + + private: + void RegisterWindow(SdlWindow* window); + void UnregisterWindow(SdlWindow* window); + + private: + graphics::cairo::CairoGraphicsFactory* cairo_factory_; + bool release_cairo_factory_; + + cru::platform::unix::UnixEventLoop event_loop_; + std::vector<std::function<void()>> quit_handlers_; + + bool is_quit_on_all_window_closed_; + std::vector<SdlWindow*> windows_; +}; +} // namespace cru::platform::gui::xcb diff --git a/include/cru/platform/gui/sdl/Window.h b/include/cru/platform/gui/sdl/Window.h new file mode 100644 index 00000000..1bcd42bf --- /dev/null +++ b/include/cru/platform/gui/sdl/Window.h @@ -0,0 +1,104 @@ +#pragma once +#include <cru/base/Base.h> +#include "../../GraphicsBase.h" +#include "../Window.h" +#include "Base.h" + +#include <SDL_video.h> +#include <cstddef> +#include <optional> + +namespace cru::platform::gui::sdl { +class SdlUiApplication; + +class SdlWindow : public SdlResource, public virtual INativeWindow { + CRU_DEFINE_CLASS_LOG_TAG("cru::platform::gui::xcb::SdlWindow") + + friend SdlUiApplication; + + public: + explicit SdlWindow(SdlUiApplication* application); + ~SdlWindow() override; + + bool IsCreated() override; + void Close() override; + + INativeWindow* GetParent() override; + void SetParent(INativeWindow* parent) override; + + WindowStyleFlag GetStyleFlag() override; + void SetStyleFlag(WindowStyleFlag flag) override; + + String GetTitle() override; + void SetTitle(String title) override; + + WindowVisibilityType GetVisibility() override; + void SetVisibility(WindowVisibilityType visibility) override; + + Size GetClientSize() override; + void SetClientSize(const Size& size) override; + + Rect GetClientRect() override; + void SetClientRect(const Rect& rect) override; + + Rect GetWindowRect() override; + void SetWindowRect(const Rect& rect) override; + + bool RequestFocus() override; + + Point GetMousePosition() override; + + bool CaptureMouse() override; + bool ReleaseMouse() override; + + void SetCursor(std::shared_ptr<ICursor> cursor) override; + + void SetToForeground() override; + + void RequestRepaint() override; + + std::unique_ptr<graphics::IPainter> BeginPaint() override; + + IEvent<std::nullptr_t>* CreateEvent() override; + IEvent<std::nullptr_t>* DestroyEvent() override; + IEvent<std::nullptr_t>* PaintEvent() override; + + IEvent<WindowVisibilityType>* VisibilityChangeEvent() override; + IEvent<Size>* ResizeEvent() override; + IEvent<FocusChangeType>* FocusEvent() override; + + IEvent<MouseEnterLeaveType>* MouseEnterLeaveEvent() override; + IEvent<Point>* MouseMoveEvent() override; + IEvent<NativeMouseButtonEventArgs>* MouseDownEvent() override; + IEvent<NativeMouseButtonEventArgs>* MouseUpEvent() override; + IEvent<NativeMouseWheelEventArgs>* MouseWheelEvent() override; + IEvent<NativeKeyEventArgs>* KeyDownEvent() override; + IEvent<NativeKeyEventArgs>* KeyUpEvent() override; + + IInputMethodContext* GetInputMethodContext() override; + + public: + std::optional<SDL_Window*> GetSdlWindow(); + SdlUiApplication* GetSdlUiApplication(); + + private: + SdlUiApplication* application_; + std::optional<SDL_Window*> sdl_window_; + SdlWindow* parent_; + WindowStyleFlag style_; + + Event<std::nullptr_t> create_event_; + Event<std::nullptr_t> destroy_event_; + Event<std::nullptr_t> paint_event_; + Event<WindowVisibilityType> visibility_change_event_; + Event<Size> resize_event_; + Event<FocusChangeType> focus_event_; + Event<MouseEnterLeaveType> mouse_enter_leave_event_; + Event<Point> mouse_move_event_; + Event<NativeMouseButtonEventArgs> mouse_down_event_; + Event<NativeMouseButtonEventArgs> mouse_up_event_; + Event<NativeMouseWheelEventArgs> mouse_wheel_event_; + Event<NativeKeyEventArgs> key_down_event_; + Event<NativeKeyEventArgs> key_up_event_; +}; +} // namespace cru::platform::gui::xcb diff --git a/src/platform/gui/sdl/CMakeLists.txt b/src/platform/gui/sdl/CMakeLists.txt index 5dcc408b..f4266622 100644 --- a/src/platform/gui/sdl/CMakeLists.txt +++ b/src/platform/gui/sdl/CMakeLists.txt @@ -1,2 +1,10 @@ find_package(SDL2 REQUIRED CONFIG REQUIRED COMPONENTS SDL2) +add_library(CruPlatformGuiSdl + UiApplication.cpp + Window.cpp +) +target_link_libraries(CruPlatformGuiSdl PUBLIC + CruPlatformGui CruPlatformGraphicsCairo + SDL2::SDL2 +) diff --git a/src/platform/gui/sdl/UiApplication.cpp b/src/platform/gui/sdl/UiApplication.cpp new file mode 100644 index 00000000..a961ce84 --- /dev/null +++ b/src/platform/gui/sdl/UiApplication.cpp @@ -0,0 +1,102 @@ + +#include "cru/platform/gui/sdl/UiApplication.h" + +#include "cru/base/Base.h" +#include "cru/platform/graphics/cairo/CairoGraphicsFactory.h" +#include "cru/platform/gui/sdl/Window.h" + +#include <algorithm> + +namespace cru::platform::gui::sdl { +SdlUiApplication::SdlUiApplication( + graphics::cairo::CairoGraphicsFactory *cairo_factory) { + release_cairo_factory_ = false; + if (cairo_factory == nullptr) { + cairo_factory = new graphics::cairo::CairoGraphicsFactory(); + release_cairo_factory_ = true; + } + cairo_factory_ = cairo_factory; +} + +SdlUiApplication::~SdlUiApplication() { + if (release_cairo_factory_) { + delete cairo_factory_; + } +} + +graphics::cairo::CairoGraphicsFactory *SdlUiApplication::GetCairoFactory() { + return cairo_factory_; +} + +int SdlUiApplication::Run() { + auto exit_code = event_loop_.Run(); + + for (const auto &handler : this->quit_handlers_) { + handler(); + } + + return exit_code; +} + +void SdlUiApplication::RequestQuit(int quit_code) { + event_loop_.RequestQuit(quit_code); +} + +void SdlUiApplication::AddOnQuitHandler(std::function<void()> handler) { + this->quit_handlers_.push_back(std::move(handler)); +} + +bool SdlUiApplication::IsQuitOnAllWindowClosed() { + return is_quit_on_all_window_closed_; +} + +void SdlUiApplication::SetQuitOnAllWindowClosed( + bool quit_on_all_window_closed) { + is_quit_on_all_window_closed_ = quit_on_all_window_closed; +} + +long long SdlUiApplication::SetImmediate(std::function<void()> action) { + return event_loop_.SetImmediate(std::move(action)); +} + +long long SdlUiApplication::SetTimeout(std::chrono::milliseconds milliseconds, + std::function<void()> action) { + return event_loop_.SetTimeout(std::move(action), std::move(milliseconds)); +} + +long long SdlUiApplication::SetInterval(std::chrono::milliseconds milliseconds, + std::function<void()> action) { + return event_loop_.SetInterval(std::move(action), std::move(milliseconds)); +} + +void SdlUiApplication::CancelTimer(long long id) { + return event_loop_.CancelTimer(static_cast<int>(id)); +} + +std::vector<INativeWindow *> SdlUiApplication::GetAllWindow() { + std::vector<INativeWindow *> windows(windows_.size()); + std::ranges::copy(windows_, windows.begin()); + return windows; +} + +INativeWindow *SdlUiApplication::CreateWindow() { return new SdlWindow(this); } + +cru::platform::graphics::IGraphicsFactory * +SdlUiApplication::GetGraphicsFactory() { + return cairo_factory_; +} + +ICursorManager *SdlUiApplication::GetCursorManager() { NotImplemented(); } + +IClipboard *SdlUiApplication::GetClipboard() { NotImplemented(); } + +IMenu *SdlUiApplication::GetApplicationMenu() { return nullptr; } + +void SdlUiApplication::RegisterWindow(SdlWindow *window) { + windows_.push_back(window); +} + +void SdlUiApplication::UnregisterWindow(SdlWindow *window) { + std::erase(windows_, window); +} +} // namespace cru::platform::gui::sdl diff --git a/src/platform/gui/sdl/Window.cpp b/src/platform/gui/sdl/Window.cpp new file mode 100644 index 00000000..e802b82f --- /dev/null +++ b/src/platform/gui/sdl/Window.cpp @@ -0,0 +1,170 @@ +#include "cru/platform/gui/sdl/Window.h" +#include "cru/base/Base.h" +#include "cru/platform/Check.h" +#include "cru/platform/GraphicsBase.h" +#include "cru/platform/graphics/NullPainter.h" +#include "cru/platform/graphics/Painter.h" +#include "cru/platform/gui/Base.h" +#include "cru/platform/gui/Window.h" +#include "cru/platform/gui/sdl/UiApplication.h" + +#include <SDL_video.h> +#include <cairo-xcb.h> +#include <cairo.h> +#include <cassert> +#include <memory> +#include <optional> + +namespace cru::platform::gui::sdl { + +SdlWindow::SdlWindow(SdlUiApplication *application) + : application_(application), parent_(nullptr) { + application->RegisterWindow(this); +} + +SdlWindow::~SdlWindow() { application_->UnregisterWindow(this); } + +bool SdlWindow::IsCreated() { return sdl_window_.has_value(); } + +void SdlWindow::Close() { + if (sdl_window_) { + SDL_DestroyWindow(*sdl_window_); + } +} + +INativeWindow *SdlWindow::GetParent() { return parent_; } + +void SdlWindow::SetParent(INativeWindow *parent) { + parent_ = CheckPlatform<SdlWindow>(parent, GetPlatformIdUtf8()); + NotImplemented(); +} + +WindowStyleFlag SdlWindow::GetStyleFlag() { return style_; } + +void SdlWindow::SetStyleFlag(WindowStyleFlag flag) { + style_ = flag; + NotImplemented(); +} + +String SdlWindow::GetTitle() { NotImplemented(); } + +void SdlWindow::SetTitle(String title) { NotImplemented(); } + +WindowVisibilityType SdlWindow::GetVisibility() { NotImplemented(); } + +void SdlWindow::SetVisibility(WindowVisibilityType visibility) { + NotImplemented(); +} + +Size SdlWindow::GetClientSize() { return GetClientRect().GetSize(); } + +void SdlWindow::SetClientSize(const Size &size) { + auto rect = GetClientRect(); + SetClientRect(Rect(rect.GetLeftTop(), size)); +} + +Rect SdlWindow::GetClientRect() { + if (!sdl_window_) return {}; + NotImplemented(); +} + +void SdlWindow::SetClientRect(const Rect &rect) { + if (!sdl_window_) return; + NotImplemented(); +} + +Rect SdlWindow::GetWindowRect() { + if (!sdl_window_) return {}; + NotImplemented(); +} + +void SdlWindow::SetWindowRect(const Rect &rect) { + if (!sdl_window_) return; + NotImplemented(); +} + +bool SdlWindow::RequestFocus() { + if (!sdl_window_) return false; + NotImplemented(); +} + +Point SdlWindow::GetMousePosition() { NotImplemented(); } + +bool SdlWindow::CaptureMouse() { + if (!sdl_window_) return false; + NotImplemented(); +} + +bool SdlWindow::ReleaseMouse() { + if (!sdl_window_) return false; + NotImplemented(); +} + +void SdlWindow::SetCursor(std::shared_ptr<ICursor> cursor) { + if (!sdl_window_) return; + NotImplemented(); +} + +void SdlWindow::SetToForeground() { + SetVisibility(WindowVisibilityType::Show); + NotImplemented(); +} + +void SdlWindow::RequestRepaint() { + if (!sdl_window_) return; + NotImplemented(); +} + +std::unique_ptr<graphics::IPainter> SdlWindow::BeginPaint() { + if (!sdl_window_.has_value()) { + return std::make_unique<graphics::NullPainter>(); + } + + NotImplemented(); +} + +IEvent<std::nullptr_t> *SdlWindow::CreateEvent() { return &create_event_; } + +IEvent<std::nullptr_t> *SdlWindow::DestroyEvent() { return &destroy_event_; } + +IEvent<std::nullptr_t> *SdlWindow::PaintEvent() { return &paint_event_; } + +IEvent<WindowVisibilityType> *SdlWindow::VisibilityChangeEvent() { + return &visibility_change_event_; +} + +IEvent<Size> *SdlWindow::ResizeEvent() { return &resize_event_; } + +IEvent<FocusChangeType> *SdlWindow::FocusEvent() { return &focus_event_; } + +IEvent<MouseEnterLeaveType> *SdlWindow::MouseEnterLeaveEvent() { + return &mouse_enter_leave_event_; +} + +IEvent<Point> *SdlWindow::MouseMoveEvent() { return &mouse_move_event_; } + +IEvent<NativeMouseButtonEventArgs> *SdlWindow::MouseDownEvent() { + return &mouse_down_event_; +} + +IEvent<NativeMouseButtonEventArgs> *SdlWindow::MouseUpEvent() { + return &mouse_up_event_; +} + +IEvent<NativeMouseWheelEventArgs> *SdlWindow::MouseWheelEvent() { + return &mouse_wheel_event_; +} + +IEvent<NativeKeyEventArgs> *SdlWindow::KeyDownEvent() { + return &key_down_event_; +} + +IEvent<NativeKeyEventArgs> *SdlWindow::KeyUpEvent() { return &key_up_event_; } + +IInputMethodContext *SdlWindow::GetInputMethodContext() { NotImplemented(); } + +std::optional<SDL_Window *> SdlWindow::GetSdlWindow() { return sdl_window_; } + +SdlUiApplication *SdlWindow::GetSdlUiApplication() { return application_; } + +} // namespace cru::platform::gui::sdl |