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