We now dynamically add scroll bars to the parameter web view!

Some BeOS classes really are very stupid or just inferior:
- added DynamicScrollView class that adds and removes scroll bars as needed
  and automatically takes care of the correct scroller range and proportions.
- added TabView class that is smart enough to resize its container view
  and the tab views as well.

Both classes could be used in other environments, too. DynamicScrollView
would be a nice addition to BScrollView R2 - might be put into a shared
source directory for now (or into libbe's BPrivate namespace?).
The TabView additions could almost be moved to BTabView without breaking
compatibility, just the resizing mode of the tab views have to be respected.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6612 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2004-02-17 03:54:48 +00:00
parent fce6c4e478
commit b70fa5139e

View File

@ -1,5 +1,5 @@
/*
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
@ -10,6 +10,7 @@
#include <ParameterWeb.h>
#include <Slider.h>
#include <ScrollBar.h>
#include <StringView.h>
#include <Button.h>
#include <TextControl.h>
@ -20,6 +21,7 @@
#include <TabView.h>
#include <MenuField.h>
#include <MessageFilter.h>
#include <Window.h>
using namespace BPrivate;
@ -27,14 +29,50 @@ using namespace BPrivate;
namespace BPrivate {
class DynamicScrollView : public BView {
public:
DynamicScrollView(const char *name, BView *target);
virtual ~DynamicScrollView();
virtual void AttachedToWindow(void);
virtual void FrameResized(float width, float height);
void SetContentBounds(BRect bounds);
BRect ContentBounds() const { return fContentBounds; }
private:
void UpdateBars();
BScrollBar *fHorizontalScrollBar, *fVerticalScrollBar;
BRect fContentBounds;
BView *fTarget;
bool fIsDocumentScroller;
};
class GroupView : public BView {
public:
GroupView(BRect frame, const char *name);
virtual ~GroupView();
virtual void AttachedToWindow();
virtual void AllAttached();
virtual void GetPreferredSize(float *_width, float *_height);
void SetContentBounds(BRect bounds);
BRect ContentBounds() const { return fContentBounds; }
private:
BRect fContentBounds;
};
class TabView : public BTabView {
public:
TabView(BRect frame, const char *name, button_width width = B_WIDTH_AS_USUAL,
uint32 resizingMode = B_FOLLOW_ALL, uint32 flags = B_FULL_UPDATE_ON_RESIZE
| B_WILL_DRAW | B_NAVIGABLE_JUMP | B_FRAME_EVENTS | B_NAVIGABLE);
virtual void FrameResized(float width, float height);
virtual void Select(int32 tab);
};
class SeparatorView : public BView {
@ -118,12 +156,162 @@ parameter_should_be_hidden(BParameter &parameter)
// #pragma mark -
DynamicScrollView::DynamicScrollView(const char *name, BView *target)
: BView(target->Frame(), name, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS),
fHorizontalScrollBar(NULL),
fVerticalScrollBar(NULL),
fTarget(target),
fIsDocumentScroller(false)
{
fContentBounds.Set(-1, -1, -1, -1);
SetViewColor(fTarget->ViewColor());
AddChild(target);
}
DynamicScrollView::~DynamicScrollView()
{
}
void
DynamicScrollView::AttachedToWindow(void)
{
fIsDocumentScroller = Parent() == NULL
&& Window() != NULL
&& Window()->Look() == B_DOCUMENT_WINDOW_LOOK
&& Frame().right == Window()->Bounds().right
&& Frame().bottom == Window()->Bounds().bottom;
UpdateBars();
}
void
DynamicScrollView::FrameResized(float width, float height)
{
UpdateBars();
}
void
DynamicScrollView::SetContentBounds(BRect bounds)
{
fContentBounds = bounds;
if (Window())
UpdateBars();
}
void
DynamicScrollView::UpdateBars()
{
// we need the size that the view wants to have, and the one
// it could have (without the space for the scroll bars)
float width, height;
if (fContentBounds == BRect(-1, -1, -1, -1))
fTarget->GetPreferredSize(&width, &height);
else {
width = fContentBounds.Width();
height = fContentBounds.Height();
}
BRect bounds = Bounds();
// do we have to remove a scroll bar?
bool horizontal = width > Bounds().Width();
bool vertical = height > Bounds().Height();
bool horizontalChanged = false;
bool verticalChanged = false;
if (!horizontal && fHorizontalScrollBar != NULL) {
RemoveChild(fHorizontalScrollBar);
delete fHorizontalScrollBar;
fHorizontalScrollBar = NULL;
fTarget->ResizeBy(0, B_H_SCROLL_BAR_HEIGHT);
horizontalChanged = true;
}
if (!vertical && fVerticalScrollBar != NULL) {
RemoveChild(fVerticalScrollBar);
delete fVerticalScrollBar;
fVerticalScrollBar = NULL;
fTarget->ResizeBy(B_V_SCROLL_BAR_WIDTH, 0);
verticalChanged = true;
}
// or do we have to add a scroll bar?
if (horizontal && fHorizontalScrollBar == NULL) {
BRect rect = Frame();
rect.top = rect.bottom + 1 - B_H_SCROLL_BAR_HEIGHT;
if (vertical || fIsDocumentScroller)
rect.right -= B_V_SCROLL_BAR_WIDTH;
fHorizontalScrollBar = new BScrollBar(rect, "horizontal", fTarget, 0, width, B_HORIZONTAL);
fTarget->ResizeBy(0, -B_H_SCROLL_BAR_HEIGHT);
AddChild(fHorizontalScrollBar);
horizontalChanged = true;
}
if (vertical && fVerticalScrollBar == NULL) {
BRect rect = Frame();
rect.left = rect.right + 1 - B_V_SCROLL_BAR_WIDTH;
if (horizontal || fIsDocumentScroller)
rect.bottom -= B_H_SCROLL_BAR_HEIGHT;
fVerticalScrollBar = new BScrollBar(rect, "vertical", fTarget, 0, height, B_VERTICAL);
fTarget->ResizeBy(-B_V_SCROLL_BAR_WIDTH, 0);
AddChild(fVerticalScrollBar);
verticalChanged = true;
}
// adapt the scroll bars, so that they don't overlap each other
if (!fIsDocumentScroller) {
if (horizontalChanged && !verticalChanged && vertical)
fVerticalScrollBar->ResizeBy(0, (horizontal ? -1 : 1) * B_H_SCROLL_BAR_HEIGHT);
if (verticalChanged && !horizontalChanged && horizontal)
fHorizontalScrollBar->ResizeBy((vertical ? -1 : 1) * B_V_SCROLL_BAR_WIDTH, 0);
}
// update the scroll bar range & proportions
bounds = Bounds();
if (fHorizontalScrollBar != NULL)
bounds.bottom -= B_H_SCROLL_BAR_HEIGHT;
if (fVerticalScrollBar != NULL)
bounds.right -= B_V_SCROLL_BAR_WIDTH;
if (fHorizontalScrollBar != NULL) {
float delta = width - bounds.Width();
if (delta < 0)
delta = 0;
fHorizontalScrollBar->SetRange(0, delta);
fHorizontalScrollBar->SetSteps(1, bounds.Width());
fHorizontalScrollBar->SetProportion(bounds.Width() / width);
}
if (fVerticalScrollBar != NULL) {
float delta = height - bounds.Height();
if (delta < 0)
delta = 0;
fVerticalScrollBar->SetRange(0, delta);
fVerticalScrollBar->SetSteps(1, bounds.Height());
fVerticalScrollBar->SetProportion(bounds.Height() / height);
}
}
// #pragma mark -
GroupView::GroupView(BRect frame, const char *name)
: BView(frame, name, B_FOLLOW_NONE, B_WILL_DRAW)
: BView(frame, name, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
// ToDo: show scroll bars if necessary!
}
@ -142,6 +330,72 @@ GroupView::AttachedToWindow()
control->SetTarget(control);
}
}
void
GroupView::AllAttached()
{
}
void
GroupView::GetPreferredSize(float *_width, float *_height)
{
if (_width)
*_width = fContentBounds.Width();
if (_height)
*_height = fContentBounds.Height();
}
void
GroupView::SetContentBounds(BRect bounds)
{
fContentBounds = bounds;
}
// #pragma mark -
/** BTabView is really stupid - it doesn't even resize its content
* view when it is resized itself.
* This derived class fixes this issue, and also resizes all tab
* content views to the size of the container view when they are
* selected (does not take their resize flags into account, though).
*/
TabView::TabView(BRect frame, const char *name, button_width width,
uint32 resizingMode, uint32 flags)
: BTabView(frame, name, width, resizingMode, flags)
{
}
void
TabView::FrameResized(float width, float height)
{
BRect rect = Bounds();
rect.InsetBySelf(1, 1);
rect.top += TabHeight();
ContainerView()->ResizeTo(rect.Width(), rect.Height());
}
void
TabView::Select(int32 tab)
{
BTabView::Select(tab);
BView *view = ViewForTab(Selection());
if (view != NULL) {
BRect rect = ContainerView()->Bounds();
view->ResizeTo(rect.Width(), rect.Height());
}
}
@ -429,10 +683,10 @@ DefaultMediaTheme::MakeViewFor(BParameterWeb *web, const BRect *hintRect)
// do we have more than one attached parameter group?
// if so, use a tabbed view with a tab for each group
BTabView *tabView = NULL;
TabView *tabView = NULL;
if (web->CountGroups() > 1)
tabView = new BTabView(rect, "web");
tabView = new TabView(rect, "web");
rect.OffsetTo(B_ORIGIN);
@ -445,31 +699,21 @@ DefaultMediaTheme::MakeViewFor(BParameterWeb *web, const BRect *hintRect)
if (groupView == NULL)
continue;
// the top-level group views must not be larger than their hintRect
if (GroupView *view = dynamic_cast<GroupView *>(groupView))
view->ResizeTo(rect.Width() - 10, rect.Height() - 10);
if (tabView == NULL) {
// if we don't need a container to put that view into,
// we're done here
return groupView;
// we're done here (but the groupView may span over the
// whole hintRect)
groupView->MoveBy(-5, -5);
groupView->ResizeBy(10, 10);
return new DynamicScrollView(groupView->Name(), groupView);
}
tabView->AddTab(groupView);
// enlarge the bounding rectangle as needed
if (groupView->Bounds().Width() + 5 > rect.Width())
rect.right = groupView->Bounds().Width() - 1;
if (groupView->Bounds().Height() > rect.Height())
rect.bottom = groupView->Bounds().Height();
}
if (tabView != NULL) {
tabView->ResizeTo(rect.right + 10, rect.bottom + tabView->TabHeight());
rect = tabView->Bounds();
rect.InsetBySelf(1, 1);
rect.top += tabView->TabHeight();
tabView->ContainerView()->ResizeTo(rect.Width(), rect.Height());
tabView->AddTab(new DynamicScrollView(groupView->Name(), groupView));
}
return tabView;
@ -485,13 +729,13 @@ DefaultMediaTheme::MakeViewFor(BParameterGroup &group, const BRect &hintRect)
return NULL;
BRect rect(hintRect);
BView *view = new GroupView(rect, group.Name());
GroupView *view = new GroupView(rect, group.Name());
// Create the parameter views - but don't add them yet
rect.OffsetTo(B_ORIGIN);
rect.InsetBySelf(5, 5);
BList views;
for (int32 i = 0; i < group.CountParameters(); i++) {
BParameter *parameter = group.ParameterAt(i);
@ -518,7 +762,7 @@ DefaultMediaTheme::MakeViewFor(BParameterGroup &group, const BRect &hintRect)
}
// Add the sub-group views
rect.right = rect.left + 50;
rect.bottom = rect.top + 10;
float lastHeight = 0;
@ -553,6 +797,7 @@ DefaultMediaTheme::MakeViewFor(BParameterGroup &group, const BRect &hintRect)
}
view->ResizeTo(rect.left + 10, rect.bottom + 5);
view->SetContentBounds(view->Bounds());
if (group.CountParameters() == 0)
return view;
@ -607,6 +852,7 @@ DefaultMediaTheme::MakeViewFor(BParameterGroup &group, const BRect &hintRect)
}
}
view->SetContentBounds(view->Bounds());
return view;
}