IK: align BTextView text rect/fix alignment

Recalculate line breaks in FrameResized() if word-wrap is on, otherwise
only move the text rect into position. StyledEdit was recalculating line
breaks before on resize (we have to in this mode) and the frame offset
updates for non-wrapping text views are inexpensive. This makes resizing
text view's work like StyledEdit everywhere.

Scroll to cursor when word-wrap setting changes if text view is editable.
If you are viewing a long document changing word-wrap can move the cursor
quite far, so scroll back to it.

Fix _ActualTabWidth() pen location for right and center-aligned text views
so that tabs widths are calculated correctly.

Reset fTextRect horizontal limits to bounds minus insets in
_RecalculateLineBreaks(), then grow fTextRect based on alignment when
wrap is off.

Fixing insets also fixes right and center-aligned BTextViews.
Left-aligned text view's grow right, right-aligned ones grow left,
and center-aligned ones grow out.

Make extra scrolling space for all aligned text views go the other way
from how it did in hrev24130 (and on left-aligned text view's too) so
that half the text is visible when you edit past the end or before the
beginnning of a text view instead of none of it.

Fixes #1651 #12608 #13796 #15189

Do not _RecalculateLineBreaks() if text view bounds are invalid.
In SetText() detect invalid text view bounds and resize the view to the
width and height of the first line. Then recalculate line breaks.
This fixes BAlert text view size issues.

Fixes #16481 (regression from hrev54496.)

Remove useless and heavy computation. There is no point in computing line
breaks for a 10px wide text view and it takes a long time because it needs
a lot of linebreaks. The view eventually gets laid out properly.

Fixes #5582 (which was not locale-related, after all.)

Only apply default insets if text rect is set to bounds. This ensures
that apps that manipulate the text rect can continue to do so without
the default insets interfering while apps that don't can benefit
from the defaults. If you want to set the text rect to bounds and
not use the default insets you must override the default by calling
SetInsets(). This prevent the default insets from being applied once
apps have changed the text rect fixing a bug in Icon-O-Matic where the
text rect insets were being applied incorrectly.

Fixes #16488 (regression from hrev54496.)

Reduce left and right insets inside text views from full label spacing
to half label spacing. Unify padding between BTextControl and BTextView.

Move fLayoutData->UpdateInsets() to private BTextView::_UpdateInsets()
because we need access to BTextView member variables when deciding
whether or not to add the default padding or not.

_UpdateInsets() changes:
* Don't update insets if BTextView::SetInsets() was called.
* Don't add default insets unless fTextRect is set to view Bounds().
* Do not set the right and bottom insets to left and top if negative,
  set them to 0 like we do to left and top -- DeskCalc bug otherwise.

Fixes #15688

Other BTextView fixes:
* Replace max_c and min_c with std::max and std::min respectively.
* Remove scrolling from one instance of BTextView::SetText() as it
  produced undesired results while editing a scrolled text view.
* Add default insets in _UpdateInsets()
* Fix scrolling when entering and deleting text so that some part of
  the text is always visible. Make visible scroll width depend on font
  size.
* Allow scrolling to a negative offset in x but not y. This allows you
  to scroll the entire contents of right and centered-aligned text views
  whose content does not fit in the box.
* Change _Refresh() to take an offset instead of a bool so that you can
  scroll to any offset.
* Replace TextLength() with fText->Length() in a couple of places.

TextControl changes:
* Set text rect in BTextControl::DoLayout().
* Remove AlignTextRect() from TextInput.

Fix the following problems in apps:

ScreenSaver: Set text rect in PreviewView::AddPreview().
Tracker: Set "Edit name" text view insets to 2. Tweek text rect position
  to be on top of label in icon, mini-icon, and list mode. Add a TODO that
  the text rect is a pixel off from the name on some files.
Mail: Remove _AlignTextRect() and FrameResized() from AddressTextControl.
  Use default insets on the text view, defaults are fine here.
DeskCalc: Set insets based on font size in ExpressionTextView
  SetTextRect() instead of manipulating the text rect.
  Remove _CheckTextRect() and related methods from InputTextView.
Icon-O-Matic: Remove _CheckTextRect() and related methods from InputTextView.
WebPositive: Remove _AlignTextRect() and FrameResized() from URLTextView
  and call SetInsets().
StyledEdit: Word-wrap and FrameResized() changes ported to BTextView.

Fixes #16476 #16480 #16488 (regressions from hrev54496.)

Change-Id: Ifeca6077f8815ccd86d5a3880f99556298aaf0fe
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3152
Reviewed-by: John Scipione <[email protected]>
This commit is contained in:
John Scipione
2020-09-07 22:10:36 +00:00
parent 3d43a90508
commit d9385a9d38
19 changed files with 348 additions and 410 deletions
+6 -2
View File
@@ -1,11 +1,13 @@
/* /*
* Copyright 2007-2009, Haiku, Inc. All rights reserved. * Copyright 2007-2020 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _TEXTVIEW_H #ifndef _TEXTVIEW_H
#define _TEXTVIEW_H #define _TEXTVIEW_H
#include <stdint.h>
#include <Locker.h> #include <Locker.h>
#include <View.h> #include <View.h>
@@ -297,7 +299,7 @@ private:
int32 numBytes); int32 numBytes);
void _Refresh(int32 fromOffset, int32 toOffset, void _Refresh(int32 fromOffset, int32 toOffset,
bool scroll); int32 scrollTo = INT32_MIN);
void _RecalculateLineBreaks(int32* startLine, void _RecalculateLineBreaks(int32* startLine,
int32* endLine); int32* endLine);
int32 _FindLineBreak(int32 fromOffset, int32 _FindLineBreak(int32 fromOffset,
@@ -411,6 +413,8 @@ private:
void _FilterDisallowedChars(char* text, void _FilterDisallowedChars(char* text,
ssize_t& length, text_run_array* runArray); ssize_t& length, text_run_array* runArray);
void _UpdateInsets(const BRect& rect);
private: private:
BPrivate::TextGapBuffer* fText; BPrivate::TextGapBuffer* fText;
LineBuffer* fLines; LineBuffer* fLines;
-2
View File
@@ -763,8 +763,6 @@ CalcView::FrameResized(float width, float height)
fExpressionTextView->SetFontAndColor(&font, B_FONT_ALL, &fontColor); fExpressionTextView->SetFontAndColor(&font, B_FONT_ALL, &fontColor);
expressionRect.OffsetTo(B_ORIGIN); expressionRect.OffsetTo(B_ORIGIN);
float inset = (expressionRect.Height() - fExpressionTextView->LineHeight(0)) / 2;
expressionRect.InsetBy(0, inset);
fExpressionTextView->SetTextRect(expressionRect); fExpressionTextView->SetTextRect(expressionRect);
Invalidate(); Invalidate();
} }
+6 -1
View File
@@ -14,6 +14,7 @@
#include <stdio.h> #include <stdio.h>
#include <Beep.h> #include <Beep.h>
#include <ControlLook.h>
#include <Window.h> #include <Window.h>
#include "CalcView.h" #include "CalcView.h"
@@ -134,6 +135,9 @@ ExpressionTextView::GetDragParameters(BMessage* dragMessage,
void void
ExpressionTextView::SetTextRect(BRect rect) ExpressionTextView::SetTextRect(BRect rect)
{ {
float hInset = floorf(be_control_look->DefaultLabelSpacing() / 2);
float vInset = floorf((rect.Height() - LineHeight(0)) / 2);
InputTextView::SetInsets(hInset, vInset, hInset, vInset);
InputTextView::SetTextRect(rect); InputTextView::SetTextRect(rect);
int32 count = fPreviousExpressions.CountItems(); int32 count = fPreviousExpressions.CountItems();
@@ -199,7 +203,8 @@ ExpressionTextView::SetValue(BString value)
float stringWidth = font.StringWidth(value); float stringWidth = font.StringWidth(value);
// make the string shorter if it does not fit in the view // make the string shorter if it does not fit in the view
float viewWidth = Frame().Width(); float viewWidth = Frame().Width()
- floorf(be_control_look->DefaultLabelSpacing() / 2);
if (value.CountChars() > 3 && stringWidth > viewWidth) { if (value.CountChars() > 3 && stringWidth > viewWidth) {
// get the position of the first digit // get the position of the first digit
int32 firstDigit = 0; int32 firstDigit = 0;
+1 -1
View File
@@ -33,7 +33,7 @@ class ExpressionTextView : public InputTextView {
virtual void GetDragParameters(BMessage* dragMessage, virtual void GetDragParameters(BMessage* dragMessage,
BBitmap** bitmap, BPoint* point, BBitmap** bitmap, BPoint* point,
BHandler** handler); BHandler** handler);
void SetTextRect(BRect rect); virtual void SetTextRect(BRect rect);
// InputTextView // InputTextView
virtual void RevertChanges(); virtual void RevertChanges();
-49
View File
@@ -113,52 +113,3 @@ InputTextView::Invoke(BMessage* message)
} }
return B_BAD_VALUE; return B_BAD_VALUE;
} }
// #pragma mark -
void
InputTextView::Select(int32 start, int32 finish)
{
BTextView::Select(start, finish);
_CheckTextRect();
}
void
InputTextView::InsertText(const char* inText, int32 inLength, int32 inOffset,
const text_run_array* inRuns)
{
BTextView::InsertText(inText, inLength, inOffset, inRuns);
_CheckTextRect();
}
void
InputTextView::DeleteText(int32 fromOffset, int32 toOffset)
{
BTextView::DeleteText(fromOffset, toOffset);
_CheckTextRect();
}
// #pragma mark -
void
InputTextView::_CheckTextRect()
{
// update text rect and make sure
// the cursor/selection is in view
BRect textRect(TextRect());
float width = ceilf(StringWidth(Text()) + 2.0);
if (textRect.Width() < width) {
textRect.right = textRect.left + width;
SetTextRect(textRect);
ScrollToSelection();
}
}
-12
View File
@@ -37,18 +37,6 @@ class InputTextView : public BTextView, public BInvoker {
virtual void ApplyChanges() = 0; virtual void ApplyChanges() = 0;
protected: protected:
// BTextView
virtual void Select(int32 start, int32 finish);
virtual void InsertText(const char* inText,
int32 inLength,
int32 inOffset,
const text_run_array* inRuns);
virtual void DeleteText(int32 fromOffset,
int32 toOffset);
void _CheckTextRect();
bool fWasFocus; bool fWasFocus;
}; };
@@ -16,7 +16,8 @@ InputTextView::InputTextView(BRect frame, const char* name,
uint32 resizingMode, uint32 resizingMode,
uint32 flags) uint32 flags)
: BTextView(frame, name, textRect, resizingMode, flags), : BTextView(frame, name, textRect, resizingMode, flags),
fWasFocus(false) fWasFocus(false),
fTextBeforeFocus("")
{ {
SetWordWrap(false); SetWordWrap(false);
} }
@@ -117,50 +118,3 @@ InputTextView::Invoke(BMessage* message)
} }
return B_BAD_VALUE; return B_BAD_VALUE;
} }
// #pragma mark -
// Select
void
InputTextView::Select(int32 start, int32 finish)
{
BTextView::Select(start, finish);
_CheckTextRect();
}
// InsertText
void
InputTextView::InsertText(const char* inText, int32 inLength, int32 inOffset,
const text_run_array* inRuns)
{
BTextView::InsertText(inText, inLength, inOffset, inRuns);
_CheckTextRect();
}
// DeleteText
void
InputTextView::DeleteText(int32 fromOffset, int32 toOffset)
{
BTextView::DeleteText(fromOffset, toOffset);
_CheckTextRect();
}
// #pragma mark -
// _CheckTextRect
void
InputTextView::_CheckTextRect()
{
// update text rect and make sure
// the cursor/selection is in view
BRect textRect(TextRect());
float width = ceilf(StringWidth(Text()) + 2.0);
if (textRect.Width() != width) {
textRect.right = textRect.left + width;
SetTextRect(textRect);
ScrollToSelection();
}
}
@@ -34,21 +34,8 @@ class InputTextView : public BTextView,
virtual void ApplyChanges() = 0; virtual void ApplyChanges() = 0;
protected: protected:
// BTextView
virtual void Select(int32 start, int32 finish);
virtual void InsertText(const char* inText,
int32 inLength,
int32 inOffset,
const text_run_array* inRuns);
virtual void DeleteText(int32 fromOffset,
int32 toOffset);
void _CheckTextRect();
bool fWasFocus; bool fWasFocus;
BString fTextBeforeFocus; BString fTextBeforeFocus;
}; };
#endif // INPUT_TEXT_VIEW_H #endif // INPUT_TEXT_VIEW_H
+1 -31
View File
@@ -48,7 +48,6 @@ public:
virtual ~TextView(); virtual ~TextView();
virtual void MessageReceived(BMessage* message); virtual void MessageReceived(BMessage* message);
virtual void FrameResized(float width, float height);
virtual void KeyDown(const char* bytes, int32 numBytes); virtual void KeyDown(const char* bytes, int32 numBytes);
virtual void MakeFocus(bool focused = true); virtual void MakeFocus(bool focused = true);
@@ -66,9 +65,6 @@ protected:
const text_run_array* runs); const text_run_array* runs);
virtual void DeleteText(int32 fromOffset, int32 toOffset); virtual void DeleteText(int32 fromOffset, int32 toOffset);
private:
void _AlignTextRect();
private: private:
AddressTextControl* fAddressTextControl; AddressTextControl* fAddressTextControl;
TextViewCompleter* fAutoCompleter; TextViewCompleter* fAutoCompleter;
@@ -221,14 +217,6 @@ AddressTextControl::TextView::MessageReceived(BMessage* message)
} }
void
AddressTextControl::TextView::FrameResized(float width, float height)
{
BTextView::FrameResized(width, height);
_AlignTextRect();
}
void void
AddressTextControl::TextView::KeyDown(const char* bytes, int32 numBytes) AddressTextControl::TextView::KeyDown(const char* bytes, int32 numBytes)
{ {
@@ -383,25 +371,6 @@ AddressTextControl::TextView::DeleteText(int32 fromOffset,
} }
void
AddressTextControl::TextView::_AlignTextRect()
{
// Layout the text rect to be in the middle, normally this means there
// is one pixel spacing on each side.
BRect textRect(Bounds());
textRect.left = 0.0;
float vInset = max_c(1,
floorf((textRect.Height() - LineHeight(0)) / 2.0 + 0.5));
float hInset = 0;
if (be_control_look != NULL)
hInset = be_control_look->DefaultLabelSpacing();
textRect.InsetBy(hInset, vInset);
SetTextRect(textRect);
}
// #pragma mark - PopUpButton // #pragma mark - PopUpButton
@@ -888,6 +857,7 @@ void
AddressTextControl::SetEditable(bool editable) AddressTextControl::SetEditable(bool editable)
{ {
fTextView->MakeEditable(IsEnabled() && editable); fTextView->MakeEditable(IsEnabled() && editable);
fTextView->MakeSelectable(IsEnabled() && editable);
fEditable = editable; fEditable = editable;
if (editable && fPopUpButton->IsHidden(this)) if (editable && fPopUpButton->IsHidden(this))
-9
View File
@@ -51,19 +51,10 @@ StyledEditView::~StyledEditView()
} }
void void
StyledEditView::FrameResized(float width, float height) StyledEditView::FrameResized(float width, float height)
{ {
BTextView::FrameResized(width, height); BTextView::FrameResized(width, height);
if (DoesWordWrap()) {
BRect textRect;
textRect = Bounds();
textRect.OffsetTo(B_ORIGIN);
textRect.InsetBy(TEXT_INSET, TEXT_INSET);
SetTextRect(textRect);
}
} }
+2 -6
View File
@@ -502,20 +502,16 @@ StyledEditWindow::MessageReceived(BMessage* message)
break; break;
case WRAP_LINES: case WRAP_LINES:
{ {
BRect textRect(fTextView->Bounds()); // update wrap setting
textRect.OffsetTo(B_ORIGIN);
textRect.InsetBy(TEXT_INSET, TEXT_INSET);
if (fTextView->DoesWordWrap()) { if (fTextView->DoesWordWrap()) {
fTextView->SetWordWrap(false); fTextView->SetWordWrap(false);
fWrapItem->SetMarked(false); fWrapItem->SetMarked(false);
// the width comes from stylededit R5. TODO: find a better way
textRect.SetRightBottom(BPoint(1500.0, textRect.RightBottom().y));
} else { } else {
fTextView->SetWordWrap(true); fTextView->SetWordWrap(true);
fWrapItem->SetMarked(true); fWrapItem->SetMarked(true);
} }
fTextView->SetTextRect(textRect);
// update buttons
_UpdateCleanUndoRedoSaveRevert(); _UpdateCleanUndoRedoSaveRevert();
break; break;
} }
+1 -31
View File
@@ -147,7 +147,6 @@ public:
virtual ~URLTextView(); virtual ~URLTextView();
virtual void MessageReceived(BMessage* message); virtual void MessageReceived(BMessage* message);
virtual void FrameResized(float width, float height);
virtual void MouseDown(BPoint where); virtual void MouseDown(BPoint where);
virtual void KeyDown(const char* bytes, int32 numBytes); virtual void KeyDown(const char* bytes, int32 numBytes);
virtual void MakeFocus(bool focused = true); virtual void MakeFocus(bool focused = true);
@@ -163,9 +162,6 @@ protected:
const text_run_array* inRuns); const text_run_array* inRuns);
virtual void DeleteText(int32 fromOffset, int32 toOffset); virtual void DeleteText(int32 fromOffset, int32 toOffset);
private:
void _AlignTextRect();
private: private:
URLInputGroup* fURLInputGroup; URLInputGroup* fURLInputGroup;
TextViewCompleter* fURLAutoCompleter; TextViewCompleter* fURLAutoCompleter;
@@ -183,6 +179,7 @@ URLInputGroup::URLTextView::URLTextView(URLInputGroup* parent)
{ {
MakeResizable(true); MakeResizable(true);
SetStylable(true); SetStylable(true);
SetInsets(be_control_look->DefaultLabelSpacing(), 2, 0, 2);
fURLAutoCompleter->SetModificationsReported(true); fURLAutoCompleter->SetModificationsReported(true);
} }
@@ -208,14 +205,6 @@ URLInputGroup::URLTextView::MessageReceived(BMessage* message)
} }
void
URLInputGroup::URLTextView::FrameResized(float width, float height)
{
BTextView::FrameResized(width, height);
_AlignTextRect();
}
void void
URLInputGroup::URLTextView::MouseDown(BPoint where) URLInputGroup::URLTextView::MouseDown(BPoint where)
{ {
@@ -411,25 +400,6 @@ URLInputGroup::URLTextView::DeleteText(int32 fromOffset, int32 toOffset)
} }
void
URLInputGroup::URLTextView::_AlignTextRect()
{
// Layout the text rect to be in the middle, normally this means there
// is one pixel spacing on each side.
BRect textRect(Bounds());
textRect.left = 0.0;
float vInset = max_c(1,
floorf((textRect.Height() - LineHeight(0)) / 2.0 + 0.5));
float hInset = kHorizontalTextRectInset;
if (be_control_look)
hInset = be_control_look->DefaultLabelSpacing();
textRect.InsetBy(hInset, vInset);
SetTextRect(textRect);
}
const uint32 kGoBitmapWidth = 14; const uint32 kGoBitmapWidth = 14;
const uint32 kGoBitmapHeight = 14; const uint32 kGoBitmapHeight = 14;
const color_space kGoBitmapFormat = B_RGBA32; const color_space kGoBitmapFormat = B_RGBA32;
+3 -4
View File
@@ -1,11 +1,12 @@
/* /*
* Copyright 2001-2015, Haiku Inc. * Copyright 2001-2020 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Frans van Nispen (xlr8@tref.nl) * Frans van Nispen (xlr8@tref.nl)
* Stephan Aßmus <superstippi@gmx.de> * Stephan Aßmus <superstippi@gmx.de>
* Ingo Weinhold <bonefish@cs.tu-berlin.de> * Ingo Weinhold <bonefish@cs.tu-berlin.de>
* John Scipione <jscipione@gmail.com>
*/ */
@@ -637,7 +638,6 @@ void
BTextControl::SetAlignment(alignment labelAlignment, alignment textAlignment) BTextControl::SetAlignment(alignment labelAlignment, alignment textAlignment)
{ {
fText->SetAlignment(textAlignment); fText->SetAlignment(textAlignment);
fText->AlignTextRect();
if (fLabelAlign != labelAlignment) { if (fLabelAlign != labelAlignment) {
fLabelAlign = labelAlignment; fLabelAlign = labelAlignment;
@@ -911,6 +911,7 @@ BTextControl::DoLayout()
// place the text view and set the divider // place the text view and set the divider
textFrame.InsetBy(kFrameMargin, kFrameMargin); textFrame.InsetBy(kFrameMargin, kFrameMargin);
BLayoutUtils::AlignInFrame(fText, textFrame); BLayoutUtils::AlignInFrame(fText, textFrame);
fText->SetTextRect(textFrame.OffsetToCopy(B_ORIGIN));
fDivider = divider; fDivider = divider;
@@ -1115,7 +1116,6 @@ BTextControl::_InitText(const char* initialText, const BMessage* archive)
SetText(initialText); SetText(initialText);
fText->SetAlignment(B_ALIGN_LEFT); fText->SetAlignment(B_ALIGN_LEFT);
fText->AlignTextRect();
} }
// Although this is not strictly initializing the text view, // Although this is not strictly initializing the text view,
@@ -1171,7 +1171,6 @@ BTextControl::_LayoutTextView()
frame.InsetBy(kFrameMargin, kFrameMargin); frame.InsetBy(kFrameMargin, kFrameMargin);
fText->MoveTo(frame.left, frame.top); fText->MoveTo(frame.left, frame.top);
fText->ResizeTo(frame.Width(), frame.Height()); fText->ResizeTo(frame.Width(), frame.Height());
fText->AlignTextRect();
TRACE("width: %.2f, height: %.2f\n", Frame().Width(), Frame().Height()); TRACE("width: %.2f, height: %.2f\n", Frame().Width(), Frame().Height());
TRACE("fDivider: %.2f\n", fDivider); TRACE("fDivider: %.2f\n", fDivider);
+2 -40
View File
@@ -1,10 +1,11 @@
/* /*
* Copyright 2001-2015, Haiku Inc. All rights reserved. * Copyright 2001-2020 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Frans van Nispen (xlr8@tref.nl) * Frans van Nispen (xlr8@tref.nl)
* Marc Flerackers (mflerackers@androme.be) * Marc Flerackers (mflerackers@androme.be)
* John Scipione (jscipione@gmail.com)
*/ */
@@ -14,7 +15,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <ControlLook.h>
#include <InterfaceDefs.h> #include <InterfaceDefs.h>
#include <LayoutUtils.h> #include <LayoutUtils.h>
#include <Message.h> #include <Message.h>
@@ -84,8 +84,6 @@ void
_BTextInput_::FrameResized(float width, float height) _BTextInput_::FrameResized(float width, float height)
{ {
BTextView::FrameResized(width, height); BTextView::FrameResized(width, height);
AlignTextRect();
} }
@@ -162,42 +160,6 @@ _BTextInput_::MinSize()
} }
void
_BTextInput_::AlignTextRect()
{
// the label font could require the control to be higher than
// necessary for the text view, we compensate this by layouting
// the text rect to be in the middle, normally this means there
// is one pixel spacing on each side
BRect textRect(Bounds());
float vInset = max_c(1,
floorf((textRect.Height() - LineHeight(0)) / 2.0));
float hInset = 2;
float textFontWidth = TextRect().right;
switch (Alignment()) {
case B_ALIGN_LEFT:
hInset = be_control_look->DefaultLabelSpacing();
break;
case B_ALIGN_RIGHT:
hInset = textRect.right - textFontWidth;
hInset -= be_control_look->DefaultLabelSpacing();
break;
case B_ALIGN_CENTER:
hInset = (textRect.right - textFontWidth) / 2.0;
break;
default:
break;
}
textRect.InsetBy(hInset, vInset);
SetTextRect(textRect);
}
void void
_BTextInput_::SetInitialText() _BTextInput_::SetInitialText()
{ {
+2 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2008, Haiku Inc. All rights reserved. * Copyright 2001-2020 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -11,6 +11,7 @@
#ifndef _TEXT_CONTROLI_H #ifndef _TEXT_CONTROLI_H
#define _TEXT_CONTROLI_H #define _TEXT_CONTROLI_H
#include <TextView.h> #include <TextView.h>
@@ -36,7 +37,6 @@ virtual void MakeFocus(bool focusState = true);
virtual BSize MinSize(); virtual BSize MinSize();
void AlignTextRect();
void SetInitialText(); void SetInitialText();
virtual void Paste(BClipboard *clipboard); virtual void Paste(BClipboard *clipboard);
+304 -142
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2015 Haiku, Inc. All rights reserved. * Copyright 2001-2020 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -25,6 +25,7 @@
#include <TextView.h> #include <TextView.h>
#include <algorithm>
#include <new> #include <new>
#include <stdio.h> #include <stdio.h>
@@ -34,6 +35,7 @@
#include <Beep.h> #include <Beep.h>
#include <Bitmap.h> #include <Bitmap.h>
#include <Clipboard.h> #include <Clipboard.h>
#include <ControlLook.h>
#include <Debug.h> #include <Debug.h>
#include <Entry.h> #include <Entry.h>
#include <Input.h> #include <Input.h>
@@ -155,28 +157,11 @@ struct BTextView::LayoutData {
topInset(0), topInset(0),
rightInset(0), rightInset(0),
bottomInset(0), bottomInset(0),
valid(false) valid(false),
overridden(false)
{ {
} }
void UpdateInsets(const BRect& bounds, const BRect& textRect)
{
// we disallow negative insets, as they would cause parts of the
// text to be hidden
leftInset = textRect.left >= bounds.left
? textRect.left - bounds.left
: 0;
topInset = textRect.top >= bounds.top
? textRect.top - bounds.top
: 0;
rightInset = bounds.right >= textRect.right
? bounds.right - textRect.right
: leftInset;
bottomInset = bounds.bottom >= textRect.bottom
? bounds.bottom - textRect.bottom
: topInset;
}
float leftInset; float leftInset;
float topInset; float topInset;
float rightInset; float rightInset;
@@ -184,7 +169,8 @@ struct BTextView::LayoutData {
BSize min; BSize min;
BSize preferred; BSize preferred;
bool valid; bool valid : 1;
bool overridden : 1;
}; };
@@ -260,7 +246,15 @@ BTextView::BTextView(BRect frame, const char* name, BRect textRect,
uint32 resizeMask, uint32 flags) uint32 resizeMask, uint32 flags)
: :
BView(frame, name, resizeMask, BView(frame, name, resizeMask,
flags | B_FRAME_EVENTS | B_PULSE_NEEDED | B_INPUT_METHOD_AWARE) flags | B_FRAME_EVENTS | B_PULSE_NEEDED | B_INPUT_METHOD_AWARE),
fText(NULL),
fLines(NULL),
fStyles(NULL),
fDisallowedChars(NULL),
fUndo(NULL),
fDragRunner(NULL),
fClickRunner(NULL),
fLayoutData(NULL)
{ {
_InitObject(textRect, NULL, NULL); _InitObject(textRect, NULL, NULL);
SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR); SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
@@ -272,7 +266,15 @@ BTextView::BTextView(BRect frame, const char* name, BRect textRect,
uint32 resizeMask, uint32 flags) uint32 resizeMask, uint32 flags)
: :
BView(frame, name, resizeMask, BView(frame, name, resizeMask,
flags | B_FRAME_EVENTS | B_PULSE_NEEDED | B_INPUT_METHOD_AWARE) flags | B_FRAME_EVENTS | B_PULSE_NEEDED | B_INPUT_METHOD_AWARE),
fText(NULL),
fLines(NULL),
fStyles(NULL),
fDisallowedChars(NULL),
fUndo(NULL),
fDragRunner(NULL),
fClickRunner(NULL),
fLayoutData(NULL)
{ {
_InitObject(textRect, initialFont, initialColor); _InitObject(textRect, initialFont, initialColor);
SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR); SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
@@ -282,7 +284,15 @@ BTextView::BTextView(BRect frame, const char* name, BRect textRect,
BTextView::BTextView(const char* name, uint32 flags) BTextView::BTextView(const char* name, uint32 flags)
: :
BView(name, BView(name,
flags | B_FRAME_EVENTS | B_PULSE_NEEDED | B_INPUT_METHOD_AWARE) flags | B_FRAME_EVENTS | B_PULSE_NEEDED | B_INPUT_METHOD_AWARE),
fText(NULL),
fLines(NULL),
fStyles(NULL),
fDisallowedChars(NULL),
fUndo(NULL),
fDragRunner(NULL),
fClickRunner(NULL),
fLayoutData(NULL)
{ {
_InitObject(Bounds(), NULL, NULL); _InitObject(Bounds(), NULL, NULL);
SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR); SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
@@ -293,7 +303,15 @@ BTextView::BTextView(const char* name, const BFont* initialFont,
const rgb_color* initialColor, uint32 flags) const rgb_color* initialColor, uint32 flags)
: :
BView(name, BView(name,
flags | B_FRAME_EVENTS | B_PULSE_NEEDED | B_INPUT_METHOD_AWARE) flags | B_FRAME_EVENTS | B_PULSE_NEEDED | B_INPUT_METHOD_AWARE),
fText(NULL),
fLines(NULL),
fStyles(NULL),
fDisallowedChars(NULL),
fUndo(NULL),
fDragRunner(NULL),
fClickRunner(NULL),
fLayoutData(NULL)
{ {
_InitObject(Bounds(), initialFont, initialColor); _InitObject(Bounds(), initialFont, initialColor);
SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR); SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
@@ -302,7 +320,15 @@ BTextView::BTextView(const char* name, const BFont* initialFont,
BTextView::BTextView(BMessage* archive) BTextView::BTextView(BMessage* archive)
: :
BView(archive) BView(archive),
fText(NULL),
fLines(NULL),
fStyles(NULL),
fDisallowedChars(NULL),
fUndo(NULL),
fDragRunner(NULL),
fClickRunner(NULL),
fLayoutData(NULL)
{ {
CALLED(); CALLED();
BRect rect; BRect rect;
@@ -376,7 +402,7 @@ BTextView::BTextView(BMessage* archive)
text_run_array* runArray = UnflattenRunArray(flattenedRun, text_run_array* runArray = UnflattenRunArray(flattenedRun,
(int32*)&runSize); (int32*)&runSize);
if (runArray) { if (runArray) {
SetRunArray(0, TextLength(), runArray); SetRunArray(0, fText->Length(), runArray);
FreeRunArray(runArray); FreeRunArray(runArray);
} }
} }
@@ -394,8 +420,8 @@ BTextView::~BTextView()
delete fStyles; delete fStyles;
delete fDisallowedChars; delete fDisallowedChars;
delete fUndo; delete fUndo;
delete fClickRunner;
delete fDragRunner; delete fDragRunner;
delete fClickRunner;
delete fLayoutData; delete fLayoutData;
} }
@@ -451,7 +477,7 @@ BTextView::Archive(BMessage* data, bool deep) const
if (err == B_OK) { if (err == B_OK) {
int32 runSize = 0; int32 runSize = 0;
text_run_array* runArray = RunArray(0, TextLength()); text_run_array* runArray = RunArray(0, fText->Length());
void* flattened = FlattenRunArray(runArray, &runSize); void* flattened = FlattenRunArray(runArray, &runSize);
if (flattened != NULL) { if (flattened != NULL) {
@@ -774,6 +800,53 @@ void
BTextView::FrameResized(float newWidth, float newHeight) BTextView::FrameResized(float newWidth, float newHeight)
{ {
BView::FrameResized(newWidth, newHeight); BView::FrameResized(newWidth, newHeight);
if (fWrap) {
// recalculate line breaks
_ResetTextRect();
} else {
// don't recalculate line breaks,
// move text rect into position and redraw.
BRect oldTextRect(fTextRect);
BRect bounds(0, 0, newWidth, newHeight);
switch (fAlignment) {
default:
case B_ALIGN_LEFT:
// move text rect to left top corner
fTextRect.OffsetTo(bounds.left, fTextRect.top);
fTextRect.OffsetBy(fLayoutData->leftInset, 0);
break;
case B_ALIGN_RIGHT:
{
// move text rect to right top corner
float textRectWidthPlusInsets = fTextRect.Width()
+ fLayoutData->leftInset + fLayoutData->rightInset;
float maxWidth = std::max(bounds.Width(),
textRectWidthPlusInsets);
fTextRect.OffsetTo(maxWidth - fTextRect.Width(),
fTextRect.top);
fTextRect.OffsetBy(-fLayoutData->rightInset, 0);
break;
}
case B_ALIGN_CENTER:
// move text rect to center
fTextRect.OffsetTo(ceilf((fTextRect.Width() - bounds.Width())
/ 2), fTextRect.top);
break;
}
// only redraw if text rect changes
if (fTextRect != oldTextRect) {
// Make sure that the dirty area outside the text is redrawn too.
BRegion dirty(oldTextRect | fTextRect);
Invalidate(&dirty);
}
}
_UpdateScrollbars(); _UpdateScrollbars();
} }
@@ -1103,10 +1176,16 @@ BTextView::SetText(const char* text, int32 length, const text_run_array* runs)
if (text != NULL && length > 0) if (text != NULL && length > 0)
InsertText(text, length, 0, runs); InsertText(text, length, 0, runs);
// bounds are invalid, set them based on text
if (!Bounds().IsValid()) {
ResizeTo(LineWidth(0), LineHeight(0));
fTextRect = Bounds();
_UpdateInsets(fTextRect);
}
// recalculate line breaks and draw the text // recalculate line breaks and draw the text
_Refresh(0, length, false); _Refresh(0, length);
fCaretOffset = fSelStart = fSelEnd = 0; fCaretOffset = fSelStart = fSelEnd = 0;
ScrollTo(B_ORIGIN);
// draw the caret // draw the caret
_ShowCaret(); _ShowCaret();
@@ -1144,7 +1223,7 @@ BTextView::SetText(BFile* file, int32 offset, int32 length,
} }
// recalculate line breaks and draw the text // recalculate line breaks and draw the text
_Refresh(0, length, false); _Refresh(0, length);
fCaretOffset = fSelStart = fSelEnd = 0; fCaretOffset = fSelStart = fSelEnd = 0;
ScrollToOffset(fSelStart); ScrollToOffset(fSelStart);
@@ -1201,6 +1280,7 @@ BTextView::Delete(int32 startOffset, int32 endOffset)
startOffset = 0; startOffset = 0;
else if (startOffset > fText->Length()) else if (startOffset > fText->Length())
startOffset = fText->Length(); startOffset = fText->Length();
if (endOffset < 0) if (endOffset < 0)
endOffset = 0; endOffset = 0;
else if (endOffset > fText->Length()) else if (endOffset > fText->Length())
@@ -1230,7 +1310,7 @@ BTextView::Delete(int32 startOffset, int32 endOffset)
fSelEnd = fSelStart = fCaretOffset; fSelEnd = fSelStart = fCaretOffset;
// recalculate line breaks and draw what's left // recalculate line breaks and draw what's left
_Refresh(startOffset, endOffset, false); _Refresh(startOffset, endOffset, fCaretOffset);
// draw the caret // draw the caret
_ShowCaret(); _ShowCaret();
@@ -1567,7 +1647,7 @@ BTextView::SetFontAndColor(int32 startOffset, int32 endOffset,
// B_SUPPORTS_LAYOUT) and have it _Refresh() automatically? // B_SUPPORTS_LAYOUT) and have it _Refresh() automatically?
InvalidateLayout(); InvalidateLayout();
// recalc the line breaks and redraw with new style // recalc the line breaks and redraw with new style
_Refresh(startOffset, endOffset, false); _Refresh(startOffset, endOffset);
} else { } else {
// the line breaks wont change, simply redraw // the line breaks wont change, simply redraw
_RequestDrawLines(_LineAt(startOffset), _LineAt(endOffset)); _RequestDrawLines(_LineAt(startOffset), _LineAt(endOffset));
@@ -1631,7 +1711,7 @@ BTextView::SetRunArray(int32 startOffset, int32 endOffset,
_SetRunArray(startOffset, endOffset, runs); _SetRunArray(startOffset, endOffset, runs);
_Refresh(startOffset, endOffset, false); _Refresh(startOffset, endOffset);
} }
@@ -1740,7 +1820,7 @@ BTextView::PointAt(int32 offset, float* _height) const
float lineWidth = onEmptyLastLine ? 0.0 : LineWidth(lineNum); float lineWidth = onEmptyLastLine ? 0.0 : LineWidth(lineNum);
float alignmentOffset = fTextRect.Width() - lineWidth; float alignmentOffset = fTextRect.Width() - lineWidth;
if (fAlignment == B_ALIGN_CENTER) if (fAlignment == B_ALIGN_CENTER)
alignmentOffset /= 2; alignmentOffset = floorf(alignmentOffset / 2);
result.x += alignmentOffset; result.x += alignmentOffset;
} }
@@ -1788,12 +1868,12 @@ BTextView::OffsetAt(BPoint point) const
if (fAlignment != B_ALIGN_LEFT) { if (fAlignment != B_ALIGN_LEFT) {
float alignmentOffset = fTextRect.Width() - LineWidth(lineNum); float alignmentOffset = fTextRect.Width() - LineWidth(lineNum);
if (fAlignment == B_ALIGN_CENTER) if (fAlignment == B_ALIGN_CENTER)
alignmentOffset /= 2; alignmentOffset = floorf(alignmentOffset / 2);
point.x -= alignmentOffset; point.x -= alignmentOffset;
} }
point.x -= fTextRect.left; point.x -= fTextRect.left;
point.x = max_c(point.x, 0.0); point.x = std::max(point.x, 0.0f);
// ToDo: The following code isn't very efficient, because it always starts // ToDo: The following code isn't very efficient, because it always starts
// from the left end, so when the point is near the right end it's very // from the left end, so when the point is near the right end it's very
@@ -2041,14 +2121,14 @@ BTextView::GetTextRegion(int32 startOffset, int32 endOffset,
if (startPt.y == endPt.y) { if (startPt.y == endPt.y) {
// this is a one-line region // this is a one-line region
selRect.left = max_c(startPt.x, fTextRect.left); selRect.left = std::max(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 - 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 = max_c(startPt.x, fTextRect.left); selRect.left = std::max(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 - 1.0;
@@ -2082,13 +2162,11 @@ BTextView::ScrollToOffset(int32 offset)
BPoint point = PointAt(offset, &lineHeight); BPoint point = PointAt(offset, &lineHeight);
// horizontal // horizontal
float extraSpace = fAlignment == B_ALIGN_LEFT ? float extraSpace = ceilf(bounds.IntegerWidth() / 2);
ceilf(bounds.IntegerWidth() / 2) : 0.0;
if (point.x < bounds.left) if (point.x < bounds.left)
xDiff = point.x - bounds.left - extraSpace;
else if (point.x > bounds.right)
xDiff = point.x - bounds.right + extraSpace; xDiff = point.x - bounds.right + extraSpace;
else if (point.x > bounds.right)
xDiff = point.x - bounds.left - extraSpace;
// vertical // vertical
if (point.y < bounds.top) if (point.y < bounds.top)
@@ -2098,9 +2176,7 @@ BTextView::ScrollToOffset(int32 offset)
yDiff = point.y + lineHeight - bounds.bottom; yDiff = point.y + lineHeight - bounds.bottom;
} }
// prevent negative scroll offset // prevent negative scroll offset in y
if (bounds.left + xDiff < 0.0)
xDiff = -bounds.left;
if (bounds.top + yDiff < 0.0) if (bounds.top + yDiff < 0.0)
yDiff = -bounds.top; yDiff = -bounds.top;
@@ -2150,11 +2226,13 @@ BTextView::SetTextRect(BRect rect)
return; return;
if (!fWrap) { if (!fWrap) {
rect.right = Bounds().right - fLayoutData->rightInset; rect.right = Bounds().right;
rect.bottom = Bounds().bottom - fLayoutData->bottomInset; rect.bottom = Bounds().bottom;
} }
fLayoutData->UpdateInsets(Bounds().OffsetToCopy(B_ORIGIN), rect); _UpdateInsets(rect);
fTextRect = rect;
_ResetTextRect(); _ResetTextRect();
} }
@@ -2180,7 +2258,7 @@ BTextView::_ResetTextRect()
// and rewrap (potentially adjusting the right and the bottom of the text // and rewrap (potentially adjusting the right and the bottom of the text
// rect) // rect)
_Refresh(0, TextLength(), false); _Refresh(0, fText->Length());
// Make sure that the dirty area outside the text is redrawn too. // Make sure that the dirty area outside the text is redrawn too.
BRegion invalid(oldTextRect | fTextRect); BRegion invalid(oldTextRect | fTextRect);
@@ -2203,6 +2281,8 @@ BTextView::SetInsets(float left, float top, float right, float bottom)
fLayoutData->rightInset = right; fLayoutData->rightInset = right;
fLayoutData->bottomInset = bottom; fLayoutData->bottomInset = bottom;
fLayoutData->overridden = true;
InvalidateLayout(); InvalidateLayout();
Invalidate(); Invalidate();
} }
@@ -2246,7 +2326,7 @@ BTextView::SetTabWidth(float width)
fTabWidth = width; fTabWidth = width;
if (Window() != NULL) if (Window() != NULL)
_Refresh(0, fText->Length(), false); _Refresh(0, fText->Length());
} }
@@ -2324,8 +2404,12 @@ BTextView::SetWordWrap(bool wrap)
fWrap = wrap; fWrap = wrap;
if (wrap) if (wrap)
_ResetTextRect(); _ResetTextRect(); // calls _Refresh
_Refresh(0, fText->Length(), false); else
_Refresh(0, fText->Length());
if (fEditable)
ScrollToOffset(fCaretOffset);
if (updateOnScreen) { if (updateOnScreen) {
// show the caret, hilite the selection // show the caret, hilite the selection
@@ -2477,7 +2561,7 @@ BTextView::MakeResizable(bool resize, BView* resizeView)
_NewOffscreen(); _NewOffscreen();
} }
_Refresh(0, fText->Length(), false); _Refresh(0, fText->Length());
} }
@@ -2614,7 +2698,7 @@ BTextView::GetHeightForWidth(float width, float* min, float* max,
// TODO: don't change the actual text rect! // TODO: don't change the actual text rect!
fTextRect.right = fTextRect.left + width; fTextRect.right = fTextRect.left + width;
_Refresh(0, TextLength(), false); _Refresh(0, fText->Length());
if (min != NULL) if (min != NULL)
*min = fTextRect.Height(); *min = fTextRect.Height();
@@ -2741,9 +2825,8 @@ BTextView::AllocRunArray(int32 entryCount, int32* outSize)
// Call constructors explicitly as the text_run_array // Call constructors explicitly as the text_run_array
// was allocated with malloc (and has to, for backwards // was allocated with malloc (and has to, for backwards
// compatibility) // compatibility)
for (int32 i = 0; i < runArray->count; i++) { for (int32 i = 0; i < runArray->count; i++)
new (&runArray->runs[i].font) BFont; new (&runArray->runs[i].font) BFont;
}
if (outSize != NULL) if (outSize != NULL)
*outSize = size; *outSize = size;
@@ -2910,9 +2993,9 @@ BTextView::InsertText(const char* text, int32 length, int32 offset,
} }
} }
if (fStylable && runs != NULL) { if (fStylable && runs != NULL)
_SetRunArray(offset, offset + length, runs); _SetRunArray(offset, offset + length, runs);
} else { else {
// apply null-style to inserted text // apply null-style to inserted text
_ApplyStyleRange(offset, offset + length); _ApplyStyleRange(offset, offset + length);
} }
@@ -3130,7 +3213,7 @@ BTextView::_InitObject(BRect textRect, const BFont* initialFont,
fTrackingMouse = NULL; fTrackingMouse = NULL;
fLayoutData = new LayoutData; fLayoutData = new LayoutData;
fLayoutData->UpdateInsets(Bounds().OffsetToCopy(B_ORIGIN), fTextRect); _UpdateInsets(textRect);
fLastClickOffset = -1; fLastClickOffset = -1;
@@ -3160,8 +3243,7 @@ BTextView::_HandleBackspace(int32 modifiers)
} }
if (fUndo) { if (fUndo) {
TypingUndoBuffer* undoBuffer = dynamic_cast<TypingUndoBuffer*>( TypingUndoBuffer* undoBuffer = dynamic_cast<TypingUndoBuffer*>(fUndo);
fUndo);
if (!undoBuffer) { if (!undoBuffer) {
delete fUndo; delete fUndo;
fUndo = undoBuffer = new TypingUndoBuffer(this); fUndo = undoBuffer = new TypingUndoBuffer(this);
@@ -3180,7 +3262,7 @@ BTextView::_HandleBackspace(int32 modifiers)
DeleteText(fSelStart, fSelEnd); DeleteText(fSelStart, fSelEnd);
fCaretOffset = fSelEnd = fSelStart; fCaretOffset = fSelEnd = fSelStart;
_Refresh(fSelStart, fSelEnd, true); _Refresh(fSelStart, fSelEnd, fCaretOffset);
} }
@@ -3382,8 +3464,7 @@ BTextView::_HandleDelete(int32 modifiers)
} }
if (fUndo) { if (fUndo) {
TypingUndoBuffer* undoBuffer = dynamic_cast<TypingUndoBuffer*>( TypingUndoBuffer* undoBuffer = dynamic_cast<TypingUndoBuffer*>(fUndo);
fUndo);
if (!undoBuffer) { if (!undoBuffer) {
delete fUndo; delete fUndo;
fUndo = undoBuffer = new TypingUndoBuffer(this); fUndo = undoBuffer = new TypingUndoBuffer(this);
@@ -3402,7 +3483,7 @@ BTextView::_HandleDelete(int32 modifiers)
DeleteText(fSelStart, fSelEnd); DeleteText(fSelStart, fSelEnd);
fCaretOffset = fSelEnd = fSelStart; fCaretOffset = fSelEnd = fSelStart;
_Refresh(fSelStart, fSelEnd, true); _Refresh(fSelStart, fSelEnd, fCaretOffset);
} }
@@ -3632,10 +3713,10 @@ BTextView::_HandleAlphaKey(const char* bytes, int32 numBytes)
\param fromOffset The offset from where to refresh. \param fromOffset The offset from where to refresh.
\param toOffset The offset where to refresh to. \param toOffset The offset where to refresh to.
\param scroll If \c true, scroll the view to the end offset. \param scrollTo Scroll the view to \a scrollTo offset if not \c INT32_MIN.
*/ */
void void
BTextView::_Refresh(int32 fromOffset, int32 toOffset, bool scroll) BTextView::_Refresh(int32 fromOffset, int32 toOffset, int32 scrollTo)
{ {
// TODO: Cleanup // TODO: Cleanup
float saveHeight = fTextRect.Height(); float saveHeight = fTextRect.Height();
@@ -3671,8 +3752,8 @@ BTextView::_Refresh(int32 fromOffset, int32 toOffset, bool scroll)
// draw only those lines that are visible // draw only those lines that are visible
int32 fromVisible = _LineAt(BPoint(0.0f, bounds.top)); int32 fromVisible = _LineAt(BPoint(0.0f, bounds.top));
int32 toVisible = _LineAt(BPoint(0.0f, bounds.bottom)); int32 toVisible = _LineAt(BPoint(0.0f, bounds.bottom));
fromLine = max_c(fromVisible, fromLine); fromLine = std::max(fromVisible, fromLine);
toLine = min_c(toLine, toVisible); toLine = std::min(toLine, toVisible);
_AutoResize(false); _AutoResize(false);
@@ -3691,8 +3772,8 @@ BTextView::_Refresh(int32 fromOffset, int32 toOffset, bool scroll)
if (newHeight != saveHeight || fMinTextRectWidth != saveWidth) if (newHeight != saveHeight || fMinTextRectWidth != saveWidth)
_UpdateScrollbars(); _UpdateScrollbars();
if (scroll) if (scrollTo != INT32_MIN)
ScrollToOffset(fSelEnd); ScrollToOffset(scrollTo);
Flush(); Flush();
} }
@@ -3708,7 +3789,13 @@ BTextView::_RecalculateLineBreaks(int32* startLine, int32* endLine)
{ {
CALLED(); CALLED();
// are we insane? float width = fTextRect.Width();
// don't try to compute anything if the text rect is not set
if (!fTextRect.IsValid() || width == 0)
return;
// sanity check
*startLine = (*startLine < 0) ? 0 : *startLine; *startLine = (*startLine < 0) ? 0 : *startLine;
*endLine = (*endLine > fLines->NumLines() - 1) ? fLines->NumLines() - 1 *endLine = (*endLine > fLines->NumLines() - 1) ? fLines->NumLines() - 1
: *endLine; : *endLine;
@@ -3716,13 +3803,6 @@ BTextView::_RecalculateLineBreaks(int32* startLine, int32* endLine)
int32 textLength = fText->Length(); int32 textLength = fText->Length();
int32 lineIndex = (*startLine > 0) ? *startLine - 1 : 0; int32 lineIndex = (*startLine > 0) ? *startLine - 1 : 0;
int32 recalThreshold = (*fLines)[*endLine + 1]->offset; int32 recalThreshold = (*fLines)[*endLine + 1]->offset;
float width = max_c(fTextRect.Width(), 10);
// TODO: The minimum width of 10 is a work around for the following
// problem: If the text rect is too small, we are not calculating any
// line heights, not even for the first line. Maybe this is a bug
// in the algorithm, but other places in the class rely on at least
// the first line to return a valid height. Maybe "10" should really
// be the width of the very first glyph instead.
STELine* curLine = (*fLines)[lineIndex]; STELine* curLine = (*fLines)[lineIndex];
STELine* nextLine = curLine + 1; STELine* nextLine = curLine + 1;
@@ -3781,16 +3861,44 @@ BTextView::_RecalculateLineBreaks(int32* startLine, int32* endLine)
// has always a width of 0 // has always a width of 0
(*fLines)[fLines->NumLines()]->width = 0; (*fLines)[fLines->NumLines()]->width = 0;
// update the text rect // update text rect
fTextRect.left = Bounds().left + fLayoutData->leftInset;
fTextRect.right = Bounds().right - fLayoutData->rightInset;
// always set text rect bottom
float newHeight = TextHeight(0, fLines->NumLines() - 1); float newHeight = TextHeight(0, fLines->NumLines() - 1);
fTextRect.bottom = fTextRect.top + newHeight; fTextRect.bottom = fTextRect.top + newHeight;
if (!fWrap) { if (!fWrap) {
fMinTextRectWidth = fLines->MaxWidth(); fMinTextRectWidth = fLines->MaxWidth();
fTextRect.right = ceilf(fTextRect.left + fMinTextRectWidth);
// expand width if needed
switch (fAlignment) {
default:
case B_ALIGN_LEFT:
// grow right
fTextRect.right = std::max(fTextRect.right,
fTextRect.left + fMinTextRectWidth);
break;
case B_ALIGN_RIGHT:
// grow left
fTextRect.left = std::min(fTextRect.left,
fTextRect.right - fMinTextRectWidth);
break;
case B_ALIGN_CENTER:
// grow out
if (fMinTextRectWidth > fTextRect.Width()) {
fTextRect.InsetBy(ceilf((fTextRect.Width()
- fMinTextRectWidth) / 2.0f), 0);
}
break;
}
} }
*endLine = lineIndex - 1; *endLine = lineIndex - 1;
*startLine = min_c(*startLine, *endLine); *startLine = std::min(*startLine, *endLine);
} }
@@ -3881,7 +3989,7 @@ BTextView::_FindLineBreak(int32 fromOffset, float* _ascent, float* _descent,
} }
} }
delta = max_c(delta, 1); delta = std::max(delta, (int32)1);
// do not include B_ENTER-terminator into width & height calculations // do not include B_ENTER-terminator into width & height calculations
deltaWidth = _TabExpandedStyledWidth(offset, deltaWidth = _TabExpandedStyledWidth(offset,
@@ -3912,8 +4020,8 @@ BTextView::_FindLineBreak(int32 fromOffset, float* _ascent, float* _descent,
} }
} }
*_ascent = max_c(ascent, *_ascent); *_ascent = std::max(ascent, *_ascent);
*_descent = max_c(descent, *_descent); *_descent = std::max(descent, *_descent);
offset += delta; offset += delta;
delta = 0; delta = 0;
@@ -3936,12 +4044,12 @@ BTextView::_FindLineBreak(int32 fromOffset, float* _ascent, float* _descent,
break; break;
} }
*_ascent = max_c(ascent, *_ascent); *_ascent = std::max(ascent, *_ascent);
*_descent = max_c(descent, *_descent); *_descent = std::max(descent, *_descent);
} }
} }
return min_c(offset, limit); return std::min(offset, limit);
} }
@@ -4138,8 +4246,8 @@ BTextView::_StyledWidth(int32 fromOffset, int32 length, float* _ascent,
int32 numBytes; int32 numBytes;
while ((numBytes = fStyles->Iterate(fromOffset, length, fInline, &font, while ((numBytes = fStyles->Iterate(fromOffset, length, fInline, &font,
NULL, &ascent, &descent)) != 0) { NULL, &ascent, &descent)) != 0) {
maxAscent = max_c(ascent, maxAscent); maxAscent = std::max(ascent, maxAscent);
maxDescent = max_c(descent, maxDescent); maxDescent = std::max(descent, maxDescent);
#if USE_WIDTHBUFFER #if USE_WIDTHBUFFER
// Use _BWidthBuffer_ if possible // Use _BWidthBuffer_ if possible
@@ -4186,13 +4294,13 @@ BTextView::_DoInsertText(const char* text, int32 length, int32 offset,
{ {
_CancelInputMethod(); _CancelInputMethod();
if (TextLength() + length > MaxBytes()) if (fText->Length() + length > MaxBytes())
return; return;
if (fSelStart != fSelEnd) if (fSelStart != fSelEnd)
Select(fSelStart, fSelStart); Select(fSelStart, fSelStart);
const int32 textLength = TextLength(); const int32 textLength = fText->Length();
if (offset > textLength) if (offset > textLength)
offset = textLength; offset = textLength;
@@ -4200,7 +4308,7 @@ BTextView::_DoInsertText(const char* text, int32 length, int32 offset,
InsertText(text, length, offset, runs); InsertText(text, length, offset, runs);
// recalc line breaks and draw the text // recalc line breaks and draw the text
_Refresh(offset, offset + length, false); _Refresh(offset, offset + length);
} }
@@ -4224,12 +4332,11 @@ BTextView::_DrawLine(BView* view, const int32 &lineNum,
startLeft = PointAt(line->offset).x; startLeft = PointAt(line->offset).x;
} else } else
startLeft = PointAt(startOffset).x; startLeft = PointAt(startOffset).x;
} } else if (fAlignment != B_ALIGN_LEFT) {
else if (fAlignment != B_ALIGN_LEFT) {
float alignmentOffset = fTextRect.Width() - LineWidth(lineNum); float alignmentOffset = fTextRect.Width() - LineWidth(lineNum);
if (fAlignment == B_ALIGN_CENTER) if (fAlignment == B_ALIGN_CENTER)
alignmentOffset /= 2; alignmentOffset = floorf(alignmentOffset / 2);
startLeft = fTextRect.left + alignmentOffset; startLeft += alignmentOffset;
} }
int32 length = (line + 1)->offset; int32 length = (line + 1)->offset;
@@ -4242,7 +4349,8 @@ BTextView::_DrawLine(BView* view, const int32 &lineNum,
if (ByteAt((line + 1)->offset - 1) == B_ENTER) if (ByteAt((line + 1)->offset - 1) == B_ENTER)
length--; length--;
view->MovePenTo(startLeft, line->origin + line->ascent + fTextRect.top + 1); view->MovePenTo(startLeft,
line->origin + line->ascent + fTextRect.top + 1);
if (erase) { if (erase) {
eraseRect.top = line->origin + fTextRect.top; eraseRect.top = line->origin + fTextRect.top;
@@ -4268,7 +4376,7 @@ BTextView::_DrawLine(BView* view, const int32 &lineNum,
view->SetFont(font); view->SetFont(font);
view->SetHighColor(*color); view->SetHighColor(*color);
tabChars = min_c(numBytes, length); tabChars = std::min(numBytes, length);
do { do {
foundTab = fText->FindChar(B_TAB, offset, &tabChars); foundTab = fText->FindChar(B_TAB, offset, &tabChars);
if (foundTab) { if (foundTab) {
@@ -4316,24 +4424,44 @@ BTextView::_DrawLine(BView* view, const int32 &lineNum,
view->PopState(); view->PopState();
} }
int32 returnedBytes = tabChars;
const char* stringToDraw = fText->GetString(offset, &returnedBytes);
view->SetDrawingMode(textRenderingMode);
view->DrawString(stringToDraw, returnedBytes);
if (foundTab) { if (foundTab) {
float penPos = PenLocation().x - fTextRect.left; float penPos = PenLocation().x - fTextRect.left;
switch (fAlignment) {
default:
case B_ALIGN_LEFT:
// nothing more to do
break;
case B_ALIGN_RIGHT:
// subtract distance from left to line
penPos -= fTextRect.Width() - LineWidth(lineNum);
break;
case B_ALIGN_CENTER:
// subtract half distance from left to line
penPos -= floorf((fTextRect.Width()
- LineWidth(lineNum)) / 2);
break;
}
float tabWidth = _ActualTabWidth(penPos); float tabWidth = _ActualTabWidth(penPos);
if (numTabs > 1)
// add in the rest of the tabs (if there are any)
tabWidth += ((numTabs - 1) * fTabWidth); tabWidth += ((numTabs - 1) * fTabWidth);
// move pen by tab(s) width
view->MovePenBy(tabWidth, 0.0); view->MovePenBy(tabWidth, 0.0);
tabChars += numTabs; tabChars += numTabs;
} else {
int32 size = tabChars;
const char* stringToDraw = fText->GetString(offset, &size);
view->SetDrawingMode(textRenderingMode);
view->DrawString(stringToDraw, size);
} }
offset += tabChars; offset += tabChars;
length -= tabChars; length -= tabChars;
numBytes -= tabChars; numBytes -= tabChars;
tabChars = min_c(numBytes, length); tabChars = std::min(numBytes, length);
numTabs = 0; numTabs = 0;
} while (foundTab && tabChars > 0); } while (foundTab && tabChars > 0);
} }
@@ -4349,8 +4477,8 @@ BTextView::_DrawLines(int32 startLine, int32 endLine, int32 startOffset,
// clip the text // clip the text
BRect textRect(fTextRect); BRect textRect(fTextRect);
float minWidth float minWidth = Bounds().Width() - fLayoutData->leftInset
= Bounds().Width() - fLayoutData->leftInset - fLayoutData->rightInset; - fLayoutData->rightInset;
if (textRect.Width() < minWidth) if (textRect.Width() < minWidth)
textRect.right = textRect.left + minWidth; textRect.right = textRect.left + minWidth;
BRect clipRect = Bounds() & textRect; BRect clipRect = Bounds() & textRect;
@@ -4464,7 +4592,7 @@ BTextView::_DrawCaret(int32 offset, bool visible)
{ {
float lineHeight; float lineHeight;
BPoint caretPoint = PointAt(offset, &lineHeight); BPoint caretPoint = PointAt(offset, &lineHeight);
caretPoint.x = min_c(caretPoint.x, fTextRect.right); caretPoint.x = std::min(caretPoint.x, fTextRect.right);
BRect caretRect; BRect caretRect;
caretRect.left = caretRect.right = caretPoint.x; caretRect.left = caretRect.right = caretPoint.x;
@@ -4738,8 +4866,8 @@ BTextView::_MessageDropped(BMessage* message, BPoint where, BPoint offset)
return false; return false;
int32 dropOffset = OffsetAt(where); int32 dropOffset = OffsetAt(where);
if (dropOffset > TextLength()) if (dropOffset > fText->Length())
dropOffset = TextLength(); dropOffset = fText->Length();
// if this view initiated the drag, move instead of copy // if this view initiated the drag, move instead of copy
if (internalDrop) { if (internalDrop) {
@@ -4795,11 +4923,10 @@ BTextView::_PerformAutoScrolling()
// R5 does a pretty soft auto-scroll, we try to do the same by // R5 does a pretty soft auto-scroll, we try to do the same by
// simply scrolling the distance between cursor and border // simply scrolling the distance between cursor and border
if (fWhere.x > bounds.right) { if (fWhere.x > bounds.right)
scrollBy.x = fWhere.x - bounds.right; scrollBy.x = fWhere.x - bounds.right;
} else if (fWhere.x < bounds.left) { else if (fWhere.x < bounds.left)
scrollBy.x = fWhere.x - bounds.left; // negative value scrollBy.x = fWhere.x - bounds.left; // negative value
}
// prevent from scrolling out of view // prevent from scrolling out of view
if (scrollBy.x != 0.0) { if (scrollBy.x != 0.0) {
@@ -4812,11 +4939,10 @@ BTextView::_PerformAutoScrolling()
if (CountLines() > 1) { if (CountLines() > 1) {
// scroll in Y only if multiple lines! // scroll in Y only if multiple lines!
if (fWhere.y > bounds.bottom) { if (fWhere.y > bounds.bottom)
scrollBy.y = fWhere.y - bounds.bottom; scrollBy.y = fWhere.y - bounds.bottom;
} else if (fWhere.y < bounds.top) { else if (fWhere.y < bounds.top)
scrollBy.y = fWhere.y - bounds.top; // negative value scrollBy.y = fWhere.y - bounds.top; // negative value
}
// prevent from scrolling out of view // prevent from scrolling out of view
if (scrollBy.y != 0.0) { if (scrollBy.y != 0.0) {
@@ -4849,25 +4975,29 @@ BTextView::_UpdateScrollbars()
+ fLayoutData->leftInset + fLayoutData->rightInset); + fLayoutData->leftInset + fLayoutData->rightInset);
long maxRange = dataWidth - viewWidth; long maxRange = dataWidth - viewWidth;
maxRange = max_c(maxRange, 0); maxRange = std::max(maxRange, 0l);
horizontalScrollBar->SetRange(0, (float)maxRange); horizontalScrollBar->SetRange(0, (float)maxRange);
horizontalScrollBar->SetProportion((float)viewWidth / (float)dataWidth); horizontalScrollBar->SetProportion((float)viewWidth
horizontalScrollBar->SetSteps(kHorizontalScrollBarStep, dataWidth / 10); / (float)dataWidth);
horizontalScrollBar->SetSteps(kHorizontalScrollBarStep,
dataWidth / 10);
} }
// how about a vertical scroll bar? // how about a vertical scroll bar?
if (verticalScrollBar != NULL) { if (verticalScrollBar != NULL) {
long viewHeight = bounds.IntegerHeight(); long viewHeight = bounds.IntegerHeight();
long dataHeight = (long)ceilf(fTextRect.IntegerHeight() long dataHeight = (long)ceilf(fLayoutData->topInset
+ fLayoutData->topInset + fLayoutData->bottomInset); + fTextRect.IntegerHeight() + fLayoutData->bottomInset);
long maxRange = dataHeight - viewHeight; long maxRange = dataHeight - viewHeight;
maxRange = max_c(maxRange, 0); maxRange = std::max(maxRange, 0l);
verticalScrollBar->SetRange(0, maxRange); verticalScrollBar->SetRange(0, maxRange);
verticalScrollBar->SetProportion((float)viewHeight / (float)dataHeight); verticalScrollBar->SetProportion((float)viewHeight
verticalScrollBar->SetSteps(kVerticalScrollBarStep, viewHeight); / (float)dataHeight);
verticalScrollBar->SetSteps(kVerticalScrollBarStep,
viewHeight);
} }
} }
@@ -4911,25 +5041,25 @@ BTextView::_AutoResize(bool redraw)
return; return;
BRect bounds = Bounds(); BRect bounds = Bounds();
float oldWidth = bounds.Width();
float newWidth = ceilf(fLayoutData->leftInset + fTextRect.Width()
+ fLayoutData->rightInset);
if (fContainerView != NULL) { if (fContainerView != NULL) {
// NOTE: This container view thing is only used by Tracker. // NOTE: This container view thing is only used by Tracker.
// move container view if not left aligned // move container view if not left aligned
float oldWidth = bounds.Width();
float newWidth = ceilf(fLayoutData->leftInset
+ fTextRect.Width() + fLayoutData->rightInset);
if (fAlignment == B_ALIGN_CENTER) { if (fAlignment == B_ALIGN_CENTER) {
if (fmod(ceilf(newWidth - oldWidth), 2.0) != 0.0) if (fmod(ceilf(newWidth - oldWidth), 2.0) != 0.0)
newWidth += 1; newWidth += 1;
fContainerView->MoveBy(ceilf(oldWidth - newWidth) / 2, 0); fContainerView->MoveBy(ceilf(oldWidth - newWidth) / 2, 0);
} else if (fAlignment == B_ALIGN_RIGHT) { } else if (fAlignment == B_ALIGN_RIGHT)
fContainerView->MoveBy(ceilf(oldWidth - newWidth), 0); fContainerView->MoveBy(ceilf(oldWidth - newWidth), 0);
}
// resize container view // resize container view
fContainerView->ResizeBy(ceilf(newWidth - oldWidth), 0); fContainerView->ResizeBy(ceilf(newWidth - oldWidth), 0);
} }
if (redraw) if (redraw)
_RequestDrawLines(0, 0); _RequestDrawLines(0, 0);
@@ -5471,7 +5601,7 @@ BTextView::_CountProperties(BMessage* specifier, int32 form,
CALLED(); CALLED();
if (strcmp(property, "Text") == 0) { if (strcmp(property, "Text") == 0) {
reply->what = B_REPLY; reply->what = B_REPLY;
reply->AddInt32("result", TextLength()); reply->AddInt32("result", fText->Length());
reply->AddInt32("error", B_OK); reply->AddInt32("error", B_OK);
return true; return true;
} }
@@ -5539,7 +5669,7 @@ BTextView::_HandleInputMethodChanged(BMessage* message)
} }
if (confirmed) { if (confirmed) {
_Refresh(fSelStart, fSelEnd, true); _Refresh(fSelStart, fSelEnd, fSelEnd);
_ShowCaret(); _ShowCaret();
// now we need to feed ourselves the individual characters as if the // now we need to feed ourselves the individual characters as if the
@@ -5565,7 +5695,7 @@ BTextView::_HandleInputMethodChanged(BMessage* message)
prevPos = currPos; prevPos = currPos;
} }
_Refresh(fSelStart, fSelEnd, true); _Refresh(fSelStart, fSelEnd, fSelEnd);
} else { } else {
// temporarily show transient state of inline input // temporarily show transient state of inline input
int32 selectionStart = 0; int32 selectionStart = 0;
@@ -5579,10 +5709,9 @@ BTextView::_HandleInputMethodChanged(BMessage* message)
const int32 inlineOffset = fInline->Offset(); const int32 inlineOffset = fInline->Offset();
InsertText(string, stringLen, fSelStart, NULL); InsertText(string, stringLen, fSelStart, NULL);
_Refresh(inlineOffset, fSelEnd, true); _Refresh(inlineOffset, fSelEnd, fSelEnd);
_ShowCaret(); _ShowCaret();
} }
} }
@@ -5627,8 +5756,8 @@ BTextView::_CancelInputMethod()
fInline = NULL; fInline = NULL;
if (inlineInput->IsActive() && Window()) { if (inlineInput->IsActive() && Window()) {
_Refresh(inlineInput->Offset(), fText->Length() - inlineInput->Offset(), _Refresh(inlineInput->Offset(), fText->Length()
false); - inlineInput->Offset());
BMessage message(B_INPUT_METHOD_EVENT); BMessage message(B_INPUT_METHOD_EVENT);
message.AddInt32("be:opcode", B_INPUT_METHOD_STOPPED); message.AddInt32("be:opcode", B_INPUT_METHOD_STOPPED);
@@ -5677,7 +5806,7 @@ BTextView::_LineAt(const BPoint& point) const
bool bool
BTextView::_IsOnEmptyLastLine(int32 offset) const BTextView::_IsOnEmptyLastLine(int32 offset) const
{ {
return (offset == TextLength() && offset > 0 return (offset == fText->Length() && offset > 0
&& fText->RealCharAt(offset - 1) == B_ENTER); && fText->RealCharAt(offset - 1) == B_ENTER);
} }
@@ -5734,7 +5863,7 @@ BTextView::_ShowContextMenu(BPoint where)
GetSelection(&start, &finish); GetSelection(&start, &finish);
bool canEdit = IsEditable(); bool canEdit = IsEditable();
int32 length = TextLength(); int32 length = fText->Length();
BPopUpMenu* menu = new BPopUpMenu(B_EMPTY_STRING, false, false); BPopUpMenu* menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
@@ -5804,6 +5933,39 @@ BTextView::_FilterDisallowedChars(char* text, ssize_t& length,
} }
void
BTextView::_UpdateInsets(const BRect& rect)
{
// do not update insets if SetInsets() was called
if (fLayoutData->overridden)
return;
const BRect& bounds = Bounds();
// we disallow negative insets, as they would cause parts of the
// text to be hidden
fLayoutData->leftInset = rect.left >= bounds.left
? rect.left - bounds.left : 0;
fLayoutData->topInset = rect.top >= bounds.top
? rect.top - bounds.top : 0;
fLayoutData->rightInset = bounds.right >= rect.right
? bounds.right - rect.right : 0;
fLayoutData->bottomInset = bounds.bottom >= rect.bottom
? bounds.bottom - rect.bottom : 0;
// only add default insets if text rect is set to bounds
if (rect == bounds && (fEditable || fSelectable)) {
float hPadding = be_control_look->DefaultLabelSpacing();
float hInset = floorf(hPadding / 2.0f);
float vInset = 1;
fLayoutData->leftInset += hInset;
fLayoutData->topInset += vInset;
fLayoutData->rightInset += hInset;
fLayoutData->bottomInset += vInset;
}
}
// #pragma mark - BTextView::TextTrackState // #pragma mark - BTextView::TextTrackState
+14 -12
View File
@@ -366,11 +366,14 @@ BTextWidget::StartEdit(BRect bounds, BPoseView* view, BPose* pose)
return; return;
} }
// TODO fix text rect being off by a pixel on some files
// get bounds with full text length // get bounds with full text length
BRect rect(bounds); BRect rect(bounds);
BRect textRect(bounds); BRect textRect(bounds);
rect.OffsetBy(-2, -1);
rect.right += 1; // label offset
rect.OffsetBy(1, -2);
BFont font; BFont font;
view->GetFont(&font); view->GetFont(&font);
@@ -378,22 +381,21 @@ BTextWidget::StartEdit(BRect bounds, BPoseView* view, BPose* pose)
&font, 0, B_FOLLOW_ALL, B_WILL_DRAW); &font, 0, B_FOLLOW_ALL, B_WILL_DRAW);
textView->SetWordWrap(false); textView->SetWordWrap(false);
textView->SetInsets(2, 2, 2, 2);
DisallowMetaKeys(textView); DisallowMetaKeys(textView);
fText->SetUpEditing(textView); fText->SetUpEditing(textView);
textView->AddFilter(new BMessageFilter(B_KEY_DOWN, TextViewFilter)); textView->AddFilter(new BMessageFilter(B_KEY_DOWN, TextViewFilter));
rect.right = rect.left + textView->LineWidth() + 3; rect.right = rect.left + textView->LineWidth();
// center new width, if necessary rect.bottom = rect.top + textView->LineHeight() - 1;
if (view->ViewMode() == kIconMode
|| (view->ViewMode() == kListMode && fAlignment == B_ALIGN_CENTER)) { // enlarge rect by inset amount
rect.OffsetBy(bounds.Width() / 2 - rect.Width() / 2, 0); rect.InsetBy(-2, -2);
}
// undo label offset
textRect = rect.OffsetToCopy(-1, 2);
rect.bottom = rect.top + textView->LineHeight() + 1;
textRect = rect.OffsetToCopy(2, 1);
textRect.right -= 3;
textRect.bottom--;
textView->SetTextRect(textRect); textView->SetTextRect(textRect);
BPoint origin = view->LeftTop(); BPoint origin = view->LeftTop();
@@ -302,7 +302,6 @@ HeaderView::Draw(BRect)
// Font information // Font information
font_height fontMetrics; font_height fontMetrics;
BFont currentFont; BFont currentFont;
float lineHeight = 0;
float lineBase = 0; float lineBase = 0;
// Draw the main title if the user is not currently editing it // Draw the main title if the user is not currently editing it
@@ -311,7 +310,6 @@ HeaderView::Draw(BRect)
SetFontSize(be_bold_font->Size()); SetFontSize(be_bold_font->Size());
GetFont(&currentFont); GetFont(&currentFont);
currentFont.GetHeight(&fontMetrics); currentFont.GetHeight(&fontMetrics);
lineHeight = CurrentFontHeight() + 5;
lineBase = fTitleRect.bottom - fontMetrics.descent; lineBase = fTitleRect.bottom - fontMetrics.descent;
SetHighColor(labelColor); SetHighColor(labelColor);
MovePenTo(BPoint(fIconRect.right + 6, lineBase)); MovePenTo(BPoint(fIconRect.right + 6, lineBase));
@@ -146,6 +146,7 @@ PreviewView::AddPreview()
fNoPreview->SetExplicitSize(BSize(previewWidth, previewHeight)); fNoPreview->SetExplicitSize(BSize(previewWidth, previewHeight));
fNoPreview->ResizeTo(previewWidth, previewHeight); fNoPreview->ResizeTo(previewWidth, previewHeight);
fNoPreview->SetTextRect(BRect(0, 0, previewWidth, previewHeight));
fNoPreview->SetInsets(0, previewHeight / 3, 0, 0); fNoPreview->SetInsets(0, previewHeight / 3, 0, 0);
return fSaverView; return fSaverView;