xref: /haiku/src/apps/deskbar/InlineScrollView.cpp (revision bab64f65bb775dc23060e276f1f1c4498ab7af6c)
1 /*
2  * Copyright 2012, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  *		Stefano Ceccherini (stefano.ceccherini@gmail.com)
8  *		John Scipione (jscipione@gmail.com)
9  */
10 
11 
12 #include "InlineScrollView.h"
13 
14 #include <ControlLook.h>
15 #include <Debug.h>
16 #include <InterfaceDefs.h>
17 #include <Menu.h>
18 #include <Point.h>
19 #include <Screen.h>
20 #include <Window.h>
21 
22 
23 const int kDefaultScrollStep = 19;
24 const int kScrollerDimension = 12;
25 
26 
27 class ScrollArrow : public BView {
28 public:
29 							ScrollArrow(BRect frame);
30 	virtual					~ScrollArrow();
31 
IsEnabled() const32 			bool			IsEnabled() const { return fEnabled; };
33 			void			SetEnabled(bool enabled);
34 
35 private:
36 			bool			fEnabled;
37 };
38 
39 
40 class UpScrollArrow : public ScrollArrow {
41 public:
42 							UpScrollArrow(BRect frame);
43 	virtual					~UpScrollArrow();
44 
45 	virtual	void			Draw(BRect updateRect);
46 	virtual	void			MouseDown(BPoint where);
47 };
48 
49 
50 class DownScrollArrow : public ScrollArrow {
51 public:
52 							DownScrollArrow(BRect frame);
53 	virtual					~DownScrollArrow();
54 
55 	virtual	void			Draw(BRect updateRect);
56 	virtual	void			MouseDown(BPoint where);
57 };
58 
59 
60 class LeftScrollArrow : public ScrollArrow {
61 public:
62 							LeftScrollArrow(BRect frame);
63 	virtual					~LeftScrollArrow();
64 
65 	virtual	void			Draw(BRect updateRect);
66 	virtual	void			MouseDown(BPoint where);
67 };
68 
69 
70 class RightScrollArrow : public ScrollArrow {
71 public:
72 							RightScrollArrow(BRect frame);
73 	virtual					~RightScrollArrow();
74 
75 	virtual	void			Draw(BRect updateRect);
76 	virtual	void			MouseDown(BPoint where);
77 };
78 
79 
80 //	#pragma mark -
81 
82 
ScrollArrow(BRect frame)83 ScrollArrow::ScrollArrow(BRect frame)
84 	:
85 	BView(frame, "menu scroll arrow", B_FOLLOW_NONE, B_WILL_DRAW),
86 	fEnabled(false)
87 {
88 	SetViewUIColor(B_MENU_BACKGROUND_COLOR);
89 }
90 
91 
~ScrollArrow()92 ScrollArrow::~ScrollArrow()
93 {
94 }
95 
96 
97 void
SetEnabled(bool enabled)98 ScrollArrow::SetEnabled(bool enabled)
99 {
100 	fEnabled = enabled;
101 	Invalidate();
102 }
103 
104 
105 //	#pragma mark -
106 
107 
UpScrollArrow(BRect frame)108 UpScrollArrow::UpScrollArrow(BRect frame)
109 	:
110 	ScrollArrow(frame)
111 {
112 }
113 
114 
~UpScrollArrow()115 UpScrollArrow::~UpScrollArrow()
116 {
117 }
118 
119 
120 void
Draw(BRect updateRect)121 UpScrollArrow::Draw(BRect updateRect)
122 {
123 	SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
124 		B_DARKEN_1_TINT));
125 
126 	if (IsEnabled())
127 		SetHighColor(0, 0, 0);
128 	else {
129 		SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
130 			B_DARKEN_2_TINT));
131 	}
132 
133 	FillRect(Bounds(), B_SOLID_LOW);
134 
135 	float middle = Bounds().right / 2;
136 	FillTriangle(BPoint(middle, (kScrollerDimension / 2) - 3),
137 		BPoint(middle + 5, (kScrollerDimension / 2) + 2),
138 		BPoint(middle - 5, (kScrollerDimension / 2) + 2));
139 }
140 
141 
142 void
MouseDown(BPoint where)143 UpScrollArrow::MouseDown(BPoint where)
144 {
145 	if (!IsEnabled())
146 		return;
147 
148 	TInlineScrollView* parent = dynamic_cast<TInlineScrollView*>(Parent());
149 	if (parent == NULL)
150 		return;
151 
152 	float smallStep;
153 	float largeStep;
154 	parent->GetSteps(&smallStep, &largeStep);
155 
156 	BMessage* message = Window()->CurrentMessage();
157 	int32 modifiers = 0;
158 	message->FindInt32("modifiers", &modifiers);
159 	// pressing the shift key scrolls faster
160 	if ((modifiers & B_SHIFT_KEY) != 0)
161 		parent->ScrollBy(-largeStep);
162 	else
163 		parent->ScrollBy(-smallStep);
164 
165 	snooze(5000);
166 }
167 
168 
169 //	#pragma mark -
170 
171 
DownScrollArrow(BRect frame)172 DownScrollArrow::DownScrollArrow(BRect frame)
173 	:
174 	ScrollArrow(frame)
175 {
176 }
177 
178 
~DownScrollArrow()179 DownScrollArrow::~DownScrollArrow()
180 {
181 }
182 
183 
184 void
Draw(BRect updateRect)185 DownScrollArrow::Draw(BRect updateRect)
186 {
187 	SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
188 		B_DARKEN_1_TINT));
189 
190 	if (IsEnabled())
191 		SetHighColor(0, 0, 0);
192 	else {
193 		SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
194 			B_DARKEN_2_TINT));
195 	}
196 
197 	BRect frame = Bounds();
198 	FillRect(frame, B_SOLID_LOW);
199 
200 	float middle = Bounds().right / 2;
201 	FillTriangle(BPoint(middle, frame.bottom - (kScrollerDimension / 2) + 3),
202 		BPoint(middle + 5, frame.bottom - (kScrollerDimension / 2) - 2),
203 		BPoint(middle - 5, frame.bottom - (kScrollerDimension / 2) - 2));
204 }
205 
206 
207 void
MouseDown(BPoint where)208 DownScrollArrow::MouseDown(BPoint where)
209 {
210 	if (!IsEnabled())
211 		return;
212 
213 	TInlineScrollView* grandparent
214 		= dynamic_cast<TInlineScrollView*>(Parent()->Parent());
215 	if (grandparent == NULL)
216 		return;
217 
218 	float smallStep;
219 	float largeStep;
220 	grandparent->GetSteps(&smallStep, &largeStep);
221 
222 	BMessage* message = Window()->CurrentMessage();
223 	int32 modifiers = 0;
224 	message->FindInt32("modifiers", &modifiers);
225 	// pressing the shift key scrolls faster
226 	if ((modifiers & B_SHIFT_KEY) != 0)
227 		grandparent->ScrollBy(largeStep);
228 	else
229 		grandparent->ScrollBy(smallStep);
230 
231 	snooze(5000);
232 }
233 
234 
235 //	#pragma mark -
236 
237 
LeftScrollArrow(BRect frame)238 LeftScrollArrow::LeftScrollArrow(BRect frame)
239 	:
240 	ScrollArrow(frame)
241 {
242 }
243 
244 
~LeftScrollArrow()245 LeftScrollArrow::~LeftScrollArrow()
246 {
247 }
248 
249 
250 void
Draw(BRect updateRect)251 LeftScrollArrow::Draw(BRect updateRect)
252 {
253 	SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_1_TINT));
254 
255 	if (IsEnabled())
256 		SetHighColor(0, 0, 0);
257 	else {
258 		SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
259 			B_DARKEN_2_TINT));
260 	}
261 
262 	FillRect(Bounds(), B_SOLID_LOW);
263 
264 	float middle = Bounds().bottom / 2;
265 	FillTriangle(BPoint((kScrollerDimension / 2) - 3, middle),
266 		BPoint((kScrollerDimension / 2) + 2, middle + 5),
267 		BPoint((kScrollerDimension / 2) + 2, middle - 5));
268 }
269 
270 
271 void
MouseDown(BPoint where)272 LeftScrollArrow::MouseDown(BPoint where)
273 {
274 	if (!IsEnabled())
275 		return;
276 
277 	TInlineScrollView* parent = dynamic_cast<TInlineScrollView*>(Parent());
278 	if (parent == NULL)
279 		return;
280 
281 	float smallStep;
282 	float largeStep;
283 	parent->GetSteps(&smallStep, &largeStep);
284 
285 	BMessage* message = Window()->CurrentMessage();
286 	int32 modifiers = 0;
287 	message->FindInt32("modifiers", &modifiers);
288 	// pressing the shift key scrolls faster
289 	if ((modifiers & B_SHIFT_KEY) != 0)
290 		parent->ScrollBy(-largeStep);
291 	else
292 		parent->ScrollBy(-smallStep);
293 
294 	snooze(5000);
295 }
296 
297 
298 //	#pragma mark -
299 
300 
RightScrollArrow(BRect frame)301 RightScrollArrow::RightScrollArrow(BRect frame)
302 	:
303 	ScrollArrow(frame)
304 {
305 }
306 
307 
~RightScrollArrow()308 RightScrollArrow::~RightScrollArrow()
309 {
310 }
311 
312 
313 void
Draw(BRect updateRect)314 RightScrollArrow::Draw(BRect updateRect)
315 {
316 	SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_1_TINT));
317 
318 	if (IsEnabled())
319 		SetHighColor(0, 0, 0);
320 	else {
321 		SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
322 			B_DARKEN_2_TINT));
323 	}
324 
325 	BRect frame = Bounds();
326 	FillRect(frame, B_SOLID_LOW);
327 
328 	float middle = Bounds().bottom / 2;
329 	FillTriangle(BPoint(kScrollerDimension / 2 + 3, middle),
330 		BPoint(kScrollerDimension / 2 - 2, middle + 5),
331 		BPoint(kScrollerDimension / 2 - 2, middle - 5));
332 }
333 
334 
335 void
MouseDown(BPoint where)336 RightScrollArrow::MouseDown(BPoint where)
337 {
338 	if (!IsEnabled())
339 		return;
340 
341 	TInlineScrollView* grandparent
342 		= dynamic_cast<TInlineScrollView*>(Parent()->Parent());
343 	if (grandparent == NULL)
344 		return;
345 
346 	float smallStep;
347 	float largeStep;
348 	grandparent->GetSteps(&smallStep, &largeStep);
349 
350 	BMessage* message = Window()->CurrentMessage();
351 	int32 modifiers = 0;
352 	message->FindInt32("modifiers", &modifiers);
353 	// pressing the shift key scrolls faster
354 	if ((modifiers & B_SHIFT_KEY) != 0)
355 		grandparent->ScrollBy(largeStep);
356 	else
357 		grandparent->ScrollBy(smallStep);
358 
359 	snooze(5000);
360 }
361 
362 
363 //	#pragma mark -
364 
365 
TInlineScrollView(BView * target,enum orientation orientation)366 TInlineScrollView::TInlineScrollView(BView* target,
367 	enum orientation orientation)
368 	:
369 	BView(BRect(0, 0, 0, 0), "inline scroll view", B_FOLLOW_NONE, B_WILL_DRAW),
370 	fTarget(target),
371 	fBeginScrollArrow(NULL),
372 	fEndScrollArrow(NULL),
373 	fScrollStep(kDefaultScrollStep),
374 	fScrollValue(0),
375 	fScrollLimit(0),
376 	fOrientation(orientation)
377 {
378 }
379 
380 
~TInlineScrollView()381 TInlineScrollView::~TInlineScrollView()
382 {
383 	if (fBeginScrollArrow != NULL) {
384 		fBeginScrollArrow->RemoveSelf();
385 		delete fBeginScrollArrow;
386 		fBeginScrollArrow = NULL;
387 	}
388 
389 	if (fEndScrollArrow != NULL) {
390 		fEndScrollArrow->RemoveSelf();
391 		delete fEndScrollArrow;
392 		fEndScrollArrow = NULL;
393 	}
394 }
395 
396 
397 void
AttachedToWindow()398 TInlineScrollView::AttachedToWindow()
399 {
400 	BView::AttachedToWindow();
401 
402 	if (fTarget == NULL)
403 		return;
404 
405 	AddChild(fTarget);
406 	fTarget->MoveTo(0, 0);
407 }
408 
409 
410 void
DetachedFromWindow()411 TInlineScrollView::DetachedFromWindow()
412 {
413 	BView::DetachedFromWindow();
414 
415 	if (fTarget != NULL)
416 		fTarget->RemoveSelf();
417 
418 	if (fBeginScrollArrow != NULL)
419 		fBeginScrollArrow->RemoveSelf();
420 
421 	if (fEndScrollArrow != NULL)
422 		fEndScrollArrow->RemoveSelf();
423 }
424 
425 
426 void
Draw(BRect updateRect)427 TInlineScrollView::Draw(BRect updateRect)
428 {
429 	BRect frame = Bounds();
430 	be_control_look->DrawButtonBackground(this, frame, updateRect,
431 		ui_color(B_MENU_BACKGROUND_COLOR));
432 }
433 
434 
435 //	#pragma mark -
436 
437 
438 void
AttachScrollers()439 TInlineScrollView::AttachScrollers()
440 {
441 	if (fTarget == NULL)
442 		return;
443 
444 	BRect frame = Bounds();
445 
446 	if (HasScrollers()) {
447 		if (fOrientation == B_VERTICAL) {
448 			fScrollLimit = fTarget->Bounds().Height()
449 				- (frame.Height() - 2 * kScrollerDimension);
450 		} else {
451 			fScrollLimit = fTarget->Bounds().Width()
452 				- (frame.Width() - 2 * kScrollerDimension);
453 		}
454 
455 		if (fScrollValue > fScrollLimit) {
456 			// If scroll value is above limit scroll back
457 			float delta = fScrollLimit - fScrollValue;
458 			if (fOrientation == B_VERTICAL)
459 				fTarget->ScrollBy(0, delta);
460 			else
461 				fTarget->ScrollBy(delta, 0);
462 
463 			fScrollValue = fScrollLimit;
464 		}
465 		return;
466 	}
467 
468 	fTarget->MakeFocus(true);
469 
470 	if (fOrientation == B_VERTICAL) {
471 		if (fBeginScrollArrow == NULL) {
472 			fBeginScrollArrow = new UpScrollArrow(
473 				BRect(frame.left, frame.top, frame.right,
474 					kScrollerDimension - 1));
475 			AddChild(fBeginScrollArrow);
476 		}
477 
478 		if (fEndScrollArrow == NULL) {
479 			fEndScrollArrow = new DownScrollArrow(
480 				BRect(0, frame.bottom - 2 * kScrollerDimension + 1, frame.right,
481 					frame.bottom - kScrollerDimension));
482 			fTarget->AddChild(fEndScrollArrow);
483 		}
484 
485 		fTarget->MoveBy(0, kScrollerDimension);
486 
487 		fScrollLimit = fTarget->Bounds().Height()
488 			- (frame.Height() - 2 * kScrollerDimension);
489 	} else {
490 		if (fBeginScrollArrow == NULL) {
491 			fBeginScrollArrow = new LeftScrollArrow(
492 				BRect(frame.left, frame.top,
493 					frame.left + kScrollerDimension - 1, frame.bottom));
494 			AddChild(fBeginScrollArrow);
495 		}
496 
497 		if (fEndScrollArrow == NULL) {
498 			fEndScrollArrow = new RightScrollArrow(
499 				BRect(frame.right - 2 * kScrollerDimension + 1, frame.top,
500 					frame.right, frame.bottom));
501 			fTarget->AddChild(fEndScrollArrow);
502 		}
503 
504 		fTarget->MoveBy(kScrollerDimension, 0);
505 
506 		fScrollLimit = fTarget->Bounds().Width()
507 			- (frame.Width() - 2 * kScrollerDimension);
508 	}
509 
510 	fBeginScrollArrow->SetEnabled(false);
511 	fEndScrollArrow->SetEnabled(true);
512 
513 	fScrollValue = 0;
514 }
515 
516 
517 void
DetachScrollers()518 TInlineScrollView::DetachScrollers()
519 {
520 	if (!HasScrollers())
521 		return;
522 
523 	if (fEndScrollArrow) {
524 		fEndScrollArrow->RemoveSelf();
525 		delete fEndScrollArrow;
526 		fEndScrollArrow = NULL;
527 	}
528 
529 	if (fBeginScrollArrow) {
530 		fBeginScrollArrow->RemoveSelf();
531 		delete fBeginScrollArrow;
532 		fBeginScrollArrow = NULL;
533 	}
534 
535 	if (fTarget) {
536 		// We don't remember the position where the last scrolling
537 		// ended, so scroll back to the beginning.
538 		if (fOrientation == B_VERTICAL)
539 			fTarget->MoveBy(0, -kScrollerDimension);
540 		else
541 			fTarget->MoveBy(-kScrollerDimension, 0);
542 
543 		fTarget->ScrollTo(0, 0);
544 		fScrollValue = 0;
545 	}
546 }
547 
548 
549 bool
HasScrollers() const550 TInlineScrollView::HasScrollers() const
551 {
552 	return fTarget != NULL && fBeginScrollArrow != NULL
553 		&& fEndScrollArrow != NULL;
554 }
555 
556 
557 void
SetSmallStep(float step)558 TInlineScrollView::SetSmallStep(float step)
559 {
560 	fScrollStep = step;
561 }
562 
563 
564 void
GetSteps(float * _smallStep,float * _largeStep) const565 TInlineScrollView::GetSteps(float* _smallStep, float* _largeStep) const
566 {
567 	if (_smallStep != NULL)
568 		*_smallStep = fScrollStep;
569 	if (_largeStep != NULL) {
570 		*_largeStep = fScrollStep * 3;
571 	}
572 }
573 
574 
575 void
ScrollBy(const float & step)576 TInlineScrollView::ScrollBy(const float& step)
577 {
578 	if (!HasScrollers())
579 		return;
580 
581 	if (step > 0) {
582 		if (fScrollValue == 0)
583 			fBeginScrollArrow->SetEnabled(true);
584 
585 		if (fScrollValue + step >= fScrollLimit) {
586 			// If we reached the limit, only scroll to the end
587 			if (fOrientation == B_VERTICAL) {
588 				fTarget->ScrollBy(0, fScrollLimit - fScrollValue);
589 				fEndScrollArrow->MoveBy(0, fScrollLimit - fScrollValue);
590 			} else {
591 				fTarget->ScrollBy(fScrollLimit - fScrollValue, 0);
592 				fEndScrollArrow->MoveBy(fScrollLimit - fScrollValue, 0);
593 			}
594 			fEndScrollArrow->SetEnabled(false);
595 			fScrollValue = fScrollLimit;
596 		} else {
597 			if (fOrientation == B_VERTICAL) {
598 				fTarget->ScrollBy(0, step);
599 				fEndScrollArrow->MoveBy(0, step);
600 			} else {
601 				fTarget->ScrollBy(step, 0);
602 				fEndScrollArrow->MoveBy(step, 0);
603 			}
604 			fScrollValue += step;
605 		}
606 	} else if (step < 0) {
607 		if (fScrollValue == fScrollLimit)
608 			fEndScrollArrow->SetEnabled(true);
609 
610 		if (fScrollValue + step <= 0) {
611 			if (fOrientation == B_VERTICAL) {
612 				fTarget->ScrollBy(0, -fScrollValue);
613 				fEndScrollArrow->MoveBy(0, -fScrollValue);
614 			} else {
615 				fTarget->ScrollBy(-fScrollValue, 0);
616 				fEndScrollArrow->MoveBy(-fScrollValue, 0);
617 			}
618 			fBeginScrollArrow->SetEnabled(false);
619 			fScrollValue = 0;
620 		} else {
621 			if (fOrientation == B_VERTICAL) {
622 				fTarget->ScrollBy(0, step);
623 				fEndScrollArrow->MoveBy(0, step);
624 			} else {
625 				fTarget->ScrollBy(step, 0);
626 				fEndScrollArrow->MoveBy(step, 0);
627 			}
628 			fScrollValue += step;
629 		}
630 	}
631 
632 	//fTarget->Invalidate();
633 }
634