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