xref: /haiku/src/kits/interface/ScrollView.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
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 
17 static const float kFancyBorderSize = 2;
18 static const float kPlainBorderSize = 1;
19 
20 
21 BScrollView::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 
32 BScrollView::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 
42 BScrollView::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 
83 BScrollView::~BScrollView()
84 {
85 }
86 
87 
88 // #pragma mark -
89 
90 
91 BArchivable*
92 BScrollView::Instantiate(BMessage* archive)
93 {
94 	if (validate_instantiation(archive, "BScrollView"))
95 		return new BScrollView(archive);
96 
97 	return NULL;
98 }
99 
100 
101 status_t
102 BScrollView::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 
124 void
125 BScrollView::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 
152 void
153 BScrollView::DetachedFromWindow()
154 {
155 	BView::DetachedFromWindow();
156 }
157 
158 
159 void
160 BScrollView::AllAttached()
161 {
162 	BView::AllAttached();
163 }
164 
165 
166 void
167 BScrollView::AllDetached()
168 {
169 	BView::AllDetached();
170 }
171 
172 
173 void
174 BScrollView::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 
232 void
233 BScrollView::WindowActivated(bool active)
234 {
235 	if (fHighlighted)
236 		Invalidate();
237 
238 	BView::WindowActivated(active);
239 }
240 
241 
242 void
243 BScrollView::MakeFocus(bool state)
244 {
245 	BView::MakeFocus(state);
246 }
247 
248 
249 // #pragma mark -
250 
251 
252 void
253 BScrollView::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 
264 BSize
265 BScrollView::MinSize()
266 {
267 	BSize size = _ComputeSize(fTarget != NULL ? fTarget->MinSize()
268 		: BSize(16, 16));
269 
270 	return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
271 }
272 
273 
274 BSize
275 BScrollView::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 
284 BSize
285 BScrollView::PreferredSize()
286 {
287 	BSize size = _ComputeSize(fTarget != NULL ? fTarget->PreferredSize()
288 		: BSize(32, 32));
289 
290 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size);
291 }
292 
293 
294 void
295 BScrollView::ResizeToPreferred()
296 {
297 	if (Window() == NULL)
298 		return;
299 	BView::ResizeToPreferred();
300 }
301 
302 
303 void
304 BScrollView::InvalidateLayout(bool descendants)
305 {
306 	BView::InvalidateLayout(descendants);
307 }
308 
309 
310 void
311 BScrollView::DoLayout()
312 {
313 	if (!(Flags() & B_SUPPORTS_LAYOUT))
314 		return;
315 
316 	// If the user set a layout, we let the base class version call its hook.
317 	if (GetLayout()) {
318 		BView::DoLayout();
319 		return;
320 	}
321 
322 	BRect innerFrame = _InnerFrame();
323 
324 	if (fTarget != NULL) {
325 		fTarget->MoveTo(innerFrame.left, innerFrame.top);
326 		fTarget->ResizeTo(innerFrame.Width(), innerFrame.Height());
327 
328 		//BLayoutUtils::AlignInFrame(fTarget, fTarget->Bounds());
329 	}
330 
331 	_AlignScrollBars(fHorizontalScrollBar != NULL, fVerticalScrollBar != NULL,
332 		innerFrame);
333 }
334 
335 
336 void
337 BScrollView::FrameMoved(BPoint position)
338 {
339 	BView::FrameMoved(position);
340 }
341 
342 
343 void
344 BScrollView::FrameResized(float width, float height)
345 {
346 	BView::FrameResized(width, height);
347 
348 	if (fBorder == B_NO_BORDER)
349 		return;
350 
351 	BRect bounds = Bounds();
352 	float border = _BorderSize() - 1;
353 
354 	if (be_control_look && fHorizontalScrollBar && fVerticalScrollBar) {
355 		BRect scrollCorner(bounds);
356 		scrollCorner.left = min_c(
357 			fPreviousWidth - fVerticalScrollBar->Frame().Height(),
358 			fHorizontalScrollBar->Frame().right + 1);
359 		scrollCorner.top = min_c(
360 			fPreviousHeight - fHorizontalScrollBar->Frame().Width(),
361 			fVerticalScrollBar->Frame().bottom + 1);
362 		Invalidate(scrollCorner);
363 	}
364 
365 	// changes in width
366 
367 	if (bounds.Width() > fPreviousWidth) {
368 		// invalidate the region between the old and the new right border
369 		BRect rect = bounds;
370 		rect.left += fPreviousWidth - border;
371 		rect.right--;
372 		Invalidate(rect);
373 	} else if (bounds.Width() < fPreviousWidth) {
374 		// invalidate the region of the new right border
375 		BRect rect = bounds;
376 		rect.left = rect.right - border;
377 		Invalidate(rect);
378 	}
379 
380 	// changes in height
381 
382 	if (bounds.Height() > fPreviousHeight) {
383 		// invalidate the region between the old and the new bottom border
384 		BRect rect = bounds;
385 		rect.top += fPreviousHeight - border;
386 		rect.bottom--;
387 		Invalidate(rect);
388 	} else if (bounds.Height() < fPreviousHeight) {
389 		// invalidate the region of the new bottom border
390 		BRect rect = bounds;
391 		rect.top = rect.bottom - border;
392 		Invalidate(rect);
393 	}
394 
395 	fPreviousWidth = uint16(bounds.Width());
396 	fPreviousHeight = uint16(bounds.Height());
397 }
398 
399 
400 // #pragma mark -
401 
402 
403 void
404 BScrollView::MessageReceived(BMessage* message)
405 {
406 	switch (message->what) {
407 		default:
408 			BView::MessageReceived(message);
409 	}
410 }
411 
412 
413 void
414 BScrollView::MouseDown(BPoint point)
415 {
416 	BView::MouseDown(point);
417 }
418 
419 
420 void
421 BScrollView::MouseUp(BPoint point)
422 {
423 	BView::MouseUp(point);
424 }
425 
426 
427 void
428 BScrollView::MouseMoved(BPoint point, uint32 code, const BMessage *dragMessage)
429 {
430 	BView::MouseMoved(point, code, dragMessage);
431 }
432 
433 
434 // #pragma mark -
435 
436 
437 BScrollBar*
438 BScrollView::ScrollBar(orientation posture) const
439 {
440 	if (posture == B_HORIZONTAL)
441 		return fHorizontalScrollBar;
442 
443 	return fVerticalScrollBar;
444 }
445 
446 
447 void
448 BScrollView::SetBorder(border_style border)
449 {
450 	if (fBorder == border)
451 		return;
452 
453 	if (Flags() & B_SUPPORTS_LAYOUT) {
454 		fBorder = border;
455 		SetFlags(_ModifyFlags(Flags(), border));
456 
457 		DoLayout();
458 
459 		BRect bounds(Bounds());
460 		Invalidate(BRect(bounds.LeftTop(), bounds.RightBottom()));
461 		Invalidate(BRect(bounds.LeftBottom(), bounds.RightBottom()));
462 		return;
463 	}
464 
465 	float offset = _BorderSize() - _BorderSize(border);
466 	float resize = 2 * offset;
467 
468 	float horizontalGap = 0, verticalGap = 0;
469 	float change = 0;
470 	if (border == B_NO_BORDER || fBorder == B_NO_BORDER) {
471 		if (fHorizontalScrollBar != NULL)
472 			verticalGap = border != B_NO_BORDER ? 1 : -1;
473 		if (fVerticalScrollBar != NULL)
474 			horizontalGap = border != B_NO_BORDER ? 1 : -1;
475 
476 		change = border != B_NO_BORDER ? -1 : 1;
477 		if (fHorizontalScrollBar == NULL || fVerticalScrollBar == NULL)
478 			change *= 2;
479 	}
480 
481 	fBorder = border;
482 
483 	int32 savedResizingMode = 0;
484 	if (fTarget != NULL) {
485 		savedResizingMode = fTarget->ResizingMode();
486 		fTarget->SetResizingMode(B_FOLLOW_NONE);
487 	}
488 
489 	MoveBy(offset, offset);
490 	ResizeBy(-resize - horizontalGap, -resize - verticalGap);
491 
492 	if (fTarget != NULL) {
493 		fTarget->MoveBy(-offset, -offset);
494 		fTarget->SetResizingMode(savedResizingMode);
495 	}
496 
497 	if (fHorizontalScrollBar != NULL) {
498 		fHorizontalScrollBar->MoveBy(-offset - verticalGap, offset + verticalGap);
499 		fHorizontalScrollBar->ResizeBy(resize + horizontalGap - change, 0);
500 	}
501 	if (fVerticalScrollBar != NULL) {
502 		fVerticalScrollBar->MoveBy(offset + horizontalGap, -offset - horizontalGap);
503 		fVerticalScrollBar->ResizeBy(0, resize + verticalGap - change);
504 	}
505 
506 	SetFlags(_ModifyFlags(Flags(), border));
507 }
508 
509 
510 border_style
511 BScrollView::Border() const
512 {
513 	return fBorder;
514 }
515 
516 
517 status_t
518 BScrollView::SetBorderHighlighted(bool state)
519 {
520 	if (fHighlighted == state)
521 		return B_OK;
522 
523 	if (fBorder != B_FANCY_BORDER)
524 		// highlighting only works for B_FANCY_BORDER
525 		return B_ERROR;
526 
527 	fHighlighted = state;
528 
529 	if (fHorizontalScrollBar != NULL)
530 		fHorizontalScrollBar->SetBorderHighlighted(state);
531 	if (fVerticalScrollBar != NULL)
532 		fVerticalScrollBar->SetBorderHighlighted(state);
533 
534 	BRect bounds = Bounds();
535 	if (be_control_look != NULL)
536 		bounds.InsetBy(1, 1);
537 
538 	Invalidate(BRect(bounds.left, bounds.top, bounds.right, bounds.top));
539 	Invalidate(BRect(bounds.left, bounds.top + 1, bounds.left,
540 		bounds.bottom - 1));
541 	Invalidate(BRect(bounds.right, bounds.top + 1, bounds.right,
542 		bounds.bottom - 1));
543 	Invalidate(BRect(bounds.left, bounds.bottom, bounds.right, bounds.bottom));
544 
545 	return B_OK;
546 }
547 
548 
549 bool
550 BScrollView::IsBorderHighlighted() const
551 {
552 	return fHighlighted;
553 }
554 
555 
556 void
557 BScrollView::SetTarget(BView *target)
558 {
559 	if (fTarget == target)
560 		return;
561 
562 	if (fTarget != NULL) {
563 		fTarget->TargetedByScrollView(NULL);
564 		RemoveChild(fTarget);
565 
566 		// we are not supposed to delete the view
567 	}
568 
569 	fTarget = target;
570 	if (fHorizontalScrollBar != NULL)
571 		fHorizontalScrollBar->SetTarget(target);
572 	if (fVerticalScrollBar != NULL)
573 		fVerticalScrollBar->SetTarget(target);
574 
575 	if (target != NULL) {
576 		target->MoveTo(_BorderSize(), _BorderSize());
577 		BRect innerFrame = _InnerFrame();
578 		target->ResizeTo(innerFrame.Width() - 1, innerFrame.Height() - 1);
579 		target->TargetedByScrollView(this);
580 
581 		AddChild(target, ChildAt(0));
582 			// This way, we are making sure that the target will
583 			// be added top most in the list (which is important
584 			// for unarchiving)
585 	}
586 }
587 
588 
589 BView*
590 BScrollView::Target() const
591 {
592 	return fTarget;
593 }
594 
595 
596 // #pragma mark -
597 
598 
599 
600 BHandler*
601 BScrollView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
602 	int32 form, const char* property)
603 {
604 	return BView::ResolveSpecifier(msg, index, specifier, form, property);
605 }
606 
607 
608 status_t
609 BScrollView::GetSupportedSuites(BMessage *data)
610 {
611 	return BView::GetSupportedSuites(data);
612 }
613 
614 
615 status_t
616 BScrollView::Perform(perform_code code, void* _data)
617 {
618 	switch (code) {
619 		case PERFORM_CODE_MIN_SIZE:
620 			((perform_data_min_size*)_data)->return_value
621 				= BScrollView::MinSize();
622 			return B_OK;
623 		case PERFORM_CODE_MAX_SIZE:
624 			((perform_data_max_size*)_data)->return_value
625 				= BScrollView::MaxSize();
626 			return B_OK;
627 		case PERFORM_CODE_PREFERRED_SIZE:
628 			((perform_data_preferred_size*)_data)->return_value
629 				= BScrollView::PreferredSize();
630 			return B_OK;
631 		case PERFORM_CODE_LAYOUT_ALIGNMENT:
632 			((perform_data_layout_alignment*)_data)->return_value
633 				= BScrollView::LayoutAlignment();
634 			return B_OK;
635 		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
636 			((perform_data_has_height_for_width*)_data)->return_value
637 				= BScrollView::HasHeightForWidth();
638 			return B_OK;
639 		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
640 		{
641 			perform_data_get_height_for_width* data
642 				= (perform_data_get_height_for_width*)_data;
643 			BScrollView::GetHeightForWidth(data->width, &data->min, &data->max,
644 				&data->preferred);
645 			return B_OK;
646 		}
647 		case PERFORM_CODE_SET_LAYOUT:
648 		{
649 			perform_data_set_layout* data = (perform_data_set_layout*)_data;
650 			BScrollView::SetLayout(data->layout);
651 			return B_OK;
652 		}
653 		case PERFORM_CODE_INVALIDATE_LAYOUT:
654 		{
655 			perform_data_invalidate_layout* data
656 				= (perform_data_invalidate_layout*)_data;
657 			BScrollView::InvalidateLayout(data->descendants);
658 			return B_OK;
659 		}
660 		case PERFORM_CODE_DO_LAYOUT:
661 		{
662 			BScrollView::DoLayout();
663 			return B_OK;
664 		}
665 	}
666 
667 	return BView::Perform(code, _data);
668 }
669 
670 
671 // #pragma mark -
672 
673 
674 void
675 BScrollView::_Init(bool horizontal, bool vertical)
676 {
677 	fHorizontalScrollBar = NULL;
678 	fVerticalScrollBar = NULL;
679 	fHighlighted = false;
680 
681 	if (be_control_look != NULL)
682 		SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
683 
684 	if (horizontal) {
685 		fHorizontalScrollBar = new BScrollBar(BRect(0, 0, 14, 14), "_HSB_",
686 			fTarget, 0, 1000, B_HORIZONTAL);
687 		AddChild(fHorizontalScrollBar);
688 	}
689 
690 	if (vertical) {
691 		fVerticalScrollBar = new BScrollBar(BRect(0, 0, 14, 14), "_VSB_",
692 			fTarget, 0, 1000, B_VERTICAL);
693 		AddChild(fVerticalScrollBar);
694 	}
695 
696 	BRect targetFrame;
697 	if (fTarget) {
698 		// layout target and add it
699 		fTarget->TargetedByScrollView(this);
700 		fTarget->MoveTo(B_ORIGIN);
701 
702 		if (fBorder != B_NO_BORDER)
703 			fTarget->MoveBy(_BorderSize(), _BorderSize());
704 
705 		AddChild(fTarget);
706 		targetFrame = fTarget->Frame();
707 	} else {
708 		// no target specified
709 		targetFrame = Bounds();
710 		if (horizontal)
711 			targetFrame.bottom -= B_H_SCROLL_BAR_HEIGHT + 1;
712 		if (vertical)
713 			targetFrame.right -= B_V_SCROLL_BAR_WIDTH + 1;
714 		if (fBorder == B_FANCY_BORDER) {
715 			targetFrame.bottom--;
716 			targetFrame.right--;
717 		}
718 	}
719 
720 	_AlignScrollBars(horizontal, vertical, targetFrame);
721 
722 	fPreviousWidth = uint16(Bounds().Width());
723 	fPreviousHeight = uint16(Bounds().Height());
724 }
725 
726 
727 float
728 BScrollView::_BorderSize() const
729 {
730 	return _BorderSize(fBorder);
731 }
732 
733 
734 BRect
735 BScrollView::_InnerFrame() const
736 {
737 	BRect frame = Bounds();
738 
739 	float borderSize = _BorderSize();
740 	frame.InsetBy(borderSize, borderSize);
741 
742 	if (fHorizontalScrollBar != NULL) {
743 		frame.bottom -= B_H_SCROLL_BAR_HEIGHT;
744 		if (borderSize == 0)
745 			frame.bottom--;
746 	}
747 	if (fVerticalScrollBar != NULL) {
748 		frame.right -= B_V_SCROLL_BAR_WIDTH;
749 		if (borderSize == 0)
750 			frame.right--;
751 	}
752 
753 	return frame;
754 }
755 
756 
757 BSize
758 BScrollView::_ComputeSize(BSize targetSize) const
759 {
760 	BRect frame = _ComputeFrame(
761 		BRect(0, 0, targetSize.width, targetSize.height));
762 
763 	return BSize(frame.Width(), frame.Height());
764 }
765 
766 
767 BRect
768 BScrollView::_ComputeFrame(BRect targetRect) const
769 {
770 	return _ComputeFrame(targetRect, fHorizontalScrollBar != NULL,
771 		fVerticalScrollBar != NULL, fBorder);
772 }
773 
774 
775 void
776 BScrollView::_AlignScrollBars(bool horizontal, bool vertical, BRect targetFrame)
777 {
778 	if (horizontal) {
779 		BRect rect = targetFrame;
780 		rect.top = rect.bottom + 1;
781 		rect.bottom = rect.top + B_H_SCROLL_BAR_HEIGHT;
782 		if (fBorder != B_NO_BORDER || vertical) {
783 			// extend scrollbar so that it overlaps one pixel with vertical
784 			// scrollbar
785 			rect.right++;
786 		}
787 
788 		if (fBorder != B_NO_BORDER) {
789 			// the scrollbar draws part of the surrounding frame on the left
790 			rect.left--;
791 		}
792 
793 		fHorizontalScrollBar->MoveTo(rect.left, rect.top);
794 		fHorizontalScrollBar->ResizeTo(rect.Width(), rect.Height());
795 	}
796 
797 	if (vertical) {
798 		BRect rect = targetFrame;
799 		rect.left = rect.right + 1;
800 		rect.right = rect.left + B_V_SCROLL_BAR_WIDTH;
801 		if (fBorder != B_NO_BORDER || horizontal) {
802 			// extend scrollbar so that it overlaps one pixel with vertical
803 			// scrollbar
804 			rect.bottom++;
805 		}
806 
807 		if (fBorder != B_NO_BORDER) {
808 			// the scrollbar draws part of the surrounding frame on the left
809 			rect.top--;
810 		}
811 
812 		fVerticalScrollBar->MoveTo(rect.left, rect.top);
813 		fVerticalScrollBar->ResizeTo(rect.Width(), rect.Height());
814 	}
815 }
816 
817 
818 /*!	This static method is used to calculate the frame that the
819 	ScrollView will cover depending on the frame of its target
820 	and which border style is used.
821 	It is used in the constructor and at other places.
822 */
823 /*static*/ BRect
824 BScrollView::_ComputeFrame(BRect frame, bool horizontal, bool vertical,
825 	border_style border)
826 {
827 	if (vertical)
828 		frame.right += B_V_SCROLL_BAR_WIDTH;
829 	if (horizontal)
830 		frame.bottom += B_H_SCROLL_BAR_HEIGHT;
831 
832 	float borderSize = _BorderSize(border);
833 	frame.InsetBy(-borderSize, -borderSize);
834 
835 	if (borderSize == 0) {
836 		if (vertical)
837 			frame.right++;
838 		if (horizontal)
839 			frame.bottom++;
840 	}
841 
842 	return frame;
843 }
844 
845 
846 /*static*/ BRect
847 BScrollView::_ComputeFrame(BView *target, bool horizontal, bool vertical,
848 	border_style border)
849 {
850 	return _ComputeFrame(target != NULL ? target->Frame()
851 		: BRect(0, 0, 16, 16), horizontal, vertical, border);
852 }
853 
854 
855 /*! This method returns the size of the specified border.
856 */
857 /*static*/ float
858 BScrollView::_BorderSize(border_style border)
859 {
860 	if (border == B_FANCY_BORDER)
861 		return kFancyBorderSize;
862 	if (border == B_PLAIN_BORDER)
863 		return kPlainBorderSize;
864 
865 	return 0;
866 }
867 
868 
869 /*!	This method changes the "flags" argument as passed on to
870 	the BView constructor.
871 */
872 /*static*/ int32
873 BScrollView::_ModifyFlags(int32 flags, border_style border)
874 {
875 	// We either need B_FULL_UPDATE_ON_RESIZE or
876 	// B_FRAME_EVENTS if we have to draw a border
877 	if (border != B_NO_BORDER)
878 		return flags | B_WILL_DRAW | (flags & B_FULL_UPDATE_ON_RESIZE ? 0 : B_FRAME_EVENTS);
879 
880 	return flags & ~(B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE);
881 }
882 
883 
884 //	#pragma mark -
885 
886 
887 BScrollView &
888 BScrollView::operator=(const BScrollView &)
889 {
890 	return *this;
891 }
892 
893 
894 void BScrollView::_ReservedScrollView1() {}
895 void BScrollView::_ReservedScrollView2() {}
896 void BScrollView::_ReservedScrollView3() {}
897 void BScrollView::_ReservedScrollView4() {}
898 
899