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:
@@ -303,6 +303,9 @@ private:
|
|||||||
float* outAscent, float* outDescent,
|
float* outAscent, float* outDescent,
|
||||||
float* ioWidth);
|
float* ioWidth);
|
||||||
|
|
||||||
|
int32 _FindLeftWordBoundary(int32 offset);
|
||||||
|
int32 _FindRightWordBoundary(int32 offset);
|
||||||
|
|
||||||
float _StyledWidth(int32 fromOffset, int32 length,
|
float _StyledWidth(int32 fromOffset, int32 length,
|
||||||
float* outAscent = NULL,
|
float* outAscent = NULL,
|
||||||
float* outDescent = NULL) const;
|
float* outDescent = NULL) const;
|
||||||
|
|||||||
@@ -553,11 +553,9 @@ BTextView::MouseDown(BPoint where)
|
|||||||
bigtime_t clickTime = system_time();
|
bigtime_t clickTime = system_time();
|
||||||
bigtime_t clickSpeed = 0;
|
bigtime_t clickSpeed = 0;
|
||||||
get_click_speed(&clickSpeed);
|
get_click_speed(&clickSpeed);
|
||||||
bool multipleClick = false;
|
bool multipleClick
|
||||||
if (clickTime - fClickTime < clickSpeed
|
= clickTime - fClickTime < clickSpeed
|
||||||
&& fClickOffset == fTrackingMouse->clickOffset) {
|
&& fClickOffset == fTrackingMouse->clickOffset;
|
||||||
multipleClick = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fWhere = where;
|
fWhere = where;
|
||||||
|
|
||||||
@@ -570,25 +568,29 @@ BTextView::MouseDown(BPoint where)
|
|||||||
if (region.Contains(where)) {
|
if (region.Contains(where)) {
|
||||||
// Setup things for dragging
|
// Setup things for dragging
|
||||||
fTrackingMouse->selectionRect = region.Frame();
|
fTrackingMouse->selectionRect = region.Frame();
|
||||||
|
fClickCount = 1;
|
||||||
|
fClickTime = clickTime;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (multipleClick) {
|
if (multipleClick) {
|
||||||
if (fClickCount > 1) {
|
if (fClickCount > 3) {
|
||||||
fClickCount = 0;
|
fClickCount = 0;
|
||||||
fClickTime = 0;
|
fClickTime = 0;
|
||||||
} else {
|
} else {
|
||||||
fClickCount = 2;
|
fClickCount++;
|
||||||
fClickTime = clickTime;
|
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;
|
fClickOffset = fTrackingMouse->clickOffset;
|
||||||
fClickCount = 1;
|
fClickCount = 1;
|
||||||
fClickTime = clickTime;
|
fClickTime = clickTime;
|
||||||
|
|
||||||
// Deselect any previously selected text
|
// Deselect any previously selected text
|
||||||
if (!fTrackingMouse->shiftDown)
|
|
||||||
Select(fTrackingMouse->clickOffset, fTrackingMouse->clickOffset);
|
Select(fTrackingMouse->clickOffset, fTrackingMouse->clickOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1189,10 +1191,8 @@ void
|
|||||||
BTextView::Insert(const char *inText, int32 inLength,
|
BTextView::Insert(const char *inText, int32 inLength,
|
||||||
const text_run_array *inRuns)
|
const text_run_array *inRuns)
|
||||||
{
|
{
|
||||||
if (inText != NULL && inLength > 0) {
|
if (inText != NULL && inLength > 0)
|
||||||
int32 realLength = strlen(inText);
|
_DoInsertText(inText, strnlen(inText, inLength), fSelStart, inRuns);
|
||||||
_DoInsertText(inText, min_c(inLength, realLength), fSelStart, inRuns);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1200,13 +1200,8 @@ void
|
|||||||
BTextView::Insert(int32 startOffset, const char *inText, int32 inLength,
|
BTextView::Insert(int32 startOffset, const char *inText, int32 inLength,
|
||||||
const text_run_array *inRuns)
|
const text_run_array *inRuns)
|
||||||
{
|
{
|
||||||
CALLED();
|
if (inText != NULL && inLength > 0)
|
||||||
|
_DoInsertText(inText, strnlen(inText, inLength), startOffset, inRuns);
|
||||||
// do we really need to do anything?
|
|
||||||
if (inText != NULL && inLength > 0) {
|
|
||||||
int32 realLength = strlen(inText);
|
|
||||||
_DoInsertText(inText, min_c(inLength, realLength), startOffset, inRuns);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1250,7 +1245,7 @@ BTextView::Delete(int32 startOffset, int32 endOffset)
|
|||||||
fSelEnd = fSelStart = fClickOffset;
|
fSelEnd = fSelStart = fClickOffset;
|
||||||
|
|
||||||
// recalc line breaks and draw what's left
|
// recalc line breaks and draw what's left
|
||||||
_Refresh(startOffset, endOffset, true, true);
|
_Refresh(startOffset, endOffset, true, false);
|
||||||
|
|
||||||
// draw the caret
|
// draw the caret
|
||||||
if (fActive)
|
if (fActive)
|
||||||
@@ -1421,6 +1416,7 @@ BTextView::Paste(BClipboard *clipboard)
|
|||||||
Delete();
|
Delete();
|
||||||
|
|
||||||
Insert(text, len, runArray);
|
Insert(text, len, runArray);
|
||||||
|
ScrollToOffset(fSelEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1539,7 +1535,7 @@ BTextView::Select(int32 startOffset, int32 endOffset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fSelStart = startOffset;
|
fSelStart = startOffset;
|
||||||
fSelEnd = fClickOffset = endOffset;
|
fSelEnd = endOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1632,7 +1628,7 @@ BTextView::SetFontAndColor(int32 startOffset, int32 endOffset,
|
|||||||
} else {
|
} else {
|
||||||
// the line breaks wont change, simply redraw
|
// the line breaks wont change, simply redraw
|
||||||
_RequestDrawLines(LineAt(startOffset), LineAt(endOffset), startOffset,
|
_RequestDrawLines(LineAt(startOffset), LineAt(endOffset), startOffset,
|
||||||
true);
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1926,31 +1922,11 @@ BTextView::OffsetAt(int32 line) const
|
|||||||
void
|
void
|
||||||
BTextView::FindWord(int32 inOffset, int32 *outFromOffset, int32 *outToOffset)
|
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)
|
if (outFromOffset)
|
||||||
*outFromOffset = offset;
|
*outFromOffset = _FindLeftWordBoundary(inOffset);
|
||||||
|
|
||||||
// check to the right
|
|
||||||
int32 textLen = TextLength();
|
|
||||||
for (offset = inOffset; offset < textLen;
|
|
||||||
offset = _NextInitialByte(offset)) {
|
|
||||||
if (_CharClassification(offset) != charType)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outToOffset)
|
if (outToOffset)
|
||||||
*outToOffset = offset;
|
*outToOffset = _FindRightWordBoundary(inOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2380,7 +2356,7 @@ BTextView::SetWordWrap(bool wrap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fWrap = wrap;
|
fWrap = wrap;
|
||||||
_Refresh(0, fText->Length(), true, true);
|
_Refresh(0, fText->Length(), true, false);
|
||||||
|
|
||||||
if (updateOnScreen) {
|
if (updateOnScreen) {
|
||||||
// show the caret, hilite the selection
|
// show the caret, hilite the selection
|
||||||
@@ -3556,7 +3532,7 @@ BTextView::_Refresh(int32 fromOffset, int32 toOffset, bool erase, bool scroll)
|
|||||||
_UpdateScrollbars();
|
_UpdateScrollbars();
|
||||||
|
|
||||||
if (scroll)
|
if (scroll)
|
||||||
ScrollToSelection();
|
ScrollToOffset(fSelEnd);
|
||||||
|
|
||||||
Flush();
|
Flush();
|
||||||
}
|
}
|
||||||
@@ -3608,7 +3584,7 @@ BTextView::_RecalculateLineBreaks(int32 *startLine, int32 *endLine)
|
|||||||
newLine.ascent = 0;
|
newLine.ascent = 0;
|
||||||
fLines->InsertLine(&newLine, lineIndex);
|
fLines->InsertLine(&newLine, lineIndex);
|
||||||
} else {
|
} else {
|
||||||
// update the exising line
|
// update the existing line
|
||||||
nextLine->offset = toOffset;
|
nextLine->offset = toOffset;
|
||||||
nextLine->origin = ceilf(curLine->origin + ascent + descent) + 1;
|
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.
|
/*! \brief Calculate the width of the text within the given limits.
|
||||||
\param fromOffset The offset where to start.
|
\param fromOffset The offset where to start.
|
||||||
\param length The length of the text to examine.
|
\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)
|
if (fSelStart != fSelEnd)
|
||||||
Select(fSelStart, fSelStart);
|
Select(fSelStart, fSelStart);
|
||||||
|
|
||||||
// Don't do any check, the public methods will have adjusted
|
|
||||||
// eventual bogus values...
|
|
||||||
|
|
||||||
const int32 textLength = TextLength();
|
const int32 textLength = TextLength();
|
||||||
if (inOffset > textLength)
|
if (inOffset > textLength)
|
||||||
inOffset = textLength;
|
inOffset = textLength;
|
||||||
@@ -3926,12 +3930,14 @@ BTextView::_DoInsertText(const char *inText, int32 inLength, int32 inOffset,
|
|||||||
// copy data into buffer
|
// copy data into buffer
|
||||||
InsertText(inText, inLength, inOffset, inRuns);
|
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;
|
fSelStart += inLength;
|
||||||
fClickOffset = fSelEnd = fSelStart;
|
fClickOffset = fSelEnd = fSelStart;
|
||||||
|
}
|
||||||
|
|
||||||
// recalc line breaks and draw the text
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 oldOffset = fTrackingMouse->anchor;
|
|
||||||
int32 currentOffset = OffsetAt(where);
|
int32 currentOffset = OffsetAt(where);
|
||||||
|
|
||||||
switch (fClickCount) {
|
switch (fClickCount) {
|
||||||
case 0:
|
case 3:
|
||||||
// triple click, select line by line
|
// triple click, extend selection linewise
|
||||||
|
if (currentOffset <= fTrackingMouse->anchor) {
|
||||||
fTrackingMouse->selStart
|
fTrackingMouse->selStart
|
||||||
= (*fLines)[LineAt(fTrackingMouse->selStart)]->offset;
|
= (*fLines)[LineAt(currentOffset)]->offset;
|
||||||
fTrackingMouse->selEnd
|
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;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
// double click, select word by word
|
// double click, extend selection wordwise
|
||||||
FindWord(currentOffset, &fTrackingMouse->selStart,
|
if (currentOffset <= fTrackingMouse->anchor) {
|
||||||
&fTrackingMouse->selEnd);
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// new click, select char by char
|
// new click, extend selection char by char
|
||||||
if (oldOffset < currentOffset) {
|
if (currentOffset <= fTrackingMouse->anchor) {
|
||||||
fTrackingMouse->selStart = oldOffset;
|
|
||||||
fTrackingMouse->selEnd = currentOffset;
|
|
||||||
} else {
|
|
||||||
fTrackingMouse->selStart = currentOffset;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user