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