diff options
author | crupest <crupest@outlook.com> | 2021-11-21 20:42:54 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2021-11-21 20:42:54 +0800 |
commit | 3f8e493423b7cfe96ab53531078b803da7beccbe (patch) | |
tree | a0a998c6b2b696eaf4f58870224fef31e65e3dbd | |
parent | 73b90d4fe6c93a288ca6514432fe1e83ddcf4928 (diff) | |
download | cru-3f8e493423b7cfe96ab53531078b803da7beccbe.tar.gz cru-3f8e493423b7cfe96ab53531078b803da7beccbe.tar.bz2 cru-3f8e493423b7cfe96ab53531078b803da7beccbe.zip |
...
-rw-r--r-- | include/cru/osx/graphics/quartz/TextLayout.hpp | 4 | ||||
-rw-r--r-- | include/cru/platform/graphics/NullPainter.hpp | 53 | ||||
-rw-r--r-- | include/cru/platform/graphics/TextLayout.hpp | 4 | ||||
-rw-r--r-- | include/cru/platform/gui/Window.hpp | 4 | ||||
-rw-r--r-- | include/cru/ui/render/TextRenderObject.hpp | 3 | ||||
-rw-r--r-- | src/osx/graphics/quartz/TextLayout.cpp | 71 | ||||
-rw-r--r-- | src/osx/gui/InputMethod.mm | 4 | ||||
-rw-r--r-- | src/osx/gui/Window.mm | 22 | ||||
-rw-r--r-- | src/platform/graphics/CMakeLists.txt | 9 | ||||
-rw-r--r-- | src/platform/graphics/NullPainter.cpp | 1 | ||||
-rw-r--r-- | src/ui/controls/RootControl.cpp | 2 | ||||
-rw-r--r-- | src/ui/controls/TextHostControlService.cpp | 4 | ||||
-rw-r--r-- | src/ui/render/TextRenderObject.cpp | 10 |
13 files changed, 149 insertions, 42 deletions
diff --git a/include/cru/osx/graphics/quartz/TextLayout.hpp b/include/cru/osx/graphics/quartz/TextLayout.hpp index 80c257cc..2c6347db 100644 --- a/include/cru/osx/graphics/quartz/TextLayout.hpp +++ b/include/cru/osx/graphics/quartz/TextLayout.hpp @@ -31,6 +31,10 @@ class OsxCTTextLayout : public OsxQuartzResource, public virtual ITextLayout { bool IsEditMode() override; void SetEditMode(bool enable) override; + Index GetLineIndexFromCharIndex(Index char_index) override; + Index GetLineCount() override; + float GetLineHeight(Index line_index) override; + Rect GetTextBounds(bool includingTrailingSpace = false) override; std::vector<Rect> TextRangeRect(const TextRange& text_range) override; Rect TextSinglePoint(Index position, bool trailing) override; diff --git a/include/cru/platform/graphics/NullPainter.hpp b/include/cru/platform/graphics/NullPainter.hpp new file mode 100644 index 00000000..cf790ccf --- /dev/null +++ b/include/cru/platform/graphics/NullPainter.hpp @@ -0,0 +1,53 @@ +#pragma once +#include "Painter.hpp" + +namespace cru::platform::graphics { +class NullPainter : public Object, public virtual IPainter { + public: + NullPainter() = default; + + CRU_DELETE_COPY(NullPainter) + CRU_DELETE_MOVE(NullPainter) + + ~NullPainter() override = default; + + public: + String GetPlatformId() const override { return u"NULL"; } + + String GetDebugString() override { return u"NullPainter"; } + + Matrix GetTransform() override { return Matrix(); } + void SetTransform(const Matrix& matrix) override {} + + void ConcatTransform(const Matrix& matrix) override {} + + void Clear(const Color& color) override {} + + void DrawLine(const Point& start, const Point& end, IBrush* brush, + float width) override{}; + void StrokeRectangle(const Rect& rectangle, IBrush* brush, + float width) override {} + void FillRectangle(const Rect& rectangle, IBrush* brush) override {} + void StrokeEllipse(const Rect& outline_rect, IBrush* brush, + float width) override {} + void FillEllipse(const Rect& outline_rect, IBrush* brush, + float width) override {} + + void StrokeGeometry(IGeometry* geometry, IBrush* brush, + float width) override {} + void FillGeometry(IGeometry* geometry, IBrush* brush) override {} + + void DrawText(const Point& offset, ITextLayout* text_layout, + IBrush* brush) override {} + + void PushLayer(const Rect& bounds) override{}; + + void PopLayer() override {} + + void PushState() override {} + + void PopState() override {} + + void EndDraw() override {} +}; +} // namespace cru::platform::graphics diff --git a/include/cru/platform/graphics/TextLayout.hpp b/include/cru/platform/graphics/TextLayout.hpp index d10c9f22..a040ec3b 100644 --- a/include/cru/platform/graphics/TextLayout.hpp +++ b/include/cru/platform/graphics/TextLayout.hpp @@ -20,6 +20,10 @@ struct ITextLayout : virtual IGraphicsResource { virtual bool IsEditMode() = 0; virtual void SetEditMode(bool enable) = 0; + virtual Index GetLineIndexFromCharIndex(Index char_index) = 0; + virtual Index GetLineCount() = 0; + virtual float GetLineHeight(Index line_index) = 0; + virtual Rect GetTextBounds(bool includingTrailingSpace = false) = 0; virtual std::vector<Rect> TextRangeRect(const TextRange& text_range) = 0; // Width is always 0, height is line height. diff --git a/include/cru/platform/gui/Window.hpp b/include/cru/platform/gui/Window.hpp index f6e1d650..bab5e8fe 100644 --- a/include/cru/platform/gui/Window.hpp +++ b/include/cru/platform/gui/Window.hpp @@ -18,9 +18,9 @@ struct WindowStyleFlags { static constexpr WindowStyleFlag NoCaptionAndBorder{0b1}; }; -enum class WindowVisibilityType { Show, Hide }; +enum class WindowVisibilityType { Show, Hide, Minimize }; -enum class FocusChangeType { Gain, Lost }; +enum class FocusChangeType { Gain, Lose }; enum class MouseEnterLeaveType { Enter, Leave }; diff --git a/include/cru/ui/render/TextRenderObject.hpp b/include/cru/ui/render/TextRenderObject.hpp index d6395f85..4e72e839 100644 --- a/include/cru/ui/render/TextRenderObject.hpp +++ b/include/cru/ui/render/TextRenderObject.hpp @@ -45,6 +45,9 @@ class TextRenderObject : public RenderObject { bool IsEditMode(); void SetEditMode(bool enable); + Index GetLineCount(); + Index GetLineIndexFromCharIndex(Index char_index); + float GetLineHeight(Index line_index); std::vector<Rect> TextRangeRect(const TextRange& text_range); Rect TextSinglePoint(gsl::index position, bool trailing); platform::graphics::TextHitTestResult TextHitTest(const Point& point); diff --git a/src/osx/graphics/quartz/TextLayout.cpp b/src/osx/graphics/quartz/TextLayout.cpp index 8e5022a9..de14816d 100644 --- a/src/osx/graphics/quartz/TextLayout.cpp +++ b/src/osx/graphics/quartz/TextLayout.cpp @@ -112,6 +112,30 @@ void OsxCTTextLayout::SetEditMode(bool enable) { RecreateFrame(); } +Index OsxCTTextLayout::GetLineIndexFromCharIndex(Index char_index) { + if (char_index < 0 || char_index >= text_.size()) { + return -1; + } + + auto line_index = 0; + for (Index i = 0; i < char_index; ++i) { + if (text_[i] == u'\n') { + line_index++; + } + } + + return line_index; +} + +Index OsxCTTextLayout::GetLineCount() { return line_count_; } + +float OsxCTTextLayout::GetLineHeight(Index line_index) { + if (line_index < 0 || line_index >= line_count_) { + return 0.0f; + } + return line_heights_[line_index]; +} + Rect OsxCTTextLayout::GetTextBounds(bool includingTrailingSpace) { if (text_.empty() && edit_mode_) return Rect(0, 0, 0, font_->GetFontSize()); @@ -123,8 +147,10 @@ std::vector<Rect> OsxCTTextLayout::TextRangeRect(const TextRange& text_range) { if (text_.empty()) return {}; auto tr = text_range; - text_range.CoerceInto(head_empty_line_count_, - text_.size() - tail_empty_line_count_); + tr = text_range.CoerceInto(head_empty_line_count_, + text_.size() - tail_empty_line_count_); + tr.position -= head_empty_line_count_; + std::vector<CGRect> results = DoTextRangeRect(tr); std::vector<Rect> r; @@ -162,9 +188,9 @@ TextHitTestResult OsxCTTextLayout::HitTest(const Point& point) { if (point.y < 0) { return {0, false, false}; } else { - for (int i = 0; i < head_empty_line_count_; ++i) { + for (int i = 1; i <= head_empty_line_count_; ++i) { if (point.y < i * font_->GetFontSize()) { - return {i, false, false}; + return {i - 1, false, false}; } } } @@ -175,11 +201,12 @@ TextHitTestResult OsxCTTextLayout::HitTest(const Point& point) { auto text_height = static_cast<float>(text_bounds.size.height); auto th = text_height + head_empty_line_count_ * font_->GetFontSize(); if (point.y >= th) { - for (int i = 0; i < tail_empty_line_count_; ++i) { + for (int i = 1; i <= tail_empty_line_count_; ++i) { if (point.y < th + i * font_->GetFontSize()) { - return {text_.size() - i, false, false}; + return {text_.size() - (tail_empty_line_count_ - i), false, false}; } } + return {text_.size(), false, false}; } auto p = point; @@ -209,27 +236,33 @@ TextHitTestResult OsxCTTextLayout::HitTest(const Point& point) { if (p.y >= bounds.origin.y || force_inside) { auto pp = p; pp.y = bounds.origin.y; + Index po; + bool inside_text; if (pp.x < bounds.origin.x) { - return TextHitTestResult{ - actual_text_.IndexFromCodePointToCodeUnit(range.location) + - head_empty_line_count_, - false, false}; + po = actual_text_.IndexFromCodePointToCodeUnit(range.location); + inside_text = false; } else if (pp.x > bounds.origin.x + bounds.size.width) { - auto po = actual_text_.IndexFromCodePointToCodeUnit(range.location + - range.length); - if (po != actual_text_.size()) { - Utf16PreviousCodePoint(text_, po, &po); - } - return TextHitTestResult{po + head_empty_line_count_, false, false}; + po = actual_text_.IndexFromCodePointToCodeUnit(range.location + + range.length); + inside_text = false; } else { int position = CTLineGetStringIndexForPosition( line, CGPointMake(pp.x - line_origins_[i].x, pp.y - line_origins_[i].y)); - return TextHitTestResult{text_.IndexFromCodePointToCodeUnit(position) + - head_empty_line_count_, - false, true}; + + po = actual_text_.IndexFromCodePointToCodeUnit(position); + inside_text = true; + } + + if (po != 0 && + po == actual_text_.IndexFromCodePointToCodeUnit(range.location + + range.length) && + actual_text_[po - 1] == u'\n') { + --po; } + + return {po + head_empty_line_count_, false, inside_text}; } } diff --git a/src/osx/gui/InputMethod.mm b/src/osx/gui/InputMethod.mm index 56ac2c56..45b50318 100644 --- a/src/osx/gui/InputMethod.mm +++ b/src/osx/gui/InputMethod.mm @@ -47,12 +47,12 @@ OsxInputMethodContext::OsxInputMethodContext(OsxWindow* window) OsxInputMethodContext::~OsxInputMethodContext() {} void OsxInputMethodContext::EnableIME() { - log::Debug(u"Enable IME."); + // log::Debug(u"Enable IME."); p_->Activate(); } void OsxInputMethodContext::DisableIME() { - log::Debug(u"Disable IME."); + // log::Debug(u"Disable IME."); p_->Deactivate(); } diff --git a/src/osx/gui/Window.mm b/src/osx/gui/Window.mm index 6e4c8497..fcbc5cb5 100644 --- a/src/osx/gui/Window.mm +++ b/src/osx/gui/Window.mm @@ -14,18 +14,11 @@ #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/graphics/NullPainter.hpp" #include "cru/platform/gui/TimerHelper.hpp" -#include "cru/platform/gui/Window.hpp" -#include <AppKit/NSGraphicsContext.h> -#include <AppKit/NSTextInputContext.h> -#include <AppKit/NSWindow.h> -#include <Foundation/NSAttributedString.h> -#include <Foundation/NSString.h> +#include <AppKit/AppKit.h> +#include <Foundation/Foundation.h> #include <limits> #include <memory> @@ -89,7 +82,7 @@ void OsxWindowPrivate::OnWindowDidResize() { void OsxWindowPrivate::OnBecomeKeyWindow() { focus_event_.Raise(FocusChangeType::Gain); } -void OsxWindowPrivate::OnResignKeyWindow() { focus_event_.Raise(FocusChangeType::Lost); } +void OsxWindowPrivate::OnResignKeyWindow() { focus_event_.Raise(FocusChangeType::Lose); } void OsxWindowPrivate::OnMouseEnterLeave(MouseEnterLeaveType type) { mouse_enter_leave_event_.Raise(type); @@ -234,6 +227,7 @@ void OsxWindow::SetStyleFlag(WindowStyleFlag flag) { WindowVisibilityType OsxWindow::GetVisibility() { if (!p_->window_) return WindowVisibilityType::Hide; + if ([p_->window_ isMiniaturized]) return WindowVisibilityType::Minimize; return [p_->window_ isVisible] ? WindowVisibilityType::Show : WindowVisibilityType::Hide; } @@ -242,9 +236,11 @@ void OsxWindow::SetVisibility(WindowVisibilityType visibility) { if (visibility == WindowVisibilityType::Show) { [p_->window_ orderFront:nil]; p_->visibility_change_event_.Raise(WindowVisibilityType::Show); - } else { + } else if (visibility == WindowVisibilityType::Hide) { [p_->window_ orderOut:nil]; p_->visibility_change_event_.Raise(WindowVisibilityType::Hide); + } else if (visibility == WindowVisibilityType::Minimize) { + [p_->window_ miniaturize:nil]; } } else { if (visibility == WindowVisibilityType::Show) { @@ -307,7 +303,7 @@ void OsxWindow::RequestRepaint() { std::unique_ptr<graphics::IPainter> OsxWindow::BeginPaint() { if (!p_->window_) { - p_->CreateWindow(); + return std::make_unique<graphics::NullPainter>(); } CGContextRef cg_context = CGLayerGetContext(p_->draw_layer_); diff --git a/src/platform/graphics/CMakeLists.txt b/src/platform/graphics/CMakeLists.txt index 5f841267..7d86db40 100644 --- a/src/platform/graphics/CMakeLists.txt +++ b/src/platform/graphics/CMakeLists.txt @@ -1,14 +1,17 @@ set(CRU_PLATFORM_GRAPHICS_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/platform/graphics) -add_library(cru_platform_graphics INTERFACE) -target_sources(cru_platform_graphics INTERFACE +add_library(cru_platform_graphics SHARED + NullPainter.cpp +) +target_sources(cru_platform_graphics PUBLIC ${CRU_PLATFORM_GRAPHICS_INCLUDE_DIR}/Base.hpp ${CRU_PLATFORM_GRAPHICS_INCLUDE_DIR}/Brush.hpp ${CRU_PLATFORM_GRAPHICS_INCLUDE_DIR}/Font.hpp ${CRU_PLATFORM_GRAPHICS_INCLUDE_DIR}/Geometry.hpp + ${CRU_PLATFORM_GRAPHICS_INCLUDE_DIR}/NullPainter.hpp ${CRU_PLATFORM_GRAPHICS_INCLUDE_DIR}/Factory.hpp ${CRU_PLATFORM_GRAPHICS_INCLUDE_DIR}/Resource.hpp ${CRU_PLATFORM_GRAPHICS_INCLUDE_DIR}/Painter.hpp ${CRU_PLATFORM_GRAPHICS_INCLUDE_DIR}/TextLayout.hpp ${CRU_PLATFORM_GRAPHICS_INCLUDE_DIR}/util/Painter.hpp ) -target_link_libraries(cru_platform_graphics INTERFACE cru_platform_base) +target_link_libraries(cru_platform_graphics PUBLIC cru_platform_base) diff --git a/src/platform/graphics/NullPainter.cpp b/src/platform/graphics/NullPainter.cpp new file mode 100644 index 00000000..1b02ea07 --- /dev/null +++ b/src/platform/graphics/NullPainter.cpp @@ -0,0 +1 @@ +#include "cru/platform/graphics/NullPainter.hpp" diff --git a/src/ui/controls/RootControl.cpp b/src/ui/controls/RootControl.cpp index d89982c5..278649de 100644 --- a/src/ui/controls/RootControl.cpp +++ b/src/ui/controls/RootControl.cpp @@ -41,7 +41,7 @@ void RootControl::SetGainFocusOnCreateAndDestroyWhenLoseFocus(bool value) { gain_focus_on_create_and_destroy_when_lose_focus_event_guard_ += native_window->FocusEvent()->AddHandler( [native_window](platform::gui::FocusChangeType type) { - if (type == platform::gui::FocusChangeType::Lost) { + if (type == platform::gui::FocusChangeType::Lose) { native_window->Close(); } }); diff --git a/src/ui/controls/TextHostControlService.cpp b/src/ui/controls/TextHostControlService.cpp index 46c02f50..870d643f 100644 --- a/src/ui/controls/TextHostControlService.cpp +++ b/src/ui/controls/TextHostControlService.cpp @@ -55,7 +55,7 @@ TextControlMovePattern TextControlMovePattern::kUp( gsl::index current_position) { auto text_render_object = service->GetTextRenderObject(); auto rect = text_render_object->TextSinglePoint(current_position, false); - rect.top -= text_render_object->GetFont()->GetFontSize(); + rect.top -= 1.f; auto result = text_render_object->TextHitTest(rect.GetLeftTop()); return result.trailing ? result.position + 1 : result.position; }); @@ -65,7 +65,7 @@ TextControlMovePattern TextControlMovePattern::kDown( gsl::index current_position) { auto text_render_object = service->GetTextRenderObject(); auto rect = text_render_object->TextSinglePoint(current_position, false); - rect.top += text_render_object->GetFont()->GetFontSize(); + rect.top += rect.height + 0.1f; auto result = text_render_object->TextHitTest(rect.GetLeftTop()); return result.trailing ? result.position + 1 : result.position; }); diff --git a/src/ui/render/TextRenderObject.cpp b/src/ui/render/TextRenderObject.cpp index e1036072..0e65da92 100644 --- a/src/ui/render/TextRenderObject.cpp +++ b/src/ui/render/TextRenderObject.cpp @@ -64,6 +64,16 @@ void TextRenderObject::SetEditMode(bool enable) { text_layout_->SetEditMode(enable); } +Index TextRenderObject::GetLineCount() { return text_layout_->GetLineCount(); } + +Index TextRenderObject::GetLineIndexFromCharIndex(Index char_index) { + return text_layout_->GetLineIndexFromCharIndex(char_index); +} + +float TextRenderObject::GetLineHeight(Index line_index) { + return text_layout_->GetLineHeight(line_index); +} + std::vector<Rect> TextRenderObject::TextRangeRect(const TextRange& text_range) { return text_layout_->TextRangeRect(text_range); } |