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