Text stuff: Fixed various issues with editing.
* Insert/Remove now works for simple typing. * Inserting multiple paragaphs not yet tested. * Renamed TextSpan::CharCount() to CountChars() for consistency.
This commit is contained in:
@@ -105,9 +105,9 @@ Paragraph::Insert(int32 offset, const TextSpan& newSpan)
|
|||||||
int32 index = 0;
|
int32 index = 0;
|
||||||
while (index < fTextSpans.CountItems()) {
|
while (index < fTextSpans.CountItems()) {
|
||||||
const TextSpan& span = fTextSpans.ItemAtFast(index);
|
const TextSpan& span = fTextSpans.ItemAtFast(index);
|
||||||
if (offset - span.CharCount() < 0)
|
if (offset - span.CountChars() < 0)
|
||||||
break;
|
break;
|
||||||
offset -= span.CharCount();
|
offset -= span.CountChars();
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ Paragraph::Insert(int32 offset, const TextSpan& newSpan)
|
|||||||
// Try to merge with TextSpan before if offset == 0 && index > 0
|
// Try to merge with TextSpan before if offset == 0 && index > 0
|
||||||
TextSpan span = fTextSpans.ItemAtFast(index - 1);
|
TextSpan span = fTextSpans.ItemAtFast(index - 1);
|
||||||
if (span.Style() == newSpan.Style()) {
|
if (span.Style() == newSpan.Style()) {
|
||||||
span.Insert(span.CharCount(), newSpan.Text());
|
span.Insert(span.CountChars(), newSpan.Text());
|
||||||
return fTextSpans.Replace(index - 1, span);
|
return fTextSpans.Replace(index - 1, span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ Paragraph::Insert(int32 offset, const TextSpan& newSpan)
|
|||||||
|
|
||||||
// Split the span,
|
// Split the span,
|
||||||
TextSpan spanBefore = span.SubSpan(0, offset);
|
TextSpan spanBefore = span.SubSpan(0, offset);
|
||||||
TextSpan spanAfter = span.SubSpan(offset, span.CharCount() - offset);
|
TextSpan spanAfter = span.SubSpan(offset, span.CountChars() - offset);
|
||||||
|
|
||||||
return fTextSpans.Replace(index, spanBefore)
|
return fTextSpans.Replace(index, spanBefore)
|
||||||
&& fTextSpans.Add(newSpan, index + 1)
|
&& fTextSpans.Add(newSpan, index + 1)
|
||||||
@@ -153,9 +153,9 @@ Paragraph::Remove(int32 offset, int32 length)
|
|||||||
int32 index = 0;
|
int32 index = 0;
|
||||||
while (index < fTextSpans.CountItems()) {
|
while (index < fTextSpans.CountItems()) {
|
||||||
const TextSpan& span = fTextSpans.ItemAtFast(index);
|
const TextSpan& span = fTextSpans.ItemAtFast(index);
|
||||||
if (offset - span.CharCount() < 0)
|
if (offset - span.CountChars() < 0)
|
||||||
break;
|
break;
|
||||||
offset -= span.CharCount();
|
offset -= span.CountChars();
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ Paragraph::Remove(int32 offset, int32 length)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
TextSpan span(fTextSpans.ItemAtFast(index));
|
TextSpan span(fTextSpans.ItemAtFast(index));
|
||||||
int32 removeLength = std::min(span.CharCount() - offset, length);
|
int32 removeLength = std::min(span.CountChars() - offset, length);
|
||||||
span.Remove(offset, removeLength);
|
span.Remove(offset, removeLength);
|
||||||
fTextSpans.Replace(index, span);
|
fTextSpans.Replace(index, span);
|
||||||
length -= removeLength;
|
length -= removeLength;
|
||||||
@@ -171,7 +171,7 @@ Paragraph::Remove(int32 offset, int32 length)
|
|||||||
|
|
||||||
// Remove more spans if necessary
|
// Remove more spans if necessary
|
||||||
while (length > 0 && index < fTextSpans.CountItems()) {
|
while (length > 0 && index < fTextSpans.CountItems()) {
|
||||||
int32 spanLength = fTextSpans.ItemAtFast(index).CharCount();
|
int32 spanLength = fTextSpans.ItemAtFast(index).CountChars();
|
||||||
if (spanLength <= length) {
|
if (spanLength <= length) {
|
||||||
fTextSpans.Remove(index);
|
fTextSpans.Remove(index);
|
||||||
length -= spanLength;
|
length -= spanLength;
|
||||||
@@ -182,7 +182,7 @@ Paragraph::Remove(int32 offset, int32 length)
|
|||||||
removeLength, spanLength - removeLength);
|
removeLength, spanLength - removeLength);
|
||||||
// Try to merge with first span, otherwise replace span at index
|
// Try to merge with first span, otherwise replace span at index
|
||||||
if (lastSpan.Style() == span.Style()) {
|
if (lastSpan.Style() == span.Style()) {
|
||||||
span.Insert(span.CharCount(), lastSpan.Text());
|
span.Insert(span.CountChars(), lastSpan.Text());
|
||||||
fTextSpans.Replace(index - 1, span);
|
fTextSpans.Replace(index - 1, span);
|
||||||
} else {
|
} else {
|
||||||
fTextSpans.Replace(index, lastSpan);
|
fTextSpans.Replace(index, lastSpan);
|
||||||
@@ -193,7 +193,7 @@ Paragraph::Remove(int32 offset, int32 length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See if anything from the TextSpan at offset remained
|
// See if anything from the TextSpan at offset remained
|
||||||
if (span.CharCount() == 0)
|
if (span.CountChars() == 0)
|
||||||
fTextSpans.Remove(index - 1);
|
fTextSpans.Remove(index - 1);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -213,7 +213,7 @@ Paragraph::Length() const
|
|||||||
int32 length = 0;
|
int32 length = 0;
|
||||||
for (int32 i = fTextSpans.CountItems() - 1; i >= 0; i--) {
|
for (int32 i = fTextSpans.CountItems() - 1; i >= 0; i--) {
|
||||||
const TextSpan& span = fTextSpans.ItemAtFast(i);
|
const TextSpan& span = fTextSpans.ItemAtFast(i);
|
||||||
length += span.CharCount();
|
length += span.CountChars();
|
||||||
}
|
}
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
@@ -237,7 +237,7 @@ Paragraph::GetText(int32 start, int32 length) const
|
|||||||
int32 count = fTextSpans.CountItems();
|
int32 count = fTextSpans.CountItems();
|
||||||
for (int32 i = 0; i < count; i++) {
|
for (int32 i = 0; i < count; i++) {
|
||||||
const TextSpan& span = fTextSpans.ItemAtFast(i);
|
const TextSpan& span = fTextSpans.ItemAtFast(i);
|
||||||
int32 spanLength = span.CharCount();
|
int32 spanLength = span.CountChars();
|
||||||
if (spanLength == 0)
|
if (spanLength == 0)
|
||||||
continue;
|
continue;
|
||||||
if (start > spanLength) {
|
if (start > spanLength) {
|
||||||
|
|||||||
@@ -792,7 +792,7 @@ ParagraphLayout::_ApplyAlignment()
|
|||||||
bool
|
bool
|
||||||
ParagraphLayout::_AppendGlyphInfos(const TextSpan& span)
|
ParagraphLayout::_AppendGlyphInfos(const TextSpan& span)
|
||||||
{
|
{
|
||||||
int charCount = span.CharCount();
|
int charCount = span.CountChars();
|
||||||
if (charCount == 0)
|
if (charCount == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -861,7 +861,7 @@ ParagraphLayout::_FinalizeLine(int lineStart, int lineEnd, int lineIndex,
|
|||||||
spanIndex++;
|
spanIndex++;
|
||||||
const TextSpan& span = fTextSpans.ItemAt(spanIndex);
|
const TextSpan& span = fTextSpans.ItemAt(spanIndex);
|
||||||
spanStart = spanEnd;
|
spanStart = spanEnd;
|
||||||
spanEnd += span.CharCount();
|
spanEnd += span.CountChars();
|
||||||
addSpan = true;
|
addSpan = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -910,7 +910,7 @@ ParagraphLayout::_DrawLine(BView* view, const BPoint& offset,
|
|||||||
for (int i = 0; i < spanCount; i++) {
|
for (int i = 0; i < spanCount; i++) {
|
||||||
const TextSpan& span = line.layoutedSpans.ItemAtFast(i);
|
const TextSpan& span = line.layoutedSpans.ItemAtFast(i);
|
||||||
_DrawSpan(view, offset, span, textOffset);
|
_DrawSpan(view, offset, span, textOffset);
|
||||||
textOffset += span.CharCount();
|
textOffset += span.CountChars();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,24 +70,102 @@ TextDocument::operator!=(const TextDocument& other) const
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
TextDocument::Insert(int32 offset, const BString& text)
|
TextDocument::Insert(int32 textOffset, const BString& text)
|
||||||
{
|
{
|
||||||
return Insert(offset, text, CharacterStyleAt(offset));
|
return Insert(textOffset, text, CharacterStyleAt(textOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
TextDocument::Insert(int32 offset, const BString& text, const CharacterStyle& style)
|
TextDocument::Insert(int32 textOffset, const BString& text,
|
||||||
|
const CharacterStyle& style)
|
||||||
{
|
{
|
||||||
return Insert(offset, text, style, ParagraphStyleAt(offset));
|
return Insert(textOffset, text, style, ParagraphStyleAt(textOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
TextDocument::Insert(int32 offset, const BString& text,
|
TextDocument::Insert(int32 textOffset, const BString& text,
|
||||||
const CharacterStyle& CharacterStyle, const ParagraphStyle& paragraphStyle)
|
const CharacterStyle& characterStyle, const ParagraphStyle& paragraphStyle)
|
||||||
{
|
{
|
||||||
return Replace(offset, 0, text, CharacterStyle, paragraphStyle);
|
int32 paragraphOffset;
|
||||||
|
int32 index = ParagraphIndexFor(textOffset, paragraphOffset);
|
||||||
|
if (index < 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
textOffset -= paragraphOffset;
|
||||||
|
|
||||||
|
bool hasLineBreaks = text.FindFirst('\n', 0) >= 0;
|
||||||
|
|
||||||
|
if (hasLineBreaks) {
|
||||||
|
// Split paragraph at textOffset
|
||||||
|
Paragraph paragraph1(ParagraphAt(index).Style());
|
||||||
|
Paragraph paragraph2(paragraphStyle);
|
||||||
|
const TextSpanList& textSpans = ParagraphAt(index).TextSpans();
|
||||||
|
int32 spanCount = textSpans.CountItems();
|
||||||
|
for (int32 i = 0; i < spanCount; i++) {
|
||||||
|
const TextSpan& span = textSpans.ItemAtFast(i);
|
||||||
|
int32 spanLength = span.CountChars();
|
||||||
|
if (textOffset >= spanLength) {
|
||||||
|
paragraph1.Append(span);
|
||||||
|
textOffset -= spanLength;
|
||||||
|
} else if (textOffset > 0) {
|
||||||
|
paragraph1.Append(
|
||||||
|
span.SubSpan(0, textOffset));
|
||||||
|
paragraph2.Append(
|
||||||
|
span.SubSpan(textOffset, spanLength - textOffset));
|
||||||
|
textOffset = 0;
|
||||||
|
} else {
|
||||||
|
paragraph2.Append(span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fParagraphs.Remove(index);
|
||||||
|
|
||||||
|
// Insert TextSpans, splitting 'text' into Paragraphs at line breaks.
|
||||||
|
int32 length = text.CountChars();
|
||||||
|
int32 chunkStart = 0;
|
||||||
|
while (chunkStart < length) {
|
||||||
|
int32 chunkEnd = text.FindFirst('\n', chunkStart);
|
||||||
|
bool foundLineBreak = chunkEnd > chunkStart;
|
||||||
|
if (foundLineBreak)
|
||||||
|
chunkEnd++;
|
||||||
|
else
|
||||||
|
chunkEnd = length;
|
||||||
|
|
||||||
|
BString chunk;
|
||||||
|
text.CopyCharsInto(chunk, chunkStart, chunkEnd - chunkStart);
|
||||||
|
TextSpan span(chunk, characterStyle);
|
||||||
|
|
||||||
|
if (foundLineBreak) {
|
||||||
|
if (!paragraph1.Append(span))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
if (paragraph1.Length() > 0) {
|
||||||
|
if (!fParagraphs.Add(paragraph1, index))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
paragraph1 = Paragraph(paragraphStyle);
|
||||||
|
} else {
|
||||||
|
if (!paragraph2.Prepend(span))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
if (paragraph2.Length() > 0) {
|
||||||
|
if (!fParagraphs.Add(paragraph2, index))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chunkStart = chunkEnd + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Paragraph paragraph(ParagraphAt(index));
|
||||||
|
paragraph.Insert(textOffset, TextSpan(text, characterStyle));
|
||||||
|
if (!fParagraphs.Replace(index, paragraph))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -165,31 +243,30 @@ TextDocument::Remove(int32 textOffset, int32 length)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
TextDocument::Replace(int32 offset, int32 length, const BString& text)
|
TextDocument::Replace(int32 textOffset, int32 length, const BString& text)
|
||||||
{
|
{
|
||||||
return Replace(offset, length, text, CharacterStyleAt(offset));
|
return Replace(textOffset, length, text, CharacterStyleAt(textOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
TextDocument::Replace(int32 offset, int32 length, const BString& text,
|
TextDocument::Replace(int32 textOffset, int32 length, const BString& text,
|
||||||
const CharacterStyle& style)
|
const CharacterStyle& style)
|
||||||
{
|
{
|
||||||
return Replace(offset, length, text, style, ParagraphStyleAt(offset));
|
return Replace(textOffset, length, text, style,
|
||||||
|
ParagraphStyleAt(textOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
TextDocument::Replace(int32 offset, int32 length, const BString& text,
|
TextDocument::Replace(int32 textOffset, int32 length, const BString& text,
|
||||||
const CharacterStyle& CharacterStyle, const ParagraphStyle& paragraphStyle)
|
const CharacterStyle& characterStyle, const ParagraphStyle& paragraphStyle)
|
||||||
{
|
{
|
||||||
status_t ret = Remove(offset, length);
|
status_t ret = Remove(textOffset, length);
|
||||||
if (ret != B_OK)
|
if (ret != B_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
// TODO: ...
|
return Insert(textOffset, text, characterStyle, paragraphStyle);
|
||||||
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -208,9 +285,10 @@ TextDocument::CharacterStyleAt(int32 textOffset) const
|
|||||||
int32 index = 0;
|
int32 index = 0;
|
||||||
while (index < spans.CountItems()) {
|
while (index < spans.CountItems()) {
|
||||||
const TextSpan& span = spans.ItemAtFast(index);
|
const TextSpan& span = spans.ItemAtFast(index);
|
||||||
if (textOffset - span.CharCount() < 0)
|
if (textOffset - span.CountChars() < 0)
|
||||||
return span.Style();
|
return span.Style();
|
||||||
textOffset -= span.CharCount();
|
textOffset -= span.CountChars();
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fDefaultCharacterStyle;
|
return fDefaultCharacterStyle;
|
||||||
|
|||||||
@@ -28,21 +28,21 @@ public:
|
|||||||
bool operator!=(const TextDocument& other) const;
|
bool operator!=(const TextDocument& other) const;
|
||||||
|
|
||||||
// Text insertion and removing
|
// Text insertion and removing
|
||||||
status_t Insert(int32 offset, const BString& text);
|
status_t Insert(int32 textOffset, const BString& text);
|
||||||
status_t Insert(int32 offset, const BString& text,
|
status_t Insert(int32 textOffset, const BString& text,
|
||||||
const CharacterStyle& style);
|
const CharacterStyle& style);
|
||||||
status_t Insert(int32 offset, const BString& text,
|
status_t Insert(int32 textOffset, const BString& text,
|
||||||
const CharacterStyle& characterStyle,
|
const CharacterStyle& characterStyle,
|
||||||
const ParagraphStyle& paragraphStyle);
|
const ParagraphStyle& paragraphStyle);
|
||||||
|
|
||||||
status_t Remove(int32 offset, int32 length);
|
status_t Remove(int32 textOffset, int32 length);
|
||||||
|
|
||||||
status_t Replace(int32 offset, int32 length,
|
status_t Replace(int32 textOffset, int32 length,
|
||||||
const BString& text);
|
const BString& text);
|
||||||
status_t Replace(int32 offset, int32 length,
|
status_t Replace(int32 textOffset, int32 length,
|
||||||
const BString& text,
|
const BString& text,
|
||||||
const CharacterStyle& style);
|
const CharacterStyle& style);
|
||||||
status_t Replace(int32 offset, int32 length,
|
status_t Replace(int32 textOffset, int32 length,
|
||||||
const BString& text,
|
const BString& text,
|
||||||
const CharacterStyle& characterStyle,
|
const CharacterStyle& characterStyle,
|
||||||
const ParagraphStyle& paragraphStyle);
|
const ParagraphStyle& paragraphStyle);
|
||||||
@@ -68,7 +68,7 @@ public:
|
|||||||
// Query information
|
// Query information
|
||||||
int32 Length() const;
|
int32 Length() const;
|
||||||
|
|
||||||
BString GetText(int32 start, int32 length) const;
|
BString GetText(int32 textOffset, int32 length) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ParagraphList fParagraphs;
|
ParagraphList fParagraphs;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "TextEditor.h"
|
#include "TextEditor.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
TextEditor::TextEditor()
|
TextEditor::TextEditor()
|
||||||
@@ -230,6 +231,11 @@ TextEditor::KeyDown(KeyEvent event)
|
|||||||
if (event.bytes != NULL && event.length > 0) {
|
if (event.bytes != NULL && event.length > 0) {
|
||||||
// Handle null-termintating the string
|
// Handle null-termintating the string
|
||||||
BString text(event.bytes, event.length);
|
BString text(event.bytes, event.length);
|
||||||
|
|
||||||
|
// Remove selection, if any
|
||||||
|
if (HasSelection())
|
||||||
|
Remove(SelectionStart(), SelectionLength());
|
||||||
|
|
||||||
Insert(fSelection.Caret(), text);
|
Insert(fSelection.Caret(), text);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public:
|
|||||||
inline const CharacterStyle& Style() const
|
inline const CharacterStyle& Style() const
|
||||||
{ return fStyle; }
|
{ return fStyle; }
|
||||||
|
|
||||||
inline int32 CharCount() const
|
inline int32 CountChars() const
|
||||||
{ return fCharCount; }
|
{ return fCharCount; }
|
||||||
|
|
||||||
bool Insert(int32 offset, const BString& text);
|
bool Insert(int32 offset, const BString& text);
|
||||||
|
|||||||
Reference in New Issue
Block a user