btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / cortex / DiagramView / DiagramItemGroup.cpp
blob8ad564c495b9d573a07bc3c831a85f4f9767b95e
1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions, and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 // DiagramItemGroup.cpp
34 /*! \class DiagramItemGroup.
35 \brief Basic class for managing and accessing DiagramItem objects.
37 Objects of this class can manage one or more of the DiagramItem
38 type M_BOX, M_WIRE and M_ENDPOINT. Many methods let you specify
39 which type of item you want to deal with.
42 #include "DiagramItemGroup.h"
43 #include "DiagramItem.h"
45 #include <Region.h>
47 __USE_CORTEX_NAMESPACE
49 #include <Debug.h>
50 #define D_METHOD(x) //PRINT (x)
53 DiagramItemGroup::DiagramItemGroup(uint32 acceptedTypes, bool multiSelection)
54 :fBoxes(0),
55 fWires(0),
56 fEndPoints(0),
57 fSelection(0),
58 fTypes(acceptedTypes),
59 fItemAlignment(1.0, 1.0),
60 fMultiSelection(multiSelection),
61 fLastItemUnder(0)
63 D_METHOD(("DiagramItemGroup::DiagramItemGroup()\n"));
64 fSelection = new BList(1);
68 DiagramItemGroup::~DiagramItemGroup()
70 D_METHOD(("DiagramItemGroup::~DiagramItemGroup()\n"));
72 int32 count = 0;
73 if (fWires && (fTypes & DiagramItem::M_WIRE)) {
74 count = fWires->CountItems();
75 for (int32 i = 0; i < count; ++i)
76 delete static_cast<DiagramItem*>(fWires->ItemAt(i));
77 delete fWires;
80 if (fBoxes && (fTypes & DiagramItem::M_BOX)) {
81 count = fBoxes->CountItems();
82 for (int32 i = 0; i < count; ++i)
83 delete static_cast<DiagramItem*>(fBoxes->ItemAt(i));
84 delete fBoxes;
87 if (fEndPoints && (fTypes & DiagramItem::M_ENDPOINT)) {
88 count = fEndPoints->CountItems();
89 for (int32 i = 0; i < count; ++i)
90 delete static_cast<DiagramItem*>(fEndPoints->ItemAt(i));
91 delete fEndPoints;
94 if (fSelection)
95 delete fSelection;
99 // #pragma mark - item accessors
102 /*! Returns the number of items in the group (optionally only those
103 of the given type \param whichType)
105 uint32
106 DiagramItemGroup::CountItems(uint32 whichType) const
108 D_METHOD(("DiagramItemGroup::CountItems()\n"));
109 uint32 count = 0;
110 if (whichType & fTypes) {
111 if (whichType & DiagramItem::M_BOX) {
112 if (fBoxes)
113 count += fBoxes->CountItems();
116 if (whichType & DiagramItem::M_WIRE) {
117 if (fWires)
118 count += fWires->CountItems();
121 if (whichType & DiagramItem::M_ENDPOINT) {
122 if (fEndPoints)
123 count += fEndPoints->CountItems();
127 return count;
131 /*! Returns a pointer to the item in the lists which is
132 at the given index; if none is found, this function
133 returns 0
135 DiagramItem*
136 DiagramItemGroup::ItemAt(uint32 index, uint32 whichType) const
138 D_METHOD(("DiagramItemGroup::ItemAt()\n"));
139 if (fTypes & whichType) {
140 if (whichType & DiagramItem::M_BOX) {
141 if (fBoxes && (index < CountItems(DiagramItem::M_BOX)))
142 return static_cast<DiagramItem *>(fBoxes->ItemAt(index));
143 else
144 index -= CountItems(DiagramItem::M_BOX);
147 if (whichType & DiagramItem::M_WIRE) {
148 if (fWires && (index < CountItems(DiagramItem::M_WIRE)))
149 return static_cast<DiagramItem *>(fWires->ItemAt(index));
150 else
151 index -= CountItems(DiagramItem::M_WIRE);
154 if (whichType & DiagramItem::M_ENDPOINT) {
155 if (fEndPoints && (index < CountItems(DiagramItem::M_ENDPOINT)))
156 return static_cast<DiagramItem *>(fEndPoints->ItemAt(index));
160 return 0;
164 /*! This function returns the first box or endpoint found that
165 contains the given \param point. For connections it looks at all
166 wires that 'might' contain the point and calls their method
167 howCloseTo() to find the one closest to the point.
168 The lists should be sorted by selection time for proper results!
170 DiagramItem*
171 DiagramItemGroup::ItemUnder(BPoint point)
173 D_METHOD(("DiagramItemGroup::ItemUnder()\n"));
174 if (fTypes & DiagramItem::M_BOX) {
175 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) {
176 DiagramItem *item = ItemAt(i, DiagramItem::M_BOX);
177 if (item->Frame().Contains(point) && (item->howCloseTo(point) == 1.0)) {
178 // DiagramItemGroup *group = dynamic_cast<DiagramItemGroup *>(item);
179 return (fLastItemUnder = item);
184 if (fTypes & DiagramItem::M_WIRE) {
185 float closest = 0.0;
186 DiagramItem *closestItem = 0;
187 for (uint32 i = 0; i < CountItems(DiagramItem::M_WIRE); i++) {
188 DiagramItem *item = ItemAt(i, DiagramItem::M_WIRE);
189 if (item->Frame().Contains(point)) {
190 float howClose = item->howCloseTo(point);
191 if (howClose > closest) {
192 closestItem = item;
193 if (howClose == 1.0)
194 return (fLastItemUnder = item);
195 closest = howClose;
200 if (closest > 0.5)
201 return (fLastItemUnder = closestItem);
204 if (fTypes & DiagramItem::M_ENDPOINT) {
205 for (uint32 i = 0; i < CountItems(DiagramItem::M_ENDPOINT); i++) {
206 DiagramItem *item = ItemAt(i, DiagramItem::M_ENDPOINT);
207 if (item->Frame().Contains(point) && (item->howCloseTo(point) == 1.0))
208 return (fLastItemUnder = item);
212 return (fLastItemUnder = 0); // no item was found!
216 // #pragma mark - item operations
219 //! Adds an \param item to the group; returns true on success.
220 bool
221 DiagramItemGroup::AddItem(DiagramItem *item)
223 D_METHOD(("DiagramItemGroup::AddItem()\n"));
224 if (item && (fTypes & item->type())) {
225 if (item->m_group)
226 item->m_group->RemoveItem(item);
228 switch (item->type()) {
229 case DiagramItem::M_BOX:
230 if (!fBoxes)
231 fBoxes = new BList();
232 item->m_group = this;
233 return fBoxes->AddItem(static_cast<void *>(item));
235 case DiagramItem::M_WIRE:
236 if (!fWires)
237 fWires = new BList();
238 item->m_group = this;
239 return fWires->AddItem(static_cast<void *>(item));
241 case DiagramItem::M_ENDPOINT:
242 if (!fEndPoints)
243 fEndPoints = new BList();
244 item->m_group = this;
245 return fEndPoints->AddItem(static_cast<void *>(item));
249 return false;
253 //! Removes an \param item from the group; returns true on success.
254 bool
255 DiagramItemGroup::RemoveItem(DiagramItem* item)
257 D_METHOD(("DiagramItemGroup::RemoveItem()\n"));
258 if (item && (fTypes & item->type())) {
259 // reset the lastItemUnder-pointer if it pointed to this item
260 if (fLastItemUnder == item)
261 fLastItemUnder = 0;
263 // remove it from the selection list if it was selected
264 if (item->isSelected())
265 fSelection->RemoveItem(static_cast<void *>(item));
267 // try to remove the item from its list
268 switch (item->type()) {
269 case DiagramItem::M_BOX:
270 if (fBoxes) {
271 item->m_group = 0;
272 return fBoxes->RemoveItem(static_cast<void *>(item));
274 break;
276 case DiagramItem::M_WIRE:
277 if (fWires) {
278 item->m_group = 0;
279 return fWires->RemoveItem(static_cast<void *>(item));
281 break;
283 case DiagramItem::M_ENDPOINT:
284 if (fEndPoints) {
285 item->m_group = 0;
286 return fEndPoints->RemoveItem(static_cast<void *>(item));
291 return false;
295 /*! Performs a quicksort on a list of items with the provided
296 compare function (one is already defined in the DiagramItem
297 implementation); can't handle more than one item type at a
298 time!
300 void
301 DiagramItemGroup::SortItems(uint32 whichType,
302 int (*compareFunc)(const void *, const void *))
304 D_METHOD(("DiagramItemGroup::SortItems()\n"));
305 if ((whichType != DiagramItem::M_ANY) && (fTypes & whichType)) {
306 switch (whichType) {
307 case DiagramItem::M_BOX:
308 if (fBoxes)
309 fBoxes->SortItems(compareFunc);
310 break;
312 case DiagramItem::M_WIRE:
313 if (fWires)
314 fWires->SortItems(compareFunc);
315 break;
317 case DiagramItem::M_ENDPOINT:
318 if (fEndPoints)
319 fEndPoints->SortItems(compareFunc);
320 break;
326 /*! Fires a Draw() command at all items of a specific type that
327 intersect with the \param updateRect;
328 items are drawn in reverse order; they should be sorted by
329 selection time before this function gets called, so that
330 the more recently selected item are drawn above others.
332 void
333 DiagramItemGroup::DrawItems(BRect updateRect, uint32 whichType, BRegion* updateRegion)
335 D_METHOD(("DiagramItemGroup::DrawItems()\n"));
336 if (whichType & DiagramItem::M_WIRE) {
337 for (int32 i = CountItems(DiagramItem::M_WIRE) - 1; i >= 0; i--) {
338 DiagramItem *item = ItemAt(i, DiagramItem::M_WIRE);
339 if (item->Frame().Intersects(updateRect))
340 item->Draw(updateRect);
344 if (whichType & DiagramItem::M_BOX) {
345 for (int32 i = CountItems(DiagramItem::M_BOX) - 1; i >= 0; i--) {
346 DiagramItem *item = ItemAt(i, DiagramItem::M_BOX);
347 if (item && item->Frame().Intersects(updateRect)) {
348 item->Draw(updateRect);
349 if (updateRegion)
350 updateRegion->Exclude(item->Frame());
355 if (whichType & DiagramItem::M_ENDPOINT) {
356 for (int32 i = CountItems(DiagramItem::M_ENDPOINT) - 1; i >= 0; i--) {
357 DiagramItem *item = ItemAt(i, DiagramItem::M_ENDPOINT);
358 if (item && item->Frame().Intersects(updateRect))
359 item->Draw(updateRect);
365 /*! Returns in outRegion the \param region of items that lay "over" the given
366 DiagramItem in \param which; returns false if no items are above or the item
367 doesn't exist.
369 bool
370 DiagramItemGroup::GetClippingAbove(DiagramItem *which, BRegion *region)
372 D_METHOD(("DiagramItemGroup::GetClippingAbove()\n"));
373 bool found = false;
374 if (which && region) {
375 switch (which->type()) {
376 case DiagramItem::M_BOX:
378 int32 index = fBoxes->IndexOf(which);
379 if (index >= 0) { // the item was found
380 BRect r = which->Frame();
381 for (int32 i = 0; i < index; i++) {
382 DiagramItem *item = ItemAt(i, DiagramItem::M_BOX);
383 if (item && item->Frame().Intersects(r)) {
384 region->Include(item->Frame() & r);
385 found = true;
389 break;
392 case DiagramItem::M_WIRE:
394 BRect r = which->Frame();
395 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) {
396 DiagramItem *item = ItemAt(i, DiagramItem::M_BOX);
397 if (item && item->Frame().Intersects(r)) {
398 region->Include(item->Frame() & r);
399 found = true;
402 break;
407 return found;
411 // #pragma mark - selection accessors
414 /*! Returns the type of DiagramItems in the current selection
415 (currently only one type at a time is supported!)
417 uint32
418 DiagramItemGroup::SelectedType() const
420 D_METHOD(("DiagramItemGroup::SelectedType()\n"));
421 if (CountSelectedItems() > 0)
422 return SelectedItemAt(0)->type();
424 return 0;
428 //! Returns the number of items in the current selection
429 uint32
430 DiagramItemGroup::CountSelectedItems() const
432 D_METHOD(("DiagramItemGroup::CountSelectedItems()\n"));
433 if (fSelection)
434 return fSelection->CountItems();
436 return 0;
440 /*! Returns a pointer to the item in the list which is
441 at the given \param index; if none is found, this function
442 returns 0
444 DiagramItem*
445 DiagramItemGroup::SelectedItemAt(uint32 index) const
447 D_METHOD(("DiagramItemGroup::SelectedItemAt()\n"));
448 if (fSelection)
449 return static_cast<DiagramItem *>(fSelection->ItemAt(index));
451 return 0;
455 // #pragma mark - selection related operations
458 /*! Selects an item, optionally replacing the complete former
459 selection. If the type of the item to be selected differs
460 from the type of items currently selected, this methods
461 automatically replaces the former selection
463 bool
464 DiagramItemGroup::SelectItem(DiagramItem* which, bool deselectOthers)
466 D_METHOD(("DiagramItemGroup::SelectItem()\n"));
467 bool selectionChanged = false;
468 if (which && !which->isSelected() && which->isSelectable()) {
469 // check if the item's type is the same as of the other
470 // selected items
471 if (fMultiSelection) {
472 if (which->type() != SelectedType())
473 deselectOthers = true;
476 // check if the former selection has to be deselected
477 if (deselectOthers || !fMultiSelection) {
478 while (CountSelectedItems() > 0)
479 DeselectItem(SelectedItemAt(0));
482 // select the item
483 if (deselectOthers || CountSelectedItems() == 0)
484 which->select();
485 else
486 which->selectAdding();
488 fSelection->AddItem(which);
489 selectionChanged = true;
492 // resort the lists if necessary
493 if (selectionChanged) {
494 SortItems(which->type(), compareSelectionTime);
495 SortSelectedItems(compareSelectionTime);
496 return true;
499 return false;
503 //! Simply deselects one item
504 bool
505 DiagramItemGroup::DeselectItem(DiagramItem* which)
507 D_METHOD(("DiagramItemGroup::DeselectItem()\n"));
508 if (which && which->isSelected()) {
509 fSelection->RemoveItem(which);
510 which->deselect();
511 SortItems(which->type(), compareSelectionTime);
512 SortSelectedItems(compareSelectionTime);
513 return true;
516 return false;
520 //! Selects all items of the given \param itemType
521 bool
522 DiagramItemGroup::SelectAll(uint32 itemType)
524 D_METHOD(("DiagramItemGroup::SelectAll()\n"));
525 bool selectionChanged = false;
526 if (fTypes & itemType) {
527 for (uint32 i = 0; i < CountItems(itemType); i++) {
528 if (SelectItem(ItemAt(i, itemType), false))
529 selectionChanged = true;
533 return selectionChanged;
537 //! Deselects all items of the given \param itemType
538 bool
539 DiagramItemGroup::DeselectAll(uint32 itemType)
541 D_METHOD(("DiagramItemGroup::DeselectAll()\n"));
542 bool selectionChanged = false;
543 if (fTypes & itemType) {
544 for (uint32 i = 0; i < CountItems(itemType); i++) {
545 if (DeselectItem(ItemAt(i, itemType)))
546 selectionChanged = true;
550 return selectionChanged;
554 /*! Performs a quicksort on the list of selected items with the
555 provided compare function (one is already defined in the DiagramItem
556 implementation)
558 void
559 DiagramItemGroup::SortSelectedItems(int (*compareFunc)(const void *, const void *))
561 D_METHOD(("DiagramItemGroup::SortSelectedItems()\n"));
562 fSelection->SortItems(compareFunc);
566 /*! Moves all selected items by a given amount, taking
567 item alignment into account; in updateRegion the areas
568 that still require updating by the caller are returned
570 void
571 DiagramItemGroup::DragSelectionBy(float x, float y, BRegion* updateRegion)
573 D_METHOD(("DiagramItemGroup::DragSelectionBy()\n"));
574 if (SelectedType() == DiagramItem::M_BOX) {
575 Align(&x, &y);
576 if ((x != 0) || (y != 0)) {
577 for (int32 i = CountSelectedItems() - 1; i >= 0; i--) {
578 DiagramItem *item = dynamic_cast<DiagramItem *>(SelectedItemAt(i));
579 if (item->isDraggable())
580 item->MoveBy(x, y, updateRegion);
587 //! Removes all selected items from the group
588 void
589 DiagramItemGroup::RemoveSelection()
591 D_METHOD(("DiagramItemGroup::RemoveSelection()\n"));
592 for (uint32 i = 0; i < CountSelectedItems(); i++)
593 RemoveItem(SelectedItemAt(i));
597 // #pragma mark - alignment related accessors & operations
600 void
601 DiagramItemGroup::GetItemAlignment(float *horizontal, float *vertical)
603 D_METHOD(("DiagramItemGroup::GetItemAlignment()\n"));
604 if (horizontal)
605 *horizontal = fItemAlignment.x;
606 if (vertical)
607 *vertical = fItemAlignment.y;
611 //! Align a given point(\param x, \param y) to the current grid
612 void
613 DiagramItemGroup::Align(float *x, float *y) const
615 D_METHOD(("DiagramItemGroup::Align()\n"));
616 *x = ((int)*x / (int)fItemAlignment.x) * fItemAlignment.x;
617 *y = ((int)*y / (int)fItemAlignment.y) * fItemAlignment.y;
621 //! Align a given \param point to the current grid
622 BPoint
623 DiagramItemGroup::Align(BPoint point) const
625 D_METHOD(("DiagramItemGroup::Align()\n"));
626 float x = point.x, y = point.y;
627 Align(&x, &y);
628 return BPoint(x, y);