1/*
2 * Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <ScrollView.h>
8
9#include <ControlLook.h>
10#include <LayoutUtils.h>
11#include <Message.h>
12#include <Region.h>
13#include <Window.h>
14
15#include <binary_compatibility/Interface.h>
16
17static const float kFancyBorderSize = 2;
18static const float kPlainBorderSize = 1;
19
20
21BScrollView::BScrollView(const char *name, BView *target, uint32 resizingMode,
22		uint32 flags, bool horizontal, bool vertical, border_style border)
23	: BView(_ComputeFrame(target, horizontal, vertical, border), name,
24		resizingMode, _ModifyFlags(flags, border)),
25	fTarget(target),
26	fBorder(border)
27{
28	_Init(horizontal, vertical);
29}
30
31
32BScrollView::BScrollView(const char* name, BView* target, uint32 flags,
33		bool horizontal, bool vertical, border_style border)
34	: BView(name, _ModifyFlags(flags, border)),
35	fTarget(target),
36	fBorder(border)
37{
38	_Init(horizontal, vertical);
39}
40
41
42BScrollView::BScrollView(BMessage *archive)
43	: BView(archive),
44	fHighlighted(false)
45{
46	int32 border;
47	fBorder = archive->FindInt32("_style", &border) == B_OK ?
48		(border_style)border : B_FANCY_BORDER;
49
50	// In a shallow archive, we may not have a target anymore. We must
51	// be prepared for this case
52
53	// don't confuse our scroll bars with our (eventual) target
54	int32 firstBar = 0;
55	if (!archive->FindBool("_no_target_")) {
56		fTarget = ChildAt(0);
57		firstBar++;
58	} else
59		fTarget = NULL;
60
61	// search for our scroll bars
62
63	fHorizontalScrollBar = NULL;
64	fVerticalScrollBar = NULL;
65
66	BView *view;
67	while ((view = ChildAt(firstBar++)) != NULL) {
68		BScrollBar *bar = dynamic_cast<BScrollBar *>(view);
69		if (bar == NULL)
70			continue;
71
72		if (bar->Orientation() == B_HORIZONTAL)
73			fHorizontalScrollBar = bar;
74		else if (bar->Orientation() == B_VERTICAL)
75			fVerticalScrollBar = bar;
76	}
77
78	fPreviousWidth = uint16(Bounds().Width());
79	fPreviousHeight = uint16(Bounds().Height());
80}
81
82
83BScrollView::~BScrollView()
84{
85}
86
87
88// #pragma mark -
89
90
91BArchivable*
92BScrollView::Instantiate(BMessage* archive)
93{
94	if (validate_instantiation(archive, "BScrollView"))
95		return new BScrollView(archive);
96
97	return NULL;
98}
99
100
101status_t
102BScrollView::Archive(BMessage* archive, bool deep) const
103{
104	status_t status = BView::Archive(archive, deep);
105	if (status != B_OK)
106		return status;
107
108	// If this is a deep archive, the BView class will take care
109	// of our children.
110
111	if (status == B_OK && fBorder != B_FANCY_BORDER)
112		status = archive->AddInt32("_style", fBorder);
113	if (status == B_OK && fTarget == NULL)
114		status = archive->AddBool("_no_target_", true);
115
116	// The highlighted state is not archived, but since it is
117	// usually (or should be) used to indicate focus, this
118	// is probably the right thing to do.
119
120	return status;
121}
122
123
124void
125BScrollView::AttachedToWindow()
126{
127	BView::AttachedToWindow();
128
129	if ((fHorizontalScrollBar == NULL && fVerticalScrollBar == NULL)
130		|| (fHorizontalScrollBar != NULL && fVerticalScrollBar != NULL)
131		|| Window()->Look() != B_DOCUMENT_WINDOW_LOOK)
132		return;
133
134	// If we have only one bar, we need to check if we are in the
135	// bottom right edge of a window with the B_DOCUMENT_LOOK to
136	// adjust the size of the bar to acknowledge the resize knob.
137
138	BRect bounds = ConvertToScreen(Bounds());
139	BRect windowBounds = Window()->Frame();
140
141	if (bounds.right - _BorderSize() != windowBounds.right
142		|| bounds.bottom - _BorderSize() != windowBounds.bottom)
143		return;
144
145	if (fHorizontalScrollBar)
146		fHorizontalScrollBar->ResizeBy(-B_V_SCROLL_BAR_WIDTH, 0);
147	else if (fVerticalScrollBar)
148		fVerticalScrollBar->ResizeBy(0, -B_H_SCROLL_BAR_HEIGHT);
149}
150
151
152void
153BScrollView::DetachedFromWindow()
154{
155	BView::DetachedFromWindow();
156}
157
158
159void
160BScrollView::AllAttached()
161{
162	BView::AllAttached();
163}
164
165
166void
167BScrollView::AllDetached()
168{
169	BView::AllDetached();
170}
171
172
173void
174BScrollView::Draw(BRect updateRect)
175{
176	if (be_control_look != NULL) {
177		uint32 flags = 0;
178		if (fHighlighted && Window()->IsActive())
179			flags |= BControlLook::B_FOCUSED;
180		BRect rect(Bounds());
181		rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
182
183		BRect verticalScrollBarFrame(0, 0, -1, -1);
184		if (fVerticalScrollBar)
185			verticalScrollBarFrame = fVerticalScrollBar->Frame();
186		BRect horizontalScrollBarFrame(0, 0, -1, -1);
187		if (fHorizontalScrollBar)
188			horizontalScrollBarFrame = fHorizontalScrollBar->Frame();
189
190		be_control_look->DrawScrollViewFrame(this, rect, updateRect,
191			verticalScrollBarFrame, horizontalScrollBarFrame, base, fBorder,
192			flags);
193
194		return;
195	}
196
197	if (fBorder == B_PLAIN_BORDER) {
198		SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
199			B_DARKEN_2_TINT));
200		StrokeRect(Bounds());
201		return;
202	} else if (fBorder != B_FANCY_BORDER)
203		return;
204
205	BRect bounds = Bounds();
206	SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
207		B_DARKEN_2_TINT));
208	StrokeRect(bounds.InsetByCopy(1, 1));
209
210	if (fHighlighted && Window()->IsActive()) {
211		SetHighColor(ui_color(B_NAVIGATION_BASE_COLOR));
212		StrokeRect(bounds);
213	} else {
214		SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
215			B_DARKEN_1_TINT));
216		StrokeLine(bounds.LeftBottom(), bounds.LeftTop());
217		bounds.left++;
218		StrokeLine(bounds.LeftTop(), bounds.RightTop());
219
220		SetHighColor(ui_color(B_SHINE_COLOR));
221		StrokeLine(bounds.LeftBottom(), bounds.RightBottom());
222		bounds.top++;
223		bounds.bottom--;
224		StrokeLine(bounds.RightBottom(), bounds.RightTop());
225	}
226}
227
228
229// #pragma mark -
230
231
232void
233BScrollView::WindowActivated(bool active)
234{
235	if (fHighlighted)
236		Invalidate();
237
238	BView::WindowActivated(active);
239}
240
241
242void
243BScrollView::MakeFocus(bool state)
244{
245	BView::MakeFocus(state);
246}
247
248
249// #pragma mark -
250
251
252void
253BScrollView::GetPreferredSize(float *_width, float *_height)
254{
255	BSize size = PreferredSize();
256
257	if (_width)
258		*_width = size.width;
259	if (_height)
260		*_height = size.height;
261}
262
263
264BSize
265BScrollView::MinSize()
266{
267	BSize size = _ComputeSize(fTarget != NULL ? fTarget->MinSize()
268		: BSize(16, 16));
269
270	return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
271}
272
273
274BSize
275BScrollView::MaxSize()
276{
277	BSize size = _ComputeSize(fTarget != NULL ? fTarget->MaxSize()
278		: BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
279
280	return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size);
281}
282
283
284BSize
285BScrollView::PreferredSize()
286{
287	BSize size = _ComputeSize(fTarget != NULL ? fTarget->PreferredSize()
288		: BSize(32, 32));
289
290	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size);
291}
292
293
294void
295BScrollView::ResizeToPreferred()
296{
297	if (Window() == NULL)
298		return;
299	BView::ResizeToPreferred();
300}
301
302
303void
304BScrollView::FrameMoved(BPoint position)
305{
306	BView::FrameMoved(position);
307}
308
309
310void
311BScrollView::FrameResized(float width, float height)
312{
313	BView::FrameResized(width, height);
314
315	if (fBorder == B_NO_BORDER)
316		return;
317
318	BRect bounds = Bounds();
319	float border = _BorderSize() - 1;
320
321	if (be_control_look && fHorizontalScrollBar && fVerticalScrollBar) {
322		BRect scrollCorner(bounds);
323		scrollCorner.left = min_c(
324			fPreviousWidth - fVerticalScrollBar->Frame().Height(),
325			fHorizontalScrollBar->Frame().right + 1);
326		scrollCorner.top = min_c(
327			fPreviousHeight - fHorizontalScrollBar->Frame().Width(),
328			fVerticalScrollBar->Frame().bottom + 1);
329		Invalidate(scrollCorner);
330	}
331
332	// changes in width
333
334	if (bounds.Width() > fPreviousWidth) {
335		// invalidate the region between the old and the new right border
336		BRect rect = bounds;
337		rect.left += fPreviousWidth - border;
338		rect.right--;
339		Invalidate(rect);
340	} else if (bounds.Width() < fPreviousWidth) {
341		// invalidate the region of the new right border
342		BRect rect = bounds;
343		rect.left = rect.right - border;
344		Invalidate(rect);
345	}
346
347	// changes in height
348
349	if (bounds.Height() > fPreviousHeight) {
350		// invalidate the region between the old and the new bottom border
351		BRect rect = bounds;
352		rect.top += fPreviousHeight - border;
353		rect.bottom--;
354		Invalidate(rect);
355	} else if (bounds.Height() < fPreviousHeight) {
356		// invalidate the region of the new bottom border
357		BRect rect = bounds;
358		rect.top = rect.bottom - border;
359		Invalidate(rect);
360	}
361
362	fPreviousWidth = uint16(bounds.Width());
363	fPreviousHeight = uint16(bounds.Height());
364}
365
366
367// #pragma mark -
368
369
370void
371BScrollView::MessageReceived(BMessage* message)
372{
373	switch (message->what) {
374		default:
375			BView::MessageReceived(message);
376	}
377}
378
379
380void
381BScrollView::MouseDown(BPoint point)
382{
383	BView::MouseDown(point);
384}
385
386
387void
388BScrollView::MouseUp(BPoint point)
389{
390	BView::MouseUp(point);
391}
392
393
394void
395BScrollView::MouseMoved(BPoint point, uint32 code, const BMessage *dragMessage)
396{
397	BView::MouseMoved(point, code, dragMessage);
398}
399
400
401// #pragma mark -
402
403
404BScrollBar*
405BScrollView::ScrollBar(orientation posture) const
406{
407	if (posture == B_HORIZONTAL)
408		return fHorizontalScrollBar;
409
410	return fVerticalScrollBar;
411}
412
413
414void
415BScrollView::SetBorder(border_style border)
416{
417	if (fBorder == border)
418		return;
419
420	if (Flags() & B_SUPPORTS_LAYOUT) {
421		fBorder = border;
422		SetFlags(_ModifyFlags(Flags(), border));
423
424		DoLayout();
425
426		BRect bounds(Bounds());
427		Invalidate(BRect(bounds.LeftTop(), bounds.RightBottom()));
428		Invalidate(BRect(bounds.LeftBottom(), bounds.RightBottom()));
429		return;
430	}
431
432	float offset = _BorderSize() - _BorderSize(border);
433	float resize = 2 * offset;
434
435	float horizontalGap = 0, verticalGap = 0;
436	float change = 0;
437	if (border == B_NO_BORDER || fBorder == B_NO_BORDER) {
438		if (fHorizontalScrollBar != NULL)
439			verticalGap = border != B_NO_BORDER ? 1 : -1;
440		if (fVerticalScrollBar != NULL)
441			horizontalGap = border != B_NO_BORDER ? 1 : -1;
442
443		change = border != B_NO_BORDER ? -1 : 1;
444		if (fHorizontalScrollBar == NULL || fVerticalScrollBar == NULL)
445			change *= 2;
446	}
447
448	fBorder = border;
449
450	int32 savedResizingMode = 0;
451	if (fTarget != NULL) {
452		savedResizingMode = fTarget->ResizingMode();
453		fTarget->SetResizingMode(B_FOLLOW_NONE);
454	}
455
456	MoveBy(offset, offset);
457	ResizeBy(-resize - horizontalGap, -resize - verticalGap);
458
459	if (fTarget != NULL) {
460		fTarget->MoveBy(-offset, -offset);
461		fTarget->SetResizingMode(savedResizingMode);
462	}
463
464	if (fHorizontalScrollBar != NULL) {
465		fHorizontalScrollBar->MoveBy(-offset - verticalGap, offset + verticalGap);
466		fHorizontalScrollBar->ResizeBy(resize + horizontalGap - change, 0);
467	}
468	if (fVerticalScrollBar != NULL) {
469		fVerticalScrollBar->MoveBy(offset + horizontalGap, -offset - horizontalGap);
470		fVerticalScrollBar->ResizeBy(0, resize + verticalGap - change);
471	}
472
473	SetFlags(_ModifyFlags(Flags(), border));
474}
475
476
477border_style
478BScrollView::Border() const
479{
480	return fBorder;
481}
482
483
484status_t
485BScrollView::SetBorderHighlighted(bool state)
486{
487	if (fHighlighted == state)
488		return B_OK;
489
490	if (fBorder != B_FANCY_BORDER)
491		// highlighting only works for B_FANCY_BORDER
492		return B_ERROR;
493
494	fHighlighted = state;
495
496	if (fHorizontalScrollBar != NULL)
497		fHorizontalScrollBar->SetBorderHighlighted(state);
498	if (fVerticalScrollBar != NULL)
499		fVerticalScrollBar->SetBorderHighlighted(state);
500
501	BRect bounds = Bounds();
502	if (be_control_look != NULL)
503		bounds.InsetBy(1, 1);
504
505	Invalidate(BRect(bounds.left, bounds.top, bounds.right, bounds.top));
506	Invalidate(BRect(bounds.left, bounds.top + 1, bounds.left,
507		bounds.bottom - 1));
508	Invalidate(BRect(bounds.right, bounds.top + 1, bounds.right,
509		bounds.bottom - 1));
510	Invalidate(BRect(bounds.left, bounds.bottom, bounds.right, bounds.bottom));
511
512	return B_OK;
513}
514
515
516bool
517BScrollView::IsBorderHighlighted() const
518{
519	return fHighlighted;
520}
521
522
523void
524BScrollView::SetTarget(BView *target)
525{
526	if (fTarget == target)
527		return;
528
529	if (fTarget != NULL) {
530		fTarget->TargetedByScrollView(NULL);
531		RemoveChild(fTarget);
532
533		// we are not supposed to delete the view
534	}
535
536	fTarget = target;
537	if (fHorizontalScrollBar != NULL)
538		fHorizontalScrollBar->SetTarget(target);
539	if (fVerticalScrollBar != NULL)
540		fVerticalScrollBar->SetTarget(target);
541
542	if (target != NULL) {
543		target->MoveTo(_BorderSize(), _BorderSize());
544		BRect innerFrame = _InnerFrame();
545		target->ResizeTo(innerFrame.Width() - 1, innerFrame.Height() - 1);
546		target->TargetedByScrollView(this);
547
548		AddChild(target, ChildAt(0));
549			// This way, we are making sure that the target will
550			// be added top most in the list (which is important
551			// for unarchiving)
552	}
553}
554
555
556BView*
557BScrollView::Target() const
558{
559	return fTarget;
560}
561
562
563// #pragma mark -
564
565
566
567BHandler*
568BScrollView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
569	int32 form, const char* property)
570{
571	return BView::ResolveSpecifier(msg, index, specifier, form, property);
572}
573
574
575status_t
576BScrollView::GetSupportedSuites(BMessage *data)
577{
578	return BView::GetSupportedSuites(data);
579}
580
581
582status_t
583BScrollView::Perform(perform_code code, void* _data)
584{
585	switch (code) {
586		case PERFORM_CODE_MIN_SIZE:
587			((perform_data_min_size*)_data)->return_value
588				= BScrollView::MinSize();
589			return B_OK;
590		case PERFORM_CODE_MAX_SIZE:
591			((perform_data_max_size*)_data)->return_value
592				= BScrollView::MaxSize();
593			return B_OK;
594		case PERFORM_CODE_PREFERRED_SIZE:
595			((perform_data_preferred_size*)_data)->return_value
596				= BScrollView::PreferredSize();
597			return B_OK;
598		case PERFORM_CODE_LAYOUT_ALIGNMENT:
599			((perform_data_layout_alignment*)_data)->return_value
600				= BScrollView::LayoutAlignment();
601			return B_OK;
602		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
603			((perform_data_has_height_for_width*)_data)->return_value
604				= BScrollView::HasHeightForWidth();
605			return B_OK;
606		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
607		{
608			perform_data_get_height_for_width* data
609				= (perform_data_get_height_for_width*)_data;
610			BScrollView::GetHeightForWidth(data->width, &data->min, &data->max,
611				&data->preferred);
612			return B_OK;
613		}
614		case PERFORM_CODE_SET_LAYOUT:
615		{
616			perform_data_set_layout* data = (perform_data_set_layout*)_data;
617			BScrollView::SetLayout(data->layout);
618			return B_OK;
619		}
620		case PERFORM_CODE_LAYOUT_INVALIDATED:
621		{
622			perform_data_layout_invalidated* data
623				= (perform_data_layout_invalidated*)_data;
624			BScrollView::LayoutInvalidated(data->descendants);
625			return B_OK;
626		}
627		case PERFORM_CODE_DO_LAYOUT:
628		{
629			BScrollView::DoLayout();
630			return B_OK;
631		}
632	}
633
634	return BView::Perform(code, _data);
635}
636
637
638void
639BScrollView::LayoutInvalidated(bool descendants)
640{
641}
642
643
644void
645BScrollView::DoLayout()
646{
647	if (!(Flags() & B_SUPPORTS_LAYOUT))
648		return;
649
650	// If the user set a layout, we let the base class version call its hook.
651	if (GetLayout()) {
652		BView::DoLayout();
653		return;
654	}
655
656	BRect innerFrame = _InnerFrame();
657
658	if (fTarget != NULL) {
659		fTarget->MoveTo(innerFrame.left, innerFrame.top);
660		fTarget->ResizeTo(innerFrame.Width(), innerFrame.Height());
661
662		//BLayoutUtils::AlignInFrame(fTarget, fTarget->Bounds());
663	}
664
665	_AlignScrollBars(fHorizontalScrollBar != NULL, fVerticalScrollBar != NULL,
666		innerFrame);
667}
668
669
670
671
672// #pragma mark -
673
674
675void
676BScrollView::_Init(bool horizontal, bool vertical)
677{
678	fHorizontalScrollBar = NULL;
679	fVerticalScrollBar = NULL;
680	fHighlighted = false;
681
682	if (be_control_look != NULL)
683		SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
684
685	if (horizontal) {
686		fHorizontalScrollBar = new BScrollBar(BRect(0, 0, 14, 14), "_HSB_",
687			fTarget, 0, 1000, B_HORIZONTAL);
688		AddChild(fHorizontalScrollBar);
689	}
690
691	if (vertical) {
692		fVerticalScrollBar = new BScrollBar(BRect(0, 0, 14, 14), "_VSB_",
693			fTarget, 0, 1000, B_VERTICAL);
694		AddChild(fVerticalScrollBar);
695	}
696
697	BRect targetFrame;
698	if (fTarget) {
699		// layout target and add it
700		fTarget->TargetedByScrollView(this);
701		fTarget->MoveTo(B_ORIGIN);
702
703		if (fBorder != B_NO_BORDER)
704			fTarget->MoveBy(_BorderSize(), _BorderSize());
705
706		AddChild(fTarget);
707		targetFrame = fTarget->Frame();
708	} else {
709		// no target specified
710		targetFrame = Bounds();
711		if (horizontal)
712			targetFrame.bottom -= B_H_SCROLL_BAR_HEIGHT + 1;
713		if (vertical)
714			targetFrame.right -= B_V_SCROLL_BAR_WIDTH + 1;
715		if (fBorder == B_FANCY_BORDER) {
716			targetFrame.bottom--;
717			targetFrame.right--;
718		}
719	}
720
721	_AlignScrollBars(horizontal, vertical, targetFrame);
722
723	fPreviousWidth = uint16(Bounds().Width());
724	fPreviousHeight = uint16(Bounds().Height());
725}
726
727
728float
729BScrollView::_BorderSize() const
730{
731	return _BorderSize(fBorder);
732}
733
734
735BRect
736BScrollView::_InnerFrame() const
737{
738	BRect frame = Bounds();
739
740	float borderSize = _BorderSize();
741	frame.InsetBy(borderSize, borderSize);
742
743	if (fHorizontalScrollBar != NULL) {
744		frame.bottom -= B_H_SCROLL_BAR_HEIGHT;
745		if (borderSize == 0)
746			frame.bottom--;
747	}
748	if (fVerticalScrollBar != NULL) {
749		frame.right -= B_V_SCROLL_BAR_WIDTH;
750		if (borderSize == 0)
751			frame.right--;
752	}
753
754	return frame;
755}
756
757
758BSize
759BScrollView::_ComputeSize(BSize targetSize) const
760{
761	BRect frame = _ComputeFrame(
762		BRect(0, 0, targetSize.width, targetSize.height));
763
764	return BSize(frame.Width(), frame.Height());
765}
766
767
768BRect
769BScrollView::_ComputeFrame(BRect targetRect) const
770{
771	return _ComputeFrame(targetRect, fHorizontalScrollBar != NULL,
772		fVerticalScrollBar != NULL, fBorder);
773}
774
775
776void
777BScrollView::_AlignScrollBars(bool horizontal, bool vertical, BRect targetFrame)
778{
779	if (horizontal) {
780		BRect rect = targetFrame;
781		rect.top = rect.bottom + 1;
782		rect.bottom = rect.top + B_H_SCROLL_BAR_HEIGHT;
783		if (fBorder != B_NO_BORDER || vertical) {
784			// extend scrollbar so that it overlaps one pixel with vertical
785			// scrollbar
786			rect.right++;
787		}
788
789		if (fBorder != B_NO_BORDER) {
790			// the scrollbar draws part of the surrounding frame on the left
791			rect.left--;
792		}
793
794		fHorizontalScrollBar->MoveTo(rect.left, rect.top);
795		fHorizontalScrollBar->ResizeTo(rect.Width(), rect.Height());
796	}
797
798	if (vertical) {
799		BRect rect = targetFrame;
800		rect.left = rect.right + 1;
801		rect.right = rect.left + B_V_SCROLL_BAR_WIDTH;
802		if (fBorder != B_NO_BORDER || horizontal) {
803			// extend scrollbar so that it overlaps one pixel with vertical
804			// scrollbar
805			rect.bottom++;
806		}
807
808		if (fBorder != B_NO_BORDER) {
809			// the scrollbar draws part of the surrounding frame on the left
810			rect.top--;
811		}
812
813		fVerticalScrollBar->MoveTo(rect.left, rect.top);
814		fVerticalScrollBar->ResizeTo(rect.Width(), rect.Height());
815	}
816}
817
818
819/*!	This static method is used to calculate the frame that the
820	ScrollView will cover depending on the frame of its target
821	and which border style is used.
822	It is used in the constructor and at other places.
823*/
824/*static*/ BRect
825BScrollView::_ComputeFrame(BRect frame, bool horizontal, bool vertical,
826	border_style border)
827{
828	if (vertical)
829		frame.right += B_V_SCROLL_BAR_WIDTH;
830	if (horizontal)
831		frame.bottom += B_H_SCROLL_BAR_HEIGHT;
832
833	float borderSize = _BorderSize(border);
834	frame.InsetBy(-borderSize, -borderSize);
835
836	if (borderSize == 0) {
837		if (vertical)
838			frame.right++;
839		if (horizontal)
840			frame.bottom++;
841	}
842
843	return frame;
844}
845
846
847/*static*/ BRect
848BScrollView::_ComputeFrame(BView *target, bool horizontal, bool vertical,
849	border_style border)
850{
851	return _ComputeFrame(target != NULL ? target->Frame()
852		: BRect(0, 0, 16, 16), horizontal, vertical, border);
853}
854
855
856/*! This method returns the size of the specified border.
857*/
858/*static*/ float
859BScrollView::_BorderSize(border_style border)
860{
861	if (border == B_FANCY_BORDER)
862		return kFancyBorderSize;
863	if (border == B_PLAIN_BORDER)
864		return kPlainBorderSize;
865
866	return 0;
867}
868
869
870/*!	This method changes the "flags" argument as passed on to
871	the BView constructor.
872*/
873/*static*/ int32
874BScrollView::_ModifyFlags(int32 flags, border_style border)
875{
876	// We either need B_FULL_UPDATE_ON_RESIZE or
877	// B_FRAME_EVENTS if we have to draw a border
878	if (border != B_NO_BORDER)
879		return flags | B_WILL_DRAW | (flags & B_FULL_UPDATE_ON_RESIZE ? 0 : B_FRAME_EVENTS);
880
881	return flags & ~(B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE);
882}
883
884
885//	#pragma mark -
886
887
888BScrollView &
889BScrollView::operator=(const BScrollView &)
890{
891	return *this;
892}
893
894
895void BScrollView::_ReservedScrollView1() {}
896void BScrollView::_ReservedScrollView2() {}
897void BScrollView::_ReservedScrollView3() {}
898void BScrollView::_ReservedScrollView4() {}
899
900
901extern "C" void
902B_IF_GCC_2(InvalidateLayout__11BScrollViewb,
903	_ZN11BScrollView16InvalidateLayoutEb)(BScrollView* view, bool descendants)
904{
905	perform_data_layout_invalidated data;
906	data.descendants = descendants;
907
908	view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
909}
910
911