Some BTextView fixes, most importantly the annoying up/down ping pong when
triggering auto-scrolling in BTextControls... * _BTextInput_::MinSize() added 1 to the line height, but when aligning the text rect, at least one pixel is added at the top and bottom, which makes for at least two extra pixels. * BTextView::_PerformAutoScrolling() had some code which was supposed to prevent from out-of-bounds scrolling, but the bottom maximum coordinate was not correctly calculated. This and the above item led to the ping-pong effect. * Additionally, I prevented scrolling vertically for one-line text views completely. * On mouse-up, reset the cursor. It may have to be the I-Beam cursor again, for example after de-selecting. * While mouse tracking the selection, always use the I-Beam cursor. * Also when mouse tracking, do not use the minimum/maximum text offset when the mouse is above/below the text rect. Do this only when it's also outside on left/right sides. This is less irritating and works like on other platforms. It means the first/last line can still be selected, without having to constrain the mouse to the inside of the text view. * When calculating the selection region, don't make the bottom one pixel too far up. Lines which contain glyphs that extend below the base-line have one more pixel below the glyphs that is inverted now. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30046 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -153,7 +153,9 @@ BSize
|
|||||||
_BTextInput_::MinSize()
|
_BTextInput_::MinSize()
|
||||||
{
|
{
|
||||||
BSize min;
|
BSize min;
|
||||||
min.height = ceilf(LineHeight(0) + 1.0);
|
min.height = ceilf(LineHeight(0) + 2.0);
|
||||||
|
// we always add at least one pixel vertical inset top/bottom for
|
||||||
|
// the text rect.
|
||||||
min.width = min.height * 3;
|
min.width = min.height * 3;
|
||||||
return BLayoutUtils::ComposeSize(ExplicitMinSize(), min);
|
return BLayoutUtils::ComposeSize(ExplicitMinSize(), min);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2001-2008, Haiku Inc. All rights reserved.
|
* Copyright 2001-2009, Haiku Inc. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -1831,14 +1831,27 @@ BTextView::OffsetAt(BPoint point) const
|
|||||||
const int32 textLength = fText->Length();
|
const int32 textLength = fText->Length();
|
||||||
|
|
||||||
// should we even bother?
|
// should we even bother?
|
||||||
if (point.y >= fTextRect.bottom)
|
if (point.y >= fTextRect.bottom && point.x >= fTextRect.right)
|
||||||
return textLength;
|
return textLength;
|
||||||
else if (point.y < fTextRect.top)
|
else if (point.y < fTextRect.top && point.x <= fTextRect.left)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
#define COMPILE_PROBABLY_BAD_CODE 1
|
||||||
|
|
||||||
|
#if COMPILE_PROBABLY_BAD_CODE
|
||||||
|
// NOTE: I have not been able to test what happens if all this is removed.
|
||||||
|
// For one-line text views (BTextControl), it works just fine. But I would
|
||||||
|
// need to check StyledEdit or something in various situations (new lines
|
||||||
|
// at end and other stuff)...
|
||||||
|
// special case one line text views
|
||||||
|
if (CountLines() <= 1)
|
||||||
|
point.y = fTextRect.top;
|
||||||
|
#endif
|
||||||
|
|
||||||
int32 lineNum = LineAt(point);
|
int32 lineNum = LineAt(point);
|
||||||
STELine* line = (*fLines)[lineNum];
|
STELine* line = (*fLines)[lineNum];
|
||||||
|
|
||||||
|
#if COMPILE_PROBABLY_BAD_CODE
|
||||||
// special case: if point is within the text rect and PixelToLine()
|
// special case: if point is within the text rect and PixelToLine()
|
||||||
// tells us that it's on the last line, but if point is actually
|
// tells us that it's on the last line, but if point is actually
|
||||||
// lower than the bottom of the last line, return the last offset
|
// lower than the bottom of the last line, return the last offset
|
||||||
@@ -1847,6 +1860,7 @@ BTextView::OffsetAt(BPoint point) const
|
|||||||
if (point.y >= ((line + 1)->origin + fTextRect.top))
|
if (point.y >= ((line + 1)->origin + fTextRect.top))
|
||||||
return textLength;
|
return textLength;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// convert to text rect coordinates
|
// convert to text rect coordinates
|
||||||
if (fAlignment != B_ALIGN_LEFT) {
|
if (fAlignment != B_ALIGN_LEFT) {
|
||||||
@@ -2033,14 +2047,14 @@ BTextView::GetTextRegion(int32 startOffset, int32 endOffset, BRegion *outRegion)
|
|||||||
selRect.left = max_c(startPt.x, fTextRect.left);
|
selRect.left = max_c(startPt.x, fTextRect.left);
|
||||||
selRect.top = startPt.y;
|
selRect.top = startPt.y;
|
||||||
selRect.right = endPt.x - 1.0;
|
selRect.right = endPt.x - 1.0;
|
||||||
selRect.bottom = endPt.y + endLineHeight - 1.0;
|
selRect.bottom = endPt.y + endLineHeight;
|
||||||
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 = max_c(startPt.x, fTextRect.left);
|
selRect.left = max_c(startPt.x, fTextRect.left);
|
||||||
selRect.top = startPt.y;
|
selRect.top = startPt.y;
|
||||||
selRect.right = fTextRect.right;
|
selRect.right = fTextRect.right;
|
||||||
selRect.bottom = startPt.y + startLineHeight - 1.0;
|
selRect.bottom = startPt.y + startLineHeight;
|
||||||
outRegion->Include(selRect);
|
outRegion->Include(selRect);
|
||||||
|
|
||||||
if (startPt.y + startLineHeight < endPt.y) {
|
if (startPt.y + startLineHeight < endPt.y) {
|
||||||
@@ -2048,14 +2062,14 @@ BTextView::GetTextRegion(int32 startOffset, int32 endOffset, BRegion *outRegion)
|
|||||||
selRect.left = fTextRect.left;
|
selRect.left = fTextRect.left;
|
||||||
selRect.top = startPt.y + startLineHeight;
|
selRect.top = startPt.y + startLineHeight;
|
||||||
selRect.right = fTextRect.right;
|
selRect.right = fTextRect.right;
|
||||||
selRect.bottom = endPt.y - 1.0;
|
selRect.bottom = endPt.y;
|
||||||
outRegion->Include(selRect);
|
outRegion->Include(selRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
selRect.left = fTextRect.left;
|
selRect.left = fTextRect.left;
|
||||||
selRect.top = endPt.y;
|
selRect.top = endPt.y;
|
||||||
selRect.right = endPt.x - 1.0;
|
selRect.right = endPt.x - 1.0;
|
||||||
selRect.bottom = endPt.y + endLineHeight - 1.0;
|
selRect.bottom = endPt.y + endLineHeight;
|
||||||
outRegion->Include(selRect);
|
outRegion->Include(selRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2145,11 +2159,16 @@ BTextView::SetTextRect(BRect rect)
|
|||||||
if (rect == fTextRect)
|
if (rect == fTextRect)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// The text rect height is always calculated anyways to contain the
|
||||||
|
// whole text. But it is used here to remember the inset the user
|
||||||
|
// wanted.
|
||||||
bool needsRefresh = fTextRect.left != rect.left
|
bool needsRefresh = fTextRect.left != rect.left
|
||||||
|| fTextRect.right != rect.right || fTextRect.top != rect.top;
|
|| fTextRect.right != rect.right || fTextRect.top != rect.top;
|
||||||
|
|
||||||
fLayoutData->UpdateInsets(Bounds().OffsetToCopy(B_ORIGIN), rect);
|
fLayoutData->UpdateInsets(Bounds().OffsetToCopy(B_ORIGIN), rect);
|
||||||
|
|
||||||
|
// When we already know we don't want to recalculate anything, we
|
||||||
|
// can just ignore the bottom coordinate the user provided.
|
||||||
if (!needsRefresh)
|
if (!needsRefresh)
|
||||||
rect.bottom = fTextRect.bottom;
|
rect.bottom = fTextRect.bottom;
|
||||||
|
|
||||||
@@ -4298,6 +4317,8 @@ BTextView::_PerformMouseUp(BPoint where)
|
|||||||
Select(fTrackingMouse->clickOffset, fTrackingMouse->clickOffset);
|
Select(fTrackingMouse->clickOffset, fTrackingMouse->clickOffset);
|
||||||
|
|
||||||
_StopMouseTracking();
|
_StopMouseTracking();
|
||||||
|
// adjust cursor if necessary
|
||||||
|
_TrackMouse(where, NULL, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -4394,9 +4415,10 @@ BTextView::_TrackMouse(BPoint where, const BMessage *message, bool force)
|
|||||||
|
|
||||||
if (message && AcceptsDrop(message))
|
if (message && AcceptsDrop(message))
|
||||||
_TrackDrag(where);
|
_TrackDrag(where);
|
||||||
else if ((fSelectable || fEditable) && !textRegion.Contains(where))
|
else if ((fSelectable || fEditable)
|
||||||
|
&& (fTrackingMouse != NULL || !textRegion.Contains(where))) {
|
||||||
SetViewCursor(B_CURSOR_I_BEAM, force);
|
SetViewCursor(B_CURSOR_I_BEAM, force);
|
||||||
else
|
} else
|
||||||
SetViewCursor(B_CURSOR_SYSTEM_DEFAULT, force);
|
SetViewCursor(B_CURSOR_SYSTEM_DEFAULT, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4518,7 +4540,7 @@ BTextView::_PerformAutoScrolling()
|
|||||||
{
|
{
|
||||||
// Scroll the view a bit if mouse is outside the view bounds
|
// Scroll the view a bit if mouse is outside the view bounds
|
||||||
BRect bounds = Bounds();
|
BRect bounds = Bounds();
|
||||||
BPoint scrollBy;
|
BPoint scrollBy(B_ORIGIN);
|
||||||
|
|
||||||
BPoint constraint = fWhere;
|
BPoint constraint = fWhere;
|
||||||
constraint.ConstrainTo(bounds);
|
constraint.ConstrainTo(bounds);
|
||||||
@@ -4533,27 +4555,35 @@ BTextView::_PerformAutoScrolling()
|
|||||||
scrollBy.x = -value;
|
scrollBy.x = -value;
|
||||||
}
|
}
|
||||||
|
|
||||||
float lineHeight = 0;
|
if (CountLines() > 1) {
|
||||||
float vertDiff = 0;
|
// scroll in Y only if multiple lines!
|
||||||
if (fWhere.y > bounds.bottom) {
|
|
||||||
lineHeight = LineHeight(LineAt(bounds.LeftBottom()));
|
float lineHeight = 0;
|
||||||
vertDiff = fWhere.y - bounds.bottom;
|
float vertDiff = 0;
|
||||||
} else if (fWhere.y < bounds.top) {
|
if (fWhere.y > bounds.bottom) {
|
||||||
lineHeight = LineHeight(LineAt(bounds.LeftTop()));
|
lineHeight = LineHeight(LineAt(bounds.LeftBottom()));
|
||||||
vertDiff = fWhere.y - bounds.top; // negative value
|
vertDiff = fWhere.y - bounds.bottom;
|
||||||
|
} else if (fWhere.y < bounds.top) {
|
||||||
|
lineHeight = LineHeight(LineAt(bounds.LeftTop()));
|
||||||
|
vertDiff = fWhere.y - bounds.top; // negative value
|
||||||
|
}
|
||||||
|
// Always scroll vertically line by line or by multiples of that
|
||||||
|
// based on the distance of the cursor from the border of the view
|
||||||
|
// TODO: Refine this, I can't even remember how beos works here
|
||||||
|
scrollBy.y = lineHeight > 0 ? lineHeight * (int32)(floorf(vertDiff)
|
||||||
|
/ lineHeight) : 0;
|
||||||
|
|
||||||
|
// prevent from scrolling out of view
|
||||||
|
if (scrollBy.y != 0.0) {
|
||||||
|
float bottomMax = floorf(fTextRect.bottom
|
||||||
|
+ fLayoutData->bottomInset);
|
||||||
|
if (bounds.bottom + scrollBy.y > bottomMax)
|
||||||
|
scrollBy.y = bottomMax - bounds.bottom;
|
||||||
|
else if (bounds.top + scrollBy.y < 0)
|
||||||
|
scrollBy.y = -bounds.top;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always scroll vertically line by line or by multiples of that
|
|
||||||
// based on the distance of the cursor from the border of the view
|
|
||||||
// TODO: Refine this, I can't even remember how beos works here
|
|
||||||
scrollBy.y = lineHeight > 0 ? lineHeight * (int32)(floorf(vertDiff)
|
|
||||||
/ lineHeight) : 0;
|
|
||||||
|
|
||||||
if (bounds.bottom + scrollBy.y > fTextRect.Height())
|
|
||||||
scrollBy.y = fTextRect.Height() - bounds.bottom;
|
|
||||||
else if (bounds.top + scrollBy.y < 0)
|
|
||||||
scrollBy.y = -bounds.top;
|
|
||||||
|
|
||||||
if (scrollBy != B_ORIGIN)
|
if (scrollBy != B_ORIGIN)
|
||||||
ScrollBy(scrollBy.x, scrollBy.y);
|
ScrollBy(scrollBy.x, scrollBy.y);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user