1 // DiagramItemGroup.cpp 2 3 #include "DiagramItemGroup.h" 4 #include "DiagramItem.h" 5 6 #include <Region.h> 7 8 __USE_CORTEX_NAMESPACE 9 10 #include <Debug.h> 11 #define D_METHOD(x) //PRINT (x) 12 13 // -------------------------------------------------------- // 14 // *** ctor/dtor 15 // -------------------------------------------------------- // 16 17 DiagramItemGroup::DiagramItemGroup( 18 uint32 acceptedTypes, 19 bool multiSelection) 20 : m_boxes(0), 21 m_wires(0), 22 m_endPoints(0), 23 m_selection(0), 24 m_types(acceptedTypes), 25 m_itemAlignment(1.0, 1.0), 26 m_multiSelection(multiSelection), 27 m_lastItemUnder(0) 28 { 29 D_METHOD(("DiagramItemGroup::DiagramItemGroup()\n")); 30 m_selection = new BList(1); 31 } 32 33 DiagramItemGroup::~DiagramItemGroup() 34 { 35 D_METHOD(("DiagramItemGroup::~DiagramItemGroup()\n")); 36 if (m_selection) 37 { 38 m_selection->MakeEmpty(); 39 delete m_selection; 40 } 41 if (m_boxes && (m_types & DiagramItem::M_BOX)) 42 { 43 while (countItems(DiagramItem::M_BOX) > 0) 44 { 45 DiagramItem *item = itemAt(0, DiagramItem::M_BOX); 46 if (removeItem(item)) 47 delete item; 48 } 49 delete m_boxes; 50 } 51 if (m_wires && (m_types & DiagramItem::M_WIRE)) 52 { 53 while (countItems(DiagramItem::M_WIRE) > 0) 54 { 55 DiagramItem *item = itemAt(0, DiagramItem::M_WIRE); 56 if (removeItem(item)) 57 delete item; 58 } 59 delete m_wires; 60 } 61 if (m_endPoints && (m_types & DiagramItem::M_ENDPOINT)) 62 { 63 while (countItems(DiagramItem::M_ENDPOINT) > 0) 64 { 65 DiagramItem *item = itemAt(0, DiagramItem::M_ENDPOINT); 66 if (removeItem(item)) 67 delete item; 68 } 69 delete m_endPoints; 70 } 71 } 72 73 // -------------------------------------------------------- // 74 // *** item accessors 75 // -------------------------------------------------------- // 76 77 uint32 DiagramItemGroup::countItems( 78 uint32 whichType) const 79 { 80 D_METHOD(("DiagramItemGroup::countItems()\n")); 81 uint32 count = 0; 82 if (whichType & m_types) 83 { 84 if (whichType & DiagramItem::M_BOX) 85 { 86 if (m_boxes) 87 { 88 count += m_boxes->CountItems(); 89 } 90 } 91 if (whichType & DiagramItem::M_WIRE) 92 { 93 if (m_wires) 94 { 95 count += m_wires->CountItems(); 96 } 97 } 98 if (whichType & DiagramItem::M_ENDPOINT) 99 { 100 if (m_endPoints) 101 { 102 count += m_endPoints->CountItems(); 103 } 104 } 105 } 106 return count; 107 } 108 109 DiagramItem *DiagramItemGroup::itemAt( 110 uint32 index, 111 uint32 whichType) const 112 { 113 D_METHOD(("DiagramItemGroup::itemAt()\n")); 114 if (m_types & whichType) 115 { 116 if (whichType & DiagramItem::M_BOX) 117 { 118 if (m_boxes && (index < countItems(DiagramItem::M_BOX))) 119 { 120 return static_cast<DiagramItem *>(m_boxes->ItemAt(index)); 121 } 122 else 123 { 124 index -= countItems(DiagramItem::M_BOX); 125 } 126 } 127 if (whichType & DiagramItem::M_WIRE) 128 { 129 if (m_wires && (index < countItems(DiagramItem::M_WIRE))) 130 { 131 return static_cast<DiagramItem *>(m_wires->ItemAt(index)); 132 } 133 else 134 { 135 index -= countItems(DiagramItem::M_WIRE); 136 } 137 } 138 if (whichType & DiagramItem::M_ENDPOINT) 139 { 140 if (m_endPoints && (index < countItems(DiagramItem::M_ENDPOINT))) 141 { 142 return static_cast<DiagramItem *>(m_endPoints->ItemAt(index)); 143 } 144 } 145 } 146 return 0; 147 } 148 149 // This function returns the first box or endpoint found that 150 // contains the given point. For connections it looks at all 151 // wires that 'might' contain the point and calls their method 152 // howCloseTo() to find the one closest to the point. 153 // The lists should be sorted by selection time for proper results! 154 DiagramItem *DiagramItemGroup::itemUnder( 155 BPoint point) 156 { 157 D_METHOD(("DiagramItemGroup::itemUnder()\n")); 158 if (m_types & DiagramItem::M_BOX) 159 { 160 for (uint32 i = 0; i < countItems(DiagramItem::M_BOX); i++) 161 { 162 DiagramItem *item = itemAt(i, DiagramItem::M_BOX); 163 if (item->frame().Contains(point) && (item->howCloseTo(point) == 1.0)) 164 { 165 // DiagramItemGroup *group = dynamic_cast<DiagramItemGroup *>(item); 166 return (m_lastItemUnder = item); 167 } 168 } 169 } 170 if (m_types & DiagramItem::M_WIRE) 171 { 172 float closest = 0.0; 173 DiagramItem *closestItem = 0; 174 for (uint32 i = 0; i < countItems(DiagramItem::M_WIRE); i++) 175 { 176 DiagramItem *item = itemAt(i, DiagramItem::M_WIRE); 177 if (item->frame().Contains(point)) 178 { 179 float howClose = item->howCloseTo(point); 180 if (howClose > closest) 181 { 182 closestItem = item; 183 if (howClose == 1.0) 184 return (m_lastItemUnder = item); 185 closest = howClose; 186 } 187 } 188 } 189 if (closest > 0.5) 190 { 191 return (m_lastItemUnder = closestItem); 192 } 193 } 194 if (m_types & DiagramItem::M_ENDPOINT) 195 { 196 for (uint32 i = 0; i < countItems(DiagramItem::M_ENDPOINT); i++) 197 { 198 DiagramItem *item = itemAt(i, DiagramItem::M_ENDPOINT); 199 if (item->frame().Contains(point) && (item->howCloseTo(point) == 1.0)) 200 { 201 return (m_lastItemUnder = item); 202 } 203 } 204 } 205 return (m_lastItemUnder = 0); // no item was found! 206 } 207 208 // -------------------------------------------------------- // 209 // *** item operations 210 // -------------------------------------------------------- // 211 212 bool DiagramItemGroup::addItem( 213 DiagramItem *item) 214 { 215 D_METHOD(("DiagramItemGroup::addItem()\n")); 216 if (item && (m_types & item->type())) 217 { 218 switch (item->type()) 219 { 220 case DiagramItem::M_BOX: 221 { 222 if (!m_boxes) 223 { 224 m_boxes = new BList(); 225 } 226 item->m_group = this; 227 return m_boxes->AddItem(static_cast<void *>(item)); 228 } 229 case DiagramItem::M_WIRE: 230 { 231 if (!m_wires) 232 { 233 m_wires = new BList(); 234 } 235 item->m_group = this; 236 return m_wires->AddItem(static_cast<void *>(item)); 237 } 238 case DiagramItem::M_ENDPOINT: 239 { 240 if (!m_endPoints) 241 { 242 m_endPoints = new BList(); 243 } 244 item->m_group = this; 245 return m_endPoints->AddItem(static_cast<void *>(item)); 246 } 247 } 248 } 249 return false; 250 } 251 252 bool DiagramItemGroup::removeItem( 253 DiagramItem *item) 254 { 255 D_METHOD(("DiagramItemGroup::removeItem()\n")); 256 if (item && (m_types & item->type())) 257 { 258 // reset the lastItemUnder-pointer if it pointed to this item 259 if (m_lastItemUnder == item) 260 { 261 m_lastItemUnder = 0; 262 } 263 // remove it from the selection list if it was selected 264 if (item->isSelected()) 265 { 266 m_selection->RemoveItem(static_cast<void *>(item)); 267 } 268 // try to remove the item from its list 269 switch (item->type()) 270 { 271 case DiagramItem::M_BOX: 272 { 273 if (m_boxes) 274 { 275 item->m_group = 0; 276 return m_boxes->RemoveItem(static_cast<void *>(item)); 277 } 278 } 279 case DiagramItem::M_WIRE: 280 { 281 if (m_wires) 282 { 283 item->m_group = 0; 284 return m_wires->RemoveItem(static_cast<void *>(item)); 285 } 286 } 287 case DiagramItem::M_ENDPOINT: 288 { 289 if (m_endPoints) 290 { 291 item->m_group = 0; 292 return m_endPoints->RemoveItem(static_cast<void *>(item)); 293 } 294 } 295 } 296 } 297 return false; 298 } 299 300 void DiagramItemGroup::sortItems( 301 uint32 whichType, 302 int (*compareFunc)(const void *, const void *)) 303 { 304 D_METHOD(("DiagramItemGroup::sortItems()\n")); 305 if ((whichType != DiagramItem::M_ANY) && (m_types & whichType)) 306 { 307 switch (whichType) 308 { 309 case DiagramItem::M_BOX: 310 { 311 if (m_boxes) 312 { 313 m_boxes->SortItems(compareFunc); 314 } 315 break; 316 } 317 case DiagramItem::M_WIRE: 318 { 319 if (m_wires) 320 { 321 m_wires->SortItems(compareFunc); 322 } 323 break; 324 } 325 case DiagramItem::M_ENDPOINT: 326 { 327 if (m_endPoints) 328 { 329 m_endPoints->SortItems(compareFunc); 330 } 331 break; 332 } 333 } 334 } 335 } 336 337 // items are drawn in reverse order; they should be sorted by 338 // selection time before this function gets called, so that 339 // the more recently selected item are drawn above others 340 void DiagramItemGroup::drawItems( 341 BRect updateRect, 342 uint32 whichType, 343 BRegion *updateRegion) 344 { 345 D_METHOD(("DiagramItemGroup::drawItems()\n")); 346 if (whichType & DiagramItem::M_WIRE) 347 { 348 for (int32 i = countItems(DiagramItem::M_WIRE) - 1; i >= 0; i--) 349 { 350 DiagramItem *item = itemAt(i, DiagramItem::M_WIRE); 351 if (item->frame().Intersects(updateRect)) 352 { 353 item->draw(updateRect); 354 } 355 } 356 } 357 if (whichType & DiagramItem::M_BOX) 358 { 359 for (int32 i = countItems(DiagramItem::M_BOX) - 1; i >= 0; i--) 360 { 361 DiagramItem *item = itemAt(i, DiagramItem::M_BOX); 362 if (item && item->frame().Intersects(updateRect)) 363 { 364 item->draw(updateRect); 365 if (updateRegion) 366 updateRegion->Exclude(item->frame()); 367 } 368 } 369 } 370 if (whichType & DiagramItem::M_ENDPOINT) 371 { 372 for (int32 i = countItems(DiagramItem::M_ENDPOINT) - 1; i >= 0; i--) 373 { 374 DiagramItem *item = itemAt(i, DiagramItem::M_ENDPOINT); 375 if (item && item->frame().Intersects(updateRect)) 376 { 377 item->draw(updateRect); 378 } 379 } 380 } 381 } 382 383 bool DiagramItemGroup::getClippingAbove( 384 DiagramItem *which, 385 BRegion *region) 386 { 387 D_METHOD(("DiagramItemGroup::getClippingAbove()\n")); 388 bool found = false; 389 if (which && region) 390 { 391 switch (which->type()) 392 { 393 case DiagramItem::M_BOX: 394 { 395 int32 index = m_boxes->IndexOf(which); 396 if (index >= 0) // the item was found 397 { 398 BRect r = which->frame(); 399 for (int32 i = 0; i < index; i++) 400 { 401 DiagramItem *item = itemAt(i, DiagramItem::M_BOX); 402 if (item && item->frame().Intersects(r)) 403 { 404 region->Include(item->frame() & r); 405 found = true; 406 } 407 } 408 } 409 break; 410 } 411 case DiagramItem::M_WIRE: 412 { 413 BRect r = which->frame(); 414 for (uint32 i = 0; i < countItems(DiagramItem::M_BOX); i++) 415 { 416 DiagramItem *item = itemAt(i, DiagramItem::M_BOX); 417 if (item && item->frame().Intersects(r)) 418 { 419 region->Include(item->frame() & r); 420 found = true; 421 } 422 } 423 break; 424 } 425 } 426 } 427 return found; 428 } 429 430 // -------------------------------------------------------- // 431 // *** selection accessors 432 // -------------------------------------------------------- // 433 434 uint32 DiagramItemGroup::selectedType() const 435 { 436 D_METHOD(("DiagramItemGroup::selectedType()\n")); 437 if (countSelectedItems() > 0) 438 { 439 return selectedItemAt(0)->type(); 440 } 441 return 0; 442 } 443 444 uint32 DiagramItemGroup::countSelectedItems() const 445 { 446 D_METHOD(("DiagramItemGroup::countSelectedItems()\n")); 447 if (m_selection) 448 { 449 return m_selection->CountItems(); 450 } 451 return 0; 452 } 453 454 DiagramItem *DiagramItemGroup::selectedItemAt( 455 uint32 index) const 456 { 457 D_METHOD(("DiagramItemGroup::selectedItemAt()\n")); 458 if (m_selection) 459 { 460 return static_cast<DiagramItem *>(m_selection->ItemAt(index)); 461 } 462 return 0; 463 } 464 465 // -------------------------------------------------------- // 466 // *** selection related operations 467 // -------------------------------------------------------- // 468 469 // selects an item, optionally replacing the complete former 470 // selection. If the type of the item to be selected differs 471 // from the type of items currently selected, this methods 472 // automatically replaces the former selection 473 bool DiagramItemGroup::selectItem( 474 DiagramItem *which, 475 bool deselectOthers) 476 { 477 D_METHOD(("DiagramItemGroup::selectItem()\n")); 478 bool selectionChanged = false; 479 if (which && !which->isSelected() && which->isSelectable()) 480 { 481 // check if the item's type is the same as of the other 482 // selected items 483 if (m_multiSelection) 484 { 485 if (which->type() != selectedType()) 486 { 487 deselectOthers = true; 488 } 489 } 490 491 // check if the former selection has to be deselected 492 if (deselectOthers || !m_multiSelection) 493 { 494 while (countSelectedItems() > 0) 495 { 496 deselectItem(selectedItemAt(0)); 497 } 498 } 499 500 // select the item 501 if (deselectOthers || countSelectedItems() == 0) 502 { 503 which->select(); 504 } 505 else 506 { 507 which->selectAdding(); 508 } 509 m_selection->AddItem(which); 510 selectionChanged = true; 511 } 512 513 // resort the lists if necessary 514 if (selectionChanged) 515 { 516 sortItems(which->type(), compareSelectionTime); 517 sortSelectedItems(compareSelectionTime); 518 return true; 519 } 520 return false; 521 } 522 523 bool DiagramItemGroup::deselectItem( 524 DiagramItem *which) 525 { 526 D_METHOD(("DiagramItemGroup::deselectItem()\n")); 527 if (which && which->isSelected()) 528 { 529 m_selection->RemoveItem(which); 530 which->deselect(); 531 sortItems(which->type(), compareSelectionTime); 532 sortSelectedItems(compareSelectionTime); 533 return true; 534 } 535 return false; 536 } 537 538 bool DiagramItemGroup::selectAll( 539 uint32 itemType) 540 { 541 D_METHOD(("DiagramItemGroup::selectAll()\n")); 542 bool selectionChanged = false; 543 if (m_types & itemType) 544 { 545 for (int32 i = 0; i < countItems(itemType); i++) 546 { 547 if (selectItem(itemAt(i, itemType), false)) 548 selectionChanged = true; 549 } 550 } 551 return selectionChanged; 552 } 553 554 bool DiagramItemGroup::deselectAll( 555 uint32 itemType) 556 { 557 D_METHOD(("DiagramItemGroup::deselectAll()\n")); 558 bool selectionChanged = false; 559 if (m_types & itemType) 560 { 561 for (int32 i = 0; i < countItems(itemType); i++) 562 { 563 if (deselectItem(itemAt(i, itemType))) 564 selectionChanged = true; 565 } 566 } 567 return selectionChanged; 568 } 569 570 void DiagramItemGroup::sortSelectedItems( 571 int (*compareFunc)(const void *, const void *)) 572 { 573 D_METHOD(("DiagramItemGroup::sortSelectedItems()\n")); 574 m_selection->SortItems(compareFunc); 575 } 576 577 void DiagramItemGroup::dragSelectionBy( 578 float x, 579 float y, 580 BRegion *updateRegion) 581 { 582 D_METHOD(("DiagramItemGroup::dragSelectionBy()\n")); 583 if (selectedType() == DiagramItem::M_BOX) 584 { 585 align(&x, &y); 586 if ((x != 0) || (y != 0)) 587 { 588 for (int32 i = countSelectedItems() - 1; i >= 0; i--) 589 { 590 DiagramItem *item = dynamic_cast<DiagramItem *>(selectedItemAt(i)); 591 if (item->isDraggable()) 592 { 593 item->moveBy(x, y, updateRegion); 594 } 595 } 596 } 597 } 598 } 599 600 void DiagramItemGroup::removeSelection() 601 { 602 D_METHOD(("DiagramItemGroup::removeSelection()\n")); 603 for (int32 i = 0; i < countSelectedItems(); i++) 604 { 605 removeItem(selectedItemAt(i)); 606 } 607 } 608 609 // -------------------------------------------------------- // 610 // *** alignment related accessors & operations 611 // -------------------------------------------------------- // 612 613 void DiagramItemGroup::getItemAlignment( 614 float *horizontal, 615 float *vertical) 616 { 617 D_METHOD(("DiagramItemGroup::getItemAlignment()\n")); 618 if (horizontal) 619 *horizontal = m_itemAlignment.x; 620 if (vertical) 621 *vertical = m_itemAlignment.y; 622 } 623 624 void DiagramItemGroup::align( 625 float *x, 626 float *y) const 627 { 628 D_METHOD(("DiagramItemGroup::align()\n")); 629 *x = ((int)*x / (int)m_itemAlignment.x) * m_itemAlignment.x; 630 *y = ((int)*y / (int)m_itemAlignment.y) * m_itemAlignment.y; 631 } 632 633 BPoint DiagramItemGroup::align( 634 BPoint point) const 635 { 636 D_METHOD(("DiagramItemGroup::align()\n")); 637 float x = point.x, y = point.y; 638 align(&x, &y); 639 return BPoint(x, y); 640 } 641 642 // END -- DiagramItemGroup.cpp -- 643