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 23const int kDefaultScrollStep = 19; 24const int kScrollerDimension = 12; 25 26 27class ScrollArrow : public BView { 28public: 29 ScrollArrow(BRect frame); 30 virtual ~ScrollArrow(); 31 32 bool IsEnabled() const { return fEnabled; }; 33 void SetEnabled(bool enabled); 34 35private: 36 bool fEnabled; 37}; 38 39 40class UpScrollArrow : public ScrollArrow { 41public: 42 UpScrollArrow(BRect frame); 43 virtual ~UpScrollArrow(); 44 45 virtual void Draw(BRect updateRect); 46 virtual void MouseDown(BPoint where); 47}; 48 49 50class DownScrollArrow : public ScrollArrow { 51public: 52 DownScrollArrow(BRect frame); 53 virtual ~DownScrollArrow(); 54 55 virtual void Draw(BRect updateRect); 56 virtual void MouseDown(BPoint where); 57}; 58 59 60class LeftScrollArrow : public ScrollArrow { 61public: 62 LeftScrollArrow(BRect frame); 63 virtual ~LeftScrollArrow(); 64 65 virtual void Draw(BRect updateRect); 66 virtual void MouseDown(BPoint where); 67}; 68 69 70class RightScrollArrow : public ScrollArrow { 71public: 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 83ScrollArrow::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 92ScrollArrow::~ScrollArrow() 93{ 94} 95 96 97void 98ScrollArrow::SetEnabled(bool enabled) 99{ 100 fEnabled = enabled; 101 Invalidate(); 102} 103 104 105// #pragma mark - 106 107 108UpScrollArrow::UpScrollArrow(BRect frame) 109 : 110 ScrollArrow(frame) 111{ 112} 113 114 115UpScrollArrow::~UpScrollArrow() 116{ 117} 118 119 120void 121UpScrollArrow::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 142void 143UpScrollArrow::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 172DownScrollArrow::DownScrollArrow(BRect frame) 173 : 174 ScrollArrow(frame) 175{ 176} 177 178 179DownScrollArrow::~DownScrollArrow() 180{ 181} 182 183 184void 185DownScrollArrow::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 207void 208DownScrollArrow::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 238LeftScrollArrow::LeftScrollArrow(BRect frame) 239 : 240 ScrollArrow(frame) 241{ 242} 243 244 245LeftScrollArrow::~LeftScrollArrow() 246{ 247} 248 249 250void 251LeftScrollArrow::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 271void 272LeftScrollArrow::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 301RightScrollArrow::RightScrollArrow(BRect frame) 302 : 303 ScrollArrow(frame) 304{ 305} 306 307 308RightScrollArrow::~RightScrollArrow() 309{ 310} 311 312 313void 314RightScrollArrow::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 335void 336RightScrollArrow::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 366TInlineScrollView::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 381TInlineScrollView::~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 397void 398TInlineScrollView::AttachedToWindow() 399{ 400 BView::AttachedToWindow(); 401 402 if (fTarget == NULL) 403 return; 404 405 AddChild(fTarget); 406 fTarget->MoveTo(0, 0); 407} 408 409 410void 411TInlineScrollView::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 426void 427TInlineScrollView::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 438void 439TInlineScrollView::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 506void 507TInlineScrollView::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 538bool 539TInlineScrollView::HasScrollers() const 540{ 541 return fTarget != NULL && fBeginScrollArrow != NULL 542 && fEndScrollArrow != NULL; 543} 544 545 546void 547TInlineScrollView::SetSmallStep(float step) 548{ 549 fScrollStep = step; 550} 551 552 553void 554TInlineScrollView::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 564void 565TInlineScrollView::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