Fixed artifacts when highlighing text, added Hiroshi Lockheimer to the authors list (BTextView is based on his SteEngine), reformatted the code some more to comply with our guidelines

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5563 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini
2003-12-04 14:19:30 +00:00
parent 3ae86e799a
commit 356acd7d45
+145 -161
View File
@@ -20,7 +20,9 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
// File Name: TextView.cpp // File Name: TextView.cpp
// Author: Marc Flerackers ([email protected]e) // Authors: Hiroshi Lockheimer (TextView is based on his STEEngine)
// Marc Flerackers ([email protected])
// Stefano Ceccherini ([email protected])
// Description: BTextView displays and manages styled text. // Description: BTextView displays and manages styled text.
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -66,6 +68,7 @@ struct flattened_text_run {
uint16 _reserved_; /* 0 */ uint16 _reserved_; /* 0 */
}; };
struct flattened_text_run_array { struct flattened_text_run_array {
uchar magic[4]; /* 41 6c 69 21 */ uchar magic[4]; /* 41 6c 69 21 */
uchar version[4]; /* 00 00 00 00 */ uchar version[4]; /* 00 00 00 00 */
@@ -73,6 +76,12 @@ struct flattened_text_run_array {
flattened_text_run styles[1]; flattened_text_run styles[1];
}; };
enum {
B_SEPARATOR_CHARACTER,
B_OTHER_CHARACTER
} separatorCharacters;
// _BTextTrackState_ class ----------------------------------------------------- // _BTextTrackState_ class -----------------------------------------------------
class _BTextTrackState_ { class _BTextTrackState_ {
@@ -89,8 +98,7 @@ public:
// Globals --------------------------------------------------------------------- // Globals ---------------------------------------------------------------------
static property_info static property_info
prop_list[] = prop_list[] = {
{
{ {
"Selection", "Selection",
{ B_GET_PROPERTY, 0 }, { B_GET_PROPERTY, 0 },
@@ -237,23 +245,25 @@ BTextView::BTextView(BRect frame, const char *name, BRect textRect,
BTextView::BTextView(BMessage *archive) BTextView::BTextView(BMessage *archive)
: BView(archive) : BView(archive)
{ {
const char *text;
int32 flag, flag2;
float value;
BRect rect; BRect rect;
bool toggle;
if (archive->FindRect("_trect", &rect) != B_OK) if (archive->FindRect("_trect", &rect) != B_OK)
rect.Set(0, 0, 0, 0); rect.Set(0, 0, 0, 0);
InitObject(rect, NULL, NULL); InitObject(rect, NULL, NULL);
const char *text = NULL;
if (archive->FindString("_text", &text) == B_OK) if (archive->FindString("_text", &text) == B_OK)
SetText(text); SetText(text);
int32 flag, flag2;
if (archive->FindInt32("_align", &flag) == B_OK) if (archive->FindInt32("_align", &flag) == B_OK)
SetAlignment((alignment)flag); SetAlignment((alignment)flag);
float value;
if (archive->FindFloat("_tab", &value) == B_OK) if (archive->FindFloat("_tab", &value) == B_OK)
SetTabWidth(value); SetTabWidth(value);
@@ -267,6 +277,8 @@ BTextView::BTextView(BMessage *archive)
archive->FindInt32("_sel", &flag2) == B_OK) archive->FindInt32("_sel", &flag2) == B_OK)
Select(flag, flag2); Select(flag, flag2);
bool toggle;
if (archive->FindBool("_stylable", &toggle) == B_OK) if (archive->FindBool("_stylable", &toggle) == B_OK)
SetStylable(toggle); SetStylable(toggle);
@@ -297,7 +309,7 @@ BTextView::BTextView(BMessage *archive)
const void *flattenedRunArray = NULL; const void *flattenedRunArray = NULL;
if (archive->FindData("_runs", B_RAW_TYPE, &flattenedRunArray, &runSize) == B_OK) { if (archive->FindData("_runs", B_RAW_TYPE, &flattenedRunArray, &runSize) == B_OK) {
text_run_array *runArray = UnflattenRunArray(runArray, (int32*)&runSize); text_run_array *runArray = UnflattenRunArray(runArray, (int32 *)&runSize);
SetRunArray(0, TextLength(), runArray); SetRunArray(0, TextLength(), runArray);
free(runArray); free(runArray);
} }
@@ -348,11 +360,12 @@ BTextView::Archive(BMessage *data, bool deep) const
ssize_t runSize = 0; ssize_t runSize = 0;
text_run_array *runArray = RunArray(0, TextLength()); text_run_array *runArray = RunArray(0, TextLength());
void *flattened = FlattenRunArray(runArray, (int32*)&runSize); void *flattened = FlattenRunArray(runArray, (int32*)&runSize);
if (flattened != NULL) {
data->AddData("_runs", B_RAW_TYPE, flattened, runSize); data->AddData("_runs", B_RAW_TYPE, flattened, runSize);
free(flattened); free(flattened);
}
free(runArray); free(runArray);
return err; return err;
@@ -421,7 +434,7 @@ BTextView::MouseDown(BPoint where)
bool shiftDown = modifiers() & B_SHIFT_KEY; bool shiftDown = modifiers() & B_SHIFT_KEY;
// should we initiate a drag? // should we initiate a drag?
if ((fSelStart != fSelEnd) && (!shiftDown)) { if (fSelStart != fSelEnd && !shiftDown) {
BPoint loc; BPoint loc;
ulong buttons; ulong buttons;
GetMouse(&loc, &buttons); GetMouse(&loc, &buttons);
@@ -429,7 +442,7 @@ BTextView::MouseDown(BPoint where)
// since dragging works also with the primary button. // since dragging works also with the primary button.
if (buttons == B_SECONDARY_MOUSE_BUTTON) { if (buttons == B_SECONDARY_MOUSE_BUTTON) {
// was the click within the selection range? // was the click within the selection range?
if ((mouseOffset >= fSelStart) && (mouseOffset <= fSelEnd)) { if (mouseOffset >= fSelStart && mouseOffset <= fSelEnd) {
InitiateDrag(); InitiateDrag();
return; return;
} }
@@ -441,8 +454,8 @@ BTextView::MouseDown(BPoint where)
get_click_speed(&clickSpeed); get_click_speed(&clickSpeed);
// is this a double/triple click, or is it a new click? // is this a double/triple click, or is it a new click?
if ( (clickSpeed > (system_time() - fClickTime)) && if ( clickSpeed > (system_time() - fClickTime) &&
(mouseOffset == fClickOffset) ) { mouseOffset == fClickOffset ) {
if (fClickCount > 1) { if (fClickCount > 1) {
// triple click // triple click
fClickCount = 0; fClickCount = 0;
@@ -452,8 +465,7 @@ BTextView::MouseDown(BPoint where)
fClickCount = 2; fClickCount = 2;
fClickTime = system_time(); fClickTime = system_time();
} }
} } else {
else {
// new click // new click
fClickOffset = mouseOffset; fClickOffset = mouseOffset;
fClickCount = 1; fClickCount = 1;
@@ -480,8 +492,7 @@ BTextView::MouseDown(BPoint where)
if (mouseOffset > anchor) { if (mouseOffset > anchor) {
start = anchor; start = anchor;
end = mouseOffset; end = mouseOffset;
} } else {
else {
start = mouseOffset; start = mouseOffset;
end = anchor; end = anchor;
} }
@@ -534,7 +545,7 @@ BTextView::MouseDown(BPoint where)
if (vDelta != 0) if (vDelta != 0)
ScrollBar(B_VERTICAL)->SetValue(ScrollBar(B_VERTICAL)->Value() + vDelta); ScrollBar(B_VERTICAL)->SetValue(ScrollBar(B_VERTICAL)->Value() + vDelta);
} }
if ((hDelta != 0) || (vDelta != 0)) if (hDelta != 0 || vDelta != 0)
Window()->UpdateIfNeeded(); Window()->UpdateIfNeeded();
} }
@@ -557,7 +568,7 @@ BTextView::MouseMoved(BPoint where, uint32 code, const BMessage *message)
{ {
switch (code) { switch (code) {
case B_ENTERED_VIEW: case B_ENTERED_VIEW:
if ((fActive) && (message == NULL)) if (fActive && message == NULL)
SetViewCursor(B_CURSOR_I_BEAM); SetViewCursor(B_CURSOR_I_BEAM);
break; break;
@@ -588,8 +599,7 @@ BTextView::WindowActivated(bool state)
if (state && IsFocus()) { if (state && IsFocus()) {
if (!fActive) if (!fActive)
Activate(); Activate();
} } else {
else {
if (fActive) if (fActive)
Deactivate(); Deactivate();
} }
@@ -656,7 +666,7 @@ BTextView::KeyDown(const char *bytes, int32 numBytes)
void void
BTextView::Pulse() BTextView::Pulse()
{ {
if ((fActive) && (fEditable) && (fSelStart == fSelEnd)) { if (fActive && fEditable && fSelStart == fSelEnd) {
if (system_time() > (fCaretTime + 500000.0)) if (system_time() > (fCaretTime + 500000.0))
InvertCaret(); InvertCaret();
} }
@@ -678,8 +688,7 @@ BTextView::MakeFocus(bool focusState)
if (focusState && Window()->IsActive()) { if (focusState && Window()->IsActive()) {
if (!fActive) if (!fActive)
Activate(); Activate();
} } else {
else {
if (fActive) if (fActive)
Deactivate(); Deactivate();
} }
@@ -794,9 +803,6 @@ BTextView::ResolveSpecifier(BMessage *message, int32 index,
BHandler *target = NULL; BHandler *target = NULL;
switch (propInfo.FindMatch(message, 0, specifier, form, property)) { switch (propInfo.FindMatch(message, 0, specifier, form, property)) {
case B_ERROR:
break;
case 0: case 0:
case 1: case 1:
case 2: case 2:
@@ -806,6 +812,9 @@ BTextView::ResolveSpecifier(BMessage *message, int32 index,
case 6: case 6:
target = this; target = this;
break; break;
case B_ERROR:
default:
break;
} }
if (!target) if (!target)
@@ -911,7 +920,7 @@ BTextView::SetText(const char *inText, int32 inLength,
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
BTextView::SetText (BFile *inFile, int32 startOffset, int32 inLength, BTextView::SetText(BFile *inFile, int32 startOffset, int32 inLength,
const text_run_array *inRuns) const text_run_array *inRuns)
{ {
// TODO: // TODO:
@@ -1052,7 +1061,7 @@ void
BTextView::GetText(int32 offset, int32 length, char *buffer) const BTextView::GetText(int32 offset, int32 length, char *buffer) const
{ {
int32 textLen = fText->Length(); int32 textLen = fText->Length();
if ((offset < 0) || (offset > (textLen - 1))) { if (offset < 0 || offset > (textLen - 1)) {
buffer[0] = '\0'; buffer[0] = '\0';
return; return;
} }
@@ -1132,7 +1141,8 @@ BTextView::Paste(BClipboard *clipboard)
BMessage *clip = NULL; BMessage *clip = NULL;
if (clipboard->Lock()) { if (clipboard->Lock()) {
if ((clip = clipboard->Data()) != NULL) { clip = clipboard->Data();
if (clip != NULL) {
const char *text = NULL; const char *text = NULL;
ssize_t len = 0; ssize_t len = 0;
@@ -1203,7 +1213,7 @@ BTextView::Select(int32 startOffset, int32 endOffset)
return; return;
// is the new selection any different from the current selection? // is the new selection any different from the current selection?
if ((startOffset == fSelStart) && (endOffset == fSelEnd)) if (startOffset == fSelStart && endOffset == fSelEnd)
return; return;
fStyles->InvalidateNullStyle(); fStyles->InvalidateNullStyle();
@@ -1224,8 +1234,7 @@ BTextView::Select(int32 startOffset, int32 endOffset)
Highlight(fSelStart, fSelEnd); Highlight(fSelStart, fSelEnd);
} }
fSelStart = fSelEnd = startOffset; fSelStart = fSelEnd = startOffset;
} } else {
else {
if (fActive) { if (fActive) {
// draw only those ranges that are different // draw only those ranges that are different
long start, end; long start, end;
@@ -1234,8 +1243,7 @@ BTextView::Select(int32 startOffset, int32 endOffset)
if (startOffset > fSelStart) { if (startOffset > fSelStart) {
start = fSelStart; start = fSelStart;
end = startOffset; end = startOffset;
} } else {
else {
start = startOffset; start = startOffset;
end = fSelStart; end = fSelStart;
} }
@@ -1247,8 +1255,7 @@ BTextView::Select(int32 startOffset, int32 endOffset)
if (endOffset > fSelEnd) { if (endOffset > fSelEnd) {
start = fSelEnd; start = fSelEnd;
end = endOffset; end = endOffset;
} } else {
else {
start = endOffset; start = endOffset;
end = fSelEnd; end = fSelEnd;
} }
@@ -1299,7 +1306,7 @@ BTextView::SetFontAndColor(const BFont *inFont, uint32 inMode,
fStyles->SetStyleRange(fSelStart, fSelEnd, fText->Length(), fStyles->SetStyleRange(fSelStart, fSelEnd, fText->Length(),
inMode, &newFont, inColor); inMode, &newFont, inColor);
if ((inMode & doFont) || (inMode & doSize)) if (inMode & doFont || inMode & doSize)
// recalc the line breaks and redraw with new style // recalc the line breaks and redraw with new style
Refresh(fSelStart, fSelEnd, fSelStart != fSelEnd, false); Refresh(fSelStart, fSelEnd, fSelStart != fSelEnd, false);
else else
@@ -1339,7 +1346,7 @@ BTextView::SetFontAndColor(int32 startOffset, int32 endOffset,
fStyles->SetStyleRange(startOffset, endOffset, fText->Length(), fStyles->SetStyleRange(startOffset, endOffset, fText->Length(),
inMode, &newFont, inColor); inMode, &newFont, inColor);
if ((inMode & doFont) || (inMode & doSize)) if (inMode & doFont || inMode & doSize)
// recalc the line breaks and redraw with new style // recalc the line breaks and redraw with new style
Refresh(startOffset, endOffset, startOffset != endOffset, false); Refresh(startOffset, endOffset, startOffset != endOffset, false);
else else
@@ -1413,7 +1420,7 @@ BTextView::RunArray(int32 startOffset, int32 endOffset,
if (result == NULL) if (result == NULL)
return NULL; return NULL;
text_run_array *res = (text_run_array*)malloc(sizeof(int32) + text_run_array *res = (text_run_array *)malloc(sizeof(int32) +
(sizeof(text_run) * result->count)); (sizeof(text_run) * result->count));
res->count = result->count; res->count = result->count;
@@ -1455,14 +1462,13 @@ BTextView::PointAt(int32 inOffset, float *outHeight) const
result.y = line->origin + fTextRect.top; result.y = line->origin + fTextRect.top;
// special case: go down one line if inOffset is a newline // special case: go down one line if inOffset is a newline
if ((inOffset == textLength) && ((*fText)[textLength - 1] == '\n')) { if (inOffset == textLength && (*fText)[textLength - 1] == '\n') {
float ascent, descent; float ascent, descent;
StyledWidth(inOffset, 1, &ascent, &descent); StyledWidth(inOffset, 1, &ascent, &descent);
result.y += height; result.y += height;
height = ascent + descent; height = ascent + descent;
} } else {
else {
int32 offset = line->offset; int32 offset = line->offset;
int32 length = inOffset - line->offset; int32 length = inOffset - line->offset;
int32 numChars = length; int32 numChars = length;
@@ -1480,7 +1486,7 @@ BTextView::PointAt(int32 inOffset, float *outHeight) const
offset += numChars; offset += numChars;
length -= numChars; length -= numChars;
numChars = length; numChars = length;
} while ((foundTab) && (length > 0)); } while (foundTab && length > 0);
} }
// convert from text rect coordinates // convert from text rect coordinates
@@ -1501,10 +1507,8 @@ BTextView::OffsetAt(BPoint point) const
// should we even bother? // should we even bother?
if (point.y >= fTextRect.bottom) if (point.y >= fTextRect.bottom)
return fText->Length(); return fText->Length();
else { else if (point.y < fTextRect.top)
if (point.y < fTextRect.top)
return 0; return 0;
}
int32 lineNum = LineAt(point); int32 lineNum = LineAt(point);
STELinePtr line = (*fLines)[lineNum]; STELinePtr line = (*fLines)[lineNum];
@@ -1540,8 +1544,8 @@ BTextView::OffsetAt(BPoint point) const
if (foundTab) { if (foundTab) {
// is the point in the right-half of the tab? // is the point in the right-half of the tab?
if ((point.x >= (sigmaWidth - (tabWidth / 2))) && if (point.x >= (sigmaWidth - (tabWidth / 2)) &&
(point.x < sigmaWidth)) point.x < sigmaWidth)
break; break;
} }
@@ -1565,15 +1569,13 @@ BTextView::OffsetAt(BPoint point) const
offset += delta; offset += delta;
done = true; done = true;
break; break;
} } else {
else {
// still too far to the left, measure some more // still too far to the left, measure some more
offset += delta; offset += delta;
delta /= 2; delta /= 2;
delta = (delta < 1) ? 1 : delta; delta = (delta < 1) ? 1 : delta;
} }
} } else {
else {
// oops, we overshot the point, go back some // oops, we overshot the point, go back some
sigmaWidth -= deltaWidth; sigmaWidth -= deltaWidth;
@@ -1589,7 +1591,7 @@ BTextView::OffsetAt(BPoint point) const
} while (offset < (numChars + saveOffset)); } while (offset < (numChars + saveOffset));
} }
if (done || (offset >= limit)) if (done || offset >= limit)
break; break;
if (foundTab) { if (foundTab) {
@@ -1606,18 +1608,18 @@ BTextView::OffsetAt(BPoint point) const
offset = saveOffset + numChars; offset = saveOffset + numChars;
length -= numChars; length -= numChars;
numChars = length; numChars = length;
} while ((foundTab) && (length > 0)); } while (foundTab && length > 0);
if (offset == (line + 1)->offset) { if (offset == (line + 1)->offset) {
// special case: newlines aren't visible // special case: newlines aren't visible
// return the offset of the character preceding the newline // return the offset of the character preceding the newline
if ((*fText)[offset - 1] == '\n') if ((*fText)[offset - 1] == '\n')
return (--offset); return --offset;
// special case: return the offset preceding any spaces that // special case: return the offset preceding any spaces that
// aren't at the end of the buffer // aren't at the end of the buffer
if ((offset != fText->Length()) && ((*fText)[offset - 1] == ' ')) if (offset != fText->Length() && (*fText)[offset - 1] == ' ')
return (--offset); return --offset;
} }
return offset; return offset;
@@ -1632,8 +1634,6 @@ BTextView::OffsetAt(int32 line) const
return (*fLines)[line]->offset; return (*fLines)[line]->offset;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
enum { B_SEPARATOR_CHARACTER, B_OTHER_CHARACTER };
void void
BTextView::FindWord(int32 inOffset, int32 *outFromOffset, BTextView::FindWord(int32 inOffset, int32 *outFromOffset,
int32 *outToOffset) int32 *outToOffset)
@@ -1662,29 +1662,7 @@ BTextView::FindWord(int32 inOffset, int32 *outFromOffset,
bool bool
BTextView::CanEndLine(int32 offset) BTextView::CanEndLine(int32 offset)
{ {
switch ((*fText)[offset]) { return (CharClassification(offset) == B_SEPARATOR_CHARACTER);
case '\0':
case '\t':
case '\n':
case ' ':
case '&':
case '*':
case '+':
case '-':
case '/':
case '<':
case '=':
case '>':
case '\\':
case '^':
case '|':
return true;
default:
return false;
}
return true;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
float float
@@ -1719,7 +1697,7 @@ BTextView::TextHeight(int32 startLine, int32 endLine) const
float height = (*fLines)[endLine + 1]->origin - float height = (*fLines)[endLine + 1]->origin -
(*fLines)[startLine]->origin; (*fLines)[startLine]->origin;
if ((endLine == numLines - 1) && ((*fText)[fText->Length() - 1] == '\n')) if (endLine == numLines - 1 && (*fText)[fText->Length() - 1] == '\n')
height += (*fLines)[endLine + 1]->origin - (*fLines)[endLine]->origin; height += (*fLines)[endLine + 1]->origin - (*fLines)[endLine]->origin;
return height; return height;
@@ -1739,6 +1717,7 @@ BTextView::GetTextRegion(int32 startOffset, int32 endOffset,
float endLineHeight = 0.0; float endLineHeight = 0.0;
BPoint startPt = PointAt(startOffset, &startLineHeight); BPoint startPt = PointAt(startOffset, &startLineHeight);
BPoint endPt = PointAt(endOffset, &endLineHeight); BPoint endPt = PointAt(endOffset, &endLineHeight);
BRect selRect; BRect selRect;
if (startPt.y == endPt.y) { if (startPt.y == endPt.y) {
@@ -1748,8 +1727,7 @@ BTextView::GetTextRegion(int32 startOffset, int32 endOffset,
selRect.right = endPt.x - 1.0; selRect.right = endPt.x - 1.0;
selRect.bottom = endPt.y + endLineHeight - 1.0; selRect.bottom = endPt.y + endLineHeight - 1.0;
outRegion->Include(selRect); outRegion->Include(selRect);
} } else {
else {
// more than one line in the specified offset range // more than one line in the specified offset range
selRect.left = (startPt.x < fTextRect.left) ? fTextRect.left : startPt.x; selRect.left = (startPt.x < fTextRect.left) ? fTextRect.left : startPt.x;
selRect.top = startPt.y; selRect.top = startPt.y;
@@ -1757,10 +1735,10 @@ BTextView::GetTextRegion(int32 startOffset, int32 endOffset,
selRect.bottom = startPt.y + startLineHeight - 1.0; selRect.bottom = startPt.y + startLineHeight - 1.0;
outRegion->Include(selRect); outRegion->Include(selRect);
if ((startPt.y + startLineHeight) < endPt.y) { if (startPt.y + startLineHeight < endPt.y) {
// more than two lines in the range // more than two lines in the range
selRect.left = fTextRect.left; selRect.left = fTextRect.left;
selRect.top = startPt.y + startLineHeight; selRect.top = startPt.y + startLineHeight + 1.0;
selRect.right = fTextRect.right; selRect.right = fTextRect.right;
selRect.bottom = endPt.y - 1.0; selRect.bottom = endPt.y - 1.0;
outRegion->Include(selRect); outRegion->Include(selRect);
@@ -1783,12 +1761,12 @@ BTextView::ScrollToOffset(int32 inOffset)
BPoint point = PointAt(inOffset, &lineHeight); BPoint point = PointAt(inOffset, &lineHeight);
if (ScrollBar(B_HORIZONTAL) != NULL) { if (ScrollBar(B_HORIZONTAL) != NULL) {
if ((point.x < bounds.left) || (point.x >= bounds.right)) if (point.x < bounds.left || point.x >= bounds.right)
ScrollBar(B_HORIZONTAL)->SetValue(point.x - (bounds.IntegerWidth() / 2)); ScrollBar(B_HORIZONTAL)->SetValue(point.x - (bounds.IntegerWidth() / 2));
} }
if (ScrollBar(B_VERTICAL) != NULL) { if (ScrollBar(B_VERTICAL) != NULL) {
if ((point.y < bounds.top) || ((point.y + lineHeight) >= bounds.bottom)) if (point.y < bounds.top || (point.y + lineHeight) >= bounds.bottom)
ScrollBar(B_VERTICAL)->SetValue(point.y - (bounds.IntegerHeight() / 2)); ScrollBar(B_VERTICAL)->SetValue(point.y - (bounds.IntegerHeight() / 2));
} }
} }
@@ -1809,11 +1787,9 @@ BTextView::Highlight(int32 startOffset, int32 endOffset)
BRegion selRegion; BRegion selRegion;
GetTextRegion(startOffset, endOffset, &selRegion); GetTextRegion(startOffset, endOffset, &selRegion);
ConstrainClippingRegion(&selRegion); SetDrawingMode(B_OP_INVERT);
InvertRect(selRegion.Frame()); FillRegion(&selRegion, B_SOLID_HIGH);
ConstrainClippingRegion(NULL); SetDrawingMode(B_OP_COPY);
Flush(); ////
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
@@ -1899,7 +1875,7 @@ BTextView::MakeEditable(bool editable)
if (Window() != NULL) { if (Window() != NULL) {
if (fActive) { if (fActive) {
if ((!fEditable) && (fCaretVisible)) if (!fEditable && fCaretVisible)
InvertCaret(); InvertCaret();
} }
} }
@@ -2089,7 +2065,7 @@ BTextView::FlattenRunArray(const text_run_array *inArray, int32 *outSize)
int32 size = sizeof(flattened_text_run_array) + (inArray->count - 1) * int32 size = sizeof(flattened_text_run_array) + (inArray->count - 1) *
sizeof(flattened_text_run_array); sizeof(flattened_text_run_array);
flattened_text_run_array *array = (flattened_text_run_array*)malloc(size); flattened_text_run_array *array = (flattened_text_run_array *)malloc(size);
array->magic[0] = 0x41; array->magic[0] = 0x41;
array->magic[1] = 0x6c; array->magic[1] = 0x6c;
@@ -2124,7 +2100,7 @@ BTextView::FlattenRunArray(const text_run_array *inArray, int32 *outSize)
text_run_array * text_run_array *
BTextView::UnflattenRunArray(const void *data, int32 *outSize) BTextView::UnflattenRunArray(const void *data, int32 *outSize)
{ {
flattened_text_run_array *array = (flattened_text_run_array*)data; flattened_text_run_array *array = (flattened_text_run_array *)data;
if (array->magic[0] != 0x41 || array->magic[1] != 0x6c || if (array->magic[0] != 0x41 || array->magic[1] != 0x6c ||
array->magic[2] != 0x69 || array->magic[3] != 0x21 || array->magic[2] != 0x69 || array->magic[3] != 0x21 ||
@@ -2139,7 +2115,7 @@ BTextView::UnflattenRunArray(const void *data, int32 *outSize)
int32 size = sizeof(text_run_array) + (array->count - 1) * sizeof(text_run); int32 size = sizeof(text_run_array) + (array->count - 1) * sizeof(text_run);
text_run_array *run_array = (text_run_array*)malloc(size); text_run_array *run_array = (text_run_array *)malloc(size);
run_array->count = array->count; run_array->count = array->count;
@@ -2200,7 +2176,7 @@ BTextView::DeleteText(int32 fromOffset, int32 toOffset)
//_ASSERT ( _CrtCheckMemory () ); //_ASSERT ( _CrtCheckMemory () );
// sanity checking // sanity checking
if ((fromOffset >= toOffset) || (fromOffset < 0) || (toOffset < 0)) if (fromOffset >= toOffset || fromOffset < 0 || toOffset < 0)
return; return;
// set nullStyle to style at beginning of range // set nullStyle to style at beginning of range
@@ -2236,6 +2212,9 @@ void
BTextView::GetDragParameters(BMessage *drag, BBitmap **bitmap, BTextView::GetDragParameters(BMessage *drag, BBitmap **bitmap,
BPoint *point, BHandler **handler) BPoint *point, BHandler **handler)
{ {
if (drag == NULL)
return;
// What is this for ? // What is this for ?
drag->AddInt32("be_actions", B_TRASH_TARGET); drag->AddInt32("be_actions", B_TRASH_TARGET);
@@ -2254,6 +2233,11 @@ BTextView::GetDragParameters(BMessage *drag, BBitmap **bitmap,
drag->AddPointer("be:originator", this); drag->AddPointer("be:originator", this);
free(styles); free(styles);
if (bitmap != NULL)
*bitmap = NULL;
if (handler != NULL)
*handler = NULL;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void BTextView::_ReservedTextView3() {} void BTextView::_ReservedTextView3() {}
@@ -2293,7 +2277,6 @@ BTextView::InitObject(BRect textRect, const BFont *initialFont,
void void
BTextView::HandleBackspace() BTextView::HandleBackspace()
{ {
if (fUndo) { if (fUndo) {
_BTypingUndoBuffer_ *undoBuffer = dynamic_cast<_BTypingUndoBuffer_ *>(fUndo); _BTypingUndoBuffer_ *undoBuffer = dynamic_cast<_BTypingUndoBuffer_ *>(fUndo);
if (!undoBuffer) { if (!undoBuffer) {
@@ -2335,13 +2318,11 @@ BTextView::HandleArrowKey(uint32 inArrowKey)
if (shiftDown) { if (shiftDown) {
if (selStart > 0) if (selStart > 0)
selStart = PreviousInitialByte(selStart); selStart = PreviousInitialByte(selStart);
} } else {
else {
if (selStart == selEnd) { if (selStart == selEnd) {
if (selStart > 0) if (selStart > 0)
selEnd = selStart = PreviousInitialByte(selStart); selEnd = selStart = PreviousInitialByte(selStart);
} } else
else
selEnd = selStart; selEnd = selStart;
} }
scrollToOffset = selStart; scrollToOffset = selStart;
@@ -2351,8 +2332,7 @@ BTextView::HandleArrowKey(uint32 inArrowKey)
if (shiftDown) { if (shiftDown) {
if (selEnd < fText->Length()) if (selEnd < fText->Length())
selEnd = NextInitialByte(selEnd); selEnd = NextInitialByte(selEnd);
} } else {
else {
if (selStart == selEnd) { if (selStart == selEnd) {
if (selStart < fText->Length()) if (selStart < fText->Length())
selStart = selEnd = NextInitialByte(selEnd); selStart = selEnd = NextInitialByte(selEnd);
@@ -2413,8 +2393,7 @@ BTextView::HandleDelete()
return; return;
else else
fSelEnd = NextInitialByte(fSelEnd); fSelEnd = NextInitialByte(fSelEnd);
} } else
else
Highlight(fSelStart, fSelEnd); Highlight(fSelStart, fSelEnd);
DeleteText(fSelStart, fSelEnd); DeleteText(fSelStart, fSelEnd);
@@ -2507,8 +2486,8 @@ BTextView::Refresh(int32 fromOffset, int32 toOffset, bool erase,
float newHeight = fTextRect.Height(); float newHeight = fTextRect.Height();
// if the line breaks have changed, force an erase // if the line breaks have changed, force an erase
if ( (fromLine != saveFromLine) || (toLine != saveToLine) || if ( fromLine != saveFromLine || toLine != saveToLine ||
(newHeight != saveHeight) ) newHeight != saveHeight )
erase = true; erase = true;
if (newHeight != saveHeight) { if (newHeight != saveHeight) {
@@ -2526,8 +2505,8 @@ BTextView::Refresh(int32 fromOffset, int32 toOffset, bool erase,
toLine = (toLine > toVisible) ? toVisible : toLine; toLine = (toLine > toVisible) ? toVisible : toLine;
int32 drawOffset = fromOffset; int32 drawOffset = fromOffset;
if ( (LineHeight(fromLine) != saveLineHeight) || if ( LineHeight(fromLine) != saveLineHeight ||
(newHeight < saveHeight) || (fromLine < saveFromLine) ) newHeight < saveHeight || fromLine < saveFromLine )
drawOffset = (*fLines)[fromLine]->offset; drawOffset = (*fLines)[fromLine]->offset;
DrawLines(fromLine, toLine, drawOffset, erase); DrawLines(fromLine, toLine, drawOffset, erase);
@@ -2536,7 +2515,7 @@ BTextView::Refresh(int32 fromOffset, int32 toOffset, bool erase,
BRect eraseRect = bounds; BRect eraseRect = bounds;
eraseRect.top = fTextRect.top + (*fLines)[fLines->NumLines()]->origin; eraseRect.top = fTextRect.top + (*fLines)[fLines->NumLines()]->origin;
eraseRect.bottom = fTextRect.top + saveHeight; eraseRect.bottom = fTextRect.top + saveHeight;
if ((eraseRect.bottom > eraseRect.top) && (eraseRect.Intersects(bounds))) { if (eraseRect.bottom > eraseRect.top && eraseRect.Intersects(bounds)) {
SetLowColor(ViewColor()); SetLowColor(ViewColor());
FillRect(eraseRect, B_SOLID_LOW); FillRect(eraseRect, B_SOLID_LOW);
} }
@@ -2572,7 +2551,7 @@ BTextView::RecalLineBreaks(int32 *startLine, int32 *endLine)
&descent, &width); &descent, &width);
// we want to advance at least by one character // we want to advance at least by one character
if ((toOffset == fromOffset) && (fromOffset < textLength)) if (toOffset == fromOffset && fromOffset < textLength)
toOffset = NextInitialByte(toOffset); toOffset = NextInitialByte(toOffset);
// set the ascent of this line // set the ascent of this line
@@ -2580,23 +2559,22 @@ BTextView::RecalLineBreaks(int32 *startLine, int32 *endLine)
lineIndex++; lineIndex++;
STELine saveLine = *nextLine; STELine saveLine = *nextLine;
if ( (lineIndex > fLines->NumLines()) || if ( lineIndex > fLines->NumLines() ||
(toOffset < nextLine->offset) ) { toOffset < nextLine->offset ) {
// the new line comes before the old line start, add a line // the new line comes before the old line start, add a line
STELine newLine; STELine newLine;
newLine.offset = toOffset; newLine.offset = toOffset;
newLine.origin = curLine->origin + ascent + descent; newLine.origin = curLine->origin + ascent + descent;
newLine.ascent = 0; newLine.ascent = 0;
fLines->InsertLine(&newLine, lineIndex); fLines->InsertLine(&newLine, lineIndex);
} } else {
else {
// update the exising line // update the exising line
nextLine->offset = toOffset; nextLine->offset = toOffset;
nextLine->origin = curLine->origin + ascent + descent; nextLine->origin = curLine->origin + ascent + descent;
// remove any lines that start before the current line // remove any lines that start before the current line
while ( (lineIndex < fLines->NumLines()) && while ( lineIndex < fLines->NumLines() &&
(toOffset >= ((*fLines)[lineIndex] + 1)->offset) ) toOffset >= ((*fLines)[lineIndex] + 1)->offset )
fLines->RemoveLines(lineIndex + 1); fLines->RemoveLines(lineIndex + 1);
nextLine = (*fLines)[lineIndex]; nextLine = (*fLines)[lineIndex];
@@ -2607,9 +2585,8 @@ BTextView::RecalLineBreaks(int32 *startLine, int32 *endLine)
lineIndex + 1); lineIndex + 1);
break; break;
} }
} } else {
else { if (lineIndex > 0 && lineIndex == *startLine)
if ((lineIndex > 0) && (lineIndex == *startLine))
*startLine = lineIndex - 1; *startLine = lineIndex - 1;
} }
} }
@@ -2705,14 +2682,13 @@ BTextView::FindLineBreak(int32 fromOffset, float *outAscent,
done = true; done = true;
delta++; delta++;
break; break;
} } else {
else {
// include all trailing spaces and tabs, // include all trailing spaces and tabs,
// but not spaces after tabs // but not spaces after tabs
if ((theChar != ' ') && (theChar != '\t')) if (theChar != ' ' && theChar != '\t')
break; break;
else { else {
if ((theChar == ' ') && (foundTab)) if (theChar == ' ' && foundTab)
break; break;
else { else {
if (theChar == '\t') if (theChar == '\t')
@@ -2744,18 +2720,18 @@ BTextView::FindLineBreak(int32 fromOffset, float *outAscent,
bool foundNewline = done; bool foundNewline = done;
done = true; done = true;
int32 pos = delta - 1; int32 pos = delta - 1;
if (((*fText)[offset + pos] != ' ') && if ((*fText)[offset + pos] != ' ' &&
((*fText)[offset + pos] != '\t') && (*fText)[offset + pos] != '\t' &&
((*fText)[offset + pos] != '\n')) (*fText)[offset + pos] != '\n')
break; break;
strWidth -= (deltaWidth + tabWidth); strWidth -= (deltaWidth + tabWidth);
for ( ; ((offset + pos) > offset); pos--) { for ( ; ((offset + pos) > offset); pos--) {
uchar theChar = (*fText)[offset + pos]; uchar theChar = (*fText)[offset + pos];
if ((theChar != ' ') && if (theChar != ' ' &&
(theChar != '\t') && theChar != '\t' &&
(theChar != '\n')) theChar != '\n')
break; break;
} }
@@ -2765,12 +2741,12 @@ BTextView::FindLineBreak(int32 fromOffset, float *outAscent,
if (!foundNewline) { if (!foundNewline) {
for ( ; (offset + delta) < limit; delta++) { for ( ; (offset + delta) < limit; delta++) {
if (((*fText)[offset + delta] != ' ') && if ((*fText)[offset + delta] != ' ' &&
((*fText)[offset + delta] != '\t')) (*fText)[offset + delta] != '\t')
break; break;
} }
if ( ((offset + delta) < limit) && if ( (offset + delta) < limit &&
((*fText)[offset + delta] == '\n') ) (*fText)[offset + delta] == '\n' )
delta++; delta++;
} }
// get the ascent and descent of the spaces/tabs // get the ascent and descent of the spaces/tabs
@@ -2782,7 +2758,7 @@ BTextView::FindLineBreak(int32 fromOffset, float *outAscent,
offset += delta; offset += delta;
delta = 0; delta = 0;
} while ((offset < limit) && (!done)); } while (offset < limit && !done);
if ((offset - fromOffset) < 1) { if ((offset - fromOffset) < 1) {
// there weren't any words that fit entirely in this line // there weren't any words that fit entirely in this line
@@ -2881,7 +2857,7 @@ BTextView::DrawLines(int32 startLine, int32 endLine, int32 startOffset,
long startEraseLine = startLine; long startEraseLine = startLine;
STELinePtr line = (*fLines)[startLine]; STELinePtr line = (*fLines)[startLine];
if ((erase) && (startOffset != -1)) { if (erase && startOffset != -1) {
// erase only to the right of startOffset // erase only to the right of startOffset
startEraseLine++; startEraseLine++;
long startErase = startOffset; long startErase = startOffset;
@@ -2911,7 +2887,7 @@ BTextView::DrawLines(int32 startLine, int32 endLine, int32 startOffset,
MovePenTo(fTextRect.left, line->origin + line->ascent + fTextRect.top); MovePenTo(fTextRect.left, line->origin + line->ascent + fTextRect.top);
if ((erase) && (i >= startEraseLine)) { if (erase && i >= startEraseLine) {
eraseRect.top = line->origin + fTextRect.top; eraseRect.top = line->origin + fTextRect.top;
eraseRect.bottom = (line + 1)->origin + fTextRect.top; eraseRect.bottom = (line + 1)->origin + fTextRect.top;
@@ -2975,7 +2951,7 @@ BTextView::DrawLines(int32 startLine, int32 endLine, int32 startOffset,
numChars -= tabChars; numChars -= tabChars;
tabChars = numChars; tabChars = numChars;
numTabs = 0; numTabs = 0;
} while ((foundTab) && (tabChars > 0)); } while (foundTab && tabChars > 0);
} }
} }
line++; line++;
@@ -3026,7 +3002,7 @@ BTextView::DragCaret(int32 offset)
if (offset != -1) { if (offset != -1) {
if (fActive) { if (fActive) {
// ignore if offset is within active selection // ignore if offset is within active selection
if ((offset >= fSelStart) && (offset <= fSelEnd)) { if (offset >= fSelStart && offset <= fSelEnd) {
fDragOffset = -1; fDragOffset = -1;
return; return;
} }
@@ -3104,7 +3080,7 @@ BTextView::MessageDropped(BMessage *inMessage, BPoint where, BPoint offset)
if (dropOffset > TextLength()) if (dropOffset > TextLength())
dropOffset = TextLength(); dropOffset = TextLength();
void *from; void *from = NULL;
inMessage->FindPointer("be:originator", &from); inMessage->FindPointer("be:originator", &from);
bool internalDrop = (from == this && fSelEnd != fSelStart); bool internalDrop = (from == this && fSelEnd != fSelStart);
@@ -3184,16 +3160,22 @@ BTextView::AutoResize(bool doredraw)
void void
BTextView::NewOffscreen(float padding) BTextView::NewOffscreen(float padding)
{ {
if (fOffscreen) if (fOffscreen != NULL)
DeleteOffscreen(); DeleteOffscreen();
/*
//TODO: Implement BRect bitmapRect(0, 0, fTextRect.Width() + padding, fTextRect.Height());
fOffscreen = new BBitmap(bitmapRect, fColorSpace, true, false);
if (fOffscreen != NULL && fOffscreen->Lock()) {
BView *bufferView = new BView(bitmapRect, "buffer view", 0, 0);
fOffscreen->AddChild(bufferView);
fOffscreen->Unlock();
}*/
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
BTextView::DeleteOffscreen() BTextView::DeleteOffscreen()
{ {
if (fOffscreen && fOffscreen->Lock()) { if (fOffscreen != NULL && fOffscreen->Lock()) {
delete fOffscreen; delete fOffscreen;
fOffscreen = NULL; fOffscreen = NULL;
} }
@@ -3207,8 +3189,7 @@ BTextView::Activate()
if (fSelStart != fSelEnd) { if (fSelStart != fSelEnd) {
if (fSelectable) if (fSelectable)
Highlight(fSelStart, fSelEnd); Highlight(fSelStart, fSelEnd);
} } else {
else {
if (fEditable) if (fEditable)
InvertCaret(); InvertCaret();
} }
@@ -3228,8 +3209,7 @@ BTextView::Deactivate()
if (fSelStart != fSelEnd) { if (fSelStart != fSelEnd) {
if (fSelectable) if (fSelectable)
Highlight(fSelStart, fSelEnd); Highlight(fSelStart, fSelEnd);
} } else {
else {
if (fCaretVisible) if (fCaretVisible)
InvertCaret(); InvertCaret();
} }
@@ -3260,8 +3240,8 @@ BTextView::CharClassification(int32 offset) const
case '_': case '_':
case '.': case '.':
case '\0': case '\0':
case '\t': case B_TAB:
case '\n': case B_ENTER:
case '&': case '&':
case '*': case '*':
case '+': case '+':
@@ -3316,7 +3296,9 @@ BTextView::GetProperty(BMessage *specifier, int32 form,
reply->AddInt32("result", fSelStart); reply->AddInt32("result", fSelStart);
reply->AddInt32("result", fSelEnd); reply->AddInt32("result", fSelEnd);
reply->AddInt32("error", B_OK); reply->AddInt32("error", B_OK);
return true; return true;
} else if (strcmp(property, "Text") == 0) { } else if (strcmp(property, "Text") == 0) {
int32 index, range; int32 index, range;
char *buffer; char *buffer;
@@ -3331,7 +3313,9 @@ BTextView::GetProperty(BMessage *specifier, int32 form,
reply->AddString("result", buffer); reply->AddString("result", buffer);
delete buffer; delete buffer;
reply->AddInt32("error", B_OK); reply->AddInt32("error", B_OK);
return true; return true;
} else if (strcmp(property, "text_run_array") == 0) } else if (strcmp(property, "text_run_array") == 0)
return false; return false;
else else
@@ -3354,8 +3338,8 @@ BTextView::SetProperty(BMessage *specifier, int32 form,
reply->AddInt32("error", B_OK); reply->AddInt32("error", B_OK);
return true; return true;
}
else if (strcmp(property, "Text") == 0) { } else if (strcmp(property, "Text") == 0) {
int32 index, range; int32 index, range;
const char *buffer; const char *buffer;
@@ -3371,8 +3355,8 @@ BTextView::SetProperty(BMessage *specifier, int32 form,
reply->AddInt32("error", B_OK); reply->AddInt32("error", B_OK);
return true; return true;
}
else if (strcmp(property, "text_run_array") == 0) } else if (strcmp(property, "text_run_array") == 0)
return false; return false;
else else
@@ -3389,8 +3373,8 @@ BTextView::CountProperties(BMessage *specifier, int32 form,
reply->AddInt32("error", B_OK); reply->AddInt32("error", B_OK);
return true; return true;
}
else } else
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------