1 /* 2 * Copyright 2006-2009, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9 #include "PathListView.h" 10 11 #include <new> 12 #include <stdio.h> 13 14 #include <Application.h> 15 #include <Catalog.h> 16 #include <ListItem.h> 17 #include <Locale.h> 18 #include <Menu.h> 19 #include <MenuItem.h> 20 #include <Message.h> 21 #include <Mime.h> 22 #include <Window.h> 23 24 #include "AddPathsCommand.h" 25 #include "CleanUpPathCommand.h" 26 #include "CommandStack.h" 27 #include "MovePathsCommand.h" 28 #include "Observer.h" 29 #include "RemovePathsCommand.h" 30 #include "ReversePathCommand.h" 31 #include "RotatePathIndicesCommand.h" 32 #include "Shape.h" 33 #include "ShapeContainer.h" 34 #include "Selection.h" 35 #include "UnassignPathCommand.h" 36 #include "Util.h" 37 #include "VectorPath.h" 38 39 40 #undef B_TRANSLATE_CONTEXT 41 #define B_TRANSLATE_CONTEXT "Icon-O-Matic-PathsList" 42 43 44 using std::nothrow; 45 46 static const float kMarkWidth = 14.0; 47 static const float kBorderOffset = 3.0; 48 static const float kTextOffset = 4.0; 49 50 class PathListItem : public SimpleItem, 51 public Observer { 52 public: 53 PathListItem(VectorPath* p, 54 PathListView* listView, 55 bool markEnabled) 56 : SimpleItem(""), 57 path(NULL), 58 fListView(listView), 59 fMarkEnabled(markEnabled), 60 fMarked(false) 61 { 62 SetPath(p); 63 } 64 65 virtual ~PathListItem() 66 { 67 SetPath(NULL); 68 } 69 70 // SimpleItem interface 71 virtual void Draw(BView* owner, BRect itemFrame, uint32 flags) 72 { 73 SimpleItem::DrawBackground(owner, itemFrame, flags); 74 75 // text 76 owner->SetHighColor(0, 0, 0, 255); 77 font_height fh; 78 owner->GetFontHeight(&fh); 79 BString truncatedString(Text()); 80 owner->TruncateString(&truncatedString, B_TRUNCATE_MIDDLE, 81 itemFrame.Width() 82 - kBorderOffset 83 - kMarkWidth 84 - kTextOffset 85 - kBorderOffset); 86 float height = itemFrame.Height(); 87 float textHeight = fh.ascent + fh.descent; 88 BPoint pos; 89 pos.x = itemFrame.left 90 + kBorderOffset + kMarkWidth + kTextOffset; 91 pos.y = itemFrame.top 92 + ceilf((height - textHeight) / 2.0 + fh.ascent); 93 owner->DrawString(truncatedString.String(), pos); 94 95 if (!fMarkEnabled) 96 return; 97 98 // mark 99 BRect markRect = itemFrame; 100 markRect.left += kBorderOffset; 101 markRect.right = markRect.left + kMarkWidth; 102 markRect.top = (markRect.top + markRect.bottom - kMarkWidth) / 2.0; 103 markRect.bottom = markRect.top + kMarkWidth; 104 owner->SetHighColor(tint_color(owner->LowColor(), B_DARKEN_1_TINT)); 105 owner->StrokeRect(markRect); 106 markRect.InsetBy(1, 1); 107 owner->SetHighColor(tint_color(owner->LowColor(), 1.04)); 108 owner->FillRect(markRect); 109 if (fMarked) { 110 markRect.InsetBy(2, 2); 111 owner->SetHighColor(tint_color(owner->LowColor(), 112 B_DARKEN_4_TINT)); 113 owner->SetPenSize(2); 114 owner->StrokeLine(markRect.LeftTop(), markRect.RightBottom()); 115 owner->StrokeLine(markRect.LeftBottom(), markRect.RightTop()); 116 owner->SetPenSize(1); 117 } 118 } 119 120 // Observer interface 121 virtual void ObjectChanged(const Observable* object) 122 { 123 UpdateText(); 124 } 125 126 // PathListItem 127 void SetPath(VectorPath* p) 128 { 129 if (p == path) 130 return; 131 132 if (path) { 133 path->RemoveObserver(this); 134 path->Release(); 135 } 136 137 path = p; 138 139 if (path) { 140 path->Acquire(); 141 path->AddObserver(this); 142 UpdateText(); 143 } 144 } 145 void UpdateText() 146 { 147 SetText(path->Name()); 148 Invalidate(); 149 } 150 151 void SetMarkEnabled(bool enabled) 152 { 153 if (fMarkEnabled == enabled) 154 return; 155 fMarkEnabled = enabled; 156 Invalidate(); 157 } 158 void SetMarked(bool marked) 159 { 160 if (fMarked == marked) 161 return; 162 fMarked = marked; 163 Invalidate(); 164 } 165 166 void Invalidate() 167 { 168 // :-/ 169 if (fListView->LockLooper()) { 170 fListView->InvalidateItem( 171 fListView->IndexOf(this)); 172 fListView->UnlockLooper(); 173 } 174 } 175 176 VectorPath* path; 177 private: 178 PathListView* fListView; 179 bool fMarkEnabled; 180 bool fMarked; 181 }; 182 183 184 class ShapePathListener : public PathContainerListener, 185 public ShapeContainerListener { 186 public: 187 ShapePathListener(PathListView* listView) 188 : fListView(listView), 189 fShape(NULL) 190 { 191 } 192 virtual ~ShapePathListener() 193 { 194 SetShape(NULL); 195 } 196 197 // PathContainerListener interface 198 virtual void PathAdded(VectorPath* path, int32 index) 199 { 200 fListView->_SetPathMarked(path, true); 201 } 202 virtual void PathRemoved(VectorPath* path) 203 { 204 fListView->_SetPathMarked(path, false); 205 } 206 207 // ShapeContainerListener interface 208 virtual void ShapeAdded(Shape* shape, int32 index) {} 209 virtual void ShapeRemoved(Shape* shape) 210 { 211 fListView->SetCurrentShape(NULL); 212 } 213 214 // ShapePathListener 215 void SetShape(Shape* shape) 216 { 217 if (fShape == shape) 218 return; 219 220 if (fShape) 221 fShape->Paths()->RemoveListener(this); 222 223 fShape = shape; 224 225 if (fShape) 226 fShape->Paths()->AddListener(this); 227 } 228 229 Shape* CurrentShape() const 230 { 231 return fShape; 232 } 233 234 private: 235 PathListView* fListView; 236 Shape* fShape; 237 }; 238 239 // #pragma mark - 240 241 enum { 242 MSG_ADD = 'addp', 243 244 MSG_ADD_RECT = 'addr', 245 MSG_ADD_CIRCLE = 'addc', 246 MSG_ADD_ARC = 'adda', 247 248 MSG_DUPLICATE = 'dupp', 249 250 MSG_REVERSE = 'rvrs', 251 MSG_CLEAN_UP = 'clup', 252 MSG_ROTATE_INDICES_CW = 'ricw', 253 MSG_ROTATE_INDICES_CCW = 'ricc', 254 255 MSG_REMOVE = 'remp', 256 }; 257 258 // constructor 259 PathListView::PathListView(BRect frame, 260 const char* name, 261 BMessage* message, BHandler* target) 262 : SimpleListView(frame, name, 263 NULL, B_SINGLE_SELECTION_LIST), 264 fMessage(message), 265 fMenu(NULL), 266 267 fPathContainer(NULL), 268 fShapeContainer(NULL), 269 fCommandStack(NULL), 270 271 fCurrentShape(NULL), 272 fShapePathListener(new ShapePathListener(this)) 273 { 274 SetTarget(target); 275 } 276 277 // destructor 278 PathListView::~PathListView() 279 { 280 _MakeEmpty(); 281 delete fMessage; 282 283 if (fPathContainer) 284 fPathContainer->RemoveListener(this); 285 286 if (fShapeContainer) 287 fShapeContainer->RemoveListener(fShapePathListener); 288 289 delete fShapePathListener; 290 } 291 292 // SelectionChanged 293 void 294 PathListView::SelectionChanged() 295 { 296 SimpleListView::SelectionChanged(); 297 298 if (!fSyncingToSelection) { 299 // NOTE: single selection list 300 PathListItem* item 301 = dynamic_cast<PathListItem*>(ItemAt(CurrentSelection(0))); 302 if (fMessage) { 303 BMessage message(*fMessage); 304 message.AddPointer("path", item ? (void*)item->path : NULL); 305 Invoke(&message); 306 } 307 } 308 309 _UpdateMenu(); 310 } 311 312 // MouseDown 313 void 314 PathListView::MouseDown(BPoint where) 315 { 316 if (!fCurrentShape) { 317 SimpleListView::MouseDown(where); 318 return; 319 } 320 321 bool handled = false; 322 int32 index = IndexOf(where); 323 PathListItem* item = dynamic_cast<PathListItem*>(ItemAt(index)); 324 if (item) { 325 BRect itemFrame(ItemFrame(index)); 326 itemFrame.right = itemFrame.left 327 + kBorderOffset + kMarkWidth 328 + kTextOffset / 2.0; 329 VectorPath* path = item->path; 330 if (itemFrame.Contains(where) && fCommandStack) { 331 // add or remove the path to the shape 332 ::Command* command; 333 if (fCurrentShape->Paths()->HasPath(path)) { 334 command = new UnassignPathCommand( 335 fCurrentShape, path); 336 } else { 337 VectorPath* paths[1]; 338 paths[0] = path; 339 command = new AddPathsCommand( 340 fCurrentShape->Paths(), 341 paths, 1, false, 342 fCurrentShape->Paths()->CountPaths()); 343 } 344 fCommandStack->Perform(command); 345 handled = true; 346 } 347 } 348 349 if (!handled) 350 SimpleListView::MouseDown(where); 351 } 352 353 // MessageReceived 354 void 355 PathListView::MessageReceived(BMessage* message) 356 { 357 switch (message->what) { 358 case MSG_ADD: 359 if (fCommandStack != NULL) { 360 VectorPath* path; 361 AddPathsCommand* command; 362 new_path(fPathContainer, &path, &command); 363 fCommandStack->Perform(command); 364 } 365 break; 366 367 case MSG_ADD_RECT: 368 if (fCommandStack != NULL) { 369 VectorPath* path; 370 AddPathsCommand* command; 371 new_path(fPathContainer, &path, &command); 372 if (path != NULL) { 373 path->AddPoint(BPoint(16, 16)); 374 path->AddPoint(BPoint(16, 48)); 375 path->AddPoint(BPoint(48, 48)); 376 path->AddPoint(BPoint(48, 16)); 377 path->SetClosed(true); 378 } 379 fCommandStack->Perform(command); 380 } 381 break; 382 383 case MSG_ADD_CIRCLE: 384 // TODO: ask for number of secions 385 if (fCommandStack != NULL) { 386 VectorPath* path; 387 AddPathsCommand* command; 388 new_path(fPathContainer, &path, &command); 389 if (path != NULL) { 390 // add four control points defining a circle: 391 // a 392 // b d 393 // c 394 BPoint a(32, 16); 395 BPoint b(16, 32); 396 BPoint c(32, 48); 397 BPoint d(48, 32); 398 399 path->AddPoint(a); 400 path->AddPoint(b); 401 path->AddPoint(c); 402 path->AddPoint(d); 403 404 path->SetClosed(true); 405 406 float controlDist = 0.552284 * 16; 407 path->SetPoint(0, a, a + BPoint(controlDist, 0.0), 408 a + BPoint(-controlDist, 0.0), true); 409 path->SetPoint(1, b, b + BPoint(0.0, -controlDist), 410 b + BPoint(0.0, controlDist), true); 411 path->SetPoint(2, c, c + BPoint(-controlDist, 0.0), 412 c + BPoint(controlDist, 0.0), true); 413 path->SetPoint(3, d, d + BPoint(0.0, controlDist), 414 d + BPoint(0.0, -controlDist), true); 415 } 416 fCommandStack->Perform(command); 417 } 418 break; 419 420 case MSG_DUPLICATE: 421 if (fCommandStack != NULL) { 422 PathListItem* item = dynamic_cast<PathListItem*>( 423 ItemAt(CurrentSelection(0))); 424 if (item == NULL) 425 break; 426 427 VectorPath* path; 428 AddPathsCommand* command; 429 new_path(fPathContainer, &path, &command, item->path); 430 fCommandStack->Perform(command); 431 } 432 break; 433 434 case MSG_REVERSE: 435 if (fCommandStack != NULL) { 436 PathListItem* item = dynamic_cast<PathListItem*>( 437 ItemAt(CurrentSelection(0))); 438 if (item == NULL) 439 break; 440 441 ReversePathCommand* command 442 = new (nothrow) ReversePathCommand(item->path); 443 fCommandStack->Perform(command); 444 } 445 break; 446 447 case MSG_CLEAN_UP: 448 if (fCommandStack != NULL) { 449 PathListItem* item = dynamic_cast<PathListItem*>( 450 ItemAt(CurrentSelection(0))); 451 if (item == NULL) 452 break; 453 454 CleanUpPathCommand* command 455 = new (nothrow) CleanUpPathCommand(item->path); 456 fCommandStack->Perform(command); 457 } 458 break; 459 460 case MSG_ROTATE_INDICES_CW: 461 case MSG_ROTATE_INDICES_CCW: 462 if (fCommandStack != NULL) { 463 PathListItem* item = dynamic_cast<PathListItem*>( 464 ItemAt(CurrentSelection(0))); 465 if (item == NULL) 466 break; 467 468 RotatePathIndicesCommand* command 469 = new (nothrow) RotatePathIndicesCommand(item->path, 470 message->what == MSG_ROTATE_INDICES_CW); 471 fCommandStack->Perform(command); 472 } 473 break; 474 475 case MSG_REMOVE: 476 RemoveSelected(); 477 break; 478 479 default: 480 SimpleListView::MessageReceived(message); 481 break; 482 } 483 } 484 485 // MakeDragMessage 486 void 487 PathListView::MakeDragMessage(BMessage* message) const 488 { 489 SimpleListView::MakeDragMessage(message); 490 message->AddPointer("container", fPathContainer); 491 int32 count = CountSelectedItems(); 492 for (int32 i = 0; i < count; i++) { 493 PathListItem* item = dynamic_cast<PathListItem*>( 494 ItemAt(CurrentSelection(i))); 495 if (item) 496 message->AddPointer("path", (void*)item->path); 497 else 498 break; 499 } 500 } 501 502 // AcceptDragMessage 503 bool 504 PathListView::AcceptDragMessage(const BMessage* message) const 505 { 506 return SimpleListView::AcceptDragMessage(message); 507 } 508 509 // SetDropTargetRect 510 void 511 PathListView::SetDropTargetRect(const BMessage* message, BPoint where) 512 { 513 SimpleListView::SetDropTargetRect(message, where); 514 } 515 516 // MoveItems 517 void 518 PathListView::MoveItems(BList& items, int32 toIndex) 519 { 520 if (!fCommandStack || !fPathContainer) 521 return; 522 523 int32 count = items.CountItems(); 524 VectorPath** paths = new (nothrow) VectorPath*[count]; 525 if (!paths) 526 return; 527 528 for (int32 i = 0; i < count; i++) { 529 PathListItem* item 530 = dynamic_cast<PathListItem*>((BListItem*)items.ItemAtFast(i)); 531 paths[i] = item ? item->path : NULL; 532 } 533 534 MovePathsCommand* command 535 = new (nothrow) MovePathsCommand(fPathContainer, 536 paths, count, toIndex); 537 if (!command) { 538 delete[] paths; 539 return; 540 } 541 542 fCommandStack->Perform(command); 543 } 544 545 // CopyItems 546 void 547 PathListView::CopyItems(BList& items, int32 toIndex) 548 { 549 if (!fCommandStack || !fPathContainer) 550 return; 551 552 int32 count = items.CountItems(); 553 VectorPath* paths[count]; 554 555 for (int32 i = 0; i < count; i++) { 556 PathListItem* item 557 = dynamic_cast<PathListItem*>((BListItem*)items.ItemAtFast(i)); 558 paths[i] = item ? new (nothrow) VectorPath(*item->path) : NULL; 559 } 560 561 AddPathsCommand* command 562 = new (nothrow) AddPathsCommand(fPathContainer, 563 paths, count, true, toIndex); 564 if (!command) { 565 for (int32 i = 0; i < count; i++) 566 delete paths[i]; 567 return; 568 } 569 570 fCommandStack->Perform(command); 571 } 572 573 // RemoveItemList 574 void 575 PathListView::RemoveItemList(BList& items) 576 { 577 if (!fCommandStack || !fPathContainer) 578 return; 579 580 int32 count = items.CountItems(); 581 VectorPath* paths[count]; 582 for (int32 i = 0; i < count; i++) { 583 PathListItem* item = dynamic_cast<PathListItem*>( 584 (BListItem*)items.ItemAtFast(i)); 585 if (item) 586 paths[i] = item->path; 587 else 588 paths[i] = NULL; 589 } 590 591 RemovePathsCommand* command 592 = new (nothrow) RemovePathsCommand(fPathContainer, 593 paths, count); 594 fCommandStack->Perform(command); 595 } 596 597 // CloneItem 598 BListItem* 599 PathListView::CloneItem(int32 index) const 600 { 601 if (PathListItem* item = dynamic_cast<PathListItem*>(ItemAt(index))) { 602 return new PathListItem(item->path, 603 const_cast<PathListView*>(this), 604 fCurrentShape != NULL); 605 } 606 return NULL; 607 } 608 609 // IndexOfSelectable 610 int32 611 PathListView::IndexOfSelectable(Selectable* selectable) const 612 { 613 VectorPath* path = dynamic_cast<VectorPath*>(selectable); 614 if (!path) 615 return -1; 616 617 for (int32 i = 0; 618 PathListItem* item = dynamic_cast<PathListItem*>(ItemAt(i)); 619 i++) { 620 if (item->path == path) 621 return i; 622 } 623 624 return -1; 625 } 626 627 // SelectableFor 628 Selectable* 629 PathListView::SelectableFor(BListItem* item) const 630 { 631 PathListItem* pathItem = dynamic_cast<PathListItem*>(item); 632 if (pathItem) 633 return pathItem->path; 634 return NULL; 635 } 636 637 // #pragma mark - 638 639 // PathAdded 640 void 641 PathListView::PathAdded(VectorPath* path, int32 index) 642 { 643 // NOTE: we are in the thread that messed with the 644 // ShapeContainer, so no need to lock the 645 // container, when this is changed to asynchronous 646 // notifications, then it would need to be read-locked! 647 if (!LockLooper()) 648 return; 649 650 if (_AddPath(path, index)) 651 Select(index); 652 653 UnlockLooper(); 654 } 655 656 // PathRemoved 657 void 658 PathListView::PathRemoved(VectorPath* path) 659 { 660 // NOTE: we are in the thread that messed with the 661 // ShapeContainer, so no need to lock the 662 // container, when this is changed to asynchronous 663 // notifications, then it would need to be read-locked! 664 if (!LockLooper()) 665 return; 666 667 // NOTE: we're only interested in VectorPath objects 668 _RemovePath(path); 669 670 UnlockLooper(); 671 } 672 673 // #pragma mark - 674 675 // SetPathContainer 676 void 677 PathListView::SetPathContainer(PathContainer* container) 678 { 679 if (fPathContainer == container) 680 return; 681 682 // detach from old container 683 if (fPathContainer) 684 fPathContainer->RemoveListener(this); 685 686 _MakeEmpty(); 687 688 fPathContainer = container; 689 690 if (!fPathContainer) 691 return; 692 693 fPathContainer->AddListener(this); 694 695 // sync 696 // if (!fPathContainer->ReadLock()) 697 // return; 698 699 int32 count = fPathContainer->CountPaths(); 700 for (int32 i = 0; i < count; i++) 701 _AddPath(fPathContainer->PathAtFast(i), i); 702 703 // fPathContainer->ReadUnlock(); 704 } 705 706 // SetShapeContainer 707 void 708 PathListView::SetShapeContainer(ShapeContainer* container) 709 { 710 if (fShapeContainer == container) 711 return; 712 713 // detach from old container 714 if (fShapeContainer) 715 fShapeContainer->RemoveListener(fShapePathListener); 716 717 fShapeContainer = container; 718 719 if (fShapeContainer) 720 fShapeContainer->AddListener(fShapePathListener); 721 } 722 723 // SetCommandStack 724 void 725 PathListView::SetCommandStack(CommandStack* stack) 726 { 727 fCommandStack = stack; 728 } 729 730 // SetMenu 731 void 732 PathListView::SetMenu(BMenu* menu) 733 { 734 fMenu = menu; 735 if (fMenu == NULL) 736 return; 737 738 fAddMI = new BMenuItem(B_TRANSLATE("Add"), 739 new BMessage(MSG_ADD)); 740 fAddRectMI = new BMenuItem(B_TRANSLATE("Add rect"), 741 new BMessage(MSG_ADD_RECT)); 742 fAddCircleMI = new BMenuItem(B_TRANSLATE("Add circle"/*B_UTF8_ELLIPSIS*/), 743 new BMessage(MSG_ADD_CIRCLE)); 744 // fAddArcMI = new BMenuItem("Add arc"B_UTF8_ELLIPSIS, 745 // new BMessage(MSG_ADD_ARC)); 746 fDuplicateMI = new BMenuItem(B_TRANSLATE("Duplicate"), 747 new BMessage(MSG_DUPLICATE)); 748 fReverseMI = new BMenuItem(B_TRANSLATE("Reverse"), 749 new BMessage(MSG_REVERSE)); 750 fCleanUpMI = new BMenuItem(B_TRANSLATE("Clean up"), 751 new BMessage(MSG_CLEAN_UP)); 752 fRotateIndicesRightMI = new BMenuItem(B_TRANSLATE("Rotate indices forwards"), 753 new BMessage(MSG_ROTATE_INDICES_CCW), 'R'); 754 fRotateIndicesLeftMI = new BMenuItem(B_TRANSLATE("Rotate indices backwards"), 755 new BMessage(MSG_ROTATE_INDICES_CW), 'R', B_SHIFT_KEY); 756 fRemoveMI = new BMenuItem(B_TRANSLATE("Remove"), 757 new BMessage(MSG_REMOVE)); 758 759 fMenu->AddItem(fAddMI); 760 fMenu->AddItem(fAddRectMI); 761 fMenu->AddItem(fAddCircleMI); 762 // fMenu->AddItem(fAddArcMI); 763 764 fMenu->AddSeparatorItem(); 765 766 fMenu->AddItem(fDuplicateMI); 767 fMenu->AddItem(fReverseMI); 768 fMenu->AddItem(fCleanUpMI); 769 770 fMenu->AddSeparatorItem(); 771 772 fMenu->AddItem(fRotateIndicesRightMI); 773 fMenu->AddItem(fRotateIndicesLeftMI); 774 775 fMenu->AddSeparatorItem(); 776 777 fMenu->AddItem(fRemoveMI); 778 779 fMenu->SetTargetForItems(this); 780 781 _UpdateMenu(); 782 } 783 784 // SetCurrentShape 785 void 786 PathListView::SetCurrentShape(Shape* shape) 787 { 788 if (fCurrentShape == shape) 789 return; 790 791 fCurrentShape = shape; 792 fShapePathListener->SetShape(shape); 793 794 _UpdateMarks(); 795 } 796 797 // #pragma mark - 798 799 // _AddPath 800 bool 801 PathListView::_AddPath(VectorPath* path, int32 index) 802 { 803 if (path) { 804 return AddItem( 805 new PathListItem(path, this, fCurrentShape != NULL), index); 806 } 807 return false; 808 } 809 810 // _RemovePath 811 bool 812 PathListView::_RemovePath(VectorPath* path) 813 { 814 PathListItem* item = _ItemForPath(path); 815 if (item && RemoveItem(item)) { 816 delete item; 817 return true; 818 } 819 return false; 820 } 821 822 // _ItemForPath 823 PathListItem* 824 PathListView::_ItemForPath(VectorPath* path) const 825 { 826 for (int32 i = 0; 827 PathListItem* item = dynamic_cast<PathListItem*>(ItemAt(i)); 828 i++) { 829 if (item->path == path) 830 return item; 831 } 832 return NULL; 833 } 834 835 // #pragma mark - 836 837 // _UpdateMarks 838 void 839 PathListView::_UpdateMarks() 840 { 841 int32 count = CountItems(); 842 if (fCurrentShape) { 843 // enable display of marks and mark items whoes 844 // path is contained in fCurrentShape 845 for (int32 i = 0; i < count; i++) { 846 PathListItem* item = dynamic_cast<PathListItem*>(ItemAt(i)); 847 if (!item) 848 continue; 849 item->SetMarkEnabled(true); 850 item->SetMarked(fCurrentShape->Paths()->HasPath(item->path)); 851 } 852 } else { 853 // disable display of marks 854 for (int32 i = 0; i < count; i++) { 855 PathListItem* item = dynamic_cast<PathListItem*>(ItemAt(i)); 856 if (!item) 857 continue; 858 item->SetMarkEnabled(false); 859 } 860 } 861 862 Invalidate(); 863 } 864 865 // _SetPathMarked 866 void 867 PathListView::_SetPathMarked(VectorPath* path, bool marked) 868 { 869 if (PathListItem* item = _ItemForPath(path)) { 870 item->SetMarked(marked); 871 } 872 } 873 874 // _UpdateMenu 875 void 876 PathListView::_UpdateMenu() 877 { 878 if (!fMenu) 879 return; 880 881 bool gotSelection = CurrentSelection(0) >= 0; 882 883 fDuplicateMI->SetEnabled(gotSelection); 884 fReverseMI->SetEnabled(gotSelection); 885 fCleanUpMI->SetEnabled(gotSelection); 886 fRotateIndicesLeftMI->SetEnabled(gotSelection); 887 fRotateIndicesRightMI->SetEnabled(gotSelection); 888 fRemoveMI->SetEnabled(gotSelection); 889 } 890 891 892