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 36 #include <stdlib.h> 37 #include <string.h> 38 39 #include <Debug.h> 40 #include <Volume.h> 41 #include <fs_info.h> 42 43 #include "Attributes.h" 44 #include "Commands.h" 45 #include "FSClipboard.h" 46 #include "IconCache.h" 47 #include "Pose.h" 48 #include "PoseView.h" 49 #include "Utilities.h" 50 51 52 int32 53 CalcFreeSpace(BVolume* volume) 54 { 55 off_t capacity = volume->Capacity(); 56 if (capacity == 0) 57 return 100; 58 59 int32 percent 60 = static_cast<int32>(volume->FreeBytes() / (capacity / 100)); 61 62 // warn below 20 MB of free space (if this is less than 10% of free space) 63 if (volume->FreeBytes() < 20 * 1024 * 1024 && percent < 10) 64 return -2 - percent; 65 return percent; 66 } 67 68 69 // SymLink handling: 70 // symlink pose uses the resolved model to retrieve the icon, if not broken 71 // everything else, like the attributes, etc. is retrieved directly from the 72 // symlink itself 73 BPose::BPose(Model* model, BPoseView* view, uint32 clipboardMode, 74 bool selected) 75 : fModel(model), 76 fWidgetList(4, true), 77 fClipboardMode(clipboardMode), 78 fPercent(-1), 79 fSelectionTime(0), 80 fIsSelected(selected), 81 fHasLocation(false), 82 fNeedsSaveLocation(false), 83 fListModeInited(false), 84 fWasAutoPlaced(false), 85 fBrokenSymLink(false), 86 fBackgroundClean(false) 87 { 88 CreateWidgets(view); 89 90 if (model->IsVolume()) { 91 fs_info info; 92 dev_t device = model->NodeRef()->device; 93 BVolume* volume = new BVolume(device); 94 if (volume->InitCheck() == B_OK 95 && fs_stat_dev(device, &info) == B_OK) { 96 // Philosophy here: 97 // Bars go on all read/write volumes 98 // Exceptions: Not on CDDA 99 if (strcmp(info.fsh_name,"cdda") != 0 100 && !volume->IsReadOnly()) { 101 // The volume is ok and we want space bars on it 102 gPeriodicUpdatePoses.AddPose(this, view, 103 _PeriodicUpdateCallback, volume); 104 if (TrackerSettings().ShowVolumeSpaceBar()) 105 fPercent = CalcFreeSpace(volume); 106 } else 107 delete volume; 108 } else 109 delete volume; 110 } 111 } 112 113 114 BPose::~BPose() 115 { 116 if (fModel->IsVolume()) { 117 // we might be registered for periodic updates 118 BVolume* volume = NULL; 119 if (gPeriodicUpdatePoses.RemovePose(this, (void**)&volume)) 120 delete volume; 121 } 122 123 delete fModel; 124 } 125 126 127 void 128 BPose::CreateWidgets(BPoseView* poseView) 129 { 130 for (int32 index = 0; ; index++) { 131 BColumn* column = poseView->ColumnAt(index); 132 if (!column) 133 break; 134 fWidgetList.AddItem(new BTextWidget(fModel, column, poseView)); 135 } 136 } 137 138 139 BTextWidget* 140 BPose::AddWidget(BPoseView* poseView, BColumn* column) 141 { 142 BModelOpener opener(fModel); 143 if (fModel->InitCheck() != B_OK) 144 return NULL; 145 146 BTextWidget* widget = new BTextWidget(fModel, column, poseView); 147 fWidgetList.AddItem(widget); 148 return widget; 149 } 150 151 152 BTextWidget* 153 BPose::AddWidget(BPoseView* poseView, BColumn* column, 154 ModelNodeLazyOpener &opener) 155 { 156 opener.OpenNode(); 157 if (fModel->InitCheck() != B_OK) 158 return NULL; 159 160 BTextWidget* widget = new BTextWidget(fModel, column, poseView); 161 fWidgetList.AddItem(widget); 162 return widget; 163 } 164 165 166 void 167 BPose::RemoveWidget(BPoseView*, BColumn* column) 168 { 169 int32 index; 170 BTextWidget* widget = WidgetFor(column->AttrHash(), &index); 171 if (widget) 172 delete fWidgetList.RemoveItemAt(index); 173 } 174 175 176 void 177 BPose::Commit(bool saveChanges, BPoint loc, BPoseView* poseView, 178 int32 poseIndex) 179 { 180 int32 count = fWidgetList.CountItems(); 181 for (int32 index = 0; index < count; index++) { 182 BTextWidget* widget = fWidgetList.ItemAt(index); 183 if (widget->IsActive()) { 184 widget->StopEdit(saveChanges, loc, poseView, this, poseIndex); 185 break; 186 } 187 } 188 } 189 190 191 inline bool 192 OneMouseUp(BTextWidget* widget, BPose* pose, BPoseView* poseView, 193 BColumn* column, BPoint poseLoc, BPoint where) 194 { 195 BRect rect; 196 if (poseView->ViewMode() == kListMode) 197 rect = widget->CalcClickRect(poseLoc, column, poseView); 198 else 199 rect = widget->CalcClickRect(pose->Location(poseView), 0, poseView); 200 201 if (rect.Contains(where)) { 202 widget->MouseUp(rect, poseView, pose, where); 203 return true; 204 } 205 return false; 206 } 207 208 209 void 210 BPose::MouseUp(BPoint poseLoc, BPoseView* poseView, BPoint where, int32) 211 { 212 WhileEachTextWidget(this, poseView, OneMouseUp, poseLoc, where); 213 } 214 215 216 inline void 217 OneCheckAndUpdate(BTextWidget* widget, BPose*, BPoseView* poseView, 218 BColumn* column, BPoint poseLoc) 219 { 220 widget->CheckAndUpdate(poseLoc, column, poseView, true); 221 } 222 223 224 void 225 BPose::UpdateAllWidgets(int32, BPoint poseLoc, BPoseView* poseView) 226 { 227 if (poseView->ViewMode() != kListMode) 228 poseLoc = Location(poseView); 229 230 ASSERT(fModel->IsNodeOpen()); 231 EachTextWidget(this, poseView, OneCheckAndUpdate, poseLoc); 232 } 233 234 235 void 236 BPose::UpdateWidgetAndModel(Model* resolvedModel, const char* attrName, 237 uint32 attrType, int32, BPoint poseLoc, BPoseView* poseView, bool visible) 238 { 239 if (poseView->ViewMode() != kListMode) 240 poseLoc = Location(poseView); 241 242 ASSERT(!resolvedModel || resolvedModel->IsNodeOpen()); 243 244 if (attrName) { 245 // pick up new attributes and find out if icon needs updating 246 if (resolvedModel->AttrChanged(attrName) && visible) 247 UpdateIcon(poseLoc, poseView); 248 249 // ToDo: the following code is wrong, because this sort of hashing 250 // may overlap and we get aliasing 251 uint32 attrHash = AttrHashString(attrName, attrType); 252 BTextWidget* widget = WidgetFor(attrHash); 253 if (widget) { 254 BColumn* column = poseView->ColumnFor(attrHash); 255 if (column) 256 widget->CheckAndUpdate(poseLoc, column, poseView, visible); 257 } else if (attrType == 0) { 258 // attribute got likely removed, so let's search the 259 // column for the matching attribute name 260 int32 count = fWidgetList.CountItems(); 261 for (int32 i = 0; i < count; i++) { 262 BTextWidget* widget = fWidgetList.ItemAt(i); 263 BColumn* column = poseView->ColumnFor(widget->AttrHash()); 264 if (column != NULL && !strcmp(column->AttrName(), attrName)) { 265 widget->CheckAndUpdate(poseLoc, column, poseView, 266 visible); 267 break; 268 } 269 } 270 } 271 } else { 272 // no attr name means check all widgets for stat info changes 273 274 // pick up stat changes 275 if (resolvedModel && resolvedModel->StatChanged()) { 276 if (resolvedModel->InitCheck() != B_OK) 277 return; 278 279 if (visible) 280 UpdateIcon(poseLoc, poseView); 281 } 282 283 // distribute stat changes 284 for (int32 index = 0; ; index++) { 285 BColumn* column = poseView->ColumnAt(index); 286 if (!column) 287 break; 288 289 if (column->StatField()) { 290 BTextWidget* widget = WidgetFor(column->AttrHash()); 291 if (widget) { 292 widget->CheckAndUpdate(poseLoc, column, poseView, 293 visible); 294 } 295 } 296 } 297 } 298 } 299 300 301 bool 302 BPose::_PeriodicUpdateCallback(BPose* pose, void* cookie) 303 { 304 return pose->UpdateVolumeSpaceBar((BVolume*)cookie); 305 } 306 307 308 bool 309 BPose::UpdateVolumeSpaceBar(BVolume* volume) 310 { 311 bool enabled = TrackerSettings().ShowVolumeSpaceBar(); 312 if (!enabled) { 313 if (fPercent == -1) 314 return false; 315 316 fPercent = -1; 317 return true; 318 } 319 320 int32 percent = CalcFreeSpace(volume); 321 if (fPercent != percent) { 322 if (percent > 100) 323 fPercent = 100; 324 else 325 fPercent = percent; 326 327 return true; 328 } 329 return false; 330 } 331 332 333 void 334 BPose::UpdateIcon(BPoint poseLoc, BPoseView* poseView) 335 { 336 IconCache::sIconCache->IconChanged(ResolvedModel()); 337 338 int32 iconSize = poseView->IconSizeInt(); 339 340 BRect rect; 341 if (poseView->ViewMode() == kListMode) { 342 rect = CalcRect(poseLoc, poseView); 343 rect.left += kListOffset; 344 rect.right = rect.left + iconSize; 345 rect.top = rect.bottom - iconSize; 346 } else { 347 BPoint location = Location(poseView); 348 rect.left = location.x; 349 rect.top = location.y; 350 rect.right = rect.left + iconSize; 351 rect.bottom = rect.top + iconSize; 352 } 353 354 poseView->Invalidate(rect); 355 } 356 357 358 void 359 BPose::UpdateBrokenSymLink(BPoint poseLoc, BPoseView* poseView) 360 { 361 ASSERT(TargetModel()->IsSymLink()); 362 ASSERT(!TargetModel()->LinkTo()); 363 UpdateIcon(poseLoc, poseView); 364 } 365 366 367 void 368 BPose::UpdateWasBrokenSymlink(BPoint poseLoc, BPoseView* poseView) 369 { 370 if (!fModel->IsSymLink()) 371 return; 372 373 if (fModel->LinkTo()) 374 return; 375 376 poseView->CreateSymlinkPoseTarget(fModel); 377 if (!fModel->LinkTo()) 378 return; 379 380 UpdateIcon(poseLoc, poseView); 381 fModel->LinkTo()->CloseNode(); 382 } 383 384 385 void 386 BPose::EditFirstWidget(BPoint poseLoc, BPoseView* poseView) 387 { 388 // find first editable widget 389 BColumn* column; 390 for (int32 i = 0;(column = poseView->ColumnAt(i)) != NULL;i++) { 391 BTextWidget* widget = WidgetFor(column->AttrHash()); 392 393 if (widget && widget->IsEditable()) { 394 BRect bounds; 395 // ToDo: 396 // fold the three StartEdit code sequences into a cover call 397 if (poseView->ViewMode() == kListMode) 398 bounds = widget->CalcRect(poseLoc, column, poseView); 399 else 400 bounds = widget->CalcRect(Location(poseView), NULL, poseView); 401 widget->StartEdit(bounds, poseView, this); 402 break; 403 } 404 } 405 } 406 407 408 void 409 BPose::EditPreviousNextWidgetCommon(BPoseView* poseView, bool next) 410 { 411 bool found = false; 412 int32 delta = next ? 1 : -1; 413 for (int32 index = next ? 0 : poseView->CountColumns() - 1; ; 414 index += delta) { 415 BColumn* column = poseView->ColumnAt(index); 416 if (!column) 417 break; 418 419 BTextWidget* widget = WidgetFor(column->AttrHash()); 420 if (widget && widget->IsActive()) { 421 poseView->CommitActivePose(); 422 found = true; 423 continue; 424 } 425 426 if (found && column->Editable()) { 427 BRect bounds; 428 if (poseView->ViewMode() == kListMode) { 429 int32 poseIndex = poseView->IndexOfPose(this); 430 BPoint poseLoc(0, poseIndex* poseView->ListElemHeight()); 431 bounds = widget->CalcRect(poseLoc, column, poseView); 432 } else 433 bounds = widget->CalcRect(Location(poseView), 0, poseView); 434 435 widget->StartEdit(bounds, poseView, this); 436 break; 437 } 438 } 439 } 440 441 442 void 443 BPose::EditNextWidget(BPoseView* poseView) 444 { 445 EditPreviousNextWidgetCommon(poseView, true); 446 } 447 448 449 void 450 BPose::EditPreviousWidget(BPoseView* poseView) 451 { 452 EditPreviousNextWidgetCommon(poseView, false); 453 } 454 455 456 bool 457 BPose::PointInPose(const BPoseView* poseView, BPoint where) const 458 { 459 ASSERT(poseView->ViewMode() != kListMode); 460 461 BPoint location = Location(poseView); 462 463 if (poseView->ViewMode() == kIconMode) { 464 // check icon rect, then actual icon pixel 465 BRect rect(location, location); 466 rect.right += poseView->IconSizeInt() - 1; 467 rect.bottom += poseView->IconSizeInt() - 1; 468 469 if (rect.Contains(where)) 470 return IconCache::sIconCache->IconHitTest(where - location, 471 ResolvedModel(), 472 kNormalIcon, 473 poseView->IconSize()); 474 475 BTextWidget* widget = WidgetFor(poseView->FirstColumn()->AttrHash()); 476 if (widget) { 477 float textWidth = ceilf(widget->TextWidth(poseView) + 1); 478 rect.left += (poseView->IconSizeInt() - textWidth) / 2; 479 rect.right = rect.left + textWidth; 480 } 481 482 rect.top = location.y + poseView->IconSizeInt(); 483 rect.bottom = rect.top + poseView->FontHeight(); 484 485 return rect.Contains(where); 486 } 487 488 // MINI_ICON_MODE rect calc 489 BRect rect(location, location); 490 rect.right += B_MINI_ICON + kMiniIconSeparator; 491 rect.bottom += poseView->IconPoseHeight(); 492 BTextWidget* widget = WidgetFor(poseView->FirstColumn()->AttrHash()); 493 if (widget) 494 rect.right += ceil(widget->TextWidth(poseView) + 1); 495 496 return rect.Contains(where); 497 } 498 499 500 bool 501 BPose::PointInPose(BPoint loc, const BPoseView* poseView, BPoint where, 502 BTextWidget** hitWidget) const 503 { 504 if (hitWidget) 505 *hitWidget = NULL; 506 507 // check intersection with icon 508 BRect rect; 509 rect.left = loc.x + kListOffset; 510 rect.right = rect.left + B_MINI_ICON; 511 rect.bottom = loc.y + poseView->ListElemHeight(); 512 rect.top = rect.bottom - B_MINI_ICON; 513 if (rect.Contains(where)) 514 return true; 515 516 for (int32 index = 0; ; index++) { 517 BColumn* column = poseView->ColumnAt(index); 518 if (!column) 519 break; 520 BTextWidget* widget = WidgetFor(column->AttrHash()); 521 if (widget 522 && widget->CalcClickRect(loc, column, poseView).Contains(where)) { 523 if (hitWidget) 524 *hitWidget = widget; 525 return true; 526 } 527 } 528 529 return false; 530 } 531 532 533 void 534 BPose::Draw(BRect rect, const BRect& updateRect, BPoseView* poseView, 535 BView* drawView, bool fullDraw, BPoint offset, bool selected) 536 { 537 // If the background wasn't cleared and Draw() is not called after 538 // having edited a name or similar (with fullDraw) 539 if (!fBackgroundClean && !fullDraw) { 540 fBackgroundClean = true; 541 poseView->Invalidate(rect); 542 return; 543 } else 544 fBackgroundClean = false; 545 546 bool directDraw = (drawView == poseView); 547 bool windowActive = poseView->Window()->IsActive(); 548 bool showSelectionWhenInactive = poseView->fShowSelectionWhenInactive; 549 bool isDrawingSelectionRect = poseView->fIsDrawingSelectionRect; 550 551 ModelNodeLazyOpener modelOpener(fModel); 552 553 if (poseView->ViewMode() == kListMode) { 554 uint32 size = poseView->IconSizeInt(); 555 BRect iconRect(rect); 556 iconRect.left += kListOffset; 557 iconRect.right = iconRect.left + size; 558 iconRect.top = iconRect.bottom - size; 559 if (updateRect.Intersects(iconRect)) { 560 iconRect.OffsetBy(offset); 561 DrawIcon(iconRect.LeftTop(), drawView, poseView->IconSize(), 562 directDraw, !windowActive && !showSelectionWhenInactive); 563 } 564 565 // draw text 566 int32 columnsToDraw = 1; 567 if (fullDraw) 568 columnsToDraw = poseView->CountColumns(); 569 570 for (int32 index = 0; index < columnsToDraw; index++) { 571 BColumn* column = poseView->ColumnAt(index); 572 if (!column) 573 break; 574 575 // if widget doesn't exist, create it 576 BTextWidget* widget = WidgetFor(column, poseView, modelOpener); 577 578 if (widget && widget->IsVisible()) { 579 BRect widgetRect(widget->ColumnRect(rect.LeftTop(), column, 580 poseView)); 581 582 if (updateRect.Intersects(widgetRect)) { 583 BRect widgetTextRect(widget->CalcRect(rect.LeftTop(), 584 column, poseView)); 585 586 bool selectDuringDraw = directDraw && selected 587 && windowActive; 588 589 if (index == 0 && selectDuringDraw) { 590 //draw with dark background to select text 591 drawView->PushState(); 592 drawView->SetLowColor(0, 0, 0); 593 } 594 595 if (index == 0) { 596 widget->Draw(widgetRect, widgetTextRect, 597 column->Width(), poseView, drawView, selected, 598 fClipboardMode, offset, directDraw); 599 } else { 600 widget->Draw(widgetTextRect, widgetTextRect, column->Width(), 601 poseView, drawView, false, fClipboardMode, 602 offset, directDraw); 603 } 604 605 if (index == 0 && selectDuringDraw) 606 drawView->PopState(); 607 else if (index == 0 && selected) { 608 if (windowActive || isDrawingSelectionRect) { 609 widgetTextRect.OffsetBy(offset); 610 drawView->InvertRect(widgetTextRect); 611 } else if (!windowActive 612 && showSelectionWhenInactive) { 613 widgetTextRect.OffsetBy(offset); 614 drawView->PushState(); 615 drawView->SetDrawingMode(B_OP_BLEND); 616 drawView->SetHighColor(128, 128, 128, 255); 617 drawView->FillRect(widgetTextRect); 618 drawView->PopState(); 619 } 620 } 621 } 622 } 623 } 624 } else { 625 626 // draw in icon mode 627 BPoint location(Location(poseView)); 628 BPoint iconOrigin(location); 629 iconOrigin += offset; 630 631 DrawIcon(iconOrigin, drawView, poseView->IconSize(), directDraw, 632 !windowActive && !showSelectionWhenInactive); 633 634 BColumn* column = poseView->FirstColumn(); 635 if (!column) 636 return; 637 638 BTextWidget* widget = WidgetFor(column, poseView, modelOpener); 639 if (!widget || !widget->IsVisible()) 640 return; 641 642 rect = widget->CalcRect(location, 0, poseView); 643 644 bool selectDuringDraw = directDraw && selected 645 && (poseView->IsDesktopWindow() || windowActive); 646 647 if (selectDuringDraw) { 648 // draw with dark background to select text 649 drawView->PushState(); 650 drawView->SetLowColor(0, 0, 0); 651 } 652 653 widget->Draw(rect, rect, rect.Width(), poseView, drawView, 654 selected, fClipboardMode, offset, directDraw); 655 656 if (selectDuringDraw) 657 drawView->PopState(); 658 else if (selected && directDraw) { 659 if (windowActive || isDrawingSelectionRect) { 660 rect.OffsetBy(offset); 661 drawView->InvertRect(rect); 662 } else if (!windowActive && showSelectionWhenInactive) { 663 drawView->PushState(); 664 drawView->SetDrawingMode(B_OP_BLEND); 665 drawView->SetHighColor(128, 128, 128, 255); 666 drawView->FillRect(rect); 667 drawView->PopState(); 668 } 669 } 670 } 671 } 672 673 674 void 675 BPose::DeselectWithoutErasingBackground(BRect, BPoseView* poseView) 676 { 677 ASSERT(poseView->ViewMode() != kListMode); 678 ASSERT(!IsSelected()); 679 680 BPoint location(Location(poseView)); 681 682 // draw icon directly 683 if (fPercent == -1) 684 DrawIcon(location, poseView, poseView->IconSize(), true); 685 else 686 UpdateIcon(location, poseView); 687 688 BColumn* column = poseView->FirstColumn(); 689 if (!column) 690 return; 691 692 BTextWidget* widget = WidgetFor(column->AttrHash()); 693 if (!widget || !widget->IsVisible()) 694 return; 695 696 // just invalidate the background, don't draw anything 697 poseView->Invalidate(widget->CalcRect(location, 0, poseView)); 698 } 699 700 701 void 702 BPose::MoveTo(BPoint point, BPoseView* poseView, bool inval) 703 { 704 point.x = floorf(point.x); 705 point.y = floorf(point.y); 706 707 BRect oldBounds; 708 709 BPoint oldLocation = Location(poseView); 710 711 ASSERT(poseView->ViewMode() != kListMode); 712 if (point == oldLocation || poseView->ViewMode() == kListMode) 713 return; 714 715 if (inval) 716 oldBounds = CalcRect(poseView); 717 718 // might need to move a text view if we're active 719 if (poseView->ActivePose() == this) { 720 BView* border_view = poseView->FindView("BorderView"); 721 if (border_view) { 722 border_view->MoveBy(point.x - oldLocation.x, 723 point.y - oldLocation.y); 724 } 725 } 726 727 float scale = 1.0; 728 if (poseView->ViewMode() == kIconMode) { 729 scale = poseView->IconSize() / 32.0; 730 } 731 fLocation.x = point.x / scale; 732 fLocation.y = point.y / scale; 733 734 fHasLocation = true; 735 fNeedsSaveLocation = true; 736 737 if (inval) { 738 poseView->Invalidate(oldBounds); 739 poseView->Invalidate(CalcRect(poseView)); 740 } 741 } 742 743 744 BTextWidget* 745 BPose::ActiveWidget() const 746 { 747 for (int32 i = fWidgetList.CountItems(); i-- > 0;) { 748 BTextWidget* widget = fWidgetList.ItemAt(i); 749 if (widget->IsActive()) 750 return widget; 751 } 752 return NULL; 753 } 754 755 756 BTextWidget* 757 BPose::WidgetFor(uint32 attr, int32* index) const 758 { 759 int32 count = fWidgetList.CountItems(); 760 for (int32 i = 0; i < count; i++) { 761 BTextWidget* widget = fWidgetList.ItemAt(i); 762 if (widget->AttrHash() == attr) { 763 if (index) 764 *index = i; 765 return widget; 766 } 767 } 768 769 return 0; 770 } 771 772 773 BTextWidget* 774 BPose::WidgetFor(BColumn* column, BPoseView* poseView, 775 ModelNodeLazyOpener &opener, int32* index) 776 { 777 BTextWidget* widget = WidgetFor(column->AttrHash(), index); 778 if (!widget) 779 widget = AddWidget(poseView, column, opener); 780 781 return widget; 782 } 783 784 785 // the following method is deprecated 786 bool 787 BPose::TestLargeIconPixel(BPoint point) const 788 { 789 return IconCache::sIconCache->IconHitTest(point, ResolvedModel(), 790 kNormalIcon, B_LARGE_ICON); 791 } 792 793 794 void 795 BPose::DrawIcon(BPoint where, BView* view, icon_size kind, bool direct, 796 bool drawUnselected) 797 { 798 if (fClipboardMode == kMoveSelectionTo) { 799 view->SetDrawingMode(B_OP_ALPHA); 800 view->SetHighColor(0, 0, 0, 64); 801 // set the level of transparency 802 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY); 803 } else if (direct) 804 view->SetDrawingMode(B_OP_OVER); 805 806 IconCache::sIconCache->Draw(ResolvedModel(), view, where, 807 fIsSelected && !drawUnselected ? kSelectedIcon : kNormalIcon, kind, 808 true); 809 810 if (fPercent != -1) 811 DrawBar(where, view, kind); 812 } 813 814 815 void 816 BPose::DrawBar(BPoint where,BView* view,icon_size kind) 817 { 818 view->PushState(); 819 820 int32 size, barWidth, barHeight, yOffset; 821 if (kind >= B_LARGE_ICON) { 822 size = kind - 1; 823 barWidth = (int32)((float)7 / (float)32 * (float)kind); 824 yOffset = 2; 825 barHeight = size - 4 - 2 * yOffset; 826 } else { 827 size = B_MINI_ICON; 828 barWidth = 4; 829 yOffset = 0; 830 barHeight = size - 4 - 2 * yOffset; 831 } 832 833 // the black shadowed line 834 view->SetHighColor(32, 32, 32, 92); 835 view->MovePenTo(BPoint(where.x + size, where.y + 1 + yOffset)); 836 view->StrokeLine(BPoint(where.x + size, where.y + size - yOffset)); 837 view->StrokeLine(BPoint(where.x + size - barWidth + 1, 838 where.y + size - yOffset)); 839 840 view->SetDrawingMode(B_OP_ALPHA); 841 842 // the gray frame 843 view->SetHighColor(76, 76, 76, 192); 844 BRect rect( where.x + size - barWidth,where.y + yOffset, 845 where.x + size - 1,where.y + size - 1 - yOffset); 846 view->StrokeRect(rect); 847 848 // calculate bar height 849 int32 percent = fPercent > -1 ? fPercent : -2 - fPercent; 850 int32 barPos = int32(barHeight * percent / 100.0); 851 if (barPos < 0) 852 barPos = 0; 853 else if (barPos > barHeight) 854 barPos = barHeight; 855 856 // the free space bar 857 view->SetHighColor(TrackerSettings().FreeSpaceColor()); 858 859 rect.InsetBy(1,1); 860 BRect bar(rect); 861 bar.bottom = bar.top + barPos - 1; 862 if (barPos > 0) 863 view->FillRect(bar); 864 865 // the used space bar 866 bar.top = bar.bottom + 1; 867 bar.bottom = rect.bottom; 868 view->SetHighColor(fPercent < -1 869 ? TrackerSettings().WarningSpaceColor() 870 : TrackerSettings().UsedSpaceColor()); 871 view->FillRect(bar); 872 873 view->PopState(); 874 } 875 876 877 void 878 BPose::DrawToggleSwitch(BRect, BPoseView*) 879 { 880 return; 881 } 882 883 884 BPoint 885 BPose::Location(const BPoseView* poseView) const 886 { 887 float scale = 1.0; 888 if (poseView->ViewMode() == kIconMode) 889 scale = poseView->IconSize() / 32.0; 890 891 return BPoint(fLocation.x * scale, fLocation.y * scale); 892 } 893 894 895 void 896 BPose::SetLocation(BPoint point, const BPoseView* poseView) 897 { 898 float scale = 1.0; 899 if (poseView->ViewMode() == kIconMode) 900 scale = poseView->IconSize() / 32.0; 901 902 fLocation = BPoint(floorf(point.x / scale), floorf(point.y / scale)); 903 if (isinff(fLocation.x) || isinff(fLocation.y)) 904 debugger("BPose::SetLocation() - infinite location"); 905 fHasLocation = true; 906 } 907 908 909 BRect 910 BPose::CalcRect(BPoint loc, const BPoseView* poseView, bool minimalRect) const 911 { 912 ASSERT(poseView->ViewMode() == kListMode); 913 914 BColumn* column = poseView->LastColumn(); 915 BRect rect; 916 rect.left = loc.x; 917 rect.top = loc.y; 918 rect.right = loc.x + column->Offset() + column->Width(); 919 rect.bottom = rect.top + poseView->ListElemHeight(); 920 921 if (minimalRect) { 922 BTextWidget* widget = WidgetFor(poseView->FirstColumn()->AttrHash()); 923 if (widget) { 924 rect.right = widget->CalcRect(loc, poseView->FirstColumn(), 925 poseView).right; 926 } 927 } 928 929 return rect; 930 } 931 932 933 BRect 934 BPose::CalcRect(const BPoseView* poseView) const 935 { 936 ASSERT(poseView->ViewMode() != kListMode); 937 938 BRect rect; 939 BPoint location = Location(poseView); 940 if (poseView->ViewMode() == kIconMode) { 941 rect.left = location.x; 942 rect.right = rect.left + poseView->IconSizeInt(); 943 944 BTextWidget* widget = WidgetFor(poseView->FirstColumn()->AttrHash()); 945 if (widget) { 946 float textWidth = ceilf(widget->TextWidth(poseView) + 1); 947 if (textWidth > poseView->IconSizeInt()) { 948 rect.left += (poseView->IconSizeInt() - textWidth) / 2; 949 rect.right = rect.left + textWidth; 950 } 951 } 952 953 rect.top = location.y; 954 rect.bottom = rect.top + poseView->IconPoseHeight(); 955 } else { 956 // MINI_ICON_MODE rect calc 957 rect.left = location.x; 958 rect.top = location.y; 959 rect.right = rect.left + B_MINI_ICON + kMiniIconSeparator; 960 rect.bottom = rect.top + poseView->IconPoseHeight(); 961 BTextWidget* widget = WidgetFor(poseView->FirstColumn()->AttrHash()); 962 if (widget) 963 rect.right += ceil(widget->TextWidth(poseView) + 1); 964 } 965 966 return rect; 967 } 968 969 970 #if DEBUG 971 972 void 973 BPose::PrintToStream() 974 { 975 TargetModel()->PrintToStream(); 976 switch (fClipboardMode) { 977 case kMoveSelectionTo: 978 PRINT(("clipboardMode: Cut\n")); 979 break; 980 case kCopySelectionTo: 981 PRINT(("clipboardMode: Copy\n")); 982 break; 983 default: 984 PRINT(("clipboardMode: 0 - not in clipboard\n")); 985 } 986 PRINT(("%sselected\n", IsSelected() ? "" : "not ")); 987 PRINT(("location %s x:%f y:%f\n", HasLocation() ? "" : "unknown ", 988 HasLocation() ? fLocation.x : 0, 989 HasLocation() ? fLocation.y : 0)); 990 PRINT(("%s autoplaced \n", WasAutoPlaced() ? "was" : "not")); 991 } 992 993 #endif 994