xref: /haiku/src/apps/deskbar/InlineScrollView.cpp (revision 2510baa4685f8f570c607ceedfd73473d69342c4)
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 
32 			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 
83 ScrollArrow::ScrollArrow(BRect frame)
84 	:
85 	BView(frame, "menu scroll arrow", B_FOLLOW_NONE, B_WILL_DRAW),
86 	fEnabled(false)
87 {
88 	SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR));
89 }
90 
91 
92 ScrollArrow::~ScrollArrow()
93 {
94 }
95 
96 
97 void
98 ScrollArrow::SetEnabled(bool enabled)
99 {
100 	fEnabled = enabled;
101 	Invalidate();
102 }
103 
104 
105 //	#pragma mark -
106 
107 
108 UpScrollArrow::UpScrollArrow(BRect frame)
109 	:
110 	ScrollArrow(frame)
111 {
112 }
113 
114 
115 UpScrollArrow::~UpScrollArrow()
116 {
117 }
118 
119 
120 void
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
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 option/command/control key scrolls faster
160 	if ((modifiers & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) != 0)
161 		parent->ScrollBy(-largeStep);
162 	else
163 		parent->ScrollBy(-smallStep);
164 
165 	snooze(5000);
166 }
167 
168 
169 //	#pragma mark -
170 
171 
172 DownScrollArrow::DownScrollArrow(BRect frame)
173 	:
174 	ScrollArrow(frame)
175 {
176 }
177 
178 
179 DownScrollArrow::~DownScrollArrow()
180 {
181 }
182 
183 
184 void
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
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 option/command/control key scrolls faster
226 	if ((modifiers & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) != 0)
227 		grandparent->ScrollBy(largeStep);
228 	else
229 		grandparent->ScrollBy(smallStep);
230 
231 	snooze(5000);
232 }
233 
234 
235 //	#pragma mark -
236 
237 
238 LeftScrollArrow::LeftScrollArrow(BRect frame)
239 	:
240 	ScrollArrow(frame)
241 {
242 }
243 
244 
245 LeftScrollArrow::~LeftScrollArrow()
246 {
247 }
248 
249 
250 void
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
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 option/command/control key scrolls faster
289 	if ((modifiers & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) != 0)
290 		parent->ScrollBy(-largeStep);
291 	else
292 		parent->ScrollBy(-smallStep);
293 
294 	snooze(5000);
295 }
296 
297 
298 //	#pragma mark -
299 
300 
301 RightScrollArrow::RightScrollArrow(BRect frame)
302 	:
303 	ScrollArrow(frame)
304 {
305 }
306 
307 
308 RightScrollArrow::~RightScrollArrow()
309 {
310 }
311 
312 
313 void
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
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 option/command/control key scrolls faster
354 	if ((modifiers & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) != 0)
355 		grandparent->ScrollBy(largeStep);
356 	else
357 		grandparent->ScrollBy(smallStep);
358 
359 	snooze(5000);
360 }
361 
362 
363 //	#pragma mark -
364 
365 
366 TInlineScrollView::TInlineScrollView(BRect frame, BView* target,
367 	enum orientation orientation)
368 	:
369 	BView(frame, "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 
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
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
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
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
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 		return;
455 	}
456 
457 	fTarget->MakeFocus(true);
458 
459 	if (fOrientation == B_VERTICAL) {
460 		if (fBeginScrollArrow == NULL) {
461 			fBeginScrollArrow = new UpScrollArrow(
462 				BRect(frame.left, frame.top, frame.right,
463 					kScrollerDimension - 1));
464 			AddChild(fBeginScrollArrow);
465 		}
466 
467 		if (fEndScrollArrow == NULL) {
468 			fEndScrollArrow = new DownScrollArrow(
469 				BRect(0, frame.bottom - 2 * kScrollerDimension + 1, frame.right,
470 					frame.bottom - kScrollerDimension));
471 			fTarget->AddChild(fEndScrollArrow);
472 		}
473 
474 		fTarget->MoveBy(0, kScrollerDimension);
475 
476 		fScrollLimit = fTarget->Bounds().Height()
477 			- (frame.Height() - 2 * kScrollerDimension);
478 	} else {
479 		if (fBeginScrollArrow == NULL) {
480 			fBeginScrollArrow = new LeftScrollArrow(
481 				BRect(frame.left, frame.top,
482 					frame.left + kScrollerDimension - 1, frame.bottom));
483 			AddChild(fBeginScrollArrow);
484 		}
485 
486 		if (fEndScrollArrow == NULL) {
487 			fEndScrollArrow = new RightScrollArrow(
488 				BRect(frame.right - 2 * kScrollerDimension + 1, frame.top,
489 					frame.right, frame.bottom));
490 			fTarget->AddChild(fEndScrollArrow);
491 		}
492 
493 		fTarget->MoveBy(kScrollerDimension, 0);
494 
495 		fScrollLimit = fTarget->Bounds().Width()
496 			- (frame.Width() - 2 * kScrollerDimension);
497 	}
498 
499 	fBeginScrollArrow->SetEnabled(false);
500 	fEndScrollArrow->SetEnabled(true);
501 
502 	fScrollValue = 0;
503 }
504 
505 
506 void
507 TInlineScrollView::DetachScrollers()
508 {
509 	if (!HasScrollers())
510 		return;
511 
512 	if (fEndScrollArrow) {
513 		fEndScrollArrow->RemoveSelf();
514 		delete fEndScrollArrow;
515 		fEndScrollArrow = NULL;
516 	}
517 
518 	if (fBeginScrollArrow) {
519 		fBeginScrollArrow->RemoveSelf();
520 		delete fBeginScrollArrow;
521 		fBeginScrollArrow = NULL;
522 	}
523 
524 	if (fTarget) {
525 		// We don't remember the position where the last scrolling
526 		// ended, so scroll back to the beginning.
527 		if (fOrientation == B_VERTICAL)
528 			fTarget->MoveBy(0, -kScrollerDimension);
529 		else
530 			fTarget->MoveBy(-kScrollerDimension, 0);
531 
532 		fTarget->ScrollTo(0, 0);
533 		fScrollValue = 0;
534 	}
535 }
536 
537 
538 bool
539 TInlineScrollView::HasScrollers() const
540 {
541 	return fTarget != NULL && fBeginScrollArrow != NULL
542 		&& fEndScrollArrow != NULL;
543 }
544 
545 
546 void
547 TInlineScrollView::SetSmallStep(float step)
548 {
549 	fScrollStep = step;
550 }
551 
552 
553 void
554 TInlineScrollView::GetSteps(float* _smallStep, float* _largeStep) const
555 {
556 	if (_smallStep != NULL)
557 		*_smallStep = fScrollStep;
558 	if (_largeStep != NULL) {
559 		*_largeStep = fScrollStep * 3;
560 	}
561 }
562 
563 
564 void
565 TInlineScrollView::ScrollBy(const float& step)
566 {
567 	if (!HasScrollers())
568 		return;
569 
570 	if (step > 0) {
571 		if (fScrollValue == 0)
572 			fBeginScrollArrow->SetEnabled(true);
573 
574 		if (fScrollValue + step >= fScrollLimit) {
575 			// If we reached the limit, only scroll to the end
576 			if (fOrientation == B_VERTICAL) {
577 				fTarget->ScrollBy(0, fScrollLimit - fScrollValue);
578 				fEndScrollArrow->MoveBy(0, fScrollLimit - fScrollValue);
579 			} else {
580 				fTarget->ScrollBy(fScrollLimit - fScrollValue, 0);
581 				fEndScrollArrow->MoveBy(fScrollLimit - fScrollValue, 0);
582 			}
583 			fEndScrollArrow->SetEnabled(false);
584 			fScrollValue = fScrollLimit;
585 		} else {
586 			if (fOrientation == B_VERTICAL) {
587 				fTarget->ScrollBy(0, step);
588 				fEndScrollArrow->MoveBy(0, step);
589 			} else {
590 				fTarget->ScrollBy(step, 0);
591 				fEndScrollArrow->MoveBy(step, 0);
592 			}
593 			fScrollValue += step;
594 		}
595 	} else if (step < 0) {
596 		if (fScrollValue == fScrollLimit)
597 			fEndScrollArrow->SetEnabled(true);
598 
599 		if (fScrollValue + step <= 0) {
600 			if (fOrientation == B_VERTICAL) {
601 				fTarget->ScrollBy(0, -fScrollValue);
602 				fEndScrollArrow->MoveBy(0, -fScrollValue);
603 			} else {
604 				fTarget->ScrollBy(-fScrollValue, 0);
605 				fEndScrollArrow->MoveBy(-fScrollValue, 0);
606 			}
607 			fBeginScrollArrow->SetEnabled(false);
608 			fScrollValue = 0;
609 		} else {
610 			if (fOrientation == B_VERTICAL) {
611 				fTarget->ScrollBy(0, step);
612 				fEndScrollArrow->MoveBy(0, step);
613 			} else {
614 				fTarget->ScrollBy(step, 0);
615 				fEndScrollArrow->MoveBy(step, 0);
616 			}
617 			fScrollValue += step;
618 		}
619 	}
620 
621 	//fTarget->Invalidate();
622 }
623