From 1bce247b22f95e60cfcf844264aa820998088e5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Sat, 18 Jan 2014 10:32:14 +0100 Subject: [PATCH] Fleshed out more TextEditor functionality. TextDocumentView now always has a TextEditor, but editing can be disabled. The selection code lives only in TextEditor. Implemented more cursor navigation code. --- .../haiku-depot/textview/TextDocumentView.cpp | 102 +++----- .../haiku-depot/textview/TextDocumentView.h | 13 +- src/apps/haiku-depot/textview/TextEditor.cpp | 234 ++++++++++++------ src/apps/haiku-depot/textview/TextEditor.h | 38 +-- 4 files changed, 221 insertions(+), 166 deletions(-) diff --git a/src/apps/haiku-depot/textview/TextDocumentView.cpp b/src/apps/haiku-depot/textview/TextDocumentView.cpp index a9aea3ea13..48a7a4e3ad 100644 --- a/src/apps/haiku-depot/textview/TextDocumentView.cpp +++ b/src/apps/haiku-depot/textview/TextDocumentView.cpp @@ -24,14 +24,14 @@ TextDocumentView::TextDocumentView(const char* name) fInsetRight(0.0f), fInsetBottom(0.0f), - fSelectionAnchorOffset(0), - fCaretOffset(0), - fCaretAnchorX(0.0f), + fCaretBounds(), fShowCaret(false), - fMouseDown(false) { fTextDocumentLayout.SetWidth(_TextLayoutWidth(Bounds().Width())); + + // Set default TextEditor + SetTextEditor(TextEditorRef(new(std::nothrow) TextEditor(), true)); SetViewColor(B_TRANSPARENT_COLOR); SetLowColor(255, 255, 255, 255); @@ -67,11 +67,14 @@ TextDocumentView::Draw(BRect updateRect) fTextDocumentLayout.SetWidth(_TextLayoutWidth(Bounds().Width())); fTextDocumentLayout.Draw(this, BPoint(fInsetLeft, fInsetTop), updateRect); - bool isCaret = fSelectionAnchorOffset == fCaretOffset; + if (fTextEditor.Get() == NULL) + return; + + bool isCaret = fTextEditor->SelectionLength() == 0; if (isCaret) { - if (fShowCaret && fTextEditor.Get() != NULL) - _DrawCaret(fCaretOffset); + if (fShowCaret && fTextEditor->IsEditingEnabled()) + _DrawCaret(fTextEditor->CaretOffset()); } else { _DrawSelection(); } @@ -174,11 +177,13 @@ TextDocumentView::KeyDown(const char* bytes, int32 numBytes) if (Window() != NULL && Window()->CurrentMessage() != NULL) { BMessage* message = Window()->CurrentMessage(); - message->FindInt32("key", &event.key); + message->FindInt32("raw_char", &event.key); message->FindInt32("modifiers", &event.modifiers); } fTextEditor->KeyDown(event); + fShowCaret = true; + Invalidate(); } @@ -245,16 +250,20 @@ TextDocumentView::SetTextDocument(const TextDocumentRef& document) if (fTextEditor.Get() != NULL) fTextEditor->SetDocument(document); - fSelectionAnchorOffset = 0; - fCaretOffset = 0; - fCaretAnchorX = 0.0f; - InvalidateLayout(); Invalidate(); _UpdateScrollBars(); } +void +TextDocumentView::SetEditingEnabled(bool enabled) +{ + if (fTextEditor.Get() != NULL) + fTextEditor->SetEditingEnabled(enabled); +} + + void TextDocumentView::SetTextEditor(const TextEditorRef& editor) { @@ -262,6 +271,8 @@ TextDocumentView::SetTextEditor(const TextEditorRef& editor) return; if (fTextEditor.Get() != NULL) { + fTextEditor->SetDocument(TextDocumentRef()); + fTextEditor->SetLayout(TextDocumentLayoutRef()); // TODO: Probably has to remove listeners } @@ -269,6 +280,8 @@ TextDocumentView::SetTextEditor(const TextEditorRef& editor) if (fTextEditor.Get() != NULL) { fTextEditor->SetDocument(fTextDocument); + fTextEditor->SetLayout(TextDocumentLayoutRef( + &fTextDocumentLayout)); // TODO: Probably has to add listeners } } @@ -307,38 +320,33 @@ TextDocumentView::SetInsets(float left, float top, float right, float bottom) void -TextDocumentView::SetCaret(const BPoint& location, bool extendSelection) +TextDocumentView::SetCaret(BPoint location, bool extendSelection) { - if (fTextDocument.Get() == NULL) + if (fTextEditor.Get() == NULL) return; - bool rightOfChar = false; - int32 caretOffset = fTextDocumentLayout.TextOffsetAt( - location.x - fInsetLeft, location.y - fInsetTop, rightOfChar); + location.x -= fInsetLeft; + location.y -= fInsetTop; - if (rightOfChar) - caretOffset++; - - _SetCaretOffset(caretOffset, true, extendSelection); + fTextEditor->SetCaret(location, extendSelection); + fShowCaret = !extendSelection; + Invalidate(); } bool TextDocumentView::HasSelection() const { - return fSelectionAnchorOffset != fCaretOffset; + return fTextEditor.Get() != NULL && fTextEditor->HasSelection(); } void TextDocumentView::GetSelection(int32& start, int32& end) const { - if (fSelectionAnchorOffset <= fCaretOffset) { - start = fSelectionAnchorOffset; - end = fCaretOffset; - } else { - start = fCaretOffset; - end = fSelectionAnchorOffset; + if (fTextEditor.Get()) { + start = fTextEditor->SelectionStart(); + end = fTextEditor->SelectionEnd(); } } @@ -346,8 +354,7 @@ TextDocumentView::GetSelection(int32& start, int32& end) const void TextDocumentView::Copy(BClipboard* clipboard) { - if (fSelectionAnchorOffset == fCaretOffset - || fTextDocument.Get() == NULL) { + if (!HasSelection() || fTextDocument.Get() == NULL) { // Nothing to copy, don't clear clipboard contents for now reason. return; } @@ -425,41 +432,6 @@ TextDocumentView::_UpdateScrollBars() } -void -TextDocumentView::_SetCaretOffset(int32 offset, bool updateAnchor, - bool lockSelectionAnchor) -{ - if (offset < 0) - offset = 0; - int32 length = fTextDocument->Length(); - if (offset > length) - offset = length; - - if (offset == fCaretOffset && (lockSelectionAnchor - || offset == fSelectionAnchorOffset)) { - return; - } - - if (!lockSelectionAnchor) - fSelectionAnchorOffset = offset; - - fCaretOffset = offset; - fShowCaret = true; - - if (updateAnchor) { - float x1; - float y1; - float x2; - float y2; - - fTextDocumentLayout.GetTextBounds(fCaretOffset, x1, y1, x2, y2); - fCaretAnchorX = x1; - } - - Invalidate(); -} - - void TextDocumentView::_DrawCaret(int32 textOffset) { diff --git a/src/apps/haiku-depot/textview/TextDocumentView.h b/src/apps/haiku-depot/textview/TextDocumentView.h index 85094d94f8..65ef4c4cf3 100644 --- a/src/apps/haiku-depot/textview/TextDocumentView.h +++ b/src/apps/haiku-depot/textview/TextDocumentView.h @@ -52,6 +52,7 @@ public: void SetTextDocument( const TextDocumentRef& document); + void SetEditingEnabled(bool enabled); void SetTextEditor( const TextEditorRef& editor); @@ -60,8 +61,7 @@ public: void SetInsets(float left, float top, float right, float bottom); - void SetCaret(const BPoint& where, - bool extendSelection); + void SetCaret(BPoint where, bool extendSelection); bool HasSelection() const; void GetSelection(int32& start, int32& end) const; @@ -73,9 +73,6 @@ private: void _UpdateScrollBars(); - void _SetCaretOffset(int32 offset, bool updateAnchor, - bool lockSelectionAnchor); - void _DrawCaret(int32 textOffset); void _DrawSelection(); void _GetSelectionShape(BShape& shape, @@ -91,12 +88,8 @@ private: float fInsetRight; float fInsetBottom; - int32 fSelectionAnchorOffset; - int32 fCaretOffset; - float fCaretAnchorX; - bool fShowCaret; BRect fCaretBounds; - + bool fShowCaret; bool fMouseDown; }; diff --git a/src/apps/haiku-depot/textview/TextEditor.cpp b/src/apps/haiku-depot/textview/TextEditor.cpp index f3a28b35f7..ae5948c411 100644 --- a/src/apps/haiku-depot/textview/TextEditor.cpp +++ b/src/apps/haiku-depot/textview/TextEditor.cpp @@ -14,7 +14,8 @@ TextEditor::TextEditor() fLayout(), fSelection(), fCaretAnchorX(0.0f), - fStyleAtCaret() + fStyleAtCaret(), + fEditingEnabled(true) { } @@ -25,7 +26,13 @@ TextEditor::TextEditor(const TextEditor& other) fLayout(other.fLayout), fSelection(other.fSelection), fCaretAnchorX(other.fCaretAnchorX), - fStyleAtCaret(other.fStyleAtCaret) + fStyleAtCaret(other.fStyleAtCaret), + fEditingEnabled(other.fEditingEnabled) +{ +} + + +TextEditor::~TextEditor() { } @@ -41,6 +48,7 @@ TextEditor::operator=(const TextEditor& other) fSelection = other.fSelection; fCaretAnchorX = other.fCaretAnchorX; fStyleAtCaret = other.fStyleAtCaret; + fEditingEnabled = other.fEditingEnabled; return *this; } @@ -55,7 +63,8 @@ TextEditor::operator==(const TextEditor& other) const && fLayout == other.fLayout && fSelection == other.fSelection && fCaretAnchorX == other.fCaretAnchorX - && fStyleAtCaret == other.fStyleAtCaret; + && fStyleAtCaret == other.fStyleAtCaret + && fEditingEnabled == other.fEditingEnabled; } @@ -85,6 +94,30 @@ TextEditor::SetLayout(const TextDocumentLayoutRef& ref) } +void +TextEditor::SetEditingEnabled(bool enabled) +{ + fEditingEnabled = enabled; +} + + +void +TextEditor::SetCaret(BPoint location, bool extendSelection) +{ + if (fDocument.Get() == NULL || fLayout.Get() == NULL) + return; + + bool rightOfChar = false; + int32 caretOffset = fLayout->TextOffsetAt(location.x, location.y, + rightOfChar); + + if (rightOfChar) + caretOffset++; + + _SetCaretOffset(caretOffset, true, extendSelection, true); +} + + void TextEditor::SetSelection(TextSelection selection) { @@ -116,15 +149,15 @@ TextEditor::KeyDown(KeyEvent event) switch (event.key) { case B_UP_ARROW: - _LineUp(select); + LineUp(select); break; case B_DOWN_ARROW: - _LineDown(select); + LineDown(select); break; case B_LEFT_ARROW: - if (_HasSelection() && !select) { + if (HasSelection() && !select) { _SetCaretOffset( std::min(fSelection.Caret(), fSelection.Anchor()), true, false, true @@ -134,7 +167,7 @@ TextEditor::KeyDown(KeyEvent event) break; case B_RIGHT_ARROW: - if (_HasSelection() && !select) { + if (HasSelection() && !select) { _SetCaretOffset( std::max(fSelection.Caret(), fSelection.Anchor()), true, false, true @@ -144,11 +177,11 @@ TextEditor::KeyDown(KeyEvent event) break; case B_HOME: - _LineStart(select); + LineStart(select); break; case B_END: - _LineEnd(select); + LineEnd(select); break; case B_ENTER: @@ -164,8 +197,8 @@ TextEditor::KeyDown(KeyEvent event) break; case B_BACKSPACE: - if (_HasSelection()) { - Remove(_SelectionStart(), _SelectionLength()); + if (HasSelection()) { + Remove(SelectionStart(), SelectionLength()); } else { if (fSelection.Caret() > 0) Remove(fSelection.Caret() - 1, 1); @@ -173,8 +206,8 @@ TextEditor::KeyDown(KeyEvent event) break; case B_DELETE: - if (_HasSelection()) { - Remove(_SelectionStart(), _SelectionLength()); + if (HasSelection()) { + Remove(SelectionStart(), SelectionLength()); } else { if (fSelection.Caret() < fDocument->Length()) Remove(fSelection.Caret(), 1); @@ -207,6 +240,9 @@ TextEditor::KeyDown(KeyEvent event) void TextEditor::Insert(int32 offset, const BString& string) { + if (!fEditingEnabled) + return; + // TODO: ... } @@ -214,14 +250,119 @@ TextEditor::Insert(int32 offset, const BString& string) void TextEditor::Remove(int32 offset, int32 length) { + if (!fEditingEnabled) + return; + // TODO: ... } +// #pragma mark - + + +void +TextEditor::LineUp(bool select) +{ + if (fLayout.Get() == NULL) + return; + + int32 lineIndex = fLayout->LineIndexForOffset(fSelection.Caret()); + _MoveToLine(lineIndex - 1, select); +} + + +void +TextEditor::LineDown(bool select) +{ + if (fLayout.Get() == NULL) + return; + + int32 lineIndex = fLayout->LineIndexForOffset(fSelection.Caret()); + _MoveToLine(lineIndex + 1, select); +} + + +void +TextEditor::LineStart(bool select) +{ + if (fLayout.Get() == NULL) + return; + + int32 lineIndex = fLayout->LineIndexForOffset(fSelection.Caret()); + _SetCaretOffset(fLayout->FirstOffsetOnLine(lineIndex), true, select, + true); +} + + +void +TextEditor::LineEnd(bool select) +{ + if (fLayout.Get() == NULL) + return; + + int32 lineIndex = fLayout->LineIndexForOffset(fSelection.Caret()); + _SetCaretOffset(fLayout->LastOffsetOnLine(lineIndex), true, select, + true); +} + + +// #pragma mark - + + +bool +TextEditor::HasSelection() const +{ + return SelectionLength() > 0; +} + + +int32 +TextEditor::SelectionStart() const +{ + return std::min(fSelection.Caret(), fSelection.Anchor()); +} + + +int32 +TextEditor::SelectionEnd() const +{ + return std::max(fSelection.Caret(), fSelection.Anchor()); +} + + +int32 +TextEditor::SelectionLength() const +{ + return SelectionEnd() - SelectionStart(); +} + + // #pragma mark - private -// _SetCaretOffset +// _MoveToLine +void +TextEditor::_MoveToLine(int32 lineIndex, bool select) +{ + if (lineIndex < 0 || lineIndex >= fLayout->CountLines()) + return; + + float x1; + float y1; + float x2; + float y2; + fLayout->GetLineBounds(lineIndex , x1, y1, x2, y2); + + bool rightOfCenter; + int32 textOffset = fLayout->TextOffsetAt(fCaretAnchorX, (y1 + y2) / 2, + rightOfCenter); + + if (rightOfCenter) + textOffset++; + + _SetCaretOffset(textOffset, false, select, true); +} + void TextEditor::_SetCaretOffset(int32 offset, bool updateAnchor, bool lockSelectionAnchor, bool updateSelectionStyle) @@ -241,7 +382,6 @@ TextEditor::_SetCaretOffset(int32 offset, bool updateAnchor, } -// _SetSelection void TextEditor::_SetSelection(int32 caret, int32 anchor, bool updateAnchor, bool updateSelectionStyle) @@ -249,11 +389,11 @@ TextEditor::_SetSelection(int32 caret, int32 anchor, bool updateAnchor, if (fLayout.Get() == NULL) return; - if (caret == fSelection.Caret() && caret == fSelection.Anchor()) + if (caret == fSelection.Caret() && anchor == fSelection.Anchor()) return; - fSelection.SetAnchor(anchor); fSelection.SetCaret(caret); + fSelection.SetAnchor(anchor); if (updateAnchor) { float x1; @@ -283,63 +423,3 @@ TextEditor::_UpdateStyleAtCaret() } -// #pragma mark - - - -void -TextEditor::_LineUp(bool select) -{ - // TODO -} - - -void -TextEditor::_LineDown(bool select) -{ - // TODO -} - - -void -TextEditor::_LineStart(bool select) -{ - // TODO -} - - -void -TextEditor::_LineEnd(bool select) -{ - // TODO -} - - -// #pragma mark - - - -bool -TextEditor::_HasSelection() const -{ - return _SelectionLength() > 0; -} - - -int32 -TextEditor::_SelectionStart() const -{ - return std::min(fSelection.Caret(), fSelection.Anchor()); -} - - -int32 -TextEditor::_SelectionEnd() const -{ - return std::max(fSelection.Caret(), fSelection.Anchor()); -} - - -int32 -TextEditor::_SelectionLength() const -{ - return _SelectionEnd() - _SelectionStart(); -} diff --git a/src/apps/haiku-depot/textview/TextEditor.h b/src/apps/haiku-depot/textview/TextEditor.h index 77c851e6c9..89bdb4735f 100644 --- a/src/apps/haiku-depot/textview/TextEditor.h +++ b/src/apps/haiku-depot/textview/TextEditor.h @@ -6,6 +6,7 @@ #define TEXT_EDITOR_H +#include #include #include "CharacterStyle.h" @@ -27,6 +28,7 @@ class TextEditor : public BReferenceable { public: TextEditor(); TextEditor(const TextEditor& other); + virtual ~TextEditor(); TextEditor& operator=(const TextEditor& other); bool operator==(const TextEditor& other) const; @@ -41,6 +43,11 @@ public: TextDocumentLayoutRef Layout() const { return fLayout; } + void SetEditingEnabled(bool enabled); + inline bool IsEditingEnabled() const + { return fEditingEnabled; } + + void SetCaret(BPoint location, bool extendSelection); void SetSelection(TextSelection selection); inline TextSelection Selection() const { return fSelection; } @@ -49,12 +56,25 @@ public: ::CharacterStyle CharacterStyle() const { return fStyleAtCaret; } - void KeyDown(KeyEvent event); + virtual void KeyDown(KeyEvent event); - void Insert(int32 offset, const BString& string); - void Remove(int32 offset, int32 length); + virtual void Insert(int32 offset, const BString& string); + virtual void Remove(int32 offset, int32 length); + + void LineUp(bool select); + void LineDown(bool select); + void LineStart(bool select); + void LineEnd(bool select); + + bool HasSelection() const; + int32 SelectionStart() const; + int32 SelectionEnd() const; + int32 SelectionLength() const; + inline int32 CaretOffset() const + { return fSelection.Caret(); } private: + void _MoveToLine(int32 lineIndex, bool select); void _SetCaretOffset(int32 offset, bool updateAnchor, bool lockSelectionAnchor, @@ -64,23 +84,13 @@ private: bool updateSelectionStyle); void _UpdateStyleAtCaret(); - - void _LineUp(bool select); - void _LineDown(bool select); - void _LineStart(bool select); - void _LineEnd(bool select); - - bool _HasSelection() const; - int32 _SelectionStart() const; - int32 _SelectionEnd() const; - int32 _SelectionLength() const; - private: TextDocumentRef fDocument; TextDocumentLayoutRef fLayout; TextSelection fSelection; float fCaretAnchorX; ::CharacterStyle fStyleAtCaret; + bool fEditingEnabled; };