diff options
author | crupest <crupest@outlook.com> | 2021-11-14 22:27:08 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2021-11-14 22:27:08 +0800 |
commit | a744ed1fea0eaf4d946909da7fdc0a4c0f9c5ec0 (patch) | |
tree | 7f22783f8e0c7f61362ef64e879b50729536fea3 | |
parent | 7045737332f742cec36c3d35f48fad82cd41a04b (diff) | |
download | cru-a744ed1fea0eaf4d946909da7fdc0a4c0f9c5ec0.tar.gz cru-a744ed1fea0eaf4d946909da7fdc0a4c0f9c5ec0.tar.bz2 cru-a744ed1fea0eaf4d946909da7fdc0a4c0f9c5ec0.zip |
...
-rw-r--r-- | include/cru/common/String.hpp | 28 | ||||
-rw-r--r-- | include/cru/common/StringUtil.hpp | 73 | ||||
-rw-r--r-- | include/cru/platform/graphics/Factory.hpp | 2 | ||||
-rw-r--r-- | include/cru/ui/controls/TextHostControlService.hpp | 38 | ||||
-rw-r--r-- | src/common/String.cpp | 24 | ||||
-rw-r--r-- | src/common/StringUtil.cpp | 87 | ||||
-rw-r--r-- | src/ui/controls/TextHostControlService.cpp | 39 |
7 files changed, 194 insertions, 97 deletions
diff --git a/include/cru/common/String.hpp b/include/cru/common/String.hpp index 544d24a4..0a8d88a0 100644 --- a/include/cru/common/String.hpp +++ b/include/cru/common/String.hpp @@ -174,8 +174,7 @@ class CRU_BASE_API String { void AppendCodePoint(CodePoint code_point); Utf16CodePointIterator CodePointIterator() const { - return Utf16CodePointIterator( - std::u16string_view(reinterpret_cast<char16_t*>(buffer_), size_)); + return Utf16CodePointIterator(buffer_, size_); } Index IndexFromCodeUnitToCodePoint(Index code_unit_index) const; @@ -378,6 +377,31 @@ inline void String::append(StringView str) { inline String String::From(StringView str) { return str.ToString(); } inline String ToString(StringView value) { return value.ToString(); } + +inline CodePoint Utf16PreviousCodePoint(StringView str, Index current, + Index* previous_position) { + return Utf16PreviousCodePoint(str.data(), str.size(), current, + previous_position); +} + +inline CodePoint Utf16NextCodePoint(StringView str, Index current, + Index* next_position) { + return Utf16NextCodePoint(str.data(), str.size(), current, next_position); +} + +inline bool Utf16IsValidInsertPosition(StringView str, Index position) { + return Utf16IsValidInsertPosition(str.data(), str.size(), position); +} + +inline Index Utf16PreviousWord(StringView str, Index position, + bool* is_space = nullptr) { + return Utf16PreviousWord(str.data(), str.size(), position, is_space); +} + +inline Index Utf16NextWord(StringView str, Index position, + bool* is_space = nullptr) { + return Utf16NextWord(str.data(), str.size(), position, is_space); +} } // namespace cru template <> diff --git a/include/cru/common/StringUtil.hpp b/include/cru/common/StringUtil.hpp index cd2f4e16..a24cf924 100644 --- a/include/cru/common/StringUtil.hpp +++ b/include/cru/common/StringUtil.hpp @@ -22,20 +22,21 @@ inline bool IsUtf16SurrogatePairTrailing(char16_t c) { return c >= 0xDC00 && c <= 0xDFFF; } -CodePoint CRU_BASE_API Utf8NextCodePoint(std::string_view str, Index current, - Index* next_position); +CodePoint CRU_BASE_API Utf8NextCodePoint(const char* ptr, Index size, + Index current, Index* next_position); -CodePoint CRU_BASE_API Utf16NextCodePoint(std::u16string_view str, +CodePoint CRU_BASE_API Utf16NextCodePoint(const char16_t* ptr, Index size, Index current, Index* next_position); -CodePoint CRU_BASE_API Utf16PreviousCodePoint(std::u16string_view str, +CodePoint CRU_BASE_API Utf16PreviousCodePoint(const char16_t* ptr, Index size, Index current, Index* previous_position); -template <typename StringType> -using NextCodePointFunctionType = CodePoint (*)(StringType, Index, Index*); +template <typename CharType> +using NextCodePointFunctionType = CodePoint (*)(const CharType*, Index, Index, + Index*); -template <typename StringType, - NextCodePointFunctionType<StringType> NextCodePointFunction> +template <typename CharType, + NextCodePointFunctionType<CharType> NextCodePointFunction> class CodePointIterator { public: using difference_type = Index; @@ -47,10 +48,10 @@ class CodePointIterator { public: struct past_end_tag_t {}; - explicit CodePointIterator(StringType string) - : string_(std::move(string)), position_(0) {} - explicit CodePointIterator(StringType string, past_end_tag_t) - : string_(std::move(string)), position_(string_.size()) {} + explicit CodePointIterator(const CharType* ptr, Index size, Index current = 0) + : ptr_(ptr), size_(size), position_(0) {} + explicit CodePointIterator(const CharType* ptr, Index size, past_end_tag_t) + : ptr_(ptr), size_(size), position_(size) {} CRU_DEFAULT_COPY(CodePointIterator) CRU_DEFAULT_MOVE(CodePointIterator) @@ -58,17 +59,16 @@ class CodePointIterator { ~CodePointIterator() = default; public: - StringType GetString() const { return string_; } + const CharType* GetPtr() const { return ptr_; } + Index GetSize() const { return size_; } Index GetPosition() const { return position_; } - bool IsPastEnd() const { - return position_ == static_cast<Index>(string_.size()); - } + bool IsPastEnd() const { return position_ == static_cast<Index>(size_); } public: CodePointIterator begin() const { return *this; } CodePointIterator end() const { - return CodePointIterator{string_, past_end_tag_t{}}; + return CodePointIterator{ptr_, size_, past_end_tag_t{}}; } public: @@ -96,7 +96,7 @@ class CodePointIterator { } CodePoint operator*() const { - return NextCodePointFunction(string_, position_, &next_position_cache_); + return NextCodePointFunction(ptr_, size_, position_, &next_position_cache_); } private: @@ -104,21 +104,20 @@ class CodePointIterator { if (next_position_cache_ > position_) { position_ = next_position_cache_; } else { - NextCodePointFunction(string_, position_, &position_); + NextCodePointFunction(ptr_, size_, position_, &position_); } } private: - StringType string_; + const CharType* ptr_; + Index size_; Index position_; mutable Index next_position_cache_ = 0; }; -using Utf8CodePointIterator = - CodePointIterator<std::string_view, &Utf8NextCodePoint>; +using Utf8CodePointIterator = CodePointIterator<char, &Utf8NextCodePoint>; -using Utf16CodePointIterator = - CodePointIterator<std::u16string_view, &Utf16NextCodePoint>; +using Utf16CodePointIterator = CodePointIterator<char16_t, &Utf16NextCodePoint>; void CRU_BASE_API Utf8EncodeCodePointAppend(CodePoint code_point, std::string& str); @@ -198,30 +197,28 @@ bool Utf16EncodeCodePointAppendWithFunc(CodePoint code_point, } } -std::string CRU_BASE_API ToUtf8(std::u16string_view s); -std::u16string CRU_BASE_API ToUtf16(std::string_view s); +std::string CRU_BASE_API ToUtf8(const char16_t* ptr, Index size); +std::u16string CRU_BASE_API ToUtf16(const char* s, Index size); // If given s is not a valid utf16 string, return value is UD. -bool CRU_BASE_API Utf16IsValidInsertPosition(std::u16string_view s, - gsl::index position); +bool CRU_BASE_API Utf16IsValidInsertPosition(const char16_t* ptr, Index size, + Index position); // Return position after the character making predicate returns true or 0 if no // character doing so. -gsl::index CRU_BASE_API -Utf16BackwardUntil(std::u16string_view str, gsl::index position, +Index CRU_BASE_API +Utf16BackwardUntil(const char16_t* ptr, Index size, Index position, const std::function<bool(CodePoint)>& predicate); // Return position before the character making predicate returns true or // str.size() if no character doing so. -gsl::index CRU_BASE_API -Utf16ForwardUntil(std::u16string_view str, gsl::index position, +Index CRU_BASE_API +Utf16ForwardUntil(const char16_t* ptr, Index size, Index position, const std::function<bool(CodePoint)>& predicate); -gsl::index CRU_BASE_API Utf16PreviousWord(std::u16string_view str, - gsl::index position, - bool* is_space = nullptr); -gsl::index CRU_BASE_API Utf16NextWord(std::u16string_view str, - gsl::index position, - bool* is_space = nullptr); +Index CRU_BASE_API Utf16PreviousWord(const char16_t* ptr, Index size, + Index position, bool* is_space = nullptr); +Index CRU_BASE_API Utf16NextWord(const char16_t* ptr, Index size, + Index position, bool* is_space = nullptr); char16_t CRU_BASE_API ToLower(char16_t c); char16_t CRU_BASE_API ToUpper(char16_t c); diff --git a/include/cru/platform/graphics/Factory.hpp b/include/cru/platform/graphics/Factory.hpp index ad198929..b79e1c4f 100644 --- a/include/cru/platform/graphics/Factory.hpp +++ b/include/cru/platform/graphics/Factory.hpp @@ -7,7 +7,7 @@ #include "TextLayout.hpp" namespace cru::platform::graphics { -// Entry point of the graph module. +// Entry point of the graphics module. struct IGraphicsFactory : virtual IPlatformResource { virtual std::unique_ptr<ISolidColorBrush> CreateSolidColorBrush() = 0; diff --git a/include/cru/ui/controls/TextHostControlService.hpp b/include/cru/ui/controls/TextHostControlService.hpp index b56374dc..adf72d69 100644 --- a/include/cru/ui/controls/TextHostControlService.hpp +++ b/include/cru/ui/controls/TextHostControlService.hpp @@ -23,6 +23,44 @@ struct ITextHostControl : virtual Interface { virtual render::ScrollRenderObject* GetScrollRenderObject() = 0; }; +class TextHostControlService; + +class TextControlMovePattern : public Object { + public: + static TextControlMovePattern kLeft; + static TextControlMovePattern kRight; + static TextControlMovePattern kUp; + static TextControlMovePattern kDown; + static TextControlMovePattern kHome; + static TextControlMovePattern kEnd; + static TextControlMovePattern kPageUp; + static TextControlMovePattern kPageDown; + + using MoveFunction = + std::function<gsl::index(TextHostControlService* service, StringView text, + gsl::index current_position)>; + + TextControlMovePattern(helper::ShortcutKeyBind key_bind, + MoveFunction move_function) + : key_bind_(key_bind), move_function_(move_function) {} + + CRU_DELETE_COPY(TextControlMovePattern) + CRU_DELETE_MOVE(TextControlMovePattern) + + ~TextControlMovePattern() override = default; + + public: + helper::ShortcutKeyBind GetKeyBind() const { return key_bind_; } + gsl::index Move(TextHostControlService* service, StringView text, + gsl::index current_position) { + return move_function_(service, text, current_position); + } + + private: + helper::ShortcutKeyBind key_bind_; + MoveFunction move_function_; +}; + class TextHostControlService : public Object { CRU_DEFINE_CLASS_LOG_TAG(u"cru::ui::controls::TextControlService") diff --git a/src/common/String.cpp b/src/common/String.cpp index ba31e6f6..8b53b16b 100644 --- a/src/common/String.cpp +++ b/src/common/String.cpp @@ -10,16 +10,6 @@ #include <string_view> namespace cru { -String String::FromUtf8(const char* str) { - return FromUtf16(cru::ToUtf16(std::string_view(str))); -} - -String String::FromUtf8(const char* str, Index size) { - return FromUtf16(cru::ToUtf16(std::string_view(str, size))); -} - -char16_t String::kEmptyBuffer[1] = {0}; - template <typename C> Index GetStrSize(const C* str) { Index i = 0; @@ -29,6 +19,16 @@ Index GetStrSize(const C* str) { return i; } +String String::FromUtf8(const char* str) { + return FromUtf16(cru::ToUtf16(str, GetStrSize(str))); +} + +String String::FromUtf8(const char* str, Index size) { + return FromUtf16(cru::ToUtf16(str, size)); +} + +char16_t String::kEmptyBuffer[1] = {0}; + String::String(const_pointer str) : String(str, GetStrSize(str)) {} String::String(const_pointer str, Index size) { @@ -211,9 +211,7 @@ String::iterator String::erase(const_iterator start, const_iterator end) { return s; } -std::string String::ToUtf8() const { - return cru::ToUtf8(std::u16string_view(data(), size())); -} +std::string String::ToUtf8() const { return cru::ToUtf8(buffer_, size_); } void String::AppendCodePoint(CodePoint code_point) { if (!Utf16EncodeCodePointAppendWithFunc( diff --git a/src/common/StringUtil.cpp b/src/common/StringUtil.cpp index 7492bdfd..850524b5 100644 --- a/src/common/StringUtil.cpp +++ b/src/common/StringUtil.cpp @@ -6,29 +6,29 @@ namespace cru { using details::ExtractBits; -CodePoint Utf8NextCodePoint(std::string_view str, Index current, +CodePoint Utf8NextCodePoint(const char* ptr, Index size, Index current, Index* next_position) { CodePoint result; - if (current >= static_cast<Index>(str.length())) { + if (current >= size) { result = k_invalid_code_point; } else { - const auto cu0 = static_cast<std::uint8_t>(str[current++]); + const auto cu0 = static_cast<std::uint8_t>(ptr[current++]); - auto read_next_folowing_code = [&str, ¤t]() -> CodePoint { - if (current == static_cast<Index>(str.length())) + auto read_next_folowing_code = [ptr, size, ¤t]() -> CodePoint { + if (current == size) throw TextEncodeException( u"Unexpected end when read continuing byte of multi-byte code " "point."); - const auto u = static_cast<std::uint8_t>(str[current]); + const auto u = static_cast<std::uint8_t>(ptr[current]); if (!(u & (1u << 7)) || (u & (1u << 6))) { throw TextEncodeException( u"Unexpected bad-format (not 0b10xxxxxx) continuing byte of " "multi-byte code point."); } - return ExtractBits<std::uint8_t, 6, CodePoint>(str[current++]); + return ExtractBits<std::uint8_t, 6, CodePoint>(ptr[current++]); }; if ((1u << 7) & cu0) { @@ -73,23 +73,23 @@ CodePoint Utf8NextCodePoint(std::string_view str, Index current, return result; } -CodePoint Utf16NextCodePoint(std::u16string_view str, Index current, +CodePoint Utf16NextCodePoint(const char16_t* ptr, Index size, Index current, Index* next_position) { CodePoint result; - if (current >= static_cast<Index>(str.length())) { + if (current >= size) { result = k_invalid_code_point; } else { - const auto cu0 = str[current++]; + const auto cu0 = ptr[current++]; if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point result = static_cast<CodePoint>(cu0); } else if (IsUtf16SurrogatePairLeading(cu0)) { // 2-length code point - if (current >= static_cast<Index>(str.length())) { + if (current >= size) { throw TextEncodeException( u"Unexpected end when reading second code unit of surrogate pair."); } - const auto cu1 = str[current++]; + const auto cu1 = ptr[current++]; if (!IsUtf16SurrogatePairTrailing(cu1)) { throw TextEncodeException( @@ -111,13 +111,13 @@ CodePoint Utf16NextCodePoint(std::u16string_view str, Index current, return result; } -CodePoint Utf16PreviousCodePoint(std::u16string_view str, Index current, +CodePoint Utf16PreviousCodePoint(const char16_t* ptr, Index size, Index current, Index* previous_position) { CodePoint result; if (current <= 0) { result = k_invalid_code_point; } else { - const auto cu0 = str[--current]; + const auto cu0 = ptr[--current]; if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point result = static_cast<CodePoint>(cu0); @@ -126,7 +126,7 @@ CodePoint Utf16PreviousCodePoint(std::u16string_view str, Index current, throw TextEncodeException( u"Unexpected end when reading first code unit of surrogate pair."); } - const auto cu1 = str[--current]; + const auto cu1 = ptr[--current]; if (!IsUtf16SurrogatePairLeading(cu1)) { throw TextEncodeException( @@ -160,48 +160,49 @@ void Utf16EncodeCodePointAppend(CodePoint code_point, std::u16string& str) { throw TextEncodeException(u"Code point out of range."); } -std::string ToUtf8(std::u16string_view s) { +std::string ToUtf8(const char16_t* ptr, Index size) { std::string result; - for (CodePoint cp : Utf16CodePointIterator{s}) { + for (CodePoint cp : Utf16CodePointIterator(ptr, size)) { Utf8EncodeCodePointAppend(cp, result); } return result; } -std::u16string ToUtf16(std::string_view s) { +std::u16string ToUtf16(const char* ptr, Index size) { std::u16string result; - for (CodePoint cp : Utf8CodePointIterator{s}) { + for (CodePoint cp : Utf8CodePointIterator(ptr, size)) { Utf16EncodeCodePointAppend(cp, result); } return result; } -bool Utf16IsValidInsertPosition(std::u16string_view s, gsl::index position) { +bool Utf16IsValidInsertPosition(const char16_t* ptr, Index size, + Index position) { if (position < 0) return false; - if (position > static_cast<gsl::index>(s.size())) return false; + if (position > size) return false; if (position == 0) return true; - if (position == static_cast<gsl::index>(s.size())) return true; - return !IsUtf16SurrogatePairTrailing(s[position]); + if (position == size) return true; + return !IsUtf16SurrogatePairTrailing(ptr[position]); } -gsl::index Utf16BackwardUntil(std::u16string_view str, gsl::index position, - const std::function<bool(CodePoint)>& predicate) { +Index Utf16BackwardUntil(const char16_t* ptr, Index size, Index position, + const std::function<bool(CodePoint)>& predicate) { if (position <= 0) return position; while (true) { - gsl::index p = position; - auto c = Utf16PreviousCodePoint(str, p, &position); + Index p = position; + auto c = Utf16PreviousCodePoint(ptr, size, p, &position); if (predicate(c)) return p; if (c == k_invalid_code_point) return p; } UnreachableCode(); } -gsl::index Utf16ForwardUntil(std::u16string_view str, gsl::index position, - const std::function<bool(CodePoint)>& predicate) { - if (position >= static_cast<gsl::index>(str.size())) return position; +Index Utf16ForwardUntil(const char16_t* ptr, Index size, Index position, + const std::function<bool(CodePoint)>& predicate) { + if (position >= size) return position; while (true) { - gsl::index p = position; - auto c = Utf16NextCodePoint(str, p, &position); + Index p = position; + auto c = Utf16NextCodePoint(ptr, size, p, &position); if (predicate(c)) return p; if (c == k_invalid_code_point) return p; } @@ -210,31 +211,31 @@ gsl::index Utf16ForwardUntil(std::u16string_view str, gsl::index position, inline bool IsSpace(CodePoint c) { return c == 0x20 || c == 0xA; } -gsl::index Utf16PreviousWord(std::u16string_view str, gsl::index position, - bool* is_space) { +Index Utf16PreviousWord(const char16_t* ptr, Index size, Index position, + bool* is_space) { if (position <= 0) return position; - auto c = Utf16PreviousCodePoint(str, position, nullptr); + auto c = Utf16PreviousCodePoint(ptr, size, position, nullptr); if (IsSpace(c)) { // TODO: Currently only test against 0x20(space). if (is_space) *is_space = true; - return Utf16BackwardUntil(str, position, + return Utf16BackwardUntil(ptr, size, position, [](CodePoint c) { return !IsSpace(c); }); } else { if (is_space) *is_space = false; - return Utf16BackwardUntil(str, position, IsSpace); + return Utf16BackwardUntil(ptr, size, position, IsSpace); } } -gsl::index Utf16NextWord(std::u16string_view str, gsl::index position, - bool* is_space) { - if (position >= static_cast<gsl::index>(str.size())) return position; - auto c = Utf16NextCodePoint(str, position, nullptr); +Index Utf16NextWord(const char16_t* ptr, Index size, Index position, + bool* is_space) { + if (position >= size) return position; + auto c = Utf16NextCodePoint(ptr, size, position, nullptr); if (IsSpace(c)) { // TODO: Currently only test against 0x20(space). if (is_space) *is_space = true; - return Utf16ForwardUntil(str, position, + return Utf16ForwardUntil(ptr, size, position, [](CodePoint c) { return !IsSpace(c); }); } else { if (is_space) *is_space = false; - return Utf16ForwardUntil(str, position, IsSpace); + return Utf16ForwardUntil(ptr, size, position, IsSpace); } } diff --git a/src/ui/controls/TextHostControlService.cpp b/src/ui/controls/TextHostControlService.cpp index 2233d1e6..9f5098db 100644 --- a/src/ui/controls/TextHostControlService.cpp +++ b/src/ui/controls/TextHostControlService.cpp @@ -18,6 +18,45 @@ #include "cru/ui/render/TextRenderObject.hpp" namespace cru::ui::controls { +TextControlMovePattern TextControlMovePattern::kLeft( + helper::ShortcutKeyBind(platform::gui::KeyCode::Left), + [](TextHostControlService* service, StringView text, + gsl::index current_position) { + Utf16PreviousCodePoint(text, current_position, ¤t_position); + return current_position; + }); +TextControlMovePattern TextControlMovePattern::kRight( + helper::ShortcutKeyBind(platform::gui::KeyCode::Right), + [](TextHostControlService* service, StringView text, + gsl::index current_position) { + Utf16NextCodePoint(text, current_position, ¤t_position); + return current_position; + }); +TextControlMovePattern TextControlMovePattern::kUp( + helper::ShortcutKeyBind(platform::gui::KeyCode::Up), + [](TextHostControlService* service, StringView text, + gsl::index current_position) { return current_position; }); +TextControlMovePattern TextControlMovePattern::kDown( + helper::ShortcutKeyBind(platform::gui::KeyCode::Down), + [](TextHostControlService* service, StringView text, + gsl::index current_position) { return current_position; }); +TextControlMovePattern TextControlMovePattern::kHome( + helper::ShortcutKeyBind(platform::gui::KeyCode::Home), + [](TextHostControlService* service, StringView text, + gsl::index current_position) { return current_position; }); +TextControlMovePattern TextControlMovePattern::kEnd( + helper::ShortcutKeyBind(platform::gui::KeyCode::End), + [](TextHostControlService* service, StringView text, + gsl::index current_position) { return current_position; }); +TextControlMovePattern TextControlMovePattern::kPageUp( + helper::ShortcutKeyBind(platform::gui::KeyCode::PageUp), + [](TextHostControlService* service, StringView text, + gsl::index current_position) { return current_position; }); +TextControlMovePattern TextControlMovePattern::kPageDown( + helper::ShortcutKeyBind(platform::gui::KeyCode::PageDown), + [](TextHostControlService* service, StringView text, + gsl::index current_position) { return current_position; }); + TextHostControlService::TextHostControlService(gsl::not_null<Control*> control) : control_(control), text_host_control_(dynamic_cast<ITextHostControl*>(control.get())) { |