continued work on BTextView:

* reverted my recent change that caused Mail to always show the end
  of mails 8-) and now invoke ScrollToOffset() wherever it was missing
  (mostly in keyboard-related methods)
* _DoInsertText() only moves the caret if the text has been inserted
  in front of the caret, not after it
* overhauled selection by char/word/line and their extension mechanism
  (which now behaves as the haiku shell)
* use strnlen() instead of strlen() in those versions of Insert() which
  accept a length parameter, as strlen can potentially waste a lot of
  cycles skipping the whole string, when all we want is to clamp the length.
* cleanup (some of it automatic removal of trailing whitespace)

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29995 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Tappe
2009-04-07 15:29:23 +00:00
parent 28a650e94d
commit 3f3ab1625c
2 changed files with 342 additions and 308 deletions
+3
View File
@@ -303,6 +303,9 @@ private:
float* outAscent, float* outDescent,
float* ioWidth);
int32 _FindLeftWordBoundary(int32 offset);
int32 _FindRightWordBoundary(int32 offset);
float _StyledWidth(int32 fromOffset, int32 length,
float* outAscent = NULL,
float* outDescent = NULL) const;
+98 -67
View File
@@ -553,11 +553,9 @@ BTextView::MouseDown(BPoint where)
bigtime_t clickTime = system_time();
bigtime_t clickSpeed = 0;
get_click_speed(&clickSpeed);
bool multipleClick = false;
if (clickTime - fClickTime < clickSpeed
&& fClickOffset == fTrackingMouse->clickOffset) {
multipleClick = true;
}
bool multipleClick
= clickTime - fClickTime < clickSpeed
&& fClickOffset == fTrackingMouse->clickOffset;
fWhere = where;
@@ -570,25 +568,29 @@ BTextView::MouseDown(BPoint where)
if (region.Contains(where)) {
// Setup things for dragging
fTrackingMouse->selectionRect = region.Frame();
fClickCount = 1;
fClickTime = clickTime;
return;
}
}
if (multipleClick) {
if (fClickCount > 1) {
if (fClickCount > 3) {
fClickCount = 0;
fClickTime = 0;
} else {
fClickCount = 2;
fClickCount++;
fClickTime = clickTime;
}
} else {
} else if (!fTrackingMouse->shiftDown) {
// skip multiple click handling if shift is pressed, as we want to keep
// the current selection state (char, word or line) and just extend the
// selection in that case
fClickOffset = fTrackingMouse->clickOffset;
fClickCount = 1;
fClickTime = clickTime;
// Deselect any previously selected text
if (!fTrackingMouse->shiftDown)
Select(fTrackingMouse->clickOffset, fTrackingMouse->clickOffset);
}
@@ -1189,10 +1191,8 @@ void
BTextView::Insert(const char *inText, int32 inLength,
const text_run_array *inRuns)
{
if (inText != NULL && inLength > 0) {
int32 realLength = strlen(inText);
_DoInsertText(inText, min_c(inLength, realLength), fSelStart, inRuns);
}
if (inText != NULL && inLength > 0)
_DoInsertText(inText, strnlen(inText, inLength), fSelStart, inRuns);
}
@@ -1200,13 +1200,8 @@ void
BTextView::Insert(int32 startOffset, const char *inText, int32 inLength,
const text_run_array *inRuns)
{
CALLED();
// do we really need to do anything?
if (inText != NULL && inLength > 0) {
int32 realLength = strlen(inText);
_DoInsertText(inText, min_c(inLength, realLength), startOffset, inRuns);
}
if (inText != NULL && inLength > 0)
_DoInsertText(inText, strnlen(inText, inLength), startOffset, inRuns);
}
@@ -1250,7 +1245,7 @@ BTextView::Delete(int32 startOffset, int32 endOffset)
fSelEnd = fSelStart = fClickOffset;
// recalc line breaks and draw what's left
_Refresh(startOffset, endOffset, true, true);
_Refresh(startOffset, endOffset, true, false);
// draw the caret
if (fActive)
@@ -1421,6 +1416,7 @@ BTextView::Paste(BClipboard *clipboard)
Delete();
Insert(text, len, runArray);
ScrollToOffset(fSelEnd);
}
}
@@ -1539,7 +1535,7 @@ BTextView::Select(int32 startOffset, int32 endOffset)
}
}
fSelStart = startOffset;
fSelEnd = fClickOffset = endOffset;
fSelEnd = endOffset;
}
}
@@ -1632,7 +1628,7 @@ BTextView::SetFontAndColor(int32 startOffset, int32 endOffset,
} else {
// the line breaks wont change, simply redraw
_RequestDrawLines(LineAt(startOffset), LineAt(endOffset), startOffset,
true);
false);
}
}
@@ -1926,31 +1922,11 @@ BTextView::OffsetAt(int32 line) const
void
BTextView::FindWord(int32 inOffset, int32 *outFromOffset, int32 *outToOffset)
{
int32 offset;
uint32 charType = _CharClassification(inOffset);
// check to the left
int32 previous;
for (offset = inOffset, previous = offset; offset > 0;
previous = _PreviousInitialByte(offset)) {
if (_CharClassification(previous) != charType)
break;
offset = previous;
}
if (outFromOffset)
*outFromOffset = offset;
// check to the right
int32 textLen = TextLength();
for (offset = inOffset; offset < textLen;
offset = _NextInitialByte(offset)) {
if (_CharClassification(offset) != charType)
break;
}
*outFromOffset = _FindLeftWordBoundary(inOffset);
if (outToOffset)
*outToOffset = offset;
*outToOffset = _FindRightWordBoundary(inOffset);
}
@@ -2380,7 +2356,7 @@ BTextView::SetWordWrap(bool wrap)
}
fWrap = wrap;
_Refresh(0, fText->Length(), true, true);
_Refresh(0, fText->Length(), true, false);
if (updateOnScreen) {
// show the caret, hilite the selection
@@ -3556,7 +3532,7 @@ BTextView::_Refresh(int32 fromOffset, int32 toOffset, bool erase, bool scroll)
_UpdateScrollbars();
if (scroll)
ScrollToSelection();
ScrollToOffset(fSelEnd);
Flush();
}
@@ -3608,7 +3584,7 @@ BTextView::_RecalculateLineBreaks(int32 *startLine, int32 *endLine)
newLine.ascent = 0;
fLines->InsertLine(&newLine, lineIndex);
} else {
// update the exising line
// update the existing line
nextLine->offset = toOffset;
nextLine->origin = ceilf(curLine->origin + ascent + descent) + 1;
@@ -3824,6 +3800,37 @@ BTextView::_FindLineBreak(int32 fromOffset, float *outAscent, float *outDescent,
}
int32
BTextView::_FindLeftWordBoundary(int32 offset)
{
uint32 charType = _CharClassification(offset);
int32 previous;
while (offset > 0) {
previous = _PreviousInitialByte(offset);
if (_CharClassification(previous) != charType)
break;
offset = previous;
}
return offset;
}
int32
BTextView::_FindRightWordBoundary(int32 offset)
{
uint32 charType = _CharClassification(offset);
int32 textLen = TextLength();
while (offset < textLen) {
offset = _NextInitialByte(offset);
if (_CharClassification(offset) != charType)
break;
}
return offset;
}
/*! \brief Calculate the width of the text within the given limits.
\param fromOffset The offset where to start.
\param length The length of the text to examine.
@@ -3916,9 +3923,6 @@ BTextView::_DoInsertText(const char *inText, int32 inLength, int32 inOffset,
if (fSelStart != fSelEnd)
Select(fSelStart, fSelStart);
// Don't do any check, the public methods will have adjusted
// eventual bogus values...
const int32 textLength = TextLength();
if (inOffset > textLength)
inOffset = textLength;
@@ -3926,12 +3930,14 @@ BTextView::_DoInsertText(const char *inText, int32 inLength, int32 inOffset,
// copy data into buffer
InsertText(inText, inLength, inOffset, inRuns);
// offset the caret/selection
// offset the caret/selection, if the text was inserted before it
if (inOffset < fSelEnd) {
fSelStart += inLength;
fClickOffset = fSelEnd = fSelStart;
}
// recalc line breaks and draw the text
_Refresh(inOffset, inOffset + inLength, true, true);
_Refresh(inOffset, inOffset + inLength, true, false);
}
@@ -4305,32 +4311,57 @@ BTextView::_PerformMouseMoved(BPoint where, uint32 code)
return true;
}
int32 oldOffset = fTrackingMouse->anchor;
int32 currentOffset = OffsetAt(where);
switch (fClickCount) {
case 0:
// triple click, select line by line
case 3:
// triple click, extend selection linewise
if (currentOffset <= fTrackingMouse->anchor) {
fTrackingMouse->selStart
= (*fLines)[LineAt(fTrackingMouse->selStart)]->offset;
= (*fLines)[LineAt(currentOffset)]->offset;
fTrackingMouse->selEnd
= (*fLines)[LineAt(fTrackingMouse->selEnd) + 1]->offset;
= fTrackingMouse->shiftDown
? fSelEnd
: (*fLines)[LineAt(fTrackingMouse->anchor) + 1]->offset;
} else {
fTrackingMouse->selStart
= fTrackingMouse->shiftDown
? fSelStart
: (*fLines)[LineAt(fTrackingMouse->anchor)]->offset;
fTrackingMouse->selEnd
= (*fLines)[LineAt(currentOffset) + 1]->offset;
}
break;
case 2:
// double click, select word by word
FindWord(currentOffset, &fTrackingMouse->selStart,
&fTrackingMouse->selEnd);
// double click, extend selection wordwise
if (currentOffset <= fTrackingMouse->anchor) {
fTrackingMouse->selStart = _FindLeftWordBoundary(currentOffset);
fTrackingMouse->selEnd
= fTrackingMouse->shiftDown
? fSelEnd
: _FindRightWordBoundary(fTrackingMouse->anchor);
} else {
fTrackingMouse->selStart
= fTrackingMouse->shiftDown
? fSelStart
: _FindLeftWordBoundary(fTrackingMouse->anchor);
fTrackingMouse->selEnd = _FindRightWordBoundary(currentOffset);
}
break;
default:
// new click, select char by char
if (oldOffset < currentOffset) {
fTrackingMouse->selStart = oldOffset;
fTrackingMouse->selEnd = currentOffset;
} else {
// new click, extend selection char by char
if (currentOffset <= fTrackingMouse->anchor) {
fTrackingMouse->selStart = currentOffset;
fTrackingMouse->selEnd = oldOffset;
fTrackingMouse->selEnd
= fTrackingMouse->shiftDown
? fSelEnd : fTrackingMouse->anchor;
} else {
fTrackingMouse->selStart
= fTrackingMouse->shiftDown
? fSelStart : fTrackingMouse->anchor;
fTrackingMouse->selEnd = currentOffset;
}
break;
}