aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2021-11-15 16:26:25 +0800
committercrupest <crupest@outlook.com>2021-11-15 16:26:25 +0800
commit4ac58d91bac0cebe2bdf5e11b9d63b9c41e6b39e (patch)
tree7a4a8f587ffadb9f722b33badf2568e1d325b818
parent63b4956c3a802ee1c0fd92d1ce56e9330b6de4d2 (diff)
downloadcru-4ac58d91bac0cebe2bdf5e11b9d63b9c41e6b39e.tar.gz
cru-4ac58d91bac0cebe2bdf5e11b9d63b9c41e6b39e.tar.bz2
cru-4ac58d91bac0cebe2bdf5e11b9d63b9c41e6b39e.zip
...
-rw-r--r--include/cru/common/String.hpp15
-rw-r--r--include/cru/ui/controls/TextHostControlService.hpp13
-rw-r--r--include/cru/ui/helper/ShortcutHub.hpp4
-rw-r--r--src/ui/controls/TextHostControlService.cpp134
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, &current_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