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 // TODO: make this depend on IconSizeInt() as well? 323 rect.right = rect.left + B_MINI_ICON; 324 rect.top = rect.bottom - B_MINI_ICON; 325 } else { 326 rect.left = fLocation.x; 327 rect.top = fLocation.y; 328 rect.right = rect.left + poseView->IconSizeInt(); 329 rect.bottom = rect.top + poseView->IconSizeInt(); 330 } 331 332 poseView->Invalidate(rect); 333 } 334 335 336 void 337 BPose::UpdateBrokenSymLink(BPoint poseLoc, BPoseView *poseView) 338 { 339 ASSERT(TargetModel()->IsSymLink()); 340 ASSERT(!TargetModel()->LinkTo()); 341 UpdateIcon(poseLoc, poseView); 342 } 343 344 345 void 346 BPose::UpdateWasBrokenSymlink(BPoint poseLoc, BPoseView *poseView) 347 { 348 if (!fModel->IsSymLink()) 349 return; 350 351 if (fModel->LinkTo()) 352 return; 353 354 poseView->CreateSymlinkPoseTarget(fModel); 355 if (!fModel->LinkTo()) 356 return; 357 358 UpdateIcon(poseLoc, poseView); 359 fModel->LinkTo()->CloseNode(); 360 } 361 362 363 void 364 BPose::EditFirstWidget(BPoint poseLoc, BPoseView *poseView) 365 { 366 // find first editable widget 367 BColumn *column; 368 for (int32 i = 0;(column = poseView->ColumnAt(i)) != NULL;i++) { 369 BTextWidget *widget = WidgetFor(column->AttrHash()); 370 371 if (widget && widget->IsEditable()) { 372 BRect bounds; 373 // ToDo: 374 // fold the three StartEdit code sequences into a cover call 375 if (poseView->ViewMode() == kListMode) 376 bounds = widget->CalcRect(poseLoc, column, poseView); 377 else 378 bounds = widget->CalcRect(fLocation, NULL, poseView); 379 widget->StartEdit(bounds, poseView, this); 380 break; 381 } 382 } 383 } 384 385 386 void 387 BPose::EditPreviousNextWidgetCommon(BPoseView *poseView, bool next) 388 { 389 bool found = false; 390 int32 delta = next ? 1 : -1; 391 for (int32 index = next ? 0 : poseView->CountColumns() - 1; ; index += delta) { 392 BColumn *column = poseView->ColumnAt(index); 393 if (!column) 394 break; 395 396 BTextWidget *widget = WidgetFor(column->AttrHash()); 397 if (widget && widget->IsActive()) { 398 poseView->CommitActivePose(); 399 found = true; 400 continue; 401 } 402 403 if (found && column->Editable()) { 404 BRect bounds; 405 if (poseView->ViewMode() == kListMode) { 406 int32 poseIndex = poseView->IndexOfPose(this); 407 BPoint poseLoc(0, poseIndex * poseView->ListElemHeight()); 408 bounds = widget->CalcRect(poseLoc, column, poseView); 409 } else 410 bounds = widget->CalcRect(fLocation, 0, poseView); 411 412 widget->StartEdit(bounds, poseView, this); 413 break; 414 } 415 } 416 } 417 418 419 void 420 BPose::EditNextWidget(BPoseView *poseView) 421 { 422 EditPreviousNextWidgetCommon(poseView, true); 423 } 424 425 426 void 427 BPose::EditPreviousWidget(BPoseView *poseView) 428 { 429 EditPreviousNextWidgetCommon(poseView, false); 430 } 431 432 433 bool 434 BPose::PointInPose(const BPoseView *poseView, BPoint where) const 435 { 436 ASSERT(poseView->ViewMode() != kListMode); 437 438 if (poseView->ViewMode() == kIconMode 439 || poseView->ViewMode() == kScaleIconMode) { 440 // check icon rect, then actual icon pixel 441 BRect rect(fLocation, fLocation); 442 rect.right += poseView->IconSizeInt() - 1; 443 rect.bottom += poseView->IconSizeInt() - 1; 444 445 if (rect.Contains(where)) 446 return IconCache::sIconCache->IconHitTest(where - fLocation, 447 ResolvedModel(), 448 kNormalIcon, 449 poseView->IconSize()); 450 451 BTextWidget *widget = WidgetFor(poseView->FirstColumn()->AttrHash()); 452 if (widget) { 453 float textWidth = ceilf(widget->TextWidth(poseView) + 1); 454 rect.left += (poseView->IconSizeInt() - textWidth) / 2; 455 rect.right = rect.left + textWidth; 456 } 457 458 rect.top = fLocation.y + poseView->IconSizeInt(); 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 the background wasn't cleared and Draw() is not called after 513 // having edited a name or similar (with fullDraw) 514 if (!fBackgroundClean && !fullDraw) { 515 fBackgroundClean = true; 516 poseView->Invalidate(rect); 517 return; 518 } else 519 fBackgroundClean = false; 520 521 bool directDraw = (drawView == poseView); 522 bool windowActive = poseView->Window()->IsActive(); 523 bool showSelectionWhenInactive = poseView->fShowSelectionWhenInactive; 524 bool isDrawingSelectionRect = poseView->fIsDrawingSelectionRect; 525 526 ModelNodeLazyOpener modelOpener(fModel); 527 528 if (poseView->ViewMode() == kListMode) { 529 uint32 size = poseView->IconSizeInt(); 530 BRect iconRect(rect); 531 iconRect.OffsetBy(offset); 532 iconRect.left += kListOffset; 533 iconRect.right = iconRect.left + size; 534 iconRect.top = iconRect.bottom - size; 535 if (!updateRgn || updateRgn->Intersects(iconRect)) { 536 DrawIcon(iconRect.LeftTop(), drawView, poseView->IconSize(), directDraw, 537 !windowActive && !showSelectionWhenInactive); 538 } 539 540 // draw text 541 int32 columnsToDraw = 1; 542 if (fullDraw) 543 columnsToDraw = poseView->CountColumns(); 544 545 for (int32 index = 0; index < columnsToDraw; index++) { 546 BColumn *column = poseView->ColumnAt(index); 547 if (!column) 548 break; 549 550 // if widget doesn't exist, create it 551 BTextWidget *widget = WidgetFor(column, poseView, modelOpener); 552 553 if (widget && widget->IsVisible()) { 554 BRect widgetRect(widget->ColumnRect(rect.LeftTop(), column, 555 poseView)); 556 557 if (!updateRgn || updateRgn->Intersects(widgetRect)) { 558 BRect widgetTextRect(widget->CalcRect(rect.LeftTop(), column, 559 poseView)); 560 561 if (recalculateText) 562 widget->RecalculateText(poseView); 563 564 bool selectDuringDraw = directDraw && selected 565 && (windowActive && !poseView->EraseWidgetTextBackground()); 566 567 if (index == 0 && selectDuringDraw) { 568 //draw with dark background to select text 569 drawView->PushState(); 570 drawView->SetLowColor(0, 0, 0); 571 } 572 573 if (index == 0) 574 widget->Draw(widgetRect, widgetTextRect, column->Width(), 575 poseView, drawView, selected, fClipboardMode, offset, directDraw); 576 else 577 widget->Draw(widgetTextRect, widgetTextRect, column->Width(), 578 poseView, drawView, false, fClipboardMode, offset, directDraw); 579 580 if (index == 0 && selectDuringDraw) 581 drawView->PopState(); 582 else if (index == 0 && selected) { 583 if (windowActive || isDrawingSelectionRect) { 584 widgetTextRect.OffsetBy(offset); 585 drawView->InvertRect(widgetTextRect); 586 } else if (!windowActive && showSelectionWhenInactive) { 587 widgetTextRect.OffsetBy(offset); 588 drawView->PushState(); 589 drawView->SetDrawingMode(B_OP_BLEND); 590 drawView->SetHighColor(128, 128, 128, 255); 591 drawView->FillRect(widgetTextRect); 592 drawView->PopState(); 593 } 594 } 595 } 596 } 597 } 598 } else { 599 600 // draw in icon mode 601 if (updateRgn && !updateRgn->Intersects(rect)) 602 return; 603 604 BPoint iconOrigin(fLocation); 605 iconOrigin += offset; 606 607 DrawIcon(iconOrigin, drawView, poseView->IconSize(), directDraw, 608 !windowActive && !showSelectionWhenInactive); 609 610 BColumn *column = poseView->FirstColumn(); 611 if (!column) 612 return; 613 614 BTextWidget *widget = WidgetFor(column, poseView, modelOpener); 615 if (!widget || !widget->IsVisible()) 616 return; 617 618 rect = widget->CalcRect(fLocation, 0, poseView); 619 620 bool selectDuringDraw = directDraw && selected 621 && (poseView->IsDesktopWindow() 622 || (windowActive && !poseView->EraseWidgetTextBackground())); 623 624 if (selectDuringDraw) { 625 // draw with dark background to select text 626 drawView->PushState(); 627 drawView->SetLowColor(0, 0, 0); 628 } 629 630 widget->Draw(rect, rect, rect.Width(), poseView, drawView, 631 selected, fClipboardMode, offset, directDraw); 632 633 if (selectDuringDraw) 634 drawView->PopState(); 635 else if (selected && directDraw) { 636 if (windowActive || isDrawingSelectionRect) { 637 rect.OffsetBy(offset); 638 drawView->InvertRect(rect); 639 } else if (!windowActive && showSelectionWhenInactive) { 640 drawView->PushState(); 641 drawView->SetDrawingMode(B_OP_BLEND); 642 drawView->SetHighColor(128, 128, 128, 255); 643 drawView->FillRect(rect); 644 drawView->PopState(); 645 } 646 } 647 } 648 } 649 650 651 void 652 BPose::DeselectWithoutErasingBackground(BRect, BPoseView *poseView) 653 { 654 ASSERT(poseView->ViewMode() != kListMode); 655 ASSERT(!poseView->EraseWidgetTextBackground()); 656 ASSERT(!IsSelected()); 657 658 // draw icon directly 659 if (fPercent == -1) 660 DrawIcon(fLocation, poseView, poseView->IconSize(), true); 661 else 662 UpdateIcon(fLocation, poseView); 663 664 BColumn *column = poseView->FirstColumn(); 665 if (!column) 666 return; 667 668 BTextWidget *widget = WidgetFor(column->AttrHash()); 669 if (!widget || !widget->IsVisible()) 670 return; 671 672 // just invalidate the background, don't draw anything 673 poseView->Invalidate(widget->CalcRect(fLocation, 0, poseView)); 674 } 675 676 677 void 678 BPose::MoveTo(BPoint point, BPoseView *poseView, bool inval) 679 { 680 point.x = floorf(point.x); 681 point.y = floorf(point.y); 682 683 BRect oldBounds; 684 685 ASSERT(poseView->ViewMode() != kListMode); 686 if (point == fLocation || poseView->ViewMode() == kListMode) 687 return; 688 689 if (inval) 690 oldBounds = CalcRect(poseView); 691 692 // might need to move a text view if we're active 693 if (poseView->ActivePose() == this) { 694 BView *border_view = poseView->FindView("BorderView"); 695 if (border_view) 696 border_view->MoveBy(point.x - fLocation.x, point.y - fLocation.y); 697 } 698 699 fLocation = point; 700 fHasLocation = true; 701 fNeedsSaveLocation = true; 702 703 if (inval) { 704 poseView->Invalidate(oldBounds); 705 poseView->Invalidate(CalcRect(poseView)); 706 } 707 } 708 709 710 BTextWidget * 711 BPose::ActiveWidget() const 712 { 713 for (int32 i = fWidgetList.CountItems(); i-- > 0;) { 714 BTextWidget *widget = fWidgetList.ItemAt(i); 715 if (widget->IsActive()) 716 return widget; 717 } 718 return NULL; 719 } 720 721 722 BTextWidget * 723 BPose::WidgetFor(uint32 attr, int32 *index) const 724 { 725 int32 count = fWidgetList.CountItems(); 726 for (int32 i = 0; i < count; i++) { 727 BTextWidget *widget = fWidgetList.ItemAt(i); 728 if (widget->AttrHash() == attr) { 729 if (index) 730 *index = i; 731 return widget; 732 } 733 } 734 735 return 0; 736 } 737 738 739 BTextWidget * 740 BPose::WidgetFor(BColumn *column, BPoseView *poseView, ModelNodeLazyOpener &opener, 741 int32 *index) 742 { 743 BTextWidget *widget = WidgetFor(column->AttrHash(), index); 744 if (!widget) 745 widget = AddWidget(poseView, column, opener); 746 747 return widget; 748 } 749 750 751 /* deprecated */ 752 bool 753 BPose::TestLargeIconPixel(BPoint point) const 754 { 755 return IconCache::sIconCache->IconHitTest(point, ResolvedModel(), 756 kNormalIcon, B_LARGE_ICON); 757 } 758 /* deprecated */ 759 760 761 void 762 BPose::DrawIcon(BPoint where, BView *view, icon_size kind, bool direct, bool drawUnselected) 763 { 764 if (fClipboardMode == kMoveSelectionTo) { 765 view->SetDrawingMode(B_OP_ALPHA); 766 view->SetHighColor(0, 0, 0, 64); // set the level of transparency 767 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY); 768 } else if (direct) 769 view->SetDrawingMode(B_OP_OVER); 770 771 IconCache::sIconCache->Draw(ResolvedModel(), view, where, 772 fIsSelected && !drawUnselected ? kSelectedIcon : kNormalIcon, kind, true); 773 774 if (fPercent != -1) 775 DrawBar(where, view, kind); 776 } 777 778 779 void 780 BPose::DrawBar(BPoint where,BView *view,icon_size kind) 781 { 782 view->PushState(); 783 784 int32 size, barWidth, barHeight, yOffset; 785 if (kind >= B_LARGE_ICON) { 786 size = kind - 1; 787 barWidth = (int32)((float)7 / (float)32 * (float)kind); 788 yOffset = 2; 789 barHeight = size - 4 - 2 * yOffset; 790 } else { 791 size = B_MINI_ICON; 792 barWidth = 4; 793 yOffset = 0; 794 barHeight = size - 4 - 2 * yOffset; 795 } 796 797 // the black shadowed line 798 view->SetHighColor(32, 32, 32, 92); 799 view->MovePenTo(BPoint(where.x + size, where.y + 1 + yOffset)); 800 view->StrokeLine(BPoint(where.x + size, where.y + size - yOffset)); 801 view->StrokeLine(BPoint(where.x + size - barWidth + 1, where.y + size - yOffset)); 802 803 view->SetDrawingMode(B_OP_ALPHA); 804 805 // the gray frame 806 view->SetHighColor(76, 76, 76, 192); 807 BRect rect( where.x + size - barWidth,where.y + yOffset, 808 where.x + size - 1,where.y + size - 1 - yOffset); 809 view->StrokeRect(rect); 810 811 // calculate bar height 812 int32 percent = fPercent > -1 ? fPercent : -2 - fPercent; 813 int32 barPos = int32(barHeight * percent / 100.0); 814 if (barPos < 0) 815 barPos = 0; 816 else if (barPos > barHeight) 817 barPos = barHeight; 818 819 // the free space bar 820 view->SetHighColor(TrackerSettings().FreeSpaceColor()); 821 822 rect.InsetBy(1,1); 823 BRect bar(rect); 824 bar.bottom = bar.top + barPos - 1; 825 if (barPos > 0) 826 view->FillRect(bar); 827 828 // the used space bar 829 bar.top = bar.bottom + 1; 830 bar.bottom = rect.bottom; 831 view->SetHighColor(fPercent < -1 ? TrackerSettings().WarningSpaceColor() : TrackerSettings().UsedSpaceColor()); 832 view->FillRect(bar); 833 834 view->PopState(); 835 } 836 837 838 void 839 BPose::DrawToggleSwitch(BRect, BPoseView *) 840 { 841 return; 842 } 843 844 845 BRect 846 BPose::CalcRect(BPoint loc, const BPoseView *poseView, bool minimalRect) 847 { 848 ASSERT(poseView->ViewMode() == kListMode); 849 850 BColumn *column = poseView->LastColumn(); 851 BRect rect; 852 rect.left = loc.x; 853 rect.top = loc.y; 854 rect.right = loc.x + column->Offset() + column->Width(); 855 rect.bottom = rect.top + poseView->ListElemHeight(); 856 857 if (minimalRect) { 858 BTextWidget *widget = WidgetFor(poseView->FirstColumn()->AttrHash()); 859 if (widget) 860 rect.right = widget->CalcRect(loc, poseView->FirstColumn(), poseView).right; 861 } 862 863 return rect; 864 } 865 866 867 BRect 868 BPose::CalcRect(const BPoseView *poseView) 869 { 870 ASSERT(poseView->ViewMode() != kListMode); 871 872 BRect rect; 873 if (poseView->ViewMode() == kIconMode 874 || poseView->ViewMode() == kScaleIconMode) { 875 rect.left = fLocation.x; 876 rect.right = rect.left + poseView->IconSizeInt(); 877 878 BTextWidget *widget = WidgetFor(poseView->FirstColumn()->AttrHash()); 879 if (widget) { 880 float textWidth = ceilf(widget->TextWidth(poseView) + 1); 881 if (textWidth > poseView->IconSizeInt()) { 882 rect.left += (poseView->IconSizeInt() - textWidth) / 2; 883 rect.right = rect.left + textWidth; 884 } 885 } 886 887 rect.top = fLocation.y; 888 rect.bottom = rect.top + poseView->IconPoseHeight(); 889 } else { 890 // MINI_ICON_MODE rect calc 891 rect.left = fLocation.x; 892 rect.top = fLocation.y; 893 rect.right = rect.left + B_MINI_ICON + kMiniIconSeparator; 894 rect.bottom = rect.top + poseView->IconPoseHeight(); 895 BTextWidget *widget = WidgetFor(poseView->FirstColumn()->AttrHash()); 896 if (widget) 897 rect.right += ceil(widget->TextWidth(poseView) + 1); 898 } 899 900 return rect; 901 } 902 903 904 #if DEBUG 905 906 void 907 BPose::PrintToStream() 908 { 909 TargetModel()->PrintToStream(); 910 switch (fClipboardMode) { 911 case kMoveSelectionTo: 912 PRINT(("clipboardMode: Cut\n")); 913 break; 914 case kCopySelectionTo: 915 PRINT(("clipboardMode: Copy\n")); 916 break; 917 default: 918 PRINT(("clipboardMode: 0 - not in clipboard\n")); 919 } 920 PRINT(("%sselected\n", IsSelected() ? "" : "not ")); 921 PRINT(("location %s x:%f y:%f\n", HasLocation() ? "" : "unknown ", 922 HasLocation() ? Location().x : 0, 923 HasLocation() ? Location().y : 0)); 924 PRINT(("%s autoplaced \n", WasAutoPlaced() ? "was" : "not")); 925 } 926 927 #endif 928