diff options
-rw-r--r-- | demos/CMakeLists.txt | 8 | ||||
-rw-r--r-- | demos/input_method/main.cpp | 23 | ||||
-rw-r--r-- | include/cru/common/String.hpp | 144 | ||||
-rw-r--r-- | include/cru/osx/gui/Cursor.hpp | 43 | ||||
-rw-r--r-- | include/cru/osx/gui/Window.hpp | 2 | ||||
-rw-r--r-- | include/cru/platform/bootstrap/Bootstrap.hpp | 2 | ||||
-rw-r--r-- | src/common/String.cpp | 2 | ||||
-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 | ||||
-rw-r--r-- | src/platform/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/platform/bootstrap/Bootstrap.cpp | 8 | ||||
-rw-r--r-- | src/platform/bootstrap/CMakeLists.txt | 10 |
15 files changed, 375 insertions, 112 deletions
diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index f975a6e9..1a86c69f 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -1,14 +1,14 @@ add_library(cru_demo_base INTERFACE) -target_link_libraries(cru_demo_base INTERFACE cru_platform_boostrap) +target_link_libraries(cru_demo_base INTERFACE cru_platform_bootstrap) if(WIN32) # Currently only enable tests on Windows. add_subdirectory(main) add_subdirectory(scroll_view) add_subdirectory(input_method) -endif() - -if(UNIX AND NOT APPLE) +elseif(APPLE) + add_subdirectory(input_method) +elseif(UNIX) add_subdirectory(xcb) endif() diff --git a/demos/input_method/main.cpp b/demos/input_method/main.cpp index b509cd97..7c22783c 100644 --- a/demos/input_method/main.cpp +++ b/demos/input_method/main.cpp @@ -7,41 +7,42 @@ #include "cru/platform/gui/Window.hpp" int main() { + using namespace cru; using namespace cru::platform; using namespace cru::platform::graphics; using namespace cru::platform::gui; - IUiApplication* application = boostrap::CreateUiApplication(); + IUiApplication* application = bootstrap::CreateUiApplication(); - auto graph_factory = application->GetGraphFactory(); + auto graphics_factory = application->GetGraphicsFactory(); auto window = application->CreateWindow(nullptr); auto input_method_context = window->GetInputMethodContext(); - auto brush = graph_factory->CreateSolidColorBrush(); + auto brush = graphics_factory->CreateSolidColorBrush(); brush->SetColor(colors::black); - auto odd_clause_brush = graph_factory->CreateSolidColorBrush(); + auto odd_clause_brush = graphics_factory->CreateSolidColorBrush(); odd_clause_brush->SetColor(colors::yellow); - auto even_clause_brush = graph_factory->CreateSolidColorBrush(); + auto even_clause_brush = graphics_factory->CreateSolidColorBrush(); even_clause_brush->SetColor(colors::green); - auto target_clause_brush = graph_factory->CreateSolidColorBrush(); + auto target_clause_brush = graphics_factory->CreateSolidColorBrush(); target_clause_brush->SetColor(colors::blue); - std::shared_ptr<IFont> font = graph_factory->CreateFont(u"等线", 30); + std::shared_ptr<IFont> font = graphics_factory->CreateFont(u"等线", 30); float window_width = 10000; auto prompt_text_layout = - graph_factory->CreateTextLayout(font, + graphics_factory->CreateTextLayout(font, u"Alt+F1: Enable IME\n" u"Alt+F2: Disable IME\n" u"Alt+F3: Complete composition.\n" u"Alt+F4: Cancel composition."); std::optional<CompositionText> optional_composition_text; - std::u16string committed_text; + String committed_text; window->ResizeEvent()->AddHandler( [&prompt_text_layout, &window_width](const Size& size) { @@ -57,7 +58,7 @@ int main() { const auto anchor_y = prompt_text_layout->GetTextBounds().height; - auto text_layout = graph_factory->CreateTextLayout( + auto text_layout = graphics_factory->CreateTextLayout( font, committed_text + (optional_composition_text ? optional_composition_text->text : u"")); @@ -121,7 +122,7 @@ int main() { }); input_method_context->TextEvent()->AddHandler( - [window, &committed_text](const std::u16string_view& c) { + [window, &committed_text](const StringView& c) { committed_text += c; window->RequestRepaint(); }); diff --git a/include/cru/common/String.hpp b/include/cru/common/String.hpp index 0530c208..13176fc6 100644 --- a/include/cru/common/String.hpp +++ b/include/cru/common/String.hpp @@ -71,7 +71,7 @@ class CRU_BASE_API String { template <Index size> String(const char16_t (&str)[size]) - : String(reinterpret_cast<const_pointer>(str), size) {} + : String(reinterpret_cast<const_pointer>(str), size - 1) {} template <typename Iter> String(Iter start, Iter end) { @@ -164,7 +164,7 @@ class CRU_BASE_API String { inline void append(StringView str); public: - String& operator+=(const String& other); + String& operator+=(StringView other); public: Utf16CodePointIterator CodePointIterator() const { @@ -199,6 +199,76 @@ class CRU_BASE_API String { Index capacity_ = 0; // always 1 smaller than real buffer size }; +class CRU_BASE_API StringView { + public: + using value_type = char16_t; + using size_type = Index; + using difference_type = Index; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = const value_type*; + using const_iterator = const value_type*; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + StringView() = default; + + constexpr StringView(const_pointer ptr, Index size) + : ptr_(ptr), size_(size) {} + + template <Index size> + constexpr StringView(const value_type (&array)[size]) + : StringView(array, size - 1) {} + + StringView(const String& str) : StringView(str.data(), str.size()) {} + + CRU_DEFAULT_COPY(StringView) + CRU_DEFAULT_MOVE(StringView) + + ~StringView() = default; + + Index size() const { return size_; } + const value_type* data() const { return ptr_; } + + public: + iterator begin() { return this->ptr_; } + const_iterator begin() const { return this->ptr_; } + const_iterator cbegin() const { return this->ptr_; } + + iterator end() { return this->ptr_ + this->size_; } + const_iterator end() const { return this->ptr_ + this->size_; } + const_iterator cend() const { return this->ptr_ + this->size_; } + + reverse_iterator rbegin() { return reverse_iterator{begin()}; } + const_reverse_iterator rbegin() const { + return const_reverse_iterator{begin()}; + } + const_reverse_iterator crbegin() const { + return const_reverse_iterator{cbegin()}; + } + + reverse_iterator rend() { return reverse_iterator{end()}; } + const_reverse_iterator rend() const { return const_reverse_iterator{end()}; } + const_reverse_iterator crend() const { + return const_reverse_iterator{cend()}; + } + + StringView substr(Index pos); + StringView substr(Index pos, Index size); + + int Compare(const StringView& other) const; + + String ToString() const { return String(ptr_, size_); } + + value_type operator[](Index index) const { return ptr_[index]; } + + private: + const char16_t* ptr_; + Index size_; +}; + CRU_DEFINE_COMPARE_OPERATORS(String) inline String operator+(const String& left, const String& right) { @@ -285,76 +355,6 @@ String String::Format(T&&... args) const { return cru::Format(*this, std::forward<T>(args)...); } -class CRU_BASE_API StringView { - public: - using value_type = char16_t; - using size_type = Index; - using difference_type = Index; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const value_type*; - using iterator = const value_type*; - using const_iterator = const value_type*; - using reverse_iterator = std::reverse_iterator<iterator>; - using const_reverse_iterator = std::reverse_iterator<const_iterator>; - - StringView() = default; - - constexpr StringView(const_pointer ptr, Index size) - : ptr_(ptr), size_(size) {} - - template <Index size> - constexpr StringView(const value_type (&array)[size]) - : StringView(array, size) {} - - StringView(const String& str) : StringView(str.data(), str.size()) {} - - CRU_DEFAULT_COPY(StringView) - CRU_DEFAULT_MOVE(StringView) - - ~StringView() = default; - - Index size() const { return size_; } - const value_type* data() const { return ptr_; } - - public: - iterator begin() { return this->ptr_; } - const_iterator begin() const { return this->ptr_; } - const_iterator cbegin() const { return this->ptr_; } - - iterator end() { return this->ptr_ + this->size_; } - const_iterator end() const { return this->ptr_ + this->size_; } - const_iterator cend() const { return this->ptr_ + this->size_; } - - reverse_iterator rbegin() { return reverse_iterator{begin()}; } - const_reverse_iterator rbegin() const { - return const_reverse_iterator{begin()}; - } - const_reverse_iterator crbegin() const { - return const_reverse_iterator{cbegin()}; - } - - reverse_iterator rend() { return reverse_iterator{end()}; } - const_reverse_iterator rend() const { return const_reverse_iterator{end()}; } - const_reverse_iterator crend() const { - return const_reverse_iterator{cend()}; - } - - StringView substr(Index pos); - StringView substr(Index pos, Index size); - - int Compare(const StringView& other) const; - - String ToString() const { return String(ptr_, size_); } - - value_type operator[](Index index) const { return ptr_[index]; } - - private: - const char16_t* ptr_; - Index size_; -}; - CRU_DEFINE_COMPARE_OPERATORS(StringView) inline String::iterator String::insert(const_iterator pos, StringView str) { diff --git a/include/cru/osx/gui/Cursor.hpp b/include/cru/osx/gui/Cursor.hpp new file mode 100644 index 00000000..497f5853 --- /dev/null +++ b/include/cru/osx/gui/Cursor.hpp @@ -0,0 +1,43 @@ +#pragma once +#include "Resource.hpp" +#include "cru/platform/gui/Cursor.hpp" + +#include <memory> + +namespace cru::platform::gui::osx { +namespace details { +class OsxWindowPrivate; +class OsxCursorPrivate; +class OsxCursorManagerPrivate; +} // namespace details + +class OsxCursor : public OsxGuiResource, public virtual ICursor { + friend class OsxWindow; + friend class details::OsxWindowPrivate; + + public: + OsxCursor(IUiApplication* ui_application, SystemCursorType cursor_type); + CRU_DELETE_COPY(OsxCursor) + CRU_DELETE_MOVE(OsxCursor) + + ~OsxCursor() override; + + private: + std::unique_ptr<details::OsxCursorPrivate> p_; +}; + +class OsxCursorManager : public OsxGuiResource, public virtual ICursorManager { + public: + explicit OsxCursorManager(IUiApplication* ui_application); + + CRU_DELETE_COPY(OsxCursorManager) + CRU_DELETE_MOVE(OsxCursorManager) + + ~OsxCursorManager() override; + + std::shared_ptr<ICursor> GetSystemCursor(SystemCursorType type) override; + + private: + std::unique_ptr<details::OsxCursorManagerPrivate> p_; +}; +} // namespace cru::platform::gui::osx diff --git a/include/cru/osx/gui/Window.hpp b/include/cru/osx/gui/Window.hpp index 56ae83e6..710246bc 100644 --- a/include/cru/osx/gui/Window.hpp +++ b/include/cru/osx/gui/Window.hpp @@ -133,6 +133,6 @@ class OsxInputMethodContext : public OsxGuiResource, IEvent<StringView>* TextEvent() override; private: - details::OsxInputMethodContextPrivate* p_; + std::unique_ptr<details::OsxInputMethodContextPrivate> p_; }; } // namespace cru::platform::gui::osx diff --git a/include/cru/platform/bootstrap/Bootstrap.hpp b/include/cru/platform/bootstrap/Bootstrap.hpp index 730df28c..33fb5122 100644 --- a/include/cru/platform/bootstrap/Bootstrap.hpp +++ b/include/cru/platform/bootstrap/Bootstrap.hpp @@ -11,7 +11,7 @@ #define CRU_PLATFORM_BOOTSTRAP_API #endif -namespace cru::platform::boostrap { +namespace cru::platform::bootstrap { CRU_PLATFORM_BOOTSTRAP_API cru::platform::gui::IUiApplication* CreateUiApplication(); } diff --git a/src/common/String.cpp b/src/common/String.cpp index ef5eb176..30f83174 100644 --- a/src/common/String.cpp +++ b/src/common/String.cpp @@ -243,7 +243,7 @@ Range String::RangeFromCodePointToCodeUnit(Range code_point_range) const { IndexFromCodePointToCodeUnit(code_point_range.GetEnd())); } -String& String::operator+=(const String& other) { +String& String::operator+=(StringView other) { append(other); return *this; } 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 diff --git a/src/platform/CMakeLists.txt b/src/platform/CMakeLists.txt index 0288bed0..8d6929ec 100644 --- a/src/platform/CMakeLists.txt +++ b/src/platform/CMakeLists.txt @@ -21,4 +21,6 @@ add_subdirectory(gui) if(WIN32) add_subdirectory(bootstrap) +elseif(APPLE) + add_subdirectory(bootstrap) endif() diff --git a/src/platform/bootstrap/Bootstrap.cpp b/src/platform/bootstrap/Bootstrap.cpp index 99b5badb..c167be19 100644 --- a/src/platform/bootstrap/Bootstrap.cpp +++ b/src/platform/bootstrap/Bootstrap.cpp @@ -1,15 +1,17 @@ #include "cru/platform/bootstrap/Bootstrap.hpp" +#include "cru/osx/gui/UiApplication.hpp" #ifdef CRU_PLATFORM_WINDOWS #include "cru/win/gui/UiApplication.hpp" #else #endif -namespace cru::platform::boostrap { +namespace cru::platform::bootstrap { cru::platform::gui::IUiApplication* CreateUiApplication() { #ifdef CRU_PLATFORM_WINDOWS return new cru::platform::gui::win::WinUiApplication(); -#else +#elif CRU_PLATFORM_OSX + return new cru::platform::gui::osx::OsxUiApplication(); #endif } -} // namespace cru::platform::boostrap +} // namespace cru::platform::bootstrap diff --git a/src/platform/bootstrap/CMakeLists.txt b/src/platform/bootstrap/CMakeLists.txt index 7759415f..c979f586 100644 --- a/src/platform/bootstrap/CMakeLists.txt +++ b/src/platform/bootstrap/CMakeLists.txt @@ -1,13 +1,15 @@ set(CRU_PLATFORM_BOOTSTRAP_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/platform/bootstrap) -add_library(cru_platform_boostrap SHARED +add_library(cru_platform_bootstrap SHARED Bootstrap.cpp ) -target_sources(cru_platform_boostrap PUBLIC +target_sources(cru_platform_bootstrap PUBLIC ${CRU_PLATFORM_BOOTSTRAP_INCLUDE_DIR}/Bootstrap.hpp ) if(WIN32) - target_link_libraries(cru_platform_boostrap PUBLIC cru_win_gui) + target_link_libraries(cru_platform_bootstrap PUBLIC cru_win_gui) +elseif(APPLE) + target_link_libraries(cru_platform_bootstrap PUBLIC cru_osx_gui) endif() -target_compile_definitions(cru_platform_boostrap PRIVATE CRU_PLATFORM_BOOTSTRAP_EXPORT_API) +target_compile_definitions(cru_platform_bootstrap PRIVATE CRU_PLATFORM_BOOTSTRAP_EXPORT_API) |