11ae95ac8SAxel Dörfler/*
2fd79684aSAxel Dörfler * Copyright 2004-2015, Axel D��rfler, axeld@pinc-software.de.
31f424632SJohn Scipione * Copyright 2009 Stephan A��mus, superstippi@gmx.de.
4fd79684aSAxel Dörfler * Copyright 2014-2015 Haiku, Inc. All rights reserved.
51ae95ac8SAxel Dörfler * Distributed under the terms of the MIT License.
61f424632SJohn Scipione *
71f424632SJohn Scipione * Authors:
81f424632SJohn Scipione *		Stephan A��mus, superstippi@gmx.de
91f424632SJohn Scipione *		Axel D��rfler, axeld@pinc-software.de
101f424632SJohn Scipione *		John Scipione, jscpione@gmail.com
111ae95ac8SAxel Dörfler */
121ae95ac8SAxel Dörfler
138d8da849SAxel Dörfler
148d8da849SAxel Dörfler#include <ScrollView.h>
1516fe6dd9SAxel Dörfler
162f86ba45SStephan Aßmus#include <ControlLook.h>
179ecf9d1cSIngo Weinhold#include <LayoutUtils.h>
1816fe6dd9SAxel Dörfler#include <Message.h>
192f86ba45SStephan Aßmus#include <Region.h>
2052bb9b2dSAxel Dörfler#include <Window.h>
2116fe6dd9SAxel Dörfler
2239fbf550SOliver Tappe#include <binary_compatibility/Interface.h>
2316fe6dd9SAxel Dörfler
241f424632SJohn Scipione
2516fe6dd9SAxel Dörflerstatic const float kFancyBorderSize = 2;
2616fe6dd9SAxel Dörflerstatic const float kPlainBorderSize = 1;
2716fe6dd9SAxel Dörfler
2816fe6dd9SAxel Dörfler
291f424632SJohn ScipioneBScrollView::BScrollView(const char* name, BView* target, uint32 resizingMode,
301f424632SJohn Scipione	uint32 flags, bool horizontal, bool vertical, border_style border)
311f424632SJohn Scipione	:
32fd79684aSAxel Dörfler	BView(_ComputeFrame(target, horizontal, vertical, border,
33fd79684aSAxel Dörfler		BControlLook::B_ALL_BORDERS), name, resizingMode,
344854630dSAugustin Cavalier		_ModifyFlags(flags, target, border)),
3516fe6dd9SAxel Dörfler	fTarget(target),
369e163a7aSAxel Dörfler	fBorder(border)
379e163a7aSAxel Dörfler{
389e163a7aSAxel Dörfler	_Init(horizontal, vertical);
399e163a7aSAxel Dörfler}
409e163a7aSAxel Dörfler
419e163a7aSAxel Dörfler
429e163a7aSAxel DörflerBScrollView::BScrollView(const char* name, BView* target, uint32 flags,
431f424632SJohn Scipione	bool horizontal, bool vertical, border_style border)
441f424632SJohn Scipione	:
454854630dSAugustin Cavalier	BView(name, _ModifyFlags(flags, target, border)),
469e163a7aSAxel Dörfler	fTarget(target),
479e163a7aSAxel Dörfler	fBorder(border)
489e163a7aSAxel Dörfler{
499e163a7aSAxel Dörfler	_Init(horizontal, vertical);
509e163a7aSAxel Dörfler}
519e163a7aSAxel Dörfler
529e163a7aSAxel Dörfler
531f424632SJohn ScipioneBScrollView::BScrollView(BMessage* archive)
541f424632SJohn Scipione	:
551f424632SJohn Scipione	BView(archive),
5616fe6dd9SAxel Dörfler	fHighlighted(false)
5716fe6dd9SAxel Dörfler{
589e163a7aSAxel Dörfler	int32 border;
599e163a7aSAxel Dörfler	fBorder = archive->FindInt32("_style", &border) == B_OK ?
609e163a7aSAxel Dörfler		(border_style)border : B_FANCY_BORDER;
619e163a7aSAxel Dörfler
621f424632SJohn Scipione	// in a shallow archive, we may not have a target anymore. We must
639e163a7aSAxel Dörfler	// be prepared for this case
649e163a7aSAxel Dörfler
659e163a7aSAxel Dörfler	// don't confuse our scroll bars with our (eventual) target
669e163a7aSAxel Dörfler	int32 firstBar = 0;
679e163a7aSAxel Dörfler	if (!archive->FindBool("_no_target_")) {
689e163a7aSAxel Dörfler		fTarget = ChildAt(0);
699e163a7aSAxel Dörfler		firstBar++;
709e163a7aSAxel Dörfler	} else
719e163a7aSAxel Dörfler		fTarget = NULL;
729e163a7aSAxel Dörfler
739e163a7aSAxel Dörfler	// search for our scroll bars
74bdb4ae32SAdrien Destugues	// This will not work for managed archives (when the layout kit is used).
75bdb4ae32SAdrien Destugues	// In that case the children are attached later, and we perform the search
76bdb4ae32SAdrien Destugues	// again in the AllUnarchived method.
779e163a7aSAxel Dörfler
789e163a7aSAxel Dörfler	fHorizontalScrollBar = NULL;
799e163a7aSAxel Dörfler	fVerticalScrollBar = NULL;
809e163a7aSAxel Dörfler
811f424632SJohn Scipione	BView* view;
829e163a7aSAxel Dörfler	while ((view = ChildAt(firstBar++)) != NULL) {
839e163a7aSAxel Dörfler		BScrollBar *bar = dynamic_cast<BScrollBar *>(view);
849e163a7aSAxel Dörfler		if (bar == NULL)
859e163a7aSAxel Dörfler			continue;
869e163a7aSAxel Dörfler
879e163a7aSAxel Dörfler		if (bar->Orientation() == B_HORIZONTAL)
889e163a7aSAxel Dörfler			fHorizontalScrollBar = bar;
899e163a7aSAxel Dörfler		else if (bar->Orientation() == B_VERTICAL)
909e163a7aSAxel Dörfler			fVerticalScrollBar = bar;
919e163a7aSAxel Dörfler	}
929e163a7aSAxel Dörfler
939e163a7aSAxel Dörfler	fPreviousWidth = uint16(Bounds().Width());
949e163a7aSAxel Dörfler	fPreviousHeight = uint16(Bounds().Height());
95bdb4ae32SAdrien Destugues
969e163a7aSAxel Dörfler}
979e163a7aSAxel Dörfler
989e163a7aSAxel Dörfler
999e163a7aSAxel DörflerBScrollView::~BScrollView()
1009e163a7aSAxel Dörfler{
1019e163a7aSAxel Dörfler}
1029e163a7aSAxel Dörfler
1039e163a7aSAxel Dörfler
1041f424632SJohn Scipione// #pragma mark - Archiving
10516fe6dd9SAxel Dörfler
10616fe6dd9SAxel Dörfler
10789208c77SStephan AßmusBArchivable*
10889208c77SStephan AßmusBScrollView::Instantiate(BMessage* archive)
10916fe6dd9SAxel Dörfler{
110122e979eSAxel Dörfler	if (validate_instantiation(archive, "BScrollView"))
111122e979eSAxel Dörfler		return new BScrollView(archive);
112122e979eSAxel Dörfler
1138b35053eSAxel Dörfler	return NULL;
11416fe6dd9SAxel Dörfler}
11516fe6dd9SAxel Dörfler
11616fe6dd9SAxel Dörfler
11716fe6dd9SAxel Dörflerstatus_t
11889208c77SStephan AßmusBScrollView::Archive(BMessage* archive, bool deep) const
11916fe6dd9SAxel Dörfler{
120122e979eSAxel Dörfler	status_t status = BView::Archive(archive, deep);
121122e979eSAxel Dörfler	if (status != B_OK)
122122e979eSAxel Dörfler		return status;
123122e979eSAxel Dörfler
124122e979eSAxel Dörfler	// If this is a deep archive, the BView class will take care
125122e979eSAxel Dörfler	// of our children.
126122e979eSAxel Dörfler
127122e979eSAxel Dörfler	if (status == B_OK && fBorder != B_FANCY_BORDER)
12826a96b16SAxel Dörfler		status = archive->AddInt32("_style", fBorder);
129122e979eSAxel Dörfler	if (status == B_OK && fTarget == NULL)
130122e979eSAxel Dörfler		status = archive->AddBool("_no_target_", true);
131122e979eSAxel Dörfler
132122e979eSAxel Dörfler	// The highlighted state is not archived, but since it is
133122e979eSAxel Dörfler	// usually (or should be) used to indicate focus, this
134122e979eSAxel Dörfler	// is probably the right thing to do.
135fd79684aSAxel Dörfler
136122e979eSAxel Dörfler	return status;
13716fe6dd9SAxel Dörfler}
13816fe6dd9SAxel Dörfler
13916fe6dd9SAxel Dörfler
140bdb4ae32SAdrien Destuguesstatus_t
141bdb4ae32SAdrien DestuguesBScrollView::AllUnarchived(const BMessage* archive)
142bdb4ae32SAdrien Destugues{
143bdb4ae32SAdrien Destugues	status_t result = BView::AllUnarchived(archive);
144bdb4ae32SAdrien Destugues	if (result != B_OK)
145bdb4ae32SAdrien Destugues		return result;
146bdb4ae32SAdrien Destugues
147bdb4ae32SAdrien Destugues	// search for our scroll bars and target
148bdb4ae32SAdrien Destugues	int32 firstBar = 0;
149bdb4ae32SAdrien Destugues	BView* view;
150bdb4ae32SAdrien Destugues	while ((view = ChildAt(firstBar++)) != NULL) {
151bdb4ae32SAdrien Destugues		BScrollBar *bar = dynamic_cast<BScrollBar *>(view);
152bdb4ae32SAdrien Destugues		// We assume that the first non-scrollbar child view is the target.
153bdb4ae32SAdrien Destugues		// So the target view can't be a BScrollBar, but who would do that?
154bdb4ae32SAdrien Destugues		if (bar == NULL) {
155bdb4ae32SAdrien Destugues			// in a shallow archive, we may not have a target anymore. We must
156bdb4ae32SAdrien Destugues			// be prepared for this case
157bdb4ae32SAdrien Destugues			if (fTarget == NULL && !archive->FindBool("_no_target_"))
158bdb4ae32SAdrien Destugues				fTarget = view;
159bdb4ae32SAdrien Destugues			continue;
160bdb4ae32SAdrien Destugues		}
161bdb4ae32SAdrien Destugues
162bdb4ae32SAdrien Destugues		if (bar->Orientation() == B_HORIZONTAL)
163bdb4ae32SAdrien Destugues			fHorizontalScrollBar = bar;
164bdb4ae32SAdrien Destugues		else if (bar->Orientation() == B_VERTICAL)
165bdb4ae32SAdrien Destugues			fVerticalScrollBar = bar;
166bdb4ae32SAdrien Destugues	}
167bdb4ae32SAdrien Destugues
168bdb4ae32SAdrien Destugues	// Now connect the bars to the target, and make the target aware of them
169bdb4ae32SAdrien Destugues	if (fHorizontalScrollBar)
170bdb4ae32SAdrien Destugues		fHorizontalScrollBar->SetTarget(fTarget);
171bdb4ae32SAdrien Destugues	if (fVerticalScrollBar)
172bdb4ae32SAdrien Destugues		fVerticalScrollBar->SetTarget(fTarget);
173bdb4ae32SAdrien Destugues
174bdb4ae32SAdrien Destugues	if (fTarget)
175bdb4ae32SAdrien Destugues		fTarget->TargetedByScrollView(this);
176bdb4ae32SAdrien Destugues
177bdb4ae32SAdrien Destugues	fPreviousWidth = uint16(Bounds().Width());
178bdb4ae32SAdrien Destugues	fPreviousHeight = uint16(Bounds().Height());
179bdb4ae32SAdrien Destugues
180bdb4ae32SAdrien Destugues	return B_OK;
181bdb4ae32SAdrien Destugues}
182bdb4ae32SAdrien Destugues
183bdb4ae32SAdrien Destugues
1841f424632SJohn Scipione// #pragma mark - Hook methods
1851f424632SJohn Scipione
1861f424632SJohn Scipione
18716fe6dd9SAxel Dörflervoid
18816fe6dd9SAxel DörflerBScrollView::AttachedToWindow()
18916fe6dd9SAxel Dörfler{
190122e979eSAxel Dörfler	BView::AttachedToWindow();
19152bb9b2dSAxel Dörfler
19252bb9b2dSAxel Dörfler	if ((fHorizontalScrollBar == NULL && fVerticalScrollBar == NULL)
19327a00cddSStephan Aßmus		|| (fHorizontalScrollBar != NULL && fVerticalScrollBar != NULL)
1941f424632SJohn Scipione		|| Window()->Look() != B_DOCUMENT_WINDOW_LOOK) {
19552bb9b2dSAxel Dörfler		return;
1961f424632SJohn Scipione	}
19752bb9b2dSAxel Dörfler
19852bb9b2dSAxel Dörfler	// If we have only one bar, we need to check if we are in the
19952bb9b2dSAxel Dörfler	// bottom right edge of a window with the B_DOCUMENT_LOOK to
20052bb9b2dSAxel Dörfler	// adjust the size of the bar to acknowledge the resize knob.
20152bb9b2dSAxel Dörfler
20252bb9b2dSAxel Dörfler	BRect bounds = ConvertToScreen(Bounds());
20352bb9b2dSAxel Dörfler	BRect windowBounds = Window()->Frame();
20452bb9b2dSAxel Dörfler
2059e163a7aSAxel Dörfler	if (bounds.right - _BorderSize() != windowBounds.right
2061f424632SJohn Scipione		|| bounds.bottom - _BorderSize() != windowBounds.bottom) {
20752bb9b2dSAxel Dörfler		return;
2081f424632SJohn Scipione	}
20952bb9b2dSAxel Dörfler
210fd79684aSAxel Dörfler	if (fHorizontalScrollBar != NULL)
21152bb9b2dSAxel Dörfler		fHorizontalScrollBar->ResizeBy(-B_V_SCROLL_BAR_WIDTH, 0);
212fd79684aSAxel Dörfler	else if (fVerticalScrollBar != NULL)
21352bb9b2dSAxel Dörfler		fVerticalScrollBar->ResizeBy(0, -B_H_SCROLL_BAR_HEIGHT);
21416fe6dd9SAxel Dörfler}
21516fe6dd9SAxel Dörfler
21616fe6dd9SAxel Dörfler
21716fe6dd9SAxel Dörflervoid
21816fe6dd9SAxel DörflerBScrollView::DetachedFromWindow()
21916fe6dd9SAxel Dörfler{
22016fe6dd9SAxel Dörfler	BView::DetachedFromWindow();
22116fe6dd9SAxel Dörfler}
22216fe6dd9SAxel Dörfler
22316fe6dd9SAxel Dörfler
22416fe6dd9SAxel Dörflervoid
22516fe6dd9SAxel DörflerBScrollView::AllAttached()
22616fe6dd9SAxel Dörfler{
22716fe6dd9SAxel Dörfler	BView::AllAttached();
22816fe6dd9SAxel Dörfler}
22916fe6dd9SAxel Dörfler
23016fe6dd9SAxel Dörfler
23116fe6dd9SAxel Dörflervoid
23216fe6dd9SAxel DörflerBScrollView::AllDetached()
23316fe6dd9SAxel Dörfler{
23416fe6dd9SAxel Dörfler	BView::AllDetached();
23516fe6dd9SAxel Dörfler}
23616fe6dd9SAxel Dörfler
23716fe6dd9SAxel Dörfler
23816fe6dd9SAxel Dörflervoid
23916fe6dd9SAxel DörflerBScrollView::Draw(BRect updateRect)
24016fe6dd9SAxel Dörfler{
2411f424632SJohn Scipione	uint32 flags = 0;
2421f424632SJohn Scipione	if (fHighlighted && Window()->IsActive())
2431f424632SJohn Scipione		flags |= BControlLook::B_FOCUSED;
24489208c77SStephan Aßmus
2451f424632SJohn Scipione	BRect rect(Bounds());
2461f424632SJohn Scipione	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
24789208c77SStephan Aßmus
2481f424632SJohn Scipione	BRect verticalScrollBarFrame(0, 0, -1, -1);
2491f424632SJohn Scipione	if (fVerticalScrollBar)
2501f424632SJohn Scipione		verticalScrollBarFrame = fVerticalScrollBar->Frame();
25189208c77SStephan Aßmus
2521f424632SJohn Scipione	BRect horizontalScrollBarFrame(0, 0, -1, -1);
2531f424632SJohn Scipione	if (fHorizontalScrollBar)
2541f424632SJohn Scipione		horizontalScrollBarFrame = fHorizontalScrollBar->Frame();
25589208c77SStephan Aßmus
2561f424632SJohn Scipione	be_control_look->DrawScrollViewFrame(this, rect, updateRect,
2571f424632SJohn Scipione		verticalScrollBarFrame, horizontalScrollBarFrame, base, fBorder,
258fd79684aSAxel Dörfler		flags, fBorders);
25989208c77SStephan Aßmus}
26089208c77SStephan Aßmus
26189208c77SStephan Aßmus
26289208c77SStephan Aßmusvoid
2631f424632SJohn ScipioneBScrollView::FrameMoved(BPoint newPosition)
26489208c77SStephan Aßmus{
2651f424632SJohn Scipione	BView::FrameMoved(newPosition);
26689208c77SStephan Aßmus}
26789208c77SStephan Aßmus
26889208c77SStephan Aßmus
26989208c77SStephan Aßmusvoid
2701f424632SJohn ScipioneBScrollView::FrameResized(float newWidth, float newHeight)
27189208c77SStephan Aßmus{
2721f424632SJohn Scipione	BView::FrameResized(newWidth, newHeight);
27389208c77SStephan Aßmus
2745b0e5c0aSAugustin Cavalier	const BRect bounds = Bounds();
2755b0e5c0aSAugustin Cavalier
276e5d0c909SAugustin Cavalier	if (fTarget != NULL && (fTarget->Flags() & B_SUPPORTS_LAYOUT) != 0
277e5d0c909SAugustin Cavalier			&& (fTarget->Flags() & B_SCROLL_VIEW_AWARE) == 0) {
2784854630dSAugustin Cavalier		BSize size = fTarget->PreferredSize();
2795b0e5c0aSAugustin Cavalier		if (fHorizontalScrollBar != NULL) {
2805b0e5c0aSAugustin Cavalier			float delta = size.Width() - bounds.Width(),
2815b0e5c0aSAugustin Cavalier				proportion = bounds.Width() / size.Width();
2825b0e5c0aSAugustin Cavalier			if (delta < 0)
2835b0e5c0aSAugustin Cavalier				delta = 0;
2845b0e5c0aSAugustin Cavalier
2855b0e5c0aSAugustin Cavalier			fHorizontalScrollBar->SetRange(0, delta);
2865b0e5c0aSAugustin Cavalier			fHorizontalScrollBar->SetSteps(be_plain_font->Size() * 1.33,
2875b0e5c0aSAugustin Cavalier				bounds.Width());
2885b0e5c0aSAugustin Cavalier			fHorizontalScrollBar->SetProportion(proportion);
2895b0e5c0aSAugustin Cavalier		}
2905b0e5c0aSAugustin Cavalier		if (fVerticalScrollBar != NULL) {
2915b0e5c0aSAugustin Cavalier			float delta = size.Height() - bounds.Height(),
2925b0e5c0aSAugustin Cavalier				proportion = bounds.Height() / size.Height();
2935b0e5c0aSAugustin Cavalier			if (delta < 0)
2945b0e5c0aSAugustin Cavalier				delta = 0;
2955b0e5c0aSAugustin Cavalier
2965b0e5c0aSAugustin Cavalier			fVerticalScrollBar->SetRange(0, delta);
2975b0e5c0aSAugustin Cavalier			fVerticalScrollBar->SetSteps(be_plain_font->Size() * 1.33,
2985b0e5c0aSAugustin Cavalier				bounds.Height());
2995b0e5c0aSAugustin Cavalier			fVerticalScrollBar->SetProportion(proportion);
3005b0e5c0aSAugustin Cavalier		}
3015b0e5c0aSAugustin Cavalier	}
3025b0e5c0aSAugustin Cavalier
30389208c77SStephan Aßmus	if (fBorder == B_NO_BORDER)
30489208c77SStephan Aßmus		return;
30589208c77SStephan Aßmus
30689208c77SStephan Aßmus	float border = _BorderSize() - 1;
30789208c77SStephan Aßmus
308fd79684aSAxel Dörfler	if (fHorizontalScrollBar != NULL && fVerticalScrollBar != NULL) {
30989208c77SStephan Aßmus		BRect scrollCorner(bounds);
31089208c77SStephan Aßmus		scrollCorner.left = min_c(
31189208c77SStephan Aßmus			fPreviousWidth - fVerticalScrollBar->Frame().Height(),
31289208c77SStephan Aßmus			fHorizontalScrollBar->Frame().right + 1);
31389208c77SStephan Aßmus		scrollCorner.top = min_c(
31489208c77SStephan Aßmus			fPreviousHeight - fHorizontalScrollBar->Frame().Width(),
31589208c77SStephan Aßmus			fVerticalScrollBar->Frame().bottom + 1);
31689208c77SStephan Aßmus		Invalidate(scrollCorner);
31789208c77SStephan Aßmus	}
31889208c77SStephan Aßmus
3191f424632SJohn Scipione	// changes in newWidth
32089208c77SStephan Aßmus
32189208c77SStephan Aßmus	if (bounds.Width() > fPreviousWidth) {
32289208c77SStephan Aßmus		// invalidate the region between the old and the new right border
32389208c77SStephan Aßmus		BRect rect = bounds;
32489208c77SStephan Aßmus		rect.left += fPreviousWidth - border;
32589208c77SStephan Aßmus		rect.right--;
32689208c77SStephan Aßmus		Invalidate(rect);
32789208c77SStephan Aßmus	} else if (bounds.Width() < fPreviousWidth) {
32889208c77SStephan Aßmus		// invalidate the region of the new right border
32989208c77SStephan Aßmus		BRect rect = bounds;
33089208c77SStephan Aßmus		rect.left = rect.right - border;
33189208c77SStephan Aßmus		Invalidate(rect);
33289208c77SStephan Aßmus	}
33389208c77SStephan Aßmus
3341f424632SJohn Scipione	// changes in newHeight
33589208c77SStephan Aßmus
33689208c77SStephan Aßmus	if (bounds.Height() > fPreviousHeight) {
33789208c77SStephan Aßmus		// invalidate the region between the old and the new bottom border
33889208c77SStephan Aßmus		BRect rect = bounds;
33989208c77SStephan Aßmus		rect.top += fPreviousHeight - border;
34089208c77SStephan Aßmus		rect.bottom--;
34189208c77SStephan Aßmus		Invalidate(rect);
34289208c77SStephan Aßmus	} else if (bounds.Height() < fPreviousHeight) {
34389208c77SStephan Aßmus		// invalidate the region of the new bottom border
34489208c77SStephan Aßmus		BRect rect = bounds;
34589208c77SStephan Aßmus		rect.top = rect.bottom - border;
34689208c77SStephan Aßmus		Invalidate(rect);
34789208c77SStephan Aßmus	}
34889208c77SStephan Aßmus
34989208c77SStephan Aßmus	fPreviousWidth = uint16(bounds.Width());
35089208c77SStephan Aßmus	fPreviousHeight = uint16(bounds.Height());
35189208c77SStephan Aßmus}
35289208c77SStephan Aßmus
35389208c77SStephan Aßmus
3541f424632SJohn Scipionevoid
3551f424632SJohn ScipioneBScrollView::MessageReceived(BMessage* message)
3561f424632SJohn Scipione{
3571f424632SJohn Scipione	BView::MessageReceived(message);
3581f424632SJohn Scipione}
35989208c77SStephan Aßmus
36089208c77SStephan Aßmus
36189208c77SStephan Aßmusvoid
3621f424632SJohn ScipioneBScrollView::MouseDown(BPoint where)
36389208c77SStephan Aßmus{
3641f424632SJohn Scipione	BView::MouseDown(where);
3651f424632SJohn Scipione}
3661f424632SJohn Scipione
3671f424632SJohn Scipione
3681f424632SJohn Scipionevoid
3691f424632SJohn ScipioneBScrollView::MouseMoved(BPoint where, uint32 code,
3701f424632SJohn Scipione	const BMessage* dragMessage)
3711f424632SJohn Scipione{
3721f424632SJohn Scipione	BView::MouseMoved(where, code, dragMessage);
3731f424632SJohn Scipione}
3741f424632SJohn Scipione
3751f424632SJohn Scipione
3761f424632SJohn Scipionevoid
3771f424632SJohn ScipioneBScrollView::MouseUp(BPoint where)
3781f424632SJohn Scipione{
3791f424632SJohn Scipione	BView::MouseUp(where);
3801f424632SJohn Scipione}
3811f424632SJohn Scipione
3821f424632SJohn Scipione
3831f424632SJohn Scipionevoid
3841f424632SJohn ScipioneBScrollView::WindowActivated(bool active)
3851f424632SJohn Scipione{
3861f424632SJohn Scipione	if (fHighlighted)
3871f424632SJohn Scipione		Invalidate();
3881f424632SJohn Scipione
3891f424632SJohn Scipione	BView::WindowActivated(active);
39089208c77SStephan Aßmus}
39189208c77SStephan Aßmus
39289208c77SStephan Aßmus
3931f424632SJohn Scipione// #pragma mark - Size methods
3941f424632SJohn Scipione
3951f424632SJohn Scipione
39689208c77SStephan Aßmusvoid
3971f424632SJohn ScipioneBScrollView::GetPreferredSize(float* _width, float* _height)
39889208c77SStephan Aßmus{
3991f424632SJohn Scipione	BSize size = PreferredSize();
4001f424632SJohn Scipione
4011f424632SJohn Scipione	if (_width)
4021f424632SJohn Scipione		*_width = size.width;
4031f424632SJohn Scipione
4041f424632SJohn Scipione	if (_height)
4051f424632SJohn Scipione		*_height = size.height;
40689208c77SStephan Aßmus}
40789208c77SStephan Aßmus
40889208c77SStephan Aßmus
40989208c77SStephan Aßmusvoid
4101f424632SJohn ScipioneBScrollView::ResizeToPreferred()
41189208c77SStephan Aßmus{
4121f424632SJohn Scipione	if (Window() == NULL)
4131f424632SJohn Scipione		return;
4141f424632SJohn Scipione	BView::ResizeToPreferred();
41589208c77SStephan Aßmus}
41689208c77SStephan Aßmus
41789208c77SStephan Aßmus
41889208c77SStephan Aßmusvoid
4191f424632SJohn ScipioneBScrollView::MakeFocus(bool focus)
4201f424632SJohn Scipione{
4211f424632SJohn Scipione	BView::MakeFocus(focus);
4221f424632SJohn Scipione}
4231f424632SJohn Scipione
4241f424632SJohn Scipione
4251f424632SJohn ScipioneBSize
4261f424632SJohn ScipioneBScrollView::MinSize()
4271f424632SJohn Scipione{
4281f424632SJohn Scipione	BSize size = _ComputeSize(fTarget != NULL ? fTarget->MinSize()
4291f424632SJohn Scipione		: BSize(16, 16));
4301f424632SJohn Scipione
4311f424632SJohn Scipione	return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
4321f424632SJohn Scipione}
4331f424632SJohn Scipione
4341f424632SJohn Scipione
4351f424632SJohn ScipioneBSize
4361f424632SJohn ScipioneBScrollView::MaxSize()
4371f424632SJohn Scipione{
4381f424632SJohn Scipione	BSize size = _ComputeSize(fTarget != NULL ? fTarget->MaxSize()
4391f424632SJohn Scipione		: BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
4401f424632SJohn Scipione
4411f424632SJohn Scipione	return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size);
4421f424632SJohn Scipione}
4431f424632SJohn Scipione
4441f424632SJohn Scipione
4451f424632SJohn ScipioneBSize
4461f424632SJohn ScipioneBScrollView::PreferredSize()
44789208c77SStephan Aßmus{
4481f424632SJohn Scipione	BSize size = _ComputeSize(fTarget != NULL ? fTarget->PreferredSize()
4491f424632SJohn Scipione		: BSize(32, 32));
4501f424632SJohn Scipione
4511f424632SJohn Scipione	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size);
45289208c77SStephan Aßmus}
45389208c77SStephan Aßmus
45489208c77SStephan Aßmus
4551f424632SJohn Scipione// #pragma mark - BScrollView methods
45689208c77SStephan Aßmus
45789208c77SStephan Aßmus
45889208c77SStephan AßmusBScrollBar*
4591f424632SJohn ScipioneBScrollView::ScrollBar(orientation direction) const
46016fe6dd9SAxel Dörfler{
4611f424632SJohn Scipione	if (direction == B_HORIZONTAL)
46216fe6dd9SAxel Dörfler		return fHorizontalScrollBar;
46316fe6dd9SAxel Dörfler
46416fe6dd9SAxel Dörfler	return fVerticalScrollBar;
46516fe6dd9SAxel Dörfler}
46616fe6dd9SAxel Dörfler
46716fe6dd9SAxel Dörfler
46816fe6dd9SAxel Dörflervoid
46916fe6dd9SAxel DörflerBScrollView::SetBorder(border_style border)
47016fe6dd9SAxel Dörfler{
47126a96b16SAxel Dörfler	if (fBorder == border)
47226a96b16SAxel Dörfler		return;
47326a96b16SAxel Dörfler
4745b0e5c0aSAugustin Cavalier	if ((Flags() & B_SUPPORTS_LAYOUT) != 0) {
4755fd5fe56SKarsten Heimrich		fBorder = border;
4764854630dSAugustin Cavalier		SetFlags(_ModifyFlags(Flags(), fTarget, border));
4775fd5fe56SKarsten Heimrich
4785fd5fe56SKarsten Heimrich		DoLayout();
479fd79684aSAxel Dörfler		Invalidate();
4805fd5fe56SKarsten Heimrich		return;
4815fd5fe56SKarsten Heimrich	}
4825fd5fe56SKarsten Heimrich
4839e163a7aSAxel Dörfler	float offset = _BorderSize() - _BorderSize(border);
48426a96b16SAxel Dörfler	float resize = 2 * offset;
48526a96b16SAxel Dörfler
48626a96b16SAxel Dörfler	float horizontalGap = 0, verticalGap = 0;
48726a96b16SAxel Dörfler	float change = 0;
48826a96b16SAxel Dörfler	if (border == B_NO_BORDER || fBorder == B_NO_BORDER) {
48926a96b16SAxel Dörfler		if (fHorizontalScrollBar != NULL)
49026a96b16SAxel Dörfler			verticalGap = border != B_NO_BORDER ? 1 : -1;
49126a96b16SAxel Dörfler		if (fVerticalScrollBar != NULL)
49226a96b16SAxel Dörfler			horizontalGap = border != B_NO_BORDER ? 1 : -1;
49326a96b16SAxel Dörfler
494ecae3149SAxel Dörfler		change = border != B_NO_BORDER ? -1 : 1;
495ecae3149SAxel Dörfler		if (fHorizontalScrollBar == NULL || fVerticalScrollBar == NULL)
496ecae3149SAxel Dörfler			change *= 2;
49726a96b16SAxel Dörfler	}
49826a96b16SAxel Dörfler
49916fe6dd9SAxel Dörfler	fBorder = border;
50026a96b16SAxel Dörfler
50126a96b16SAxel Dörfler	int32 savedResizingMode = 0;
50226a96b16SAxel Dörfler	if (fTarget != NULL) {
50326a96b16SAxel Dörfler		savedResizingMode = fTarget->ResizingMode();
50426a96b16SAxel Dörfler		fTarget->SetResizingMode(B_FOLLOW_NONE);
50526a96b16SAxel Dörfler	}
50626a96b16SAxel Dörfler
50726a96b16SAxel Dörfler	MoveBy(offset, offset);
50826a96b16SAxel Dörfler	ResizeBy(-resize - horizontalGap, -resize - verticalGap);
50926a96b16SAxel Dörfler
51026a96b16SAxel Dörfler	if (fTarget != NULL) {
51126a96b16SAxel Dörfler		fTarget->MoveBy(-offset, -offset);
51226a96b16SAxel Dörfler		fTarget->SetResizingMode(savedResizingMode);
51326a96b16SAxel Dörfler	}
51426a96b16SAxel Dörfler
51526a96b16SAxel Dörfler	if (fHorizontalScrollBar != NULL) {
51626a96b16SAxel Dörfler		fHorizontalScrollBar->MoveBy(-offset - verticalGap, offset + verticalGap);
51726a96b16SAxel Dörfler		fHorizontalScrollBar->ResizeBy(resize + horizontalGap - change, 0);
51826a96b16SAxel Dörfler	}
51926a96b16SAxel Dörfler	if (fVerticalScrollBar != NULL) {
52026a96b16SAxel Dörfler		fVerticalScrollBar->MoveBy(offset + horizontalGap, -offset - horizontalGap);
52126a96b16SAxel Dörfler		fVerticalScrollBar->ResizeBy(0, resize + verticalGap - change);
52226a96b16SAxel Dörfler	}
52326a96b16SAxel Dörfler
5244854630dSAugustin Cavalier	SetFlags(_ModifyFlags(Flags(), fTarget, border));
52516fe6dd9SAxel Dörfler}
52616fe6dd9SAxel Dörfler
52716fe6dd9SAxel Dörfler
52816fe6dd9SAxel Dörflerborder_style
52916fe6dd9SAxel DörflerBScrollView::Border() const
53016fe6dd9SAxel Dörfler{
53116fe6dd9SAxel Dörfler	return fBorder;
53216fe6dd9SAxel Dörfler}
53316fe6dd9SAxel Dörfler
53416fe6dd9SAxel Dörfler
535fd79684aSAxel Dörflervoid
536fd79684aSAxel DörflerBScrollView::SetBorders(uint32 borders)
537fd79684aSAxel Dörfler{
538fd79684aSAxel Dörfler	if (fBorders == borders || (Flags() & B_SUPPORTS_LAYOUT) == 0)
539fd79684aSAxel Dörfler		return;
540fd79684aSAxel Dörfler
541fd79684aSAxel Dörfler	fBorders = borders;
542fd79684aSAxel Dörfler	DoLayout();
543fd79684aSAxel Dörfler	Invalidate();
544fd79684aSAxel Dörfler}
545fd79684aSAxel Dörfler
546fd79684aSAxel Dörfler
547fd79684aSAxel Dörfleruint32
548fd79684aSAxel DörflerBScrollView::Borders() const
549fd79684aSAxel Dörfler{
550fd79684aSAxel Dörfler	return fBorders;
551fd79684aSAxel Dörfler}
552fd79684aSAxel Dörfler
553fd79684aSAxel Dörfler
55416fe6dd9SAxel Dörflerstatus_t
5551f424632SJohn ScipioneBScrollView::SetBorderHighlighted(bool highlight)
55616fe6dd9SAxel Dörfler{
5571f424632SJohn Scipione	if (fHighlighted == highlight)
55826a96b16SAxel Dörfler		return B_OK;
55926a96b16SAxel Dörfler
56075c3c8f5SAxel Dörfler	if (fBorder != B_FANCY_BORDER)
56175c3c8f5SAxel Dörfler		// highlighting only works for B_FANCY_BORDER
56275c3c8f5SAxel Dörfler		return B_ERROR;
56375c3c8f5SAxel Dörfler
5641f424632SJohn Scipione	fHighlighted = highlight;
56516fe6dd9SAxel Dörfler
5662f86ba45SStephan Aßmus	if (fHorizontalScrollBar != NULL)
5671f424632SJohn Scipione		fHorizontalScrollBar->SetBorderHighlighted(highlight);
5682f86ba45SStephan Aßmus	if (fVerticalScrollBar != NULL)
5691f424632SJohn Scipione		fVerticalScrollBar->SetBorderHighlighted(highlight);
5702f86ba45SStephan Aßmus
57126a96b16SAxel Dörfler	BRect bounds = Bounds();
572bfbb9655SAugustin Cavalier	bounds.InsetBy(1, 1);
5732f86ba45SStephan Aßmus
57426a96b16SAxel Dörfler	Invalidate(BRect(bounds.left, bounds.top, bounds.right, bounds.top));
5759e163a7aSAxel Dörfler	Invalidate(BRect(bounds.left, bounds.top + 1, bounds.left,
5769e163a7aSAxel Dörfler		bounds.bottom - 1));
5779e163a7aSAxel Dörfler	Invalidate(BRect(bounds.right, bounds.top + 1, bounds.right,
5789e163a7aSAxel Dörfler		bounds.bottom - 1));
57926a96b16SAxel Dörfler	Invalidate(BRect(bounds.left, bounds.bottom, bounds.right, bounds.bottom));
58016fe6dd9SAxel Dörfler
58116fe6dd9SAxel Dörfler	return B_OK;
58216fe6dd9SAxel Dörfler}
58316fe6dd9SAxel Dörfler
58416fe6dd9SAxel Dörfler
58516fe6dd9SAxel Dörflerbool
58616fe6dd9SAxel DörflerBScrollView::IsBorderHighlighted() const
58716fe6dd9SAxel Dörfler{
58816fe6dd9SAxel Dörfler	return fHighlighted;
58916fe6dd9SAxel Dörfler}
59016fe6dd9SAxel Dörfler
59116fe6dd9SAxel Dörfler
59216fe6dd9SAxel Dörflervoid
5931f424632SJohn ScipioneBScrollView::SetTarget(BView* target)
59416fe6dd9SAxel Dörfler{
59575c3c8f5SAxel Dörfler	if (fTarget == target)
59675c3c8f5SAxel Dörfler		return;
59775c3c8f5SAxel Dörfler
598122e979eSAxel Dörfler	if (fTarget != NULL) {
599122e979eSAxel Dörfler		fTarget->TargetedByScrollView(NULL);
600122e979eSAxel Dörfler		RemoveChild(fTarget);
601122e979eSAxel Dörfler
60275c3c8f5SAxel Dörfler		// we are not supposed to delete the view
603122e979eSAxel Dörfler	}
604122e979eSAxel Dörfler
60516fe6dd9SAxel Dörfler	fTarget = target;
60675c3c8f5SAxel Dörfler	if (fHorizontalScrollBar != NULL)
60775c3c8f5SAxel Dörfler		fHorizontalScrollBar->SetTarget(target);
60875c3c8f5SAxel Dörfler	if (fVerticalScrollBar != NULL)
60975c3c8f5SAxel Dörfler		fVerticalScrollBar->SetTarget(target);
61075c3c8f5SAxel Dörfler
611122e979eSAxel Dörfler	if (target != NULL) {
612fd79684aSAxel Dörfler		float borderSize = _BorderSize();
613fd79684aSAxel Dörfler		target->MoveTo((fBorders & BControlLook::B_LEFT_BORDER) != 0
614fd79684aSAxel Dörfler			? borderSize : 0, (fBorders & BControlLook::B_TOP_BORDER) != 0
615fd79684aSAxel Dörfler				? borderSize : 0);
6169e163a7aSAxel Dörfler		BRect innerFrame = _InnerFrame();
6175fd5fe56SKarsten Heimrich		target->ResizeTo(innerFrame.Width() - 1, innerFrame.Height() - 1);
61875c3c8f5SAxel Dörfler		target->TargetedByScrollView(this);
61975c3c8f5SAxel Dörfler
620122e979eSAxel Dörfler		AddChild(target, ChildAt(0));
621122e979eSAxel Dörfler			// This way, we are making sure that the target will
622122e979eSAxel Dörfler			// be added top most in the list (which is important
623122e979eSAxel Dörfler			// for unarchiving)
624122e979eSAxel Dörfler	}
6254854630dSAugustin Cavalier
6264854630dSAugustin Cavalier	SetFlags(_ModifyFlags(Flags(), fTarget, fBorder));
62716fe6dd9SAxel Dörfler}
62816fe6dd9SAxel Dörfler
62916fe6dd9SAxel Dörfler
63089208c77SStephan AßmusBView*
63116fe6dd9SAxel DörflerBScrollView::Target() const
63216fe6dd9SAxel Dörfler{
63316fe6dd9SAxel Dörfler	return fTarget;
63416fe6dd9SAxel Dörfler}
63516fe6dd9SAxel Dörfler
63616fe6dd9SAxel Dörfler
6371f424632SJohn Scipione// #pragma mark - Scripting methods
63816fe6dd9SAxel Dörfler
63916fe6dd9SAxel Dörfler
64089208c77SStephan Aßmus
64189208c77SStephan AßmusBHandler*
6421f424632SJohn ScipioneBScrollView::ResolveSpecifier(BMessage* message, int32 index,
6431f424632SJohn Scipione	BMessage* specifier, int32 what, const char* property)
64416fe6dd9SAxel Dörfler{
6451f424632SJohn Scipione	return BView::ResolveSpecifier(message, index, specifier, what, property);
64616fe6dd9SAxel Dörfler}
64716fe6dd9SAxel Dörfler
64816fe6dd9SAxel Dörfler
64989208c77SStephan Aßmusstatus_t
6501f424632SJohn ScipioneBScrollView::GetSupportedSuites(BMessage* message)
65116fe6dd9SAxel Dörfler{
6521f424632SJohn Scipione	return BView::GetSupportedSuites(message);
65316fe6dd9SAxel Dörfler}
65416fe6dd9SAxel Dörfler
65516fe6dd9SAxel Dörfler
6561f424632SJohn Scipione//	#pragma mark - Perform
6571f424632SJohn Scipione
6581f424632SJohn Scipione
65989208c77SStephan Aßmusstatus_t
66089208c77SStephan AßmusBScrollView::Perform(perform_code code, void* _data)
66116fe6dd9SAxel Dörfler{
66289208c77SStephan Aßmus	switch (code) {
66389208c77SStephan Aßmus		case PERFORM_CODE_MIN_SIZE:
66489208c77SStephan Aßmus			((perform_data_min_size*)_data)->return_value
66589208c77SStephan Aßmus				= BScrollView::MinSize();
66689208c77SStephan Aßmus			return B_OK;
6671f424632SJohn Scipione
66889208c77SStephan Aßmus		case PERFORM_CODE_MAX_SIZE:
66989208c77SStephan Aßmus			((perform_data_max_size*)_data)->return_value
67089208c77SStephan Aßmus				= BScrollView::MaxSize();
67189208c77SStephan Aßmus			return B_OK;
6721f424632SJohn Scipione
67389208c77SStephan Aßmus		case PERFORM_CODE_PREFERRED_SIZE:
67489208c77SStephan Aßmus			((perform_data_preferred_size*)_data)->return_value
67589208c77SStephan Aßmus				= BScrollView::PreferredSize();
67689208c77SStephan Aßmus			return B_OK;
6771f424632SJohn Scipione
67889208c77SStephan Aßmus		case PERFORM_CODE_LAYOUT_ALIGNMENT:
67989208c77SStephan Aßmus			((perform_data_layout_alignment*)_data)->return_value
68089208c77SStephan Aßmus				= BScrollView::LayoutAlignment();
68189208c77SStephan Aßmus			return B_OK;
6821f424632SJohn Scipione
68389208c77SStephan Aßmus		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
68489208c77SStephan Aßmus			((perform_data_has_height_for_width*)_data)->return_value
68589208c77SStephan Aßmus				= BScrollView::HasHeightForWidth();
68689208c77SStephan Aßmus			return B_OK;
6871f424632SJohn Scipione
68889208c77SStephan Aßmus		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
68989208c77SStephan Aßmus		{
69089208c77SStephan Aßmus			perform_data_get_height_for_width* data
69189208c77SStephan Aßmus				= (perform_data_get_height_for_width*)_data;
69289208c77SStephan Aßmus			BScrollView::GetHeightForWidth(data->width, &data->min, &data->max,
69389208c77SStephan Aßmus				&data->preferred);
69489208c77SStephan Aßmus			return B_OK;
69589208c77SStephan Aßmus		}
6961f424632SJohn Scipione
69789208c77SStephan Aßmus		case PERFORM_CODE_SET_LAYOUT:
69889208c77SStephan Aßmus		{
69989208c77SStephan Aßmus			perform_data_set_layout* data = (perform_data_set_layout*)_data;
70089208c77SStephan Aßmus			BScrollView::SetLayout(data->layout);
70189208c77SStephan Aßmus			return B_OK;
70289208c77SStephan Aßmus		}
7031f424632SJohn Scipione
704eee4243dSAlex Wilson		case PERFORM_CODE_LAYOUT_INVALIDATED:
70589208c77SStephan Aßmus		{
706eee4243dSAlex Wilson			perform_data_layout_invalidated* data
707eee4243dSAlex Wilson				= (perform_data_layout_invalidated*)_data;
708eee4243dSAlex Wilson			BScrollView::LayoutInvalidated(data->descendants);
70989208c77SStephan Aßmus			return B_OK;
710