xref: /haiku/src/kits/interface/ScrollView.cpp (revision 002f37b0cca92e4cf72857c72ac95db5a8b09615)
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::FrameMoved(BPoint position)
305 {
306 	BView::FrameMoved(position);
307 }
308 
309 
310 void
311 BScrollView::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 
370 void
371 BScrollView::MessageReceived(BMessage* message)
372 {
373 	switch (message->what) {
374 		default:
375 			BView::MessageReceived(message);
376 	}
377 }
378 
379 
380 void
381 BScrollView::MouseDown(BPoint point)
382 {
383 	BView::MouseDown(point);
384 }
385 
386 
387 void
388 BScrollView::MouseUp(BPoint point)
389 {
390 	BView::MouseUp(point);
391 }
392 
393 
394 void
395 BScrollView::MouseMoved(BPoint point, uint32 code, const BMessage *dragMessage)
396 {
397 	BView::MouseMoved(point, code, dragMessage);
398 }
399 
400 
401 // #pragma mark -
402 
403 
404 BScrollBar*
405 BScrollView::ScrollBar(orientation posture) const
406 {
407 	if (posture == B_HORIZONTAL)
408 		return fHorizontalScrollBar;
409 
410 	return fVerticalScrollBar;
411 }
412 
413 
414 void
415 BScrollView::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 
477 border_style
478 BScrollView::Border() const
479 {
480 	return fBorder;
481 }
482 
483 
484 status_t
485 BScrollView::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 
516 bool
517 BScrollView::IsBorderHighlighted() const
518 {
519 	return fHighlighted;
520 }
521 
522 
523 void
524 BScrollView::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 
556 BView*
557 BScrollView::Target() const
558 {
559 	return fTarget;
560 }
561 
562 
563 // #pragma mark -
564 
565 
566 
567 BHandler*
568 BScrollView::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 
575 status_t
576 BScrollView::GetSupportedSuites(BMessage *data)
577 {
578 	return BView::GetSupportedSuites(data);
579 }
580 
581 
582 status_t
583 BScrollView::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 
638 void
639 BScrollView::LayoutInvalidated(bool descendants)
640 {
641 }
642 
643 
644 void
645 BScrollView::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 
675 void
676 BScrollView::_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 
728 float
729 BScrollView::_BorderSize() const
730 {
731 	return _BorderSize(fBorder);
732 }
733 
734 
735 BRect
736 BScrollView::_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 
758 BSize
759 BScrollView::_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 
768 BRect
769 BScrollView::_ComputeFrame(BRect targetRect) const
770 {
771 	return _ComputeFrame(targetRect, fHorizontalScrollBar != NULL,
772 		fVerticalScrollBar != NULL, fBorder);
773 }
774 
775 
776 void
777 BScrollView::_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
825 BScrollView::_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
848 BScrollView::_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
859 BScrollView::_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
874 BScrollView::_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 
888 BScrollView &
889 BScrollView::operator=(const BScrollView &)
890 {
891 	return *this;
892 }
893 
894 
895 void BScrollView::_ReservedScrollView1() {}
896 void BScrollView::_ReservedScrollView2() {}
897 void BScrollView::_ReservedScrollView3() {}
898 void BScrollView::_ReservedScrollView4() {}
899 
900 
901 extern "C" void
902 B_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