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 loc.x = bounds.left + 1 + kTitleColumnLeftExtraMargin; 482 break; 483 484 case B_ALIGN_CENTER: 485 loc.x = bounds.left + (bounds.Width() / 2) - (resultingWidth / 2); 486 break; 487 488 case B_ALIGN_RIGHT: 489 loc.x = bounds.right - resultingWidth - kTitleColumnRightExtraMargin; 490 break; 491 } 492 493 view->SetHighColor(0, 0, 0); 494 view->DrawString(titleString.String(), loc); 495 496 // show sort columns 497 bool secondary = (fColumn->AttrHash() == fParent->PoseView()->SecondarySort()); 498 if (secondary || (fColumn->AttrHash() == fParent->PoseView()->PrimarySort())) { 499 BPoint pt1(loc); 500 BPoint pt2(view->PenLocation()); 501 pt1.x--; 502 pt2.x--; 503 pt1.y++; 504 pt2.y++; 505 if (secondary) 506 view->StrokeLine(pt1, pt2, B_MIXED_COLORS); 507 else 508 view->StrokeLine(pt1, pt2); 509 } 510 511 BRect rect(bounds); 512 513 view->SetHighColor(sShadowColor); 514 view->StrokeRect(rect); 515 516 view->BeginLineArray(4); 517 // draw lighter gray and white inset lines 518 rect.InsetBy(1, 1); 519 view->AddLine(rect.LeftBottom(), rect.RightBottom(), 520 pressed ? sLightShadowColor : sLightShadowColor); 521 view->AddLine(rect.LeftTop(), rect.RightTop(), 522 pressed ? sDarkShadowColor : sShineColor); 523 524 view->AddLine(rect.LeftTop(), rect.LeftBottom(), 525 pressed ? sDarkShadowColor : sShineColor); 526 view->AddLine(rect.RightTop(), rect.RightBottom(), 527 pressed ? sLightShadowColor : sLightShadowColor); 528 529 view->EndLineArray(); 530 } 531 532 533 // #pragma mark - 534 535 536 ColumnTrackState::ColumnTrackState(BTitleView *view, BColumnTitle *title, 537 BPoint where) 538 : 539 fTitleView(view), 540 fTitle(title), 541 fLastPos(where) 542 { 543 } 544 545 546 void 547 ColumnTrackState::MouseMoved(BPoint where, uint32 buttons) 548 { 549 if (!ValueChanged(where)) 550 return; 551 552 Moved(where, buttons); 553 fLastPos = where; 554 } 555 556 557 // #pragma mark - 558 559 560 ColumnResizeState::ColumnResizeState(BTitleView *view, BColumnTitle *title, 561 BPoint where) 562 : ColumnTrackState(view, title, where), 563 fLastLineDrawPos(-1), 564 fInitialTrackOffset((title->fColumn->Offset() + title->fColumn->Width()) - where.x) 565 { 566 DrawLine(); 567 } 568 569 570 bool 571 ColumnResizeState::ValueChanged(BPoint where) 572 { 573 float newWidth = where.x + fInitialTrackOffset - fTitle->fColumn->Offset(); 574 if (newWidth < kMinColumnWidth) 575 newWidth = kMinColumnWidth; 576 577 return newWidth != fTitle->fColumn->Width(); 578 } 579 580 581 void 582 ColumnResizeState::Moved(BPoint where, uint32) 583 { 584 float newWidth = where.x + fInitialTrackOffset - fTitle->fColumn->Offset(); 585 if (newWidth < kMinColumnWidth) 586 newWidth = kMinColumnWidth; 587 588 BPoseView *poseView = fTitleView->PoseView(); 589 590 // bool shrink = (newWidth < fTitle->fColumn->Width()); 591 592 // resize the column 593 poseView->ResizeColumn(fTitle->fColumn, newWidth, &fLastLineDrawPos, 594 _DrawLine, _UndrawLine); 595 596 BRect bounds(fTitleView->Bounds()); 597 bounds.left = fTitle->fColumn->Offset(); 598 599 // force title redraw 600 fTitleView->Draw(bounds, true, false); 601 } 602 603 604 void 605 ColumnResizeState::Done(BPoint) 606 { 607 UndrawLine(); 608 } 609 610 611 void 612 ColumnResizeState::Clicked(BPoint, uint32) 613 { 614 UndrawLine(); 615 } 616 617 618 void 619 ColumnResizeState::DrawLine() 620 { 621 BPoseView *poseView = fTitleView->PoseView(); 622 ASSERT(!poseView->IsDesktopWindow()); 623 624 BRect poseViewBounds(poseView->Bounds()); 625 // remember the line location 626 poseViewBounds.left = fTitle->Bounds().right; 627 fLastLineDrawPos = poseViewBounds.left; 628 629 // draw the line in the new location 630 _DrawLine(poseView, poseViewBounds.LeftTop(), poseViewBounds.LeftBottom()); 631 } 632 633 634 void 635 ColumnResizeState::UndrawLine() 636 { 637 if (fLastLineDrawPos < 0) 638 return; 639 640 BRect poseViewBounds(fTitleView->PoseView()->Bounds()); 641 poseViewBounds.left = fLastLineDrawPos; 642 643 _UndrawLine(fTitleView->PoseView(), poseViewBounds.LeftTop(), 644 poseViewBounds.LeftBottom()); 645 } 646 647 648 // #pragma mark - 649 650 651 ColumnDragState::ColumnDragState(BTitleView *view, BColumnTitle *columnTitle, 652 BPoint where) 653 : ColumnTrackState(view, columnTitle, where), 654 fInitialMouseTrackOffset(where.x), 655 fTrackingRemovedColumn(false) 656 { 657 ASSERT(columnTitle); 658 ASSERT(fTitle); 659 ASSERT(fTitle->Column()); 660 DrawPressNoOutline(); 661 } 662 663 664 // ToDo: 665 // Autoscroll when dragging column left/right 666 // fix dragging back a column before the first column (now adds as last) 667 // make column swaps/adds not invalidate/redraw columns to the left 668 void 669 ColumnDragState::Moved(BPoint where, uint32) 670 { 671 // figure out where we are with the mouse 672 BRect titleBounds(fTitleView->Bounds()); 673 bool overTitleView = titleBounds.Contains(where); 674 BColumnTitle *overTitle = overTitleView 675 ? fTitleView->FindColumnTitle(where) : 0; 676 BRect titleBoundsWithMargin(titleBounds); 677 titleBoundsWithMargin.InsetBy(0, -kRemoveTitleMargin); 678 bool inMarginRect = overTitleView || titleBoundsWithMargin.Contains(where); 679 680 bool drawOutline = false; 681 bool undrawOutline = false; 682 683 if (fTrackingRemovedColumn) { 684 if (overTitleView) { 685 // tracked back with a removed title into the title bar, add it 686 // back 687 fTitleView->EndRectTracking(); 688 fColumnArchive.Seek(0, SEEK_SET); 689 BColumn *column = BColumn::InstantiateFromStream(&fColumnArchive); 690 ASSERT(column); 691 const BColumn *after = NULL; 692 if (overTitle) 693 after = overTitle->Column(); 694 fTitleView->PoseView()->AddColumn(column, after); 695 fTrackingRemovedColumn = false; 696 fTitle = fTitleView->FindColumnTitle(column); 697 fInitialMouseTrackOffset += fTitle->Bounds().left; 698 drawOutline = true; 699 } 700 } else { 701 if (!inMarginRect) { 702 // dragged a title out of the hysteresis margin around the 703 // title bar - remove it and start dragging it as a dotted outline 704 705 BRect rect(fTitle->Bounds()); 706 rect.OffsetBy(where.x - fInitialMouseTrackOffset, where.y - 5); 707 fColumnArchive.Seek(0, SEEK_SET); 708 fTitle->Column()->ArchiveToStream(&fColumnArchive); 709 fInitialMouseTrackOffset -= fTitle->Bounds().left; 710 if (fTitleView->PoseView()->RemoveColumn(fTitle->Column(), false)) { 711 fTitle = 0; 712 fTitleView->BeginRectTracking(rect); 713 fTrackingRemovedColumn = true; 714 undrawOutline = true; 715 } 716 } else if (overTitle && overTitle != fTitle 717 // over a different column 718 && (overTitle->Bounds().left >= fTitle->Bounds().right 719 // over the one to the right 720 || where.x < overTitle->Bounds().left + fTitle->Bounds().Width())){ 721 // over the one to the left, far enough to not snap right back 722 723 BColumn *column = fTitle->Column(); 724 fInitialMouseTrackOffset -= fTitle->Bounds().left; 725 // swap the columns 726 fTitleView->PoseView()->MoveColumnTo(column, overTitle->Column()); 727 // re-grab the title object looking it up by the column 728 fTitle = fTitleView->FindColumnTitle(column); 729 // recalc initialMouseTrackOffset 730 fInitialMouseTrackOffset += fTitle->Bounds().left; 731 drawOutline = true; 732 } else 733 drawOutline = true; 734 } 735 736 if (drawOutline) 737 DrawOutline(where.x - fInitialMouseTrackOffset); 738 else if (undrawOutline) 739 UndrawOutline(); 740 } 741 742 743 void 744 ColumnDragState::Done(BPoint) 745 { 746 if (fTrackingRemovedColumn) 747 fTitleView->EndRectTracking(); 748 UndrawOutline(); 749 } 750 751 752 void 753 ColumnDragState::Clicked(BPoint, uint32) 754 { 755 BPoseView *poseView = fTitleView->PoseView(); 756 uint32 hash = fTitle->Column()->AttrHash(); 757 uint32 primarySort = poseView->PrimarySort(); 758 uint32 secondarySort = poseView->SecondarySort(); 759 bool shift = (modifiers() & B_SHIFT_KEY) != 0; 760 761 // For now: 762 // if we hit the primary sort field again 763 // then if shift key was down, switch primary and secondary 764 if (hash == primarySort) { 765 if (shift && secondarySort) { 766 poseView->SetPrimarySort(secondarySort); 767 poseView->SetSecondarySort(primarySort); 768 } else 769 poseView->SetReverseSort(!poseView->ReverseSort()); 770 } else if (shift) { 771 // hit secondary sort column with shift key, disable 772 if (hash == secondarySort) 773 poseView->SetSecondarySort(0); 774 else 775 poseView->SetSecondarySort(hash); 776 } else { 777 poseView->SetPrimarySort(hash); 778 poseView->SetReverseSort(false); 779 } 780 781 if (poseView->PrimarySort() == poseView->SecondarySort()) 782 poseView->SetSecondarySort(0); 783 784 UndrawOutline(); 785 786 poseView->SortPoses(); 787 poseView->Invalidate(); 788 } 789 790 791 void 792 ColumnDragState::Pressing(BPoint, uint32) 793 { 794 } 795 796 797 bool 798 ColumnDragState::ValueChanged(BPoint) 799 { 800 return true; 801 } 802 803 804 void 805 ColumnDragState::DrawPressNoOutline() 806 { 807 fTitleView->Draw(fTitleView->Bounds(), true, false, fTitle); 808 } 809 810 811 void 812 ColumnDragState::DrawOutline(float pos) 813 { 814 BRect outline(fTitle->Bounds()); 815 outline.OffsetBy(pos, 0); 816 fTitleView->Draw(fTitleView->Bounds(), true, false, fTitle, _DrawOutline, outline); 817 } 818 819 820 void 821 ColumnDragState::UndrawOutline() 822 { 823 fTitleView->Draw(fTitleView->Bounds(), true, false); 824 } 825 826 827 OffscreenBitmap *BTitleView::offscreen = new OffscreenBitmap; 828