diff options
-rw-r--r-- | include/cru/common/String.hpp | 15 | ||||
-rw-r--r-- | include/cru/ui/controls/TextHostControlService.hpp | 13 | ||||
-rw-r--r-- | include/cru/ui/helper/ShortcutHub.hpp | 4 | ||||
-rw-r--r-- | src/ui/controls/TextHostControlService.cpp | 134 |
4 files changed, 92 insertions, 74 deletions
diff --git a/include/cru/common/String.hpp b/include/cru/common/String.hpp index 9996f617..264a44ff 100644 --- a/include/cru/common/String.hpp +++ b/include/cru/common/String.hpp @@ -395,6 +395,21 @@ inline bool Utf16IsValidInsertPosition(StringView str, Index position) { return Utf16IsValidInsertPosition(str.data(), str.size(), position); } +// Return position after the character making predicate returns true or 0 if no +// character doing so. +inline Index CRU_BASE_API +Utf16BackwardUntil(StringView str, Index position, + const std::function<bool(CodePoint)>& predicate) { + return Utf16BackwardUntil(str.data(), str.size(), position, predicate); +} +// Return position before the character making predicate returns true or +// str.size() if no character doing so. +inline Index CRU_BASE_API +Utf16ForwardUntil(StringView str, Index position, + const std::function<bool(CodePoint)>& predicate) { + return Utf16ForwardUntil(str.data(), str.size(), position, predicate); +} + inline Index Utf16PreviousWord(StringView str, Index position, bool* is_space = nullptr) { return Utf16PreviousWord(str.data(), str.size(), position, is_space); diff --git a/include/cru/ui/controls/TextHostControlService.hpp b/include/cru/ui/controls/TextHostControlService.hpp index adf72d69..da9547ac 100644 --- a/include/cru/ui/controls/TextHostControlService.hpp +++ b/include/cru/ui/controls/TextHostControlService.hpp @@ -8,6 +8,7 @@ #include "cru/ui/helper/ShortcutHub.hpp" #include <functional> +#include <vector> namespace cru::ui::render { class TextRenderObject; @@ -29,6 +30,8 @@ class TextControlMovePattern : public Object { public: static TextControlMovePattern kLeft; static TextControlMovePattern kRight; + static TextControlMovePattern kCtrlLeft; + static TextControlMovePattern kCtrlRight; static TextControlMovePattern kUp; static TextControlMovePattern kDown; static TextControlMovePattern kHome; @@ -36,6 +39,8 @@ class TextControlMovePattern : public Object { static TextControlMovePattern kPageUp; static TextControlMovePattern kPageDown; + static std::vector<TextControlMovePattern> kDefaultPatterns; + using MoveFunction = std::function<gsl::index(TextHostControlService* service, StringView text, gsl::index current_position)>; @@ -44,15 +49,15 @@ class TextControlMovePattern : public Object { MoveFunction move_function) : key_bind_(key_bind), move_function_(move_function) {} - CRU_DELETE_COPY(TextControlMovePattern) - CRU_DELETE_MOVE(TextControlMovePattern) + CRU_DEFAULT_COPY(TextControlMovePattern) + CRU_DEFAULT_MOVE(TextControlMovePattern) ~TextControlMovePattern() override = default; public: helper::ShortcutKeyBind GetKeyBind() const { return key_bind_; } gsl::index Move(TextHostControlService* service, StringView text, - gsl::index current_position) { + gsl::index current_position) const { return move_function_(service, text, current_position); } @@ -118,10 +123,10 @@ class TextHostControlService : public Object { void ScrollToCaret(); - private: gsl::not_null<render::TextRenderObject*> GetTextRenderObject(); render::ScrollRenderObject* GetScrollRenderObject(); + private: // May return nullptr. platform::gui::IInputMethodContext* GetInputMethodContext(); diff --git a/include/cru/ui/helper/ShortcutHub.hpp b/include/cru/ui/helper/ShortcutHub.hpp index 7f098a6d..ed90381d 100644 --- a/include/cru/ui/helper/ShortcutHub.hpp +++ b/include/cru/ui/helper/ShortcutHub.hpp @@ -32,6 +32,10 @@ class ShortcutKeyBind { platform::gui::KeyCode GetKey() const { return key_; } platform::gui::KeyModifier GetModifier() const { return modifier_; } + ShortcutKeyBind AddModifier(platform::gui::KeyModifier modifier) const { + return ShortcutKeyBind(key_, modifier_ | modifier); + } + bool Is(platform::gui::KeyCode key, platform::gui::KeyModifier modifier) const { return key == key_ && modifier == modifier_; diff --git a/src/ui/controls/TextHostControlService.cpp b/src/ui/controls/TextHostControlService.cpp index 9f5098db..cbbfde58 100644 --- a/src/ui/controls/TextHostControlService.cpp +++ b/src/ui/controls/TextHostControlService.cpp @@ -2,7 +2,9 @@ #include "../Helper.hpp" #include "cru/common/Logger.hpp" +#include "cru/common/String.hpp" #include "cru/common/StringUtil.hpp" +#include "cru/platform/graphics/Font.hpp" #include "cru/platform/gui/Base.hpp" #include "cru/platform/gui/Cursor.hpp" #include "cru/platform/gui/InputMethod.hpp" @@ -32,22 +34,54 @@ TextControlMovePattern TextControlMovePattern::kRight( Utf16NextCodePoint(text, current_position, ¤t_position); return current_position; }); +TextControlMovePattern TextControlMovePattern::kCtrlLeft( + helper::ShortcutKeyBind(platform::gui::KeyCode::Left, + platform::gui::KeyModifiers::ctrl), + [](TextHostControlService* service, StringView text, + gsl::index current_position) { + return Utf16PreviousWord(text, current_position); + }); +TextControlMovePattern TextControlMovePattern::kCtrlRight( + helper::ShortcutKeyBind(platform::gui::KeyCode::Right, + platform::gui::KeyModifiers::ctrl), + [](TextHostControlService* service, StringView text, + gsl::index current_position) { + return Utf16NextWord(text, current_position); + }); TextControlMovePattern TextControlMovePattern::kUp( helper::ShortcutKeyBind(platform::gui::KeyCode::Up), [](TextHostControlService* service, StringView text, - gsl::index current_position) { return current_position; }); + 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(); + auto result = text_render_object->TextHitTest(rect.GetLeftTop()); + return result.trailing ? result.position + 1 : result.position; + }); TextControlMovePattern TextControlMovePattern::kDown( helper::ShortcutKeyBind(platform::gui::KeyCode::Down), [](TextHostControlService* service, StringView text, - gsl::index current_position) { return current_position; }); + 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(); + auto result = text_render_object->TextHitTest(rect.GetLeftTop()); + return result.trailing ? result.position + 1 : result.position; + }); TextControlMovePattern TextControlMovePattern::kHome( helper::ShortcutKeyBind(platform::gui::KeyCode::Home), [](TextHostControlService* service, StringView text, - gsl::index current_position) { return current_position; }); + gsl::index current_position) { + return Utf16BackwardUntil(text, current_position, + [](char16_t c) { return c == u'\n'; }); + }); TextControlMovePattern TextControlMovePattern::kEnd( helper::ShortcutKeyBind(platform::gui::KeyCode::End), [](TextHostControlService* service, StringView text, - gsl::index current_position) { return current_position; }); + gsl::index current_position) { + return Utf16ForwardUntil(text, current_position, + [](char16_t c) { return c == u'\n'; }); + }); TextControlMovePattern TextControlMovePattern::kPageUp( helper::ShortcutKeyBind(platform::gui::KeyCode::PageUp), [](TextHostControlService* service, StringView text, @@ -57,6 +91,13 @@ TextControlMovePattern TextControlMovePattern::kPageDown( [](TextHostControlService* service, StringView text, gsl::index current_position) { return current_position; }); +std::vector<TextControlMovePattern> TextControlMovePattern::kDefaultPatterns = { + TextControlMovePattern::kLeft, TextControlMovePattern::kRight, + TextControlMovePattern::kCtrlLeft, TextControlMovePattern::kCtrlRight, + TextControlMovePattern::kUp, TextControlMovePattern::kDown, + TextControlMovePattern::kHome, TextControlMovePattern::kEnd, + TextControlMovePattern::kPageUp, TextControlMovePattern::kPageDown}; + TextHostControlService::TextHostControlService(gsl::not_null<Control*> control) : control_(control), text_host_control_(dynamic_cast<ITextHostControl*>(control.get())) { @@ -433,72 +474,25 @@ void TextHostControlService::SetUpShortcuts() { return true; }); - shortcut_hub_.RegisterShortcut(u"Left", KeyCode::Left, [this] { - auto text = this->GetTextView(); - auto caret = this->GetCaretPosition(); - Utf16PreviousCodePoint(text, caret, &caret); - this->SetSelection(caret); - return true; - }); - - shortcut_hub_.RegisterShortcut(u"ShiftLeft", - {KeyCode::Left, KeyModifiers::shift}, [this] { - auto text = this->GetTextView(); - auto caret = this->GetCaretPosition(); - Utf16PreviousCodePoint(text, caret, &caret); - this->ChangeSelectionEnd(caret); - return true; - }); - - shortcut_hub_.RegisterShortcut( - u"CtrlLeft", {KeyCode::Left, KeyModifiers::ctrl}, [this] { - auto text = this->GetTextView(); - auto caret = this->GetCaretPosition(); - this->SetSelection(Utf16PreviousWord(text, caret)); - return true; - }); - - shortcut_hub_.RegisterShortcut( - u"CtrlShiftLeft", - {KeyCode::Left, KeyModifiers::ctrl | KeyModifiers::shift}, [this] { - auto text = this->GetTextView(); - auto caret = this->GetCaretPosition(); - this->ChangeSelectionEnd(Utf16PreviousWord(text, caret)); - return true; - }); - - shortcut_hub_.RegisterShortcut(u"Right", KeyCode::Right, [this] { - auto text = this->GetTextView(); - auto caret = this->GetCaretPosition(); - Utf16NextCodePoint(text, caret, &caret); - this->SetSelection(caret); - return true; - }); + for (const auto& pattern : TextControlMovePattern::kDefaultPatterns) { + shortcut_hub_.RegisterShortcut(u"", pattern.GetKeyBind(), [this, &pattern] { + auto text = this->GetTextView(); + auto caret = this->GetCaretPosition(); + auto new_position = pattern.Move(this, text, caret); + this->SetSelection(caret); + return true; + }); - shortcut_hub_.RegisterShortcut(u"ShiftRight", - {KeyCode::Right, KeyModifiers::shift}, [this] { - auto text = this->GetTextView(); - auto caret = this->GetCaretPosition(); - Utf16NextCodePoint(text, caret, &caret); - this->ChangeSelectionEnd(caret); - return true; - }); - - shortcut_hub_.RegisterShortcut( - u"CtrlRight", {KeyCode::Right, KeyModifiers::ctrl}, [this] { - auto text = this->GetTextView(); - auto caret = this->GetCaretPosition(); - this->SetSelection(Utf16NextWord(text, caret)); - return true; - }); - - shortcut_hub_.RegisterShortcut( - u"CtrlShiftRight", - {KeyCode::Right, KeyModifiers::ctrl | KeyModifiers::shift}, [this] { - auto text = this->GetTextView(); - auto caret = this->GetCaretPosition(); - this->ChangeSelectionEnd(Utf16NextWord(text, caret)); - return true; - }); + shortcut_hub_.RegisterShortcut( + u"", + pattern.GetKeyBind().AddModifier(platform::gui::KeyModifiers::shift), + [this, &pattern] { + auto text = this->GetTextView(); + auto caret = this->GetCaretPosition(); + auto new_position = pattern.Move(this, text, caret); + this->ChangeSelectionEnd(new_position); + return true; + }); + } } } // namespace cru::ui::controls |