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