1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30 of Be Incorporated in the United States and other countries. Other brand product 31 names are registered trademarks or trademarks of their respective holders. 32 All rights reserved. 33 */ 34 35 // ListView title drawing and mouse manipulation classes 36 #include "TitleView.h" 37 38 #include <Alert.h> 39 #include <Application.h> 40 #include <Debug.h> 41 #include <PopUpMenu.h> 42 #include <Window.h> 43 44 #include <string.h> 45 46 #include "Commands.h" 47 #include "ContainerWindow.h" 48 #include "PoseView.h" 49 #include "Utilities.h" 50 51 static rgb_color sTitleBackground; 52 static rgb_color sDarkTitleBackground; 53 static rgb_color sShineColor; 54 static rgb_color sLightShadowColor; 55 static rgb_color sShadowColor; 56 static rgb_color sDarkShadowColor; 57 58 const rgb_color kHighlightColor = {100, 100, 210, 255}; 59 60 const unsigned char kHorizontalResizeCursor[] = { 61 16, 1, 7, 7, 62 0, 0, 1, 0, 1, 0, 1, 0, 9, 32, 25, 48, 57, 56, 121, 60, 63 57, 56, 25, 48, 9, 32, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 64 3, 128, 3, 128, 3, 128, 15, 224, 31, 240, 63, 248, 127, 252, 255, 254, 65 127, 252, 63, 248, 31, 240, 15, 224, 3, 128, 3, 128, 3, 128, 0, 0 66 }; 67 68 69 static void 70 _DrawLine(BPoseView *view, BPoint from, BPoint to) 71 { 72 rgb_color highColor = view->HighColor(); 73 view->SetHighColor(kHighlightColor); 74 view->StrokeLine(from, to); 75 view->SetHighColor(highColor); 76 } 77 78 79 static void 80 _UndrawLine(BPoseView *view, BPoint from, BPoint to) 81 { 82 view->StrokeLine(from, to, B_SOLID_LOW); 83 } 84 85 86 static void 87 _DrawOutline(BView *view, BRect where) 88 { 89 where.InsetBy(1, 1); 90 rgb_color highColor = view->HighColor(); 91 view->SetHighColor(kHighlightColor); 92 view->StrokeRect(where); 93 view->SetHighColor(highColor); 94 } 95 96 97 // #pragma mark - 98 99 100 BTitleView::BTitleView(BRect frame, BPoseView *view) 101 : BView(frame, "TitleView", B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW), 102 fPoseView(view), 103 fTitleList(10, true), 104 fHorizontalResizeCursor(kHorizontalResizeCursor), 105 fPreviouslyClickedColumnTitle(0) 106 { 107 sTitleBackground = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 0.88f); // 216 -> 220 108 sDarkTitleBackground = tint_color(sTitleBackground, B_DARKEN_1_TINT); 109 sShineColor = tint_color(sTitleBackground, B_LIGHTEN_MAX_TINT); 110 sLightShadowColor = tint_color(sTitleBackground, B_DARKEN_2_TINT); 111 sShadowColor = tint_color(sTitleBackground, B_DARKEN_4_TINT); 112 sDarkShadowColor = tint_color(sShadowColor, B_DARKEN_2_TINT); 113 114 SetHighColor(sTitleBackground); 115 SetLowColor(sTitleBackground); 116 SetViewColor(sTitleBackground); 117 118 BFont font(be_plain_font); 119 font.SetSize(9); 120 SetFont(&font); 121 122 Reset(); 123 } 124 125 126 BTitleView::~BTitleView() 127 { 128 } 129 130 131 void 132 BTitleView::Reset() 133 { 134 fTitleList.MakeEmpty(); 135 for (int32 index = 0; ; index++) { 136 BColumn *column = fPoseView->ColumnAt(index); 137 if (!column) 138 break; 139 fTitleList.AddItem(new BColumnTitle(this, column)); 140 } 141 } 142 143 144 void 145 BTitleView::AddTitle(BColumn *column, const BColumn *after) 146 { 147 int32 count = fTitleList.CountItems(); 148 int32 index; 149 if (after) { 150 for (index = 0; index < count; index++) { 151 BColumn *titleColumn = fTitleList.ItemAt(index)->Column(); 152 153 if (after == titleColumn) { 154 index++; 155 break; 156 } 157 } 158 } else 159 index = count; 160 161 fTitleList.AddItem(new BColumnTitle(this, column), index); 162 Invalidate(); 163 } 164 165 166 void 167 BTitleView::RemoveTitle(BColumn *column) 168 { 169 int32 count = fTitleList.CountItems(); 170 for (int32 index = 0; index < count; index++) { 171 BColumnTitle *title = fTitleList.ItemAt(index); 172 if (title->Column() == column) { 173 fTitleList.RemoveItem(title); 174 break; 175 } 176 } 177 178 Invalidate(); 179 } 180 181 182 void 183 BTitleView::Draw(BRect rect) 184 { 185 Draw(rect, false); 186 } 187 188 189 void 190 BTitleView::Draw(BRect, bool useOffscreen, bool updateOnly, 191 const BColumnTitle *pressedColumn, 192 void (*trackRectBlitter)(BView *, BRect), BRect passThru) 193 { 194 BRect bounds(Bounds()); 195 196 BView *view; 197 198 if (useOffscreen) { 199 ASSERT(offscreen); 200 BRect frame(bounds); 201 frame.right += frame.left; 202 // this is kind of messy way of avoiding being clipped by the ammount the 203 // title is scrolled to the left 204 // ToDo: 205 // fix this 206 view = offscreen->BeginUsing(frame); 207 view->SetOrigin(-bounds.left, 0); 208 view->SetLowColor(LowColor()); 209 view->SetHighColor(HighColor()); 210 BFont font(be_plain_font); 211 font.SetSize(9); 212 view->SetFont(&font); 213 } else 214 view = this; 215 216 // fill background with light gray background 217 if (!updateOnly) 218 view->FillRect(bounds, B_SOLID_LOW); 219 220 view->BeginLineArray(4); 221 view->AddLine(bounds.LeftTop(), bounds.RightTop(), sShadowColor); 222 view->AddLine(bounds.LeftBottom(), bounds.RightBottom(), sShadowColor); 223 // draw lighter gray and white inset lines 224 bounds.InsetBy(0, 1); 225 view->AddLine(bounds.LeftBottom(), bounds.RightBottom(), sLightShadowColor); 226 view->AddLine(bounds.LeftTop(), bounds.RightTop(), sShineColor); 227 view->EndLineArray(); 228 229 int32 count = fTitleList.CountItems(); 230 float minx = bounds.right; 231 float maxx = bounds.left; 232 for (int32 index = 0; index < count; index++) { 233 BColumnTitle *title = fTitleList.ItemAt(index); 234 title->Draw(view, title == pressedColumn); 235 BRect titleBounds(title->Bounds()); 236 if (titleBounds.left < minx) 237 minx = titleBounds.left; 238 if (titleBounds.right > maxx) 239 maxx = titleBounds.right; 240 } 241 242 // first and last shades before and after first column 243 BRect tmp(bounds); 244 tmp.right = maxx; 245 tmp.left = minx; 246 tmp.InsetBy(-1, 0); 247 view->BeginLineArray(2); 248 view->AddLine(tmp.LeftTop(), tmp.LeftBottom(), sShadowColor); 249 view->AddLine(tmp.RightTop(), tmp.RightBottom(), sShineColor); 250 view->EndLineArray(); 251 252 if (useOffscreen) { 253 if (trackRectBlitter) 254 (trackRectBlitter)(view, passThru); 255 view->Sync(); 256 DrawBitmap(offscreen->Bitmap()); 257 offscreen->DoneUsing(); 258 } else if (trackRectBlitter) 259 (trackRectBlitter)(view, passThru); 260 } 261 262 263 void 264 BTitleView::MouseDown(BPoint where) 265 { 266 if (!Window()->IsActive()) { 267 // wasn't active, just activate and bail 268 Window()->Activate(); 269 return; 270 } 271 272 // finish any pending edits 273 fPoseView->CommitActivePose(); 274 275 BColumnTitle *title = FindColumnTitle(where); 276 BColumnTitle *resizedTitle = InColumnResizeArea(where); 277 278 uint32 buttons; 279 GetMouse(&where, &buttons); 280 281 // Check if the user clicked the secondary mouse button. 282 // if so, display the attribute menu: 283 284 if (buttons & B_SECONDARY_MOUSE_BUTTON) { 285 BContainerWindow *window = dynamic_cast<BContainerWindow *> 286 (Window()); 287 BPopUpMenu *menu = new BPopUpMenu("Attributes", false, false); 288 menu->SetFont(be_plain_font); 289 window->NewAttributeMenu(menu); 290 window->AddMimeTypesToMenu(menu); 291 window->MarkAttributeMenu(menu); 292 menu->SetTargetForItems(window->PoseView()); 293 menu->Go(ConvertToScreen(where), true, false); 294 return; 295 } 296 297 bigtime_t doubleClickSpeed; 298 get_click_speed(&doubleClickSpeed); 299 300 if (resizedTitle) { 301 bool force = static_cast<bool>(buttons & B_TERTIARY_MOUSE_BUTTON); 302 if (force || buttons & B_PRIMARY_MOUSE_BUTTON) { 303 if (force || fPreviouslyClickedColumnTitle != 0) { 304 if (force || system_time() - fPreviousLeftClickTime < doubleClickSpeed) { 305 if (fPoseView->ResizeColumnToWidest(resizedTitle->Column())) { 306 Invalidate(); 307 return; 308 } 309 } 310 } 311 fPreviousLeftClickTime = system_time(); 312 fPreviouslyClickedColumnTitle = resizedTitle; 313 } 314 } else if (!title) 315 return; 316 317 ColumnTrackState *trackState; 318 if (resizedTitle) 319 trackState = new ColumnResizeState(this, resizedTitle, where); 320 else 321 trackState = new ColumnDragState(this, title, where); 322 323 // track the mouse 324 // - if it is pressed shortly and not moved, it is a click 325 // all else is a track 326 bigtime_t pastClickTime = system_time() + doubleClickSpeed; 327 bool pastClick = false; 328 for (;;) { 329 BPoint old(where); 330 331 GetMouse(&where, &buttons); 332 333 if (!buttons) { 334 if (!pastClick) 335 trackState->Clicked(where, buttons); 336 else 337 trackState->Done(where); 338 break; 339 } 340 341 BRect oldMarging(old, old); 342 oldMarging.InsetBy(-1, -1); 343 344 if ((pastClick && where != old) || !oldMarging.Contains(where)) { 345 // if not pressing yet, use a margin to start, else 346 // call moved on any mouse movement 347 pastClick = true; 348 trackState->MouseMoved(where, buttons); 349 } 350 if (!pastClick && system_time() > pastClickTime) 351 pastClick = true; 352 353 snooze(15000); 354 } 355 356 delete trackState; 357 } 358 359 360 void 361 BTitleView::MouseMoved(BPoint where, uint32 code, const BMessage *message) 362 { 363 switch (code) { 364 default: 365 if (InColumnResizeArea(where) && Window()->IsActive()) 366 SetViewCursor(&fHorizontalResizeCursor); 367 else 368 SetViewCursor(B_CURSOR_SYSTEM_DEFAULT); 369 break; 370 371 case B_EXITED_VIEW: 372 SetViewCursor(B_CURSOR_SYSTEM_DEFAULT); 373 break; 374 } 375 _inherited::MouseMoved(where, code, message); 376 } 377 378 379 BColumnTitle * 380 BTitleView::InColumnResizeArea(BPoint where) const 381 { 382 int32 count = fTitleList.CountItems(); 383 for (int32 index = 0; index < count; index++) { 384 BColumnTitle *title = fTitleList.ItemAt(index); 385 if (title->InColumnResizeArea(where)) 386 return title; 387 } 388 389 return NULL; 390 } 391 392 393 BColumnTitle * 394 BTitleView::FindColumnTitle(BPoint where) const 395 { 396 int32 count = fTitleList.CountItems(); 397 for (int32 index = 0; index < count; index++) { 398 BColumnTitle *title = fTitleList.ItemAt(index); 399 if (title->Bounds().Contains(where)) 400 return title; 401 } 402 403 return NULL; 404 } 405 406 407 BColumnTitle * 408 BTitleView::FindColumnTitle(const BColumn *column) const 409 { 410 int32 count = fTitleList.CountItems(); 411 for (int32 index = 0; index < count; index++) { 412 BColumnTitle *title = fTitleList.ItemAt(index); 413 if (title->Column() == column) 414 return title; 415 } 416 417 return NULL; 418 } 419 420 421 // #pragma mark - 422 423 424 BColumnTitle::BColumnTitle(BTitleView *view, BColumn *column) 425 : 426 fColumn(column), 427 fParent(view) 428 { 429 } 430 431 432 bool 433 BColumnTitle::InColumnResizeArea(BPoint where) const 434 { 435 BRect edge(Bounds()); 436 edge.left = edge.right - kEdgeSize; 437 edge.right += kEdgeSize; 438 439 return edge.Contains(where); 440 } 441 442 443 BRect 444 BColumnTitle::Bounds() const 445 { 446 BRect bounds(fColumn->Offset() - kTitleColumnLeftExtraMargin, 0, 0, kTitleViewHeight); 447 bounds.right = bounds.left + fColumn->Width() + kTitleColumnExtraMargin; 448 449 return bounds; 450 } 451 452 453 void 454 BColumnTitle::Draw(BView *view, bool pressed) 455 { 456 BRect bounds(Bounds()); 457 BPoint loc(0, bounds.bottom - 4); 458 459 view->SetLowColor(pressed ? sDarkTitleBackground : sTitleBackground); 460 view->FillRect(bounds, B_SOLID_LOW); 461 462 BString titleString(fColumn->Title()); 463 view->TruncateString(&titleString, B_TRUNCATE_END, 464 bounds.Width() - kTitleColumnExtraMargin); 465 float resultingWidth = view->StringWidth(titleString.String()); 466 467 switch (fColumn->Alignment()) { 468 case B_ALIGN_LEFT: 469 loc.x = bounds.left + 1 + kTitleColumnLeftExtraMargin; 470 break; 471 472 case B_ALIGN_CENTER: 473 loc.x = bounds.left + (bounds.Width() / 2) - (resultingWidth / 2); 474 break; 475 476 case B_ALIGN_RIGHT: 477 loc.x = bounds.right - resultingWidth - kTitleColumnRightExtraMargin; 478 break; 479 } 480 481 view->MovePenTo(loc); 482 view->SetHighColor(0, 0, 0); 483 view->DrawString(titleString.String()); 484 485 // show sort columns 486 bool secondary = (fColumn->AttrHash() == fParent->PoseView()->SecondarySort()); 487 if (secondary || (fColumn->AttrHash() == fParent->PoseView()->PrimarySort())) { 488 BPoint pt1(loc); 489 BPoint pt2(view->PenLocation()); 490 pt1.x--; 491 pt2.x--; 492 pt1.y++; 493 pt2.y++; 494 if (secondary) 495 view->StrokeLine(pt1, pt2, B_MIXED_COLORS); 496 else 497 view->StrokeLine(pt1, pt2); 498 } 499 500 BRect rect(bounds); 501 502 view->SetHighColor(sShadowColor); 503 view->StrokeRect(rect); 504 505 view->BeginLineArray(4); 506 // draw lighter gray and white inset lines 507 rect.InsetBy(1, 1); 508 view->AddLine(rect.LeftBottom(), rect.RightBottom(), 509 pressed ? sLightShadowColor : sLightShadowColor); 510 view->AddLine(rect.LeftTop(), rect.RightTop(), 511 pressed ? sDarkShadowColor : sShineColor); 512 513 view->AddLine(rect.LeftTop(), rect.LeftBottom(), 514 pressed ? sDarkShadowColor : sShineColor); 515 view->AddLine(rect.RightTop(), rect.RightBottom(), 516 pressed ? sLightShadowColor : sLightShadowColor); 517 518 view->EndLineArray(); 519 } 520 521 522 // #pragma mark - 523 524 525 ColumnTrackState::ColumnTrackState(BTitleView *view, BColumnTitle *title, 526 BPoint where) 527 : 528 fTitleView(view), 529 fTitle(title), 530 fLastPos(where) 531 { 532 } 533 534 535 void 536 ColumnTrackState::MouseMoved(BPoint where, uint32 buttons) 537 { 538 if (!ValueChanged(where)) 539 return; 540 541 Moved(where, buttons); 542 fLastPos = where; 543 } 544 545 546 // #pragma mark - 547 548 549 ColumnResizeState::ColumnResizeState(BTitleView *view, BColumnTitle *title, 550 BPoint where) 551 : ColumnTrackState(view, title, where), 552 fLastLineDrawPos(-1), 553 fInitialTrackOffset((title->fColumn->Offset() + title->fColumn->Width()) - where.x) 554 { 555 DrawLine(); 556 } 557 558 559 bool 560 ColumnResizeState::ValueChanged(BPoint where) 561 { 562 float newWidth = where.x + fInitialTrackOffset - fTitle->fColumn->Offset(); 563 if (newWidth < kMinColumnWidth) 564 newWidth = kMinColumnWidth; 565 566 return newWidth != fTitle->fColumn->Width(); 567 } 568 569 570 void 571 ColumnResizeState::Moved(BPoint where, uint32) 572 { 573 float newWidth = where.x + fInitialTrackOffset - fTitle->fColumn->Offset(); 574 if (newWidth < kMinColumnWidth) 575 newWidth = kMinColumnWidth; 576 577 BPoseView *poseView = fTitleView->PoseView(); 578 579 // bool shrink = (newWidth < fTitle->fColumn->Width()); 580 581 // resize the column 582 poseView->ResizeColumn(fTitle->fColumn, newWidth, &fLastLineDrawPos, 583 _DrawLine, _UndrawLine); 584 585 BRect bounds(fTitleView->Bounds()); 586 bounds.left = fTitle->fColumn->Offset(); 587 588 // force title redraw 589 fTitleView->Draw(bounds, true, false); 590 } 591 592 593 void 594 ColumnResizeState::Done(BPoint) 595 { 596 UndrawLine(); 597 } 598 599 600 void 601 ColumnResizeState::Clicked(BPoint, uint32) 602 { 603 UndrawLine(); 604 } 605 606 607 void 608 ColumnResizeState::DrawLine() 609 { 610 BPoseView *poseView = fTitleView->PoseView(); 611 ASSERT(!poseView->IsDesktopWindow()); 612 613 BRect poseViewBounds(poseView->Bounds()); 614 // remember the line location 615 poseViewBounds.left = fTitle->Bounds().right; 616 fLastLineDrawPos = poseViewBounds.left; 617 618 // draw the line in the new location 619 _DrawLine(poseView, poseViewBounds.LeftTop(), poseViewBounds.LeftBottom()); 620 } 621 622 623 void 624 ColumnResizeState::UndrawLine() 625 { 626 if (fLastLineDrawPos < 0) 627 return; 628 629 BRect poseViewBounds(fTitleView->PoseView()->Bounds()); 630 poseViewBounds.left = fLastLineDrawPos; 631 632 _UndrawLine(fTitleView->PoseView(), poseViewBounds.LeftTop(), 633 poseViewBounds.LeftBottom()); 634 } 635 636 637 // #pragma mark - 638 639 640 ColumnDragState::ColumnDragState(BTitleView *view, BColumnTitle *columnTitle, 641 BPoint where) 642 : ColumnTrackState(view, columnTitle, where), 643 fInitialMouseTrackOffset(where.x), 644 fTrackingRemovedColumn(false) 645 { 646 ASSERT(columnTitle); 647 ASSERT(fTitle); 648 ASSERT(fTitle->Column()); 649 DrawPressNoOutline(); 650 } 651 652 653 // ToDo: 654 // Autoscroll when dragging column left/right 655 // fix dragging back a column before the first column (now adds as last) 656 // make column swaps/adds not invalidate/redraw columns to the left 657 void 658 ColumnDragState::Moved(BPoint where, uint32) 659 { 660 // figure out where we are with the mouse 661 BRect titleBounds(fTitleView->Bounds()); 662 bool overTitleView = titleBounds.Contains(where); 663 BColumnTitle *overTitle = overTitleView 664 ? fTitleView->FindColumnTitle(where) : 0; 665 BRect titleBoundsWithMargin(titleBounds); 666 titleBoundsWithMargin.InsetBy(0, -kRemoveTitleMargin); 667 bool inMarginRect = overTitleView || titleBoundsWithMargin.Contains(where); 668 669 bool drawOutline = false; 670 bool undrawOutline = false; 671 672 if (fTrackingRemovedColumn) { 673 if (overTitleView) { 674 // tracked back with a removed title into the title bar, add it 675 // back 676 fTitleView->EndRectTracking(); 677 fColumnArchive.Seek(0, SEEK_SET); 678 BColumn *column = BColumn::InstantiateFromStream(&fColumnArchive); 679 ASSERT(column); 680 const BColumn *after = NULL; 681 if (overTitle) 682 after = overTitle->Column(); 683 fTitleView->PoseView()->AddColumn(column, after); 684 fTrackingRemovedColumn = false; 685 fTitle = fTitleView->FindColumnTitle(column); 686 fInitialMouseTrackOffset += fTitle->Bounds().left; 687 drawOutline = true; 688 } 689 } else { 690 if (!inMarginRect) { 691 // dragged a title out of the hysteresis margin around the 692 // title bar - remove it and start dragging it as a dotted outline 693 694 BRect rect(fTitle->Bounds()); 695 rect.OffsetBy(where.x - fInitialMouseTrackOffset, where.y - 5); 696 fColumnArchive.Seek(0, SEEK_SET); 697 fTitle->Column()->ArchiveToStream(&fColumnArchive); 698 fInitialMouseTrackOffset -= fTitle->Bounds().left; 699 if (fTitleView->PoseView()->RemoveColumn(fTitle->Column(), false)) { 700 fTitle = 0; 701 fTitleView->BeginRectTracking(rect); 702 fTrackingRemovedColumn = true; 703 undrawOutline = true; 704 } 705 } else if (overTitle && overTitle != fTitle 706 // over a different column 707 && (overTitle->Bounds().left >= fTitle->Bounds().right 708 // over the one to the right 709 || where.x < overTitle->Bounds().left + fTitle->Bounds().Width())){ 710 // over the one to the left, far enough to not snap right back 711 712 BColumn *column = fTitle->Column(); 713 fInitialMouseTrackOffset -= fTitle->Bounds().left; 714 // swap the columns 715 fTitleView->PoseView()->MoveColumnTo(column, overTitle->Column()); 716 // re-grab the title object looking it up by the column 717 fTitle = fTitleView->FindColumnTitle(column); 718 // recalc initialMouseTrackOffset 719 fInitialMouseTrackOffset += fTitle->Bounds().left; 720 drawOutline = true; 721 } else 722 drawOutline = true; 723 } 724 725 if (drawOutline) 726 DrawOutline(where.x - fInitialMouseTrackOffset); 727 else if (undrawOutline) 728 UndrawOutline(); 729 } 730 731 732 void 733 ColumnDragState::Done(BPoint) 734 { 735 if (fTrackingRemovedColumn) 736 fTitleView->EndRectTracking(); 737 UndrawOutline(); 738 } 739 740 741 void 742 ColumnDragState::Clicked(BPoint, uint32) 743 { 744 BPoseView *poseView = fTitleView->PoseView(); 745 uint32 hash = fTitle->Column()->AttrHash(); 746 uint32 primarySort = poseView->PrimarySort(); 747 uint32 secondarySort = poseView->SecondarySort(); 748 bool shift = (modifiers() & B_SHIFT_KEY) != 0; 749 750 // For now: 751 // if we hit the primary sort field again 752 // then if shift key was down, switch primary and secondary 753 if (hash == primarySort) { 754 if (shift && secondarySort) { 755 poseView->SetPrimarySort(secondarySort); 756 poseView->SetSecondarySort(primarySort); 757 } else 758 poseView->SetReverseSort(!poseView->ReverseSort()); 759 } else if (shift) { 760 // hit secondary sort column with shift key, disable 761 if (hash == secondarySort) 762 poseView->SetSecondarySort(0); 763 else 764 poseView->SetSecondarySort(hash); 765 } else { 766 poseView->SetPrimarySort(hash); 767 poseView->SetReverseSort(false); 768 } 769 770 if (poseView->PrimarySort() == poseView->SecondarySort()) 771 poseView->SetSecondarySort(0); 772 773 UndrawOutline(); 774 775 poseView->SortPoses(); 776 poseView->Invalidate(); 777 } 778 779 780 void 781 ColumnDragState::Pressing(BPoint, uint32) 782 { 783 } 784 785 786 bool 787 ColumnDragState::ValueChanged(BPoint) 788 { 789 return true; 790 } 791 792 793 void 794 ColumnDragState::DrawPressNoOutline() 795 { 796 fTitleView->Draw(fTitleView->Bounds(), true, false, fTitle); 797 } 798 799 800 void 801 ColumnDragState::DrawOutline(float pos) 802 { 803 BRect outline(fTitle->Bounds()); 804 outline.OffsetBy(pos, 0); 805 fTitleView->Draw(fTitleView->Bounds(), true, false, fTitle, _DrawOutline, outline); 806 } 807 808 809 void 810 ColumnDragState::UndrawOutline() 811 { 812 fTitleView->Draw(fTitleView->Bounds(), true, false); 813 } 814 815 816 OffscreenBitmap *BTitleView::offscreen = new OffscreenBitmap; 817