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