Text Editor based on SkText: delete and backspace
Change-Id: I1152f83af724634f06e1a767ef39bef2afe70b33
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/430656
Reviewed-by: Julia Lavrova <jlavrova@google.com>
Commit-Queue: Julia Lavrova <jlavrova@google.com>
diff --git a/experimental/sktext/editor/Editor.cpp b/experimental/sktext/editor/Editor.cpp
index 61f3c13..4238287 100644
--- a/experimental/sktext/editor/Editor.cpp
+++ b/experimental/sktext/editor/Editor.cpp
@@ -98,7 +98,31 @@
auto rect = std::get<3>(endOfText);
fCursor->place(SkPoint::Make(rect.fLeft, rect.fTop),
SkSize::Make(std::max(DEFAULT_CURSOR_WIDTH, rect.width()), rect.height()));
- //SkSize::Make(DEFAULT_CURSOR_WIDTH, rect.height()));
+}
+
+void Editor::updateText(std::u16string text) {
+ // TODO: Update text styles
+ sk_sp<TrivialFontChain> fontChain = sk_make_sp<TrivialFontChain>("Roboto", 40);
+ Block block(fText.size(), fontChain);
+ auto fontBlocks = SkSpan<Block>(&block, 1);
+
+ // TODO: update all objects rather than recreate them
+ fText = std::move(text);
+ fUnicodeText = Text::parse(SkSpan<uint16_t>((uint16_t*)fText.data(), fText.size()));
+ fShapedText = fUnicodeText->shape(fontBlocks, TEXT_DIRECTION);
+ fWrappedText = fShapedText->wrap(fWidth, fHeight, fUnicodeText->getUnicode());
+ fFormattedText = fWrappedText->format(TEXT_ALIGN, TEXT_DIRECTION);
+
+ // Update the cursor
+ auto endOfText = fFormattedText->indexToAdjustedGraphemePosition(fText.size());
+ auto rect = std::get<3>(endOfText);
+ fCursor->place(SkPoint::Make(rect.fLeft, rect.fTop),
+ SkSize::Make(std::max(DEFAULT_CURSOR_WIDTH, rect.width()), rect.height()));
+ // TODO: Update the mouse
+ fMouse->clearTouchInfo();
+
+ // TODO: Update the text selection
+ fSelection->clear();
}
bool Editor::moveCursor(skui::Key key) {
@@ -174,16 +198,10 @@
modi &= ~skui::ModifierKey::kFirstPress;
if (!Any(modi & (skui::ModifierKey::kControl | skui::ModifierKey::kOption |
skui::ModifierKey::kCommand))) {
- /*
if (((unsigned)c < 0x7F && (unsigned)c >= 0x20) || c == '\n') {
- char ch = (char)c;
- fEditor.insert(fTextPos, &ch, 1);
- #ifdef SK_EDITOR_DEBUG_OUT
- SkDebugf("insert: %X'%c'\n", (unsigned)c, ch);
- #endif // SK_EDITOR_DEBUG_OUT
- return this->moveCursor(Editor::Movement::kRight);
+ insertCodepoint(c);
+ return true;
}
- */
}
static constexpr skui::ModifierKey kCommandOrControl =
skui::ModifierKey::kCommand | skui::ModifierKey::kControl;
@@ -193,6 +211,51 @@
return false;
}
+bool Editor::deleteGrapheme(skui::Key key) {
+ auto cursorPosition = fCursor->getCenterPosition();
+ TextIndex startIndex = fFormattedText->positionToAdjustedGraphemeIndex(cursorPosition);
+ TextIndex endIndex = startIndex;
+ if (key == skui::Key::kBack) {
+ --startIndex;
+ fShapedText->adjustLeft(&startIndex);
+ } else {
+ ++endIndex;
+ fShapedText->adjustRight(&endIndex);
+ }
+
+ std::u16string text;
+ text.append(fText.substr(0, startIndex));
+ text.append(fText.substr(endIndex, std::u16string::npos));
+ updateText(text);
+
+ auto position = fFormattedText->indexToAdjustedGraphemePosition(startIndex);
+ SkRect cursorRect = std::get<3>(position);
+ fCursor->place(SkPoint::Make(cursorRect.fLeft, cursorRect.fTop), SkSize::Make(cursorRect.width(), cursorRect.height()));
+
+ this->invalidate();
+
+ return true;
+}
+
+bool Editor::insertCodepoint(SkUnichar unichar) {
+ auto cursorPosition = fCursor->getCenterPosition();
+ auto textIndex = fFormattedText->positionToAdjustedGraphemeIndex(cursorPosition);
+
+ std::u16string text;
+ text.append(fText.substr(0, textIndex));
+ text.append(1, (unsigned)unichar);
+ text.append(fText.substr(textIndex, std::u16string::npos));
+ updateText(text);
+
+ auto nextPosition = fFormattedText->indexToAdjustedGraphemePosition(textIndex);
+ SkRect cursorRect = std::get<3>(nextPosition);
+ fCursor->place(SkPoint::Make(cursorRect.fLeft, cursorRect.fTop), SkSize::Make(cursorRect.width(), cursorRect.height()));
+
+ this->invalidate();
+
+ return true;
+}
+
bool Editor::onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers) {
fSelection->clear();
@@ -216,28 +279,12 @@
case skui::Key::kEnd:
this->moveCursor(key);
break;
- /*
case skui::Key::kDelete:
- if (fMarkPos != Editor::TextPosition()) {
- (void)this->move(fEditor.remove(fMarkPos, fTextPos), false);
- } else {
- auto pos = fEditor.move(Editor::Movement::kRight, fTextPos);
- (void)this->move(fEditor.remove(fTextPos, pos), false);
- }
- this->inval();
- return true;
case skui::Key::kBack:
- if (fMarkPos != Editor::TextPosition()) {
- (void)this->move(fEditor.remove(fMarkPos, fTextPos), false);
- } else {
- auto pos = fEditor.move(Editor::Movement::kLeft, fTextPos);
- (void)this->move(fEditor.remove(fTextPos, pos), false);
- }
- this->inval();
+ this->deleteGrapheme(key);
return true;
case skui::Key::kOK:
return this->onChar('\n', modifiers);
- */
default:
break;
}
diff --git a/experimental/sktext/editor/Editor.h b/experimental/sktext/editor/Editor.h
index 0278ce8..664cc64 100644
--- a/experimental/sktext/editor/Editor.h
+++ b/experimental/sktext/editor/Editor.h
@@ -114,6 +114,8 @@
Editor(std::u16string text, SkSize size, SkSpan<Block> fontBlocks);
+ void updateText(std::u16string text);
+
void onAttach(sk_app::Window* w) override { fParent = w; }
void onPaint(SkSurface* surface) override;
@@ -133,6 +135,8 @@
void onPlaceholder(TextRange, const SkRect& bounds) override;
bool moveCursor(skui::Key key);
+ bool insertCodepoint(SkUnichar unichar);
+ bool deleteGrapheme(skui::Key key);
std::unique_ptr<Cursor> fCursor;
std::unique_ptr<Mouse> fMouse;
diff --git a/experimental/sktext/include/Text.h b/experimental/sktext/include/Text.h
index a55dca5..2df92a6f 100644
--- a/experimental/sktext/include/Text.h
+++ b/experimental/sktext/include/Text.h
@@ -82,6 +82,15 @@
--index;
}
}
+ void adjustRight(size_t* index) const {
+ SkASSERT(index != nullptr);
+ while (*index < this->fGlyphUnitProperties.size()) {
+ if (isClusterEdge(*index)) {
+ return;
+ }
+ ++index;
+ }
+ }
bool hasProperty(size_t index, GlyphUnitFlags flag) {
return (fGlyphUnitProperties[index] & flag) == flag;
}
diff --git a/experimental/sktext/src/Line.h b/experimental/sktext/src/Line.h
index a47d1e7..791ab51 100644
--- a/experimental/sktext/src/Line.h
+++ b/experimental/sktext/src/Line.h
@@ -170,6 +170,11 @@
~Line() = default;
TextMetrics getMetrics() const { return fTextMetrics; }
+ GlyphPos glyphStart() const { return fTextStart; }
+ GlyphPos glyphEnd() const { return fTextEnd; }
+ GlyphPos glyphTrailingEnd() const { return fWhitespacesEnd; }
+ SkScalar width() const { return fTextWidth; }
+ SkScalar withWithTrailingSpaces() const { return fTextWidth + fSpacesWidth; }
private:
friend class WrappedText;