* Made BScrollView work when using it with the layout system.

* Added a layout friendly constructor - it's not so nice to use, though, since
  the original one already doesn't get a BRect (we just don't need the
  resizing mode, and have to set the B_SUPPORTS_LAYOUT flag).
* Refactored size/frame computation a bit.
* Cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28258 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-10-21 10:14:24 +00:00
parent aa12f6f8fc
commit 9e163a7a93
3 changed files with 311 additions and 208 deletions
+81 -62
View File
@@ -1,95 +1,114 @@
/*
** Copyright 2004-2008, Haiku Inc. All Rights Reserved.
** Distributed under the terms of the MIT license.
*/
* Copyright 2004-2008, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT license.
*/
#ifndef _SCROLL_VIEW_H
#define _SCROLL_VIEW_H
/** The BScrollView is a convenience class to add a scrolling
* mechanism to the target view.
*/
#include <ScrollBar.h>
/*! The BScrollView is a convenience class to add a scrolling
mechanism to the target view.
*/
class BScrollView : public BView {
public:
BScrollView(const char *name, BView *target,
uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP,
uint32 flags = 0, bool horizontal = false, bool vertical = false,
border_style border = B_FANCY_BORDER);
BScrollView(BMessage *archive);
virtual ~BScrollView();
public:
BScrollView(const char* name, BView* target,
uint32 resizingMode
= B_FOLLOW_LEFT | B_FOLLOW_TOP,
uint32 flags = 0, bool horizontal = false,
bool vertical = false,
border_style border = B_FANCY_BORDER);
BScrollView(const char* name, BView* target,
uint32 flags, bool horizontal, bool vertical,
border_style border = B_FANCY_BORDER);
BScrollView(BMessage* archive);
virtual ~BScrollView();
static BArchivable *Instantiate(BMessage *archive);
virtual status_t Archive(BMessage *archive, bool deep = true) const;
static BArchivable* Instantiate(BMessage* archive);
virtual status_t Archive(BMessage* archive, bool deep = true) const;
virtual void Draw(BRect updateRect);
virtual void AttachedToWindow();
virtual void Draw(BRect updateRect);
virtual void AttachedToWindow();
BScrollBar *ScrollBar(orientation posture) const;
BScrollBar* ScrollBar(orientation posture) const;
virtual void SetBorder(border_style border);
border_style Border() const;
virtual void SetBorder(border_style border);
border_style Border() const;
virtual status_t SetBorderHighlighted(bool state);
bool IsBorderHighlighted() const;
virtual status_t SetBorderHighlighted(bool state);
bool IsBorderHighlighted() const;
void SetTarget(BView *target);
BView *Target() const;
void SetTarget(BView* target);
BView* Target() const;
virtual void MessageReceived(BMessage *message);
virtual void MouseDown(BPoint point);
virtual void MessageReceived(BMessage* message);
virtual void MouseDown(BPoint point);
virtual void WindowActivated(bool active);
virtual void MouseUp(BPoint point);
virtual void MouseMoved(BPoint point, uint32 code, const BMessage *msg);
virtual void WindowActivated(bool active);
virtual void MouseUp(BPoint point);
virtual void MouseMoved(BPoint point, uint32 code,
const BMessage* dragMessage);
virtual void DetachedFromWindow();
virtual void AllAttached();
virtual void AllDetached();
virtual void DetachedFromWindow();
virtual void AllAttached();
virtual void AllDetached();
virtual void FrameMoved(BPoint position);
virtual void FrameResized(float width, float height);
virtual void FrameMoved(BPoint position);
virtual void FrameResized(float width, float height);
virtual BHandler *ResolveSpecifier(BMessage *message, int32 index,
BMessage *specifier, int32 form, const char *property);
virtual BHandler* ResolveSpecifier(BMessage* message, int32 index,
BMessage* specifier, int32 form,
const char* property);
virtual void ResizeToPreferred();
virtual void GetPreferredSize(float *_width, float *_height);
virtual void MakeFocus(bool state = true);
virtual status_t GetSupportedSuites(BMessage *data);
virtual void ResizeToPreferred();
virtual void GetPreferredSize(float* _width, float* _height);
virtual void MakeFocus(bool state = true);
virtual status_t GetSupportedSuites(BMessage* data);
virtual BSize MinSize();
virtual BSize PreferredSize();
virtual BSize MinSize();
virtual BSize PreferredSize();
// private or reserved methods are following
virtual void InvalidateLayout(bool descendants = false);
virtual void DoLayout();
virtual status_t Perform(perform_code d, void *arg);
// private or reserved methods are following
private:
friend class BView;
virtual status_t Perform(perform_code d, void* arg);
virtual void _ReservedScrollView1();
virtual void _ReservedScrollView2();
virtual void _ReservedScrollView3();
virtual void _ReservedScrollView4();
private:
friend class BView;
BScrollView &operator=(const BScrollView &);
virtual void _ReservedScrollView1();
virtual void _ReservedScrollView2();
virtual void _ReservedScrollView3();
virtual void _ReservedScrollView4();
static BRect CalcFrame(BView *target, bool h, bool v, border_style);
static float BorderSize(border_style border);
static int32 ModifyFlags(int32 flags, border_style);
BScrollView& operator=(const BScrollView& other);
BView *fTarget;
BScrollBar *fHorizontalScrollBar;
BScrollBar *fVerticalScrollBar;
border_style fBorder;
uint16 fPreviousWidth;
uint16 fPreviousHeight;
bool fHighlighted;
void _Init(bool horizontal, bool vertical);
float _BorderSize() const;
BRect _InnerFrame() const;
BSize _ComputeSize(BSize targetSize) const;
BRect _ComputeFrame(BRect targetRect) const;
uint32 _reserved[3];
static BRect _ComputeFrame(BRect frame, bool horizontal,
bool vertical, border_style border);
static BRect _ComputeFrame(BView* target, bool horizontal,
bool vertical, border_style border);
static float _BorderSize(border_style border);
static int32 _ModifyFlags(int32 flags, border_style border);
BView* fTarget;
BScrollBar* fHorizontalScrollBar;
BScrollBar* fVerticalScrollBar;
border_style fBorder;
uint16 fPreviousWidth;
uint16 fPreviousHeight;
bool fHighlighted;
uint32 _reserved[3];
};
#endif /* _SCROLL_VIEW_H */
+6 -6
View File
@@ -175,7 +175,7 @@ public:
virtual void ScrollToOffset(int32 inOffset);
void ScrollToSelection();
void Highlight(int32 startOffset, int32 endOffset);
void Highlight(int32 startOffset, int32 endOffset);
void SetTextRect(BRect rect);
BRect TextRect() const;
@@ -208,9 +208,9 @@ public:
BView* resizeView = NULL);
bool IsResizable() const;
void SetDoesUndo(bool undo);
bool DoesUndo() const;
bool DoesUndo() const;
void HideTyping(bool enabled);
bool IsTypingHidden() const;
bool IsTypingHidden() const;
virtual void ResizeToPreferred();
virtual void GetPreferredSize(float* _width, float* _height);
@@ -331,7 +331,7 @@ private:
int32 startOffset = -1, bool erase = false);
void _DrawCaret(int32 offset);
void _ShowCaret();
void _HideCaret();
void _HideCaret();
void _InvertCaret();
void _DragCaret(int32 offset);
@@ -348,7 +348,7 @@ private:
bool _MessageDropped(BMessage* inMessage,
BPoint where, BPoint offset);
void _PerformAutoScrolling();
void _PerformAutoScrolling();
void _UpdateScrollbars();
void _AutoResize(bool doRedraw = true);
@@ -418,7 +418,7 @@ private:
uint32 _reserved[8];
static BPrivate::WidthBuffer* sWidths;
static BPrivate::WidthBuffer* sWidths;
};
#endif // _TEXTVIEW_H
+224 -140
View File
@@ -17,73 +17,23 @@ static const float kPlainBorderSize = 1;
BScrollView::BScrollView(const char *name, BView *target, uint32 resizingMode,
uint32 flags, bool horizontal, bool vertical, border_style border)
: BView(CalcFrame(target, horizontal, vertical, border), name,
resizingMode, ModifyFlags(flags, border)),
uint32 flags, bool horizontal, bool vertical, border_style border)
: BView(_ComputeFrame(target, horizontal, vertical, border), name,
resizingMode, _ModifyFlags(flags, border)),
fTarget(target),
fHorizontalScrollBar(NULL),
fVerticalScrollBar(NULL),
fBorder(border),
fHighlighted(false)
fBorder(border)
{
BRect targetFrame;
if (fTarget) {
// layout target and add it
fTarget->TargetedByScrollView(this);
fTarget->MoveTo(B_ORIGIN);
if (border != B_NO_BORDER)
fTarget->MoveBy(BorderSize(border), BorderSize(border));
AddChild(fTarget);
targetFrame = fTarget->Frame();
} else {
// no target specified
targetFrame = Bounds();
if (horizontal)
targetFrame.bottom -= B_H_SCROLL_BAR_HEIGHT + 1;
if (vertical)
targetFrame.right -= B_V_SCROLL_BAR_WIDTH + 1;
if (border == B_FANCY_BORDER) {
targetFrame.bottom--;
targetFrame.right--;
}
}
_Init(horizontal, vertical);
}
if (horizontal) {
BRect rect = targetFrame;
rect.top = rect.bottom + 1;
rect.bottom = rect.top + B_H_SCROLL_BAR_HEIGHT;
if (border != B_NO_BORDER || vertical) {
// extend scrollbar so that it overlaps one pixel with vertical scrollbar
rect.right++;
}
if (border != B_NO_BORDER) {
// the scrollbar draws part of the surrounding frame on the left
rect.left--;
}
fHorizontalScrollBar = new BScrollBar(rect, "_HSB_", fTarget, 0, 1000, B_HORIZONTAL);
AddChild(fHorizontalScrollBar);
}
if (vertical) {
BRect rect = targetFrame;
rect.left = rect.right + 1;
rect.right = rect.left + B_V_SCROLL_BAR_WIDTH;
if (border != B_NO_BORDER || horizontal) {
// extend scrollbar so that it overlaps one pixel with vertical scrollbar
rect.bottom++;
}
if (border != B_NO_BORDER) {
// the scrollbar draws part of the surrounding frame on the left
rect.top--;
}
fVerticalScrollBar = new BScrollBar(rect, "_VSB_", fTarget, 0, 1000, B_VERTICAL);
AddChild(fVerticalScrollBar);
}
fPreviousWidth = uint16(Bounds().Width());
fPreviousHeight = uint16(Bounds().Height());
BScrollView::BScrollView(const char* name, BView* target, uint32 flags,
bool horizontal, bool vertical, border_style border)
: BView(name, _ModifyFlags(flags, border) | B_SUPPORTS_LAYOUT),
fTarget(target),
fBorder(border)
{
_Init(horizontal, vertical);
}
@@ -116,7 +66,7 @@ BScrollView::BScrollView(BMessage *archive)
BScrollBar *bar = dynamic_cast<BScrollBar *>(view);
if (bar == NULL)
continue;
if (bar->Orientation() == B_HORIZONTAL)
fHorizontalScrollBar = bar;
else if (bar->Orientation() == B_VERTICAL)
@@ -133,6 +83,76 @@ BScrollView::~BScrollView()
}
void
BScrollView::_Init(bool horizontal, bool vertical)
{
fHorizontalScrollBar = NULL;
fVerticalScrollBar = NULL;
fHighlighted = false;
BRect targetFrame;
if (fTarget) {
// layout target and add it
fTarget->TargetedByScrollView(this);
fTarget->MoveTo(B_ORIGIN);
if (fBorder != B_NO_BORDER)
fTarget->MoveBy(_BorderSize(), _BorderSize());
AddChild(fTarget);
targetFrame = fTarget->Frame();
} else {
// no target specified
targetFrame = Bounds();
if (horizontal)
targetFrame.bottom -= B_H_SCROLL_BAR_HEIGHT + 1;
if (vertical)
targetFrame.right -= B_V_SCROLL_BAR_WIDTH + 1;
if (fBorder == B_FANCY_BORDER) {
targetFrame.bottom--;
targetFrame.right--;
}
}
if (horizontal) {
BRect rect = targetFrame;
rect.top = rect.bottom + 1;
rect.bottom = rect.top + B_H_SCROLL_BAR_HEIGHT;
if (fBorder != B_NO_BORDER || vertical) {
// extend scrollbar so that it overlaps one pixel with vertical scrollbar
rect.right++;
}
if (fBorder != B_NO_BORDER) {
// the scrollbar draws part of the surrounding frame on the left
rect.left--;
}
fHorizontalScrollBar = new BScrollBar(rect, "_HSB_", fTarget, 0, 1000,
B_HORIZONTAL);
AddChild(fHorizontalScrollBar);
}
if (vertical) {
BRect rect = targetFrame;
rect.left = rect.right + 1;
rect.right = rect.left + B_V_SCROLL_BAR_WIDTH;
if (fBorder != B_NO_BORDER || horizontal) {
// extend scrollbar so that it overlaps one pixel with vertical scrollbar
rect.bottom++;
}
if (fBorder != B_NO_BORDER) {
// the scrollbar draws part of the surrounding frame on the left
rect.top--;
}
fVerticalScrollBar = new BScrollBar(rect, "_VSB_", fTarget, 0, 1000,
B_VERTICAL);
AddChild(fVerticalScrollBar);
}
fPreviousWidth = uint16(Bounds().Width());
fPreviousHeight = uint16(Bounds().Height());
}
BArchivable *
BScrollView::Instantiate(BMessage *archive)
{
@@ -183,8 +203,8 @@ BScrollView::AttachedToWindow()
BRect bounds = ConvertToScreen(Bounds());
BRect windowBounds = Window()->Frame();
if (bounds.right - BorderSize(fBorder) != windowBounds.right
|| bounds.bottom - BorderSize(fBorder) != windowBounds.bottom)
if (bounds.right - _BorderSize() != windowBounds.right
|| bounds.bottom - _BorderSize() != windowBounds.bottom)
return;
if (fHorizontalScrollBar)
@@ -237,7 +257,7 @@ BScrollView::Draw(BRect updateRect)
StrokeLine(bounds.LeftBottom(), bounds.LeftTop());
bounds.left++;
StrokeLine(bounds.LeftTop(), bounds.RightTop());
SetHighColor(ui_color(B_SHINE_COLOR));
StrokeLine(bounds.LeftBottom(), bounds.RightBottom());
bounds.top++;
@@ -263,7 +283,7 @@ BScrollView::SetBorder(border_style border)
if (fBorder == border)
return;
float offset = BorderSize(fBorder) - BorderSize(border);
float offset = _BorderSize() - _BorderSize(border);
float resize = 2 * offset;
float horizontalGap = 0, verticalGap = 0;
@@ -304,7 +324,7 @@ BScrollView::SetBorder(border_style border)
fVerticalScrollBar->ResizeBy(0, resize + verticalGap - change);
}
SetFlags(ModifyFlags(Flags(), border));
SetFlags(_ModifyFlags(Flags(), border));
}
@@ -327,19 +347,12 @@ BScrollView::SetBorderHighlighted(bool state)
fHighlighted = state;
/* The BeBook describes something like this:
if (LockLooper()) {
Draw(Bounds());
UnlockLooper();
}
*/
// but this is much cleaner, I think:
BRect bounds = Bounds();
Invalidate(BRect(bounds.left, bounds.top, bounds.right, bounds.top));
Invalidate(BRect(bounds.left, bounds.top + 1, bounds.left, bounds.bottom - 1));
Invalidate(BRect(bounds.right, bounds.top + 1, bounds.right, bounds.bottom - 1));
Invalidate(BRect(bounds.left, bounds.top + 1, bounds.left,
bounds.bottom - 1));
Invalidate(BRect(bounds.right, bounds.top + 1, bounds.right,
bounds.bottom - 1));
Invalidate(BRect(bounds.left, bounds.bottom, bounds.right, bounds.bottom));
return B_OK;
@@ -373,7 +386,9 @@ BScrollView::SetTarget(BView *target)
fVerticalScrollBar->SetTarget(target);
if (target != NULL) {
target->MoveTo(BorderSize(fBorder), BorderSize(fBorder));
target->MoveTo(_BorderSize(), _BorderSize());
BRect innerFrame = _InnerFrame();
target->ResizeTo(innerFrame.Width(), innerFrame.Height());
target->TargetedByScrollView(this);
AddChild(target, ChildAt(0));
@@ -440,7 +455,7 @@ BScrollView::FrameResized(float width, float height)
// changes in width
BRect bounds = Bounds();
float border = BorderSize(fBorder) - 1;
float border = _BorderSize() - 1;
if (bounds.Width() > fPreviousWidth) {
// invalidate the region between the old and the new right border
@@ -475,52 +490,88 @@ BScrollView::FrameResized(float width, float height)
}
void
void
BScrollView::ResizeToPreferred()
{
BView::ResizeToPreferred();
}
void
void
BScrollView::GetPreferredSize(float *_width, float *_height)
{
BRect frame = CalcFrame(fTarget, fHorizontalScrollBar, fVerticalScrollBar, fBorder);
if (fTarget != NULL) {
float width, height;
fTarget->GetPreferredSize(&width, &height);
frame.right += width - fTarget->Frame().Width();
frame.bottom += height - fTarget->Frame().Height();
}
BSize size = PreferredSize();
if (_width)
*_width = frame.Width();
*_width = size.width;
if (_height)
*_height = frame.Height();
*_height = size.height;
}
float
BScrollView::_BorderSize() const
{
return _BorderSize(fBorder);
}
/** This static method is used to calculate the frame that the
* ScrollView will cover depending on the frame of its target
* and which border style is used.
* It is used in the constructor and at other places.
*/
BRect
BScrollView::CalcFrame(BView *target, bool horizontal, bool vertical, border_style border)
BScrollView::_InnerFrame() const
{
BRect frame = target != NULL ? target->Frame() : BRect(0, 0, 80, 80);
BRect frame = Bounds();
float borderSize = _BorderSize();
frame.InsetBy(borderSize, borderSize);
if (fHorizontalScrollBar != NULL) {
frame.bottom -= B_H_SCROLL_BAR_HEIGHT;
if (borderSize == 0)
frame.bottom--;
}
if (fVerticalScrollBar != NULL) {
frame.right -= B_V_SCROLL_BAR_WIDTH;
if (borderSize == 0)
frame.right--;
}
return frame;
}
BSize
BScrollView::_ComputeSize(BSize targetSize) const
{
BRect frame = _ComputeFrame(
BRect(0, 0, targetSize.width, targetSize.height));
return BSize(frame.Width(), frame.Height());
}
BRect
BScrollView::_ComputeFrame(BRect targetRect) const
{
return _ComputeFrame(targetRect, fHorizontalScrollBar != NULL,
fVerticalScrollBar != NULL, fBorder);
}
/*! This static method is used to calculate the frame that the
ScrollView will cover depending on the frame of its target
and which border style is used.
It is used in the constructor and at other places.
*/
/*static*/ BRect
BScrollView::_ComputeFrame(BRect frame, bool horizontal, bool vertical,
border_style border)
{
if (vertical)
frame.right += B_V_SCROLL_BAR_WIDTH;
if (horizontal)
frame.bottom += B_H_SCROLL_BAR_HEIGHT;
float borderSize = BorderSize(border);
float borderSize = _BorderSize(border);
frame.InsetBy(-borderSize, -borderSize);
if (borderSize == 0) {
@@ -534,11 +585,19 @@ BScrollView::CalcFrame(BView *target, bool horizontal, bool vertical, border_sty
}
/** This method returns the size of the specified border
*/
/*static*/ BRect
BScrollView::_ComputeFrame(BView *target, bool horizontal, bool vertical,
border_style border)
{
return _ComputeFrame(target != NULL ? target->Frame() : BRect(0, 0, 16, 16),
horizontal, vertical, border);
}
float
BScrollView::BorderSize(border_style border)
/*! This method returns the size of the specified border.
*/
/*static*/ float
BScrollView::_BorderSize(border_style border)
{
if (border == B_FANCY_BORDER)
return kFancyBorderSize;
@@ -549,12 +608,11 @@ BScrollView::BorderSize(border_style border)
}
/** This method changes the "flags" argument as passed on to
* the BView constructor.
*/
int32
BScrollView::ModifyFlags(int32 flags, border_style border)
/*! This method changes the "flags" argument as passed on to
the BView constructor.
*/
/*static*/ int32
BScrollView::_ModifyFlags(int32 flags, border_style border)
{
// We either need B_FULL_UPDATE_ON_RESIZE or
// B_FRAME_EVENTS if we have to draw a border
@@ -575,21 +633,22 @@ BScrollView::WindowActivated(bool active)
}
void
void
BScrollView::MakeFocus(bool state)
{
BView::MakeFocus(state);
}
BHandler *
BScrollView::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, int32 form, const char *property)
BHandler*
BScrollView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
int32 form, const char* property)
{
return BView::ResolveSpecifier(msg, index, specifier, form, property);
}
status_t
status_t
BScrollView::GetSupportedSuites(BMessage *data)
{
return BView::GetSupportedSuites(data);
@@ -599,17 +658,8 @@ BScrollView::GetSupportedSuites(BMessage *data)
BSize
BScrollView::MinSize()
{
// TODO: This is not yet correct.
BSize size = (fTarget ? fTarget->MinSize() : BSize(-1, -1));
if (fVerticalScrollBar)
size.width += B_V_SCROLL_BAR_WIDTH;
if (fHorizontalScrollBar)
size.height += B_H_SCROLL_BAR_HEIGHT;
float borderSize = BorderSize(fBorder);
size.width += 2 * borderSize;
size.height += 2 * borderSize;
BSize size = _ComputeSize(fTarget != NULL ? fTarget->MinSize()
: BSize(16, 16));
return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
}
@@ -618,22 +668,56 @@ BScrollView::MinSize()
BSize
BScrollView::PreferredSize()
{
// TODO: This is not yet correct.
BSize size = (fTarget ? fTarget->PreferredSize() : BSize(-1, -1));
if (fVerticalScrollBar)
size.width += B_V_SCROLL_BAR_WIDTH;
if (fHorizontalScrollBar)
size.height += B_H_SCROLL_BAR_HEIGHT;
float borderSize = BorderSize(fBorder);
size.width += 2 * borderSize;
size.height += 2 * borderSize;
BSize size = _ComputeSize(fTarget != NULL ? fTarget->PreferredSize()
: BSize(32, 32));
return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
}
void
BScrollView::InvalidateLayout(bool descendants)
{
BView::InvalidateLayout(descendants);
}
void
BScrollView::DoLayout()
{
if (!(Flags() & B_SUPPORTS_LAYOUT))
return;
// If the user set a layout, we let the base class version call its
// hook.
if (GetLayout()) {
BView::DoLayout();
return;
}
BRect innerFrame = _InnerFrame();
if (fTarget != NULL) {
fTarget->MoveTo(innerFrame.left, innerFrame.top);
fTarget->ResizeTo(innerFrame.Width(), innerFrame.Height());
//BLayoutUtils::AlignInFrame(fTarget, fTarget->Bounds());
}
if (fHorizontalScrollBar != NULL) {
fHorizontalScrollBar->MoveTo(innerFrame.left, innerFrame.bottom);
fHorizontalScrollBar->ResizeTo(innerFrame.Width(),
fHorizontalScrollBar->Bounds().Height());
}
if (fVerticalScrollBar != NULL) {
fVerticalScrollBar->MoveTo(innerFrame.right, innerFrame.top);
fVerticalScrollBar->ResizeTo(fVerticalScrollBar->Bounds().Width(),
innerFrame.Height());
}
}
status_t
BScrollView::Perform(perform_code code, void* _data)
{