diff options
Diffstat (limited to 'src/osx/gui')
-rw-r--r-- | src/osx/gui/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/osx/gui/Cursor.mm | 93 | ||||
-rw-r--r-- | src/osx/gui/CursorPrivate.h | 29 | ||||
-rw-r--r-- | src/osx/gui/UiApplication.mm | 16 | ||||
-rw-r--r-- | src/osx/gui/Window.mm | 102 |
5 files changed, 228 insertions, 15 deletions
diff --git a/src/osx/gui/CMakeLists.txt b/src/osx/gui/CMakeLists.txt index 27546fc2..e2647165 100644 --- a/src/osx/gui/CMakeLists.txt +++ b/src/osx/gui/CMakeLists.txt @@ -1,10 +1,13 @@ set(CRU_OSX_GUI_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/osx/gui) add_library(cru_osx_gui SHARED + Cursor.mm Keyboard.mm Resource.cpp UiApplication.mm Window.mm + + CursorPrivate.h ) target_sources(cru_osx_gui PUBLIC diff --git a/src/osx/gui/Cursor.mm b/src/osx/gui/Cursor.mm new file mode 100644 index 00000000..30b0f0fd --- /dev/null +++ b/src/osx/gui/Cursor.mm @@ -0,0 +1,93 @@ +#include "cru/osx/gui/Cursor.hpp" +#include "CursorPrivate.h" + +#include "cru/osx/Exception.hpp" +#include "cru/osx/gui/Resource.hpp" +#include "cru/platform/gui/Cursor.hpp" +#include "cru/platform/gui/UiApplication.hpp" + +#include <memory> + +namespace cru::platform::gui::osx { +namespace details { +OsxCursorPrivate::OsxCursorPrivate(OsxCursor* cursor, SystemCursorType cursor_type) { + cursor_ = cursor; + + switch (cursor_type) { + case SystemCursorType::Arrow: + ns_cursor_ = [NSCursor arrowCursor]; + break; + case SystemCursorType::Hand: + ns_cursor_ = [NSCursor pointingHandCursor]; + break; + case SystemCursorType::IBeam: + ns_cursor_ = [NSCursor IBeamCursor]; + break; + default: + throw Exception(u"Unknown system cursor type."); + } +} + +OsxCursorPrivate::~OsxCursorPrivate() {} +} + +OsxCursor::OsxCursor(IUiApplication* ui_application, SystemCursorType cursor_type) + : OsxGuiResource(ui_application) { + p_ = std::make_unique<details::OsxCursorPrivate>(this, cursor_type); +} + +OsxCursor::~OsxCursor() {} + +namespace details { +class OsxCursorManagerPrivate { + friend OsxCursorManager; + + public: + explicit OsxCursorManagerPrivate(OsxCursorManager* cursor_manager); + + CRU_DELETE_COPY(OsxCursorManagerPrivate) + CRU_DELETE_MOVE(OsxCursorManagerPrivate) + + ~OsxCursorManagerPrivate(); + + private: + OsxCursorManager* cursor_manager_; + + std::shared_ptr<OsxCursor> arrow_cursor_; + std::shared_ptr<OsxCursor> hand_cursor_; + std::shared_ptr<OsxCursor> ibeam_cursor_; +}; + +OsxCursorManagerPrivate::OsxCursorManagerPrivate(OsxCursorManager* cursor_manager) { + cursor_manager_ = cursor_manager; + arrow_cursor_ = + std::make_shared<OsxCursor>(cursor_manager->GetUiApplication(), SystemCursorType::Arrow); + hand_cursor_ = + std::make_shared<OsxCursor>(cursor_manager->GetUiApplication(), SystemCursorType::Hand); + ibeam_cursor_ = + std::make_shared<OsxCursor>(cursor_manager->GetUiApplication(), SystemCursorType::IBeam); +} + +OsxCursorManagerPrivate::~OsxCursorManagerPrivate() {} +} + +OsxCursorManager::OsxCursorManager(IUiApplication* ui_application) + : OsxGuiResource(ui_application) { + p_ = std::make_unique<details::OsxCursorManagerPrivate>(this); +} + +OsxCursorManager::~OsxCursorManager() {} + +std::shared_ptr<ICursor> OsxCursorManager::GetSystemCursor(SystemCursorType type) { + switch (type) { + case SystemCursorType::Arrow: + return p_->arrow_cursor_; + case SystemCursorType::Hand: + return p_->hand_cursor_; + case SystemCursorType::IBeam: + return p_->ibeam_cursor_; + default: + throw Exception(u"Unknown system cursor type."); + } +} +} diff --git a/src/osx/gui/CursorPrivate.h b/src/osx/gui/CursorPrivate.h new file mode 100644 index 00000000..5daf09f7 --- /dev/null +++ b/src/osx/gui/CursorPrivate.h @@ -0,0 +1,29 @@ +#pragma once +#include "cru/osx/gui/Cursor.hpp" + +#import <AppKit/NSCursor.h> + +namespace cru::platform::gui::osx { +class OsxWindow; + +namespace details { +class OsxWindowPrivate; + +class OsxCursorPrivate { + friend OsxWindow; + friend OsxWindowPrivate; + + public: + OsxCursorPrivate(OsxCursor* cursor, SystemCursorType cursor_type); + + CRU_DELETE_COPY(OsxCursorPrivate) + CRU_DELETE_MOVE(OsxCursorPrivate) + + ~OsxCursorPrivate(); + + private: + OsxCursor* cursor_; + NSCursor* ns_cursor_; +}; +} // namespace details +} // namespace cru::platform::gui::osx diff --git a/src/osx/gui/UiApplication.mm b/src/osx/gui/UiApplication.mm index d2e6fe30..4ac3d1df 100644 --- a/src/osx/gui/UiApplication.mm +++ b/src/osx/gui/UiApplication.mm @@ -1,7 +1,9 @@ #include "cru/osx/gui/UiApplication.hpp" #include "cru/osx/graphics/quartz/Factory.hpp" +#include "cru/osx/gui/Cursor.hpp" #include "cru/osx/gui/Window.hpp" +#include "cru/platform/graphics/Factory.hpp" #include "cru/platform/gui/UiApplication.hpp" #include "cru/platform/gui/Window.hpp" @@ -50,6 +52,8 @@ class OsxUiApplicationPrivate { std::vector<OsxWindow*> windows_; + std::unique_ptr<OsxCursorManager> cursor_manager_; + std::unique_ptr<platform::graphics::osx::quartz::QuartzGraphicsFactory> quartz_graphics_factory_; }; @@ -64,6 +68,7 @@ OsxUiApplication::OsxUiApplication() : OsxGuiResource(this), p_(new details::OsxUiApplicationPrivate(this)) { [NSApp setDelegate:p_->app_delegate_]; p_->quartz_graphics_factory_ = std::make_unique<graphics::osx::quartz::QuartzGraphicsFactory>(); + p_->cursor_manager_ = std::make_unique<OsxCursorManager>(this); } OsxUiApplication::~OsxUiApplication() {} @@ -143,6 +148,12 @@ INativeWindow* OsxUiApplication::CreateWindow(INativeWindow* parent, CreateWindo return window; } +ICursorManager* OsxUiApplication::GetCursorManager() { return p_->cursor_manager_.get(); } + +graphics::IGraphicsFactory* OsxUiApplication::GetGraphicsFactory() { + return p_->quartz_graphics_factory_.get(); +} + void OsxUiApplication::UnregisterWindow(OsxWindow* window) { p_->windows_.erase( std::remove(p_->windows_.begin(), p_->windows_.end(), static_cast<INativeWindow*>(window)), @@ -150,8 +161,9 @@ void OsxUiApplication::UnregisterWindow(OsxWindow* window) { } } -@implementation AppDelegate -cru::platform::gui::osx::details::OsxUiApplicationPrivate* _p; +@implementation AppDelegate { + cru::platform::gui::osx::details::OsxUiApplicationPrivate* _p; +} - (id)init:(cru::platform::gui::osx::details::OsxUiApplicationPrivate*)p { _p = p; diff --git a/src/osx/gui/Window.mm b/src/osx/gui/Window.mm index c2134c76..da39d34d 100644 --- a/src/osx/gui/Window.mm +++ b/src/osx/gui/Window.mm @@ -1,11 +1,16 @@ #include "cru/osx/gui/Window.hpp" +#include "CursorPrivate.h" #include "cru/common/Range.hpp" #include "cru/osx/Convert.hpp" #include "cru/osx/graphics/quartz/Painter.hpp" +#include "cru/osx/gui/Cursor.hpp" #include "cru/osx/gui/Keyboard.hpp" +#include "cru/osx/gui/Resource.hpp" #include "cru/osx/gui/UiApplication.hpp" +#include "cru/platform/Check.hpp" #include "cru/platform/gui/Base.hpp" +#include "cru/platform/gui/Cursor.hpp" #include "cru/platform/gui/InputMethod.hpp" #include "cru/platform/gui/Keyboard.hpp" #include "cru/platform/gui/Window.hpp" @@ -34,6 +39,7 @@ namespace details { class OsxWindowPrivate { friend OsxWindow; + friend OsxInputMethodContextPrivate; public: explicit OsxWindowPrivate(OsxWindow* osx_window) : osx_window_(osx_window) { @@ -52,6 +58,9 @@ class OsxWindowPrivate { void OnWindowDidResize(); private: + void UpdateCursor(); + + private: OsxWindow* osx_window_; INativeWindow* parent_; @@ -61,6 +70,12 @@ class OsxWindowPrivate { NSWindow* window_; WindowDelegate* window_delegate_; + + bool mouse_in_ = false; + + std::shared_ptr<OsxCursor> cursor_ = nullptr; + + std::unique_ptr<OsxInputMethodContext> input_method_context_; }; void OsxWindowPrivate::OnWindowWillClose() { osx_window_->destroy_event_.Raise(nullptr); } @@ -69,6 +84,16 @@ void OsxWindowPrivate::OnWindowDidUpdate() { osx_window_->paint_event_.Raise(nul void OsxWindowPrivate::OnWindowDidResize() { osx_window_->resize_event_.Raise(osx_window_->GetClientSize()); } + +void OsxWindowPrivate::UpdateCursor() { + auto cursor = cursor_ == nullptr + ? std::dynamic_pointer_cast<OsxCursor>( + osx_window_->GetUiApplication()->GetCursorManager()->GetSystemCursor( + SystemCursorType::Arrow)) + : cursor_; + + [cursor->p_->ns_cursor_ set]; +} } namespace { @@ -86,6 +111,8 @@ OsxWindow::OsxWindow(OsxUiApplication* ui_application, INativeWindow* parent, bo p_->frame_ = frame; p_->content_rect_ = {100, 100, 400, 200}; + + p_->input_method_context_ = std::make_unique<OsxInputMethodContext>(this); } OsxWindow::~OsxWindow() { @@ -155,6 +182,8 @@ void OsxWindow::SetWindowRect(const Rect& rect) { } } +void OsxWindow::RequestRepaint() { [p_->window_ update]; } + std::unique_ptr<graphics::IPainter> OsxWindow::BeginPaint() { NSGraphicsContext* ns_graphics_context = [NSGraphicsContext graphicsContextWithWindow:p_->window_]; @@ -194,9 +223,12 @@ void OsxWindow::CreateWindow() { switch (event.type) { case NSEventTypeMouseEntered: this->mouse_enter_leave_event_.Raise(MouseEnterLeaveType::Enter); + p_->mouse_in_ = true; + p_->UpdateCursor(); break; case NSEventTypeMouseExited: this->mouse_enter_leave_event_.Raise(MouseEnterLeaveType::Leave); + p_->mouse_in_ = false; break; case NSEventTypeMouseMoved: this->mouse_move_event_.Raise( @@ -247,17 +279,35 @@ void OsxWindow::CreateWindow() { }]; } +Point OsxWindow::GetMousePosition() { + auto p = [p_->window_ mouseLocationOutsideOfEventStream]; + return Point(p.x, p.y); +} + +bool OsxWindow::CaptureMouse() { return true; } + +bool OsxWindow::ReleaseMouse() { return true; } + +void OsxWindow::SetCursor(std::shared_ptr<ICursor> cursor) { + p_->cursor_ = CheckPlatform<OsxCursor>(cursor, GetPlatformId()); + if (p_->mouse_in_) { + p_->UpdateCursor(); + } +} + +IInputMethodContext* OsxWindow::GetInputMethodContext() { return p_->input_method_context_.get(); } + namespace details { class OsxInputMethodContextPrivate { friend OsxInputMethodContext; public: - explicit OsxInputMethodContextPrivate(OsxInputMethodContext* input_method_context); + OsxInputMethodContextPrivate(OsxInputMethodContext* input_method_context, OsxWindow* window); CRU_DELETE_COPY(OsxInputMethodContextPrivate) CRU_DELETE_MOVE(OsxInputMethodContextPrivate) - ~OsxInputMethodContextPrivate() = default; + ~OsxInputMethodContextPrivate(); void SetCompositionText(CompositionText composition_text) { composition_text_ = std::move(composition_text); @@ -274,7 +324,11 @@ class OsxInputMethodContextPrivate { Range GetSelectionRange() const { return selection_range_; } void SetSelectionRange(Range selection_range) { selection_range_ = selection_range; } + void PerformSel(SEL sel); + private: + OsxWindow* window_; + CompositionText composition_text_; Range selection_range_; @@ -290,6 +344,14 @@ class OsxInputMethodContextPrivate { Event<StringView> text_event_; }; +OsxInputMethodContextPrivate::OsxInputMethodContextPrivate( + OsxInputMethodContext* input_method_context, OsxWindow* window) { + input_method_context_ = input_method_context; + window_ = window; +} + +OsxInputMethodContextPrivate::~OsxInputMethodContextPrivate() {} + void OsxInputMethodContextPrivate::RaiseCompositionStartEvent() { composition_start_event_.Raise(nullptr); } @@ -299,8 +361,20 @@ void OsxInputMethodContextPrivate::RaiseCompositionEndEvent() { void OsxInputMethodContextPrivate::RaiseCompositionEvent() { composition_event_.Raise(nullptr); } void OsxInputMethodContextPrivate::RaiseTextEvent(StringView text) { text_event_.Raise(text); } + +void OsxInputMethodContextPrivate::PerformSel(SEL sel) { + [window_->p_->window_ performSelector:sel]; } +} + +OsxInputMethodContext::OsxInputMethodContext(OsxWindow* window) + : OsxGuiResource(window->GetUiApplication()) { + p_ = std::make_unique<details::OsxInputMethodContextPrivate>(this, window); +} + +OsxInputMethodContext::~OsxInputMethodContext() {} + void OsxInputMethodContext::EnableIME() { [[NSTextInputContext currentInputContext] deactivate]; } void OsxInputMethodContext::DisableIME() { [[NSTextInputContext currentInputContext] activate]; } @@ -336,34 +410,36 @@ IEvent<std::nullptr_t>* OsxInputMethodContext::CompositionEvent() { IEvent<StringView>* OsxInputMethodContext::TextEvent() { return &p_->text_event_; } } -@implementation WindowDelegate -cru::platform::gui::osx::details::OsxWindowPrivate* p_; +@implementation WindowDelegate { + cru::platform::gui::osx::details::OsxWindowPrivate* _p; +} - (id)init:(cru::platform::gui::osx::details::OsxWindowPrivate*)p { - p_ = p; + _p = p; return self; } - (void)windowWillClose:(NSNotification*)notification { - p_->OnWindowWillClose(); + _p->OnWindowWillClose(); } - (void)windowDidExpose:(NSNotification*)notification { - p_->OnWindowDidExpose(); + _p->OnWindowDidExpose(); } - (void)windowDidUpdate:(NSNotification*)notification { - p_->OnWindowDidUpdate(); + _p->OnWindowDidUpdate(); } - (void)windowDidResize:(NSNotification*)notification { - p_->OnWindowDidResize(); + _p->OnWindowDidResize(); } @end -@implementation InputClient -cru::platform::gui::osx::details::OsxInputMethodContextPrivate* _p; -NSMutableAttributedString* _text; +@implementation InputClient { + cru::platform::gui::osx::details::OsxInputMethodContextPrivate* _p; + NSMutableAttributedString* _text; +} - (id)init:(cru::platform::gui::osx::details::OsxInputMethodContextPrivate*)p { _p = p; @@ -440,6 +516,6 @@ NSMutableAttributedString* _text; } - (void)doCommandBySelector:(SEL)selector { - // TODO: Call with window. + _p->PerformSel(selector); } @end |