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