HaikuDepot: Added work-in-progress TextEditor class
The intention here is to be able to set it on a TextDocumentView to add editing capabilities.
This commit is contained in:
@@ -26,6 +26,8 @@ local textDocumentSources =
|
|||||||
TextDocument.cpp
|
TextDocument.cpp
|
||||||
TextDocumentLayout.cpp
|
TextDocumentLayout.cpp
|
||||||
TextDocumentView.cpp
|
TextDocumentView.cpp
|
||||||
|
TextEditor.cpp
|
||||||
|
TextSelection.cpp
|
||||||
TextSpan.cpp
|
TextSpan.cpp
|
||||||
TextView.cpp
|
TextView.cpp
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -0,0 +1,345 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014, Stephan Aßmus <[email protected]>.
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TextEditor.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
TextEditor::TextEditor()
|
||||||
|
:
|
||||||
|
fDocument(),
|
||||||
|
fLayout(),
|
||||||
|
fSelection(),
|
||||||
|
fCaretAnchorX(0.0f),
|
||||||
|
fStyleAtCaret()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TextEditor::TextEditor(const TextEditor& other)
|
||||||
|
:
|
||||||
|
fDocument(other.fDocument),
|
||||||
|
fLayout(other.fLayout),
|
||||||
|
fSelection(other.fSelection),
|
||||||
|
fCaretAnchorX(other.fCaretAnchorX),
|
||||||
|
fStyleAtCaret(other.fStyleAtCaret)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TextEditor&
|
||||||
|
TextEditor::operator=(const TextEditor& other)
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
fDocument = other.fDocument;
|
||||||
|
fLayout = other.fLayout;
|
||||||
|
fSelection = other.fSelection;
|
||||||
|
fCaretAnchorX = other.fCaretAnchorX;
|
||||||
|
fStyleAtCaret = other.fStyleAtCaret;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TextEditor::operator==(const TextEditor& other) const
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return fDocument == other.fDocument
|
||||||
|
&& fLayout == other.fLayout
|
||||||
|
&& fSelection == other.fSelection
|
||||||
|
&& fCaretAnchorX == other.fCaretAnchorX
|
||||||
|
&& fStyleAtCaret == other.fStyleAtCaret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TextEditor::operator!=(const TextEditor& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextEditor::SetDocument(const TextDocumentRef& ref)
|
||||||
|
{
|
||||||
|
fDocument = ref;
|
||||||
|
SetSelection(TextSelection());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextEditor::SetLayout(const TextDocumentLayoutRef& ref)
|
||||||
|
{
|
||||||
|
fLayout = ref;
|
||||||
|
SetSelection(TextSelection());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextEditor::SetSelection(TextSelection selection)
|
||||||
|
{
|
||||||
|
_SetSelection(selection.Caret(), selection.Anchor(), true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextEditor::SetCharacterStyle(::CharacterStyle style)
|
||||||
|
{
|
||||||
|
if (fStyleAtCaret == style)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fStyleAtCaret = style;
|
||||||
|
|
||||||
|
if (fSelection.Caret() != fSelection.Anchor()) {
|
||||||
|
// TODO: Apply style to selection range
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextEditor::KeyDown(KeyEvent event)
|
||||||
|
{
|
||||||
|
if (fDocument.Get() == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool select = (event.modifiers & B_SHIFT_KEY) != 0;
|
||||||
|
|
||||||
|
switch (event.key) {
|
||||||
|
case B_UP_ARROW:
|
||||||
|
_LineUp(select);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_DOWN_ARROW:
|
||||||
|
_LineDown(select);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_LEFT_ARROW:
|
||||||
|
if (_HasSelection() && !select) {
|
||||||
|
_SetCaretOffset(
|
||||||
|
std::min(fSelection.Caret(), fSelection.Anchor()),
|
||||||
|
true, false, true
|
||||||
|
);
|
||||||
|
} else
|
||||||
|
_SetCaretOffset(fSelection.Caret() - 1, true, select, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_RIGHT_ARROW:
|
||||||
|
if (_HasSelection() && !select) {
|
||||||
|
_SetCaretOffset(
|
||||||
|
std::max(fSelection.Caret(), fSelection.Anchor()),
|
||||||
|
true, false, true
|
||||||
|
);
|
||||||
|
} else
|
||||||
|
_SetCaretOffset(fSelection.Caret() + 1, true, select, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_HOME:
|
||||||
|
_LineStart(select);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_END:
|
||||||
|
_LineEnd(select);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_ENTER:
|
||||||
|
Insert(fSelection.Caret(), "\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_TAB:
|
||||||
|
// TODO: Tab support in TextLayout
|
||||||
|
Insert(fSelection.Caret(), " ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_ESCAPE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_BACKSPACE:
|
||||||
|
if (_HasSelection()) {
|
||||||
|
Remove(_SelectionStart(), _SelectionLength());
|
||||||
|
} else {
|
||||||
|
if (fSelection.Caret() > 0)
|
||||||
|
Remove(fSelection.Caret() - 1, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_DELETE:
|
||||||
|
if (_HasSelection()) {
|
||||||
|
Remove(_SelectionStart(), _SelectionLength());
|
||||||
|
} else {
|
||||||
|
if (fSelection.Caret() < fDocument->Length())
|
||||||
|
Remove(fSelection.Caret(), 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_INSERT:
|
||||||
|
// TODO: Toggle insert mode (or maybe just don't support it)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_PAGE_UP:
|
||||||
|
case B_PAGE_DOWN:
|
||||||
|
case B_SUBSTITUTE:
|
||||||
|
case B_FUNCTION_KEY:
|
||||||
|
case B_KATAKANA_HIRAGANA:
|
||||||
|
case B_HANKAKU_ZENKAKU:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (event.bytes != NULL && event.length > 0) {
|
||||||
|
// Handle null-termintating the string
|
||||||
|
BString text(event.bytes, event.length);
|
||||||
|
Insert(fSelection.Caret(), text);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextEditor::Insert(int32 offset, const BString& string)
|
||||||
|
{
|
||||||
|
// TODO: ...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextEditor::Remove(int32 offset, int32 length)
|
||||||
|
{
|
||||||
|
// TODO: ...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - private
|
||||||
|
|
||||||
|
|
||||||
|
// _SetCaretOffset
|
||||||
|
void
|
||||||
|
TextEditor::_SetCaretOffset(int32 offset, bool updateAnchor,
|
||||||
|
bool lockSelectionAnchor, bool updateSelectionStyle)
|
||||||
|
{
|
||||||
|
if (fDocument.Get() == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
offset = 0;
|
||||||
|
int32 textLength = fDocument->Length();
|
||||||
|
if (offset > textLength)
|
||||||
|
offset = textLength;
|
||||||
|
|
||||||
|
int32 caret = offset;
|
||||||
|
int32 anchor = lockSelectionAnchor ? fSelection.Anchor() : offset;
|
||||||
|
_SetSelection(caret, anchor, updateAnchor, updateSelectionStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// _SetSelection
|
||||||
|
void
|
||||||
|
TextEditor::_SetSelection(int32 caret, int32 anchor, bool updateAnchor,
|
||||||
|
bool updateSelectionStyle)
|
||||||
|
{
|
||||||
|
if (fLayout.Get() == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (caret == fSelection.Caret() && caret == fSelection.Anchor())
|
||||||
|
return;
|
||||||
|
|
||||||
|
fSelection.SetAnchor(anchor);
|
||||||
|
fSelection.SetCaret(caret);
|
||||||
|
|
||||||
|
if (updateAnchor) {
|
||||||
|
float x1;
|
||||||
|
float y1;
|
||||||
|
float x2;
|
||||||
|
float y2;
|
||||||
|
|
||||||
|
fLayout->GetTextBounds(caret, x1, y1, x2, y2);
|
||||||
|
fCaretAnchorX = x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateSelectionStyle)
|
||||||
|
_UpdateStyleAtCaret();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextEditor::_UpdateStyleAtCaret()
|
||||||
|
{
|
||||||
|
if (fDocument.Get() == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int32 offset = fSelection.Caret() - 1;
|
||||||
|
if (offset < 0)
|
||||||
|
offset = 0;
|
||||||
|
SetCharacterStyle(fDocument->CharacterStyleAt(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014, Stephan Aßmus <[email protected]>.
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef TEXT_EDITOR_H
|
||||||
|
#define TEXT_EDITOR_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "CharacterStyle.h"
|
||||||
|
#include "TextDocument.h"
|
||||||
|
#include "TextDocumentLayout.h"
|
||||||
|
#include "TextSelection.h"
|
||||||
|
|
||||||
|
|
||||||
|
class KeyEvent {
|
||||||
|
public:
|
||||||
|
const char* bytes;
|
||||||
|
int32 length;
|
||||||
|
int32 key;
|
||||||
|
int32 modifiers;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TextEditor {
|
||||||
|
public:
|
||||||
|
TextEditor();
|
||||||
|
TextEditor(const TextEditor& other);
|
||||||
|
|
||||||
|
TextEditor& operator=(const TextEditor& other);
|
||||||
|
bool operator==(const TextEditor& other) const;
|
||||||
|
bool operator!=(const TextEditor& other) const;
|
||||||
|
|
||||||
|
void SetDocument(const TextDocumentRef& ref);
|
||||||
|
TextDocumentRef Document() const
|
||||||
|
{ return fDocument; }
|
||||||
|
|
||||||
|
void SetLayout(
|
||||||
|
const TextDocumentLayoutRef& ref);
|
||||||
|
TextDocumentLayoutRef Layout() const
|
||||||
|
{ return fLayout; }
|
||||||
|
|
||||||
|
void SetSelection(TextSelection selection);
|
||||||
|
inline TextSelection Selection() const
|
||||||
|
{ return fSelection; }
|
||||||
|
|
||||||
|
void SetCharacterStyle(::CharacterStyle style);
|
||||||
|
::CharacterStyle CharacterStyle() const
|
||||||
|
{ return fStyleAtCaret; }
|
||||||
|
|
||||||
|
void KeyDown(KeyEvent event);
|
||||||
|
|
||||||
|
void Insert(int32 offset, const BString& string);
|
||||||
|
void Remove(int32 offset, int32 length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _SetCaretOffset(int32 offset,
|
||||||
|
bool updateAnchor,
|
||||||
|
bool lockSelectionAnchor,
|
||||||
|
bool updateSelectionStyle);
|
||||||
|
void _SetSelection(int32 caret, int32 anchor,
|
||||||
|
bool updateAnchor,
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TEXT_EDITOR_H
|
||||||
Reference in New Issue
Block a user