* 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
+50 -31
View File
@@ -1,33 +1,38 @@
/* /*
** Copyright 2004-2008, Haiku Inc. All Rights Reserved. * Copyright 2004-2008, Haiku Inc. All Rights Reserved.
** Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
*/ */
#ifndef _SCROLL_VIEW_H #ifndef _SCROLL_VIEW_H
#define _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> #include <ScrollBar.h>
/*! The BScrollView is a convenience class to add a scrolling
mechanism to the target view.
*/
class BScrollView : public BView { class BScrollView : public BView {
public: public:
BScrollView(const char *name, BView *target, BScrollView(const char* name, BView* target,
uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 resizingMode
uint32 flags = 0, bool horizontal = false, bool vertical = false, = B_FOLLOW_LEFT | B_FOLLOW_TOP,
uint32 flags = 0, bool horizontal = false,
bool vertical = false,
border_style border = B_FANCY_BORDER); border_style border = B_FANCY_BORDER);
BScrollView(BMessage *archive); BScrollView(const char* name, BView* target,
uint32 flags, bool horizontal, bool vertical,
border_style border = B_FANCY_BORDER);
BScrollView(BMessage* archive);
virtual ~BScrollView(); virtual ~BScrollView();
static BArchivable *Instantiate(BMessage *archive); static BArchivable* Instantiate(BMessage* archive);
virtual status_t Archive(BMessage *archive, bool deep = true) const; virtual status_t Archive(BMessage* archive, bool deep = true) const;
virtual void Draw(BRect updateRect); virtual void Draw(BRect updateRect);
virtual void AttachedToWindow(); virtual void AttachedToWindow();
BScrollBar *ScrollBar(orientation posture) const; BScrollBar* ScrollBar(orientation posture) const;
virtual void SetBorder(border_style border); virtual void SetBorder(border_style border);
border_style Border() const; border_style Border() const;
@@ -35,15 +40,16 @@ class BScrollView : public BView {
virtual status_t SetBorderHighlighted(bool state); virtual status_t SetBorderHighlighted(bool state);
bool IsBorderHighlighted() const; bool IsBorderHighlighted() const;
void SetTarget(BView *target); void SetTarget(BView* target);
BView *Target() const; BView* Target() const;
virtual void MessageReceived(BMessage *message); virtual void MessageReceived(BMessage* message);
virtual void MouseDown(BPoint point); virtual void MouseDown(BPoint point);
virtual void WindowActivated(bool active); virtual void WindowActivated(bool active);
virtual void MouseUp(BPoint point); virtual void MouseUp(BPoint point);
virtual void MouseMoved(BPoint point, uint32 code, const BMessage *msg); virtual void MouseMoved(BPoint point, uint32 code,
const BMessage* dragMessage);
virtual void DetachedFromWindow(); virtual void DetachedFromWindow();
virtual void AllAttached(); virtual void AllAttached();
@@ -52,22 +58,26 @@ class BScrollView : public BView {
virtual void FrameMoved(BPoint position); virtual void FrameMoved(BPoint position);
virtual void FrameResized(float width, float height); virtual void FrameResized(float width, float height);
virtual BHandler *ResolveSpecifier(BMessage *message, int32 index, virtual BHandler* ResolveSpecifier(BMessage* message, int32 index,
BMessage *specifier, int32 form, const char *property); BMessage* specifier, int32 form,
const char* property);
virtual void ResizeToPreferred(); virtual void ResizeToPreferred();
virtual void GetPreferredSize(float *_width, float *_height); virtual void GetPreferredSize(float* _width, float* _height);
virtual void MakeFocus(bool state = true); virtual void MakeFocus(bool state = true);
virtual status_t GetSupportedSuites(BMessage *data); virtual status_t GetSupportedSuites(BMessage* data);
virtual BSize MinSize(); virtual BSize MinSize();
virtual BSize PreferredSize(); virtual BSize PreferredSize();
virtual void InvalidateLayout(bool descendants = false);
virtual void DoLayout();
// private or reserved methods are following // private or reserved methods are following
virtual status_t Perform(perform_code d, void *arg); virtual status_t Perform(perform_code d, void* arg);
private: private:
friend class BView; friend class BView;
virtual void _ReservedScrollView1(); virtual void _ReservedScrollView1();
@@ -75,15 +85,24 @@ class BScrollView : public BView {
virtual void _ReservedScrollView3(); virtual void _ReservedScrollView3();
virtual void _ReservedScrollView4(); virtual void _ReservedScrollView4();
BScrollView &operator=(const BScrollView &); BScrollView& operator=(const BScrollView& other);
static BRect CalcFrame(BView *target, bool h, bool v, border_style); void _Init(bool horizontal, bool vertical);
static float BorderSize(border_style border); float _BorderSize() const;
static int32 ModifyFlags(int32 flags, border_style); BRect _InnerFrame() const;
BSize _ComputeSize(BSize targetSize) const;
BRect _ComputeFrame(BRect targetRect) const;
BView *fTarget; static BRect _ComputeFrame(BRect frame, bool horizontal,
BScrollBar *fHorizontalScrollBar; bool vertical, border_style border);
BScrollBar *fVerticalScrollBar; 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; border_style fBorder;
uint16 fPreviousWidth; uint16 fPreviousWidth;
uint16 fPreviousHeight; uint16 fPreviousHeight;
+217 -133
View File
@@ -18,72 +18,22 @@ static const float kPlainBorderSize = 1;
BScrollView::BScrollView(const char *name, BView *target, uint32 resizingMode, BScrollView::BScrollView(const char *name, BView *target, uint32 resizingMode,
uint32 flags, bool horizontal, bool vertical, border_style border) uint32 flags, bool horizontal, bool vertical, border_style border)
: BView(CalcFrame(target, horizontal, vertical, border), name, : BView(_ComputeFrame(target, horizontal, vertical, border), name,
resizingMode, ModifyFlags(flags, border)), resizingMode, _ModifyFlags(flags, border)),
fTarget(target), fTarget(target),
fHorizontalScrollBar(NULL), fBorder(border)
fVerticalScrollBar(NULL),
fBorder(border),
fHighlighted(false)
{ {
BRect targetFrame; _Init(horizontal, vertical);
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); BScrollView::BScrollView(const char* name, BView* target, uint32 flags,
targetFrame = fTarget->Frame(); bool horizontal, bool vertical, border_style border)
} else { : BView(name, _ModifyFlags(flags, border) | B_SUPPORTS_LAYOUT),
// no target specified fTarget(target),
targetFrame = Bounds(); fBorder(border)
if (horizontal) {
targetFrame.bottom -= B_H_SCROLL_BAR_HEIGHT + 1; _Init(horizontal, vertical);
if (vertical)
targetFrame.right -= B_V_SCROLL_BAR_WIDTH + 1;
if (border == 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 (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());
} }
@@ -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 * BArchivable *
BScrollView::Instantiate(BMessage *archive) BScrollView::Instantiate(BMessage *archive)
{ {
@@ -183,8 +203,8 @@ BScrollView::AttachedToWindow()
BRect bounds = ConvertToScreen(Bounds()); BRect bounds = ConvertToScreen(Bounds());
BRect windowBounds = Window()->Frame(); BRect windowBounds = Window()->Frame();
if (bounds.right - BorderSize(fBorder) != windowBounds.right if (bounds.right - _BorderSize() != windowBounds.right
|| bounds.bottom - BorderSize(fBorder) != windowBounds.bottom) || bounds.bottom - _BorderSize() != windowBounds.bottom)
return; return;
if (fHorizontalScrollBar) if (fHorizontalScrollBar)
@@ -263,7 +283,7 @@ BScrollView::SetBorder(border_style border)
if (fBorder == border) if (fBorder == border)
return; return;
float offset = BorderSize(fBorder) - BorderSize(border); float offset = _BorderSize() - _BorderSize(border);
float resize = 2 * offset; float resize = 2 * offset;
float horizontalGap = 0, verticalGap = 0; float horizontalGap = 0, verticalGap = 0;
@@ -304,7 +324,7 @@ BScrollView::SetBorder(border_style border)
fVerticalScrollBar->ResizeBy(0, resize + verticalGap - change); fVerticalScrollBar->ResizeBy(0, resize + verticalGap - change);
} }
SetFlags(ModifyFlags(Flags(), border)); SetFlags(_ModifyFlags(Flags(), border));
} }
@@ -327,19 +347,12 @@ BScrollView::SetBorderHighlighted(bool state)
fHighlighted = state; fHighlighted = state;
/* The BeBook describes something like this:
if (LockLooper()) {
Draw(Bounds());
UnlockLooper();
}
*/
// but this is much cleaner, I think:
BRect bounds = Bounds(); BRect bounds = Bounds();
Invalidate(BRect(bounds.left, bounds.top, bounds.right, bounds.top)); 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.left, bounds.top + 1, bounds.left,
Invalidate(BRect(bounds.right, bounds.top + 1, bounds.right, bounds.bottom - 1)); 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)); Invalidate(BRect(bounds.left, bounds.bottom, bounds.right, bounds.bottom));
return B_OK; return B_OK;
@@ -373,7 +386,9 @@ BScrollView::SetTarget(BView *target)
fVerticalScrollBar->SetTarget(target); fVerticalScrollBar->SetTarget(target);
if (target != NULL) { 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); target->TargetedByScrollView(this);
AddChild(target, ChildAt(0)); AddChild(target, ChildAt(0));
@@ -440,7 +455,7 @@ BScrollView::FrameResized(float width, float height)
// changes in width // changes in width
BRect bounds = Bounds(); BRect bounds = Bounds();
float border = BorderSize(fBorder) - 1; float border = _BorderSize() - 1;
if (bounds.Width() > fPreviousWidth) { if (bounds.Width() > fPreviousWidth) {
// invalidate the region between the old and the new right border // invalidate the region between the old and the new right border
@@ -485,42 +500,78 @@ BScrollView::ResizeToPreferred()
void void
BScrollView::GetPreferredSize(float *_width, float *_height) BScrollView::GetPreferredSize(float *_width, float *_height)
{ {
BRect frame = CalcFrame(fTarget, fHorizontalScrollBar, fVerticalScrollBar, fBorder); BSize size = PreferredSize();
if (fTarget != NULL) {
float width, height;
fTarget->GetPreferredSize(&width, &height);
frame.right += width - fTarget->Frame().Width();
frame.bottom += height - fTarget->Frame().Height();
}
if (_width) if (_width)
*_width = frame.Width(); *_width = size.width;
if (_height) 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 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) if (vertical)
frame.right += B_V_SCROLL_BAR_WIDTH; frame.right += B_V_SCROLL_BAR_WIDTH;
if (horizontal) if (horizontal)
frame.bottom += B_H_SCROLL_BAR_HEIGHT; frame.bottom += B_H_SCROLL_BAR_HEIGHT;
float borderSize = BorderSize(border); float borderSize = _BorderSize(border);
frame.InsetBy(-borderSize, -borderSize); frame.InsetBy(-borderSize, -borderSize);
if (borderSize == 0) { 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) if (border == B_FANCY_BORDER)
return kFancyBorderSize; return kFancyBorderSize;
@@ -549,12 +608,11 @@ BScrollView::BorderSize(border_style border)
} }
/** This method changes the "flags" argument as passed on to /*! This method changes the "flags" argument as passed on to
* the BView constructor. the BView constructor.
*/ */
/*static*/ int32
int32 BScrollView::_ModifyFlags(int32 flags, border_style border)
BScrollView::ModifyFlags(int32 flags, border_style border)
{ {
// We either need B_FULL_UPDATE_ON_RESIZE or // We either need B_FULL_UPDATE_ON_RESIZE or
// B_FRAME_EVENTS if we have to draw a border // B_FRAME_EVENTS if we have to draw a border
@@ -582,8 +640,9 @@ BScrollView::MakeFocus(bool state)
} }
BHandler * BHandler*
BScrollView::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, int32 form, const char *property) BScrollView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
int32 form, const char* property)
{ {
return BView::ResolveSpecifier(msg, index, specifier, form, property); return BView::ResolveSpecifier(msg, index, specifier, form, property);
} }
@@ -599,17 +658,8 @@ BScrollView::GetSupportedSuites(BMessage *data)
BSize BSize
BScrollView::MinSize() BScrollView::MinSize()
{ {
// TODO: This is not yet correct. BSize size = _ComputeSize(fTarget != NULL ? fTarget->MinSize()
BSize size = (fTarget ? fTarget->MinSize() : BSize(-1, -1)); : BSize(16, 16));
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;
return BLayoutUtils::ComposeSize(ExplicitMinSize(), size); return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
} }
@@ -618,22 +668,56 @@ BScrollView::MinSize()
BSize BSize
BScrollView::PreferredSize() BScrollView::PreferredSize()
{ {
// TODO: This is not yet correct. BSize size = _ComputeSize(fTarget != NULL ? fTarget->PreferredSize()
BSize size = (fTarget ? fTarget->PreferredSize() : BSize(-1, -1)); : BSize(32, 32));
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;
return BLayoutUtils::ComposeSize(ExplicitMinSize(), size); 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 status_t
BScrollView::Perform(perform_code code, void* _data) BScrollView::Perform(perform_code code, void* _data)
{ {