xref: /haiku/src/apps/cortex/DiagramView/DiagramItemGroup.cpp (revision 19ae20e67e91fc09cc9fc5c0e60e21e24e7a53eb)
1*c284bb0fSMatt Madia /*
2*c284bb0fSMatt Madia  * Copyright (c) 1999-2000, Eric Moon.
3*c284bb0fSMatt Madia  * All rights reserved.
4*c284bb0fSMatt Madia  *
5*c284bb0fSMatt Madia  * Redistribution and use in source and binary forms, with or without
6*c284bb0fSMatt Madia  * modification, are permitted provided that the following conditions
7*c284bb0fSMatt Madia  * are met:
8*c284bb0fSMatt Madia  *
9*c284bb0fSMatt Madia  * 1. Redistributions of source code must retain the above copyright
10*c284bb0fSMatt Madia  *    notice, this list of conditions, and the following disclaimer.
11*c284bb0fSMatt Madia  *
12*c284bb0fSMatt Madia  * 2. Redistributions in binary form must reproduce the above copyright
13*c284bb0fSMatt Madia  *    notice, this list of conditions, and the following disclaimer in the
14*c284bb0fSMatt Madia  *    documentation and/or other materials provided with the distribution.
15*c284bb0fSMatt Madia  *
16*c284bb0fSMatt Madia  * 3. The name of the author may not be used to endorse or promote products
17*c284bb0fSMatt Madia  *    derived from this software without specific prior written permission.
18*c284bb0fSMatt Madia  *
19*c284bb0fSMatt Madia  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20*c284bb0fSMatt Madia  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21*c284bb0fSMatt Madia  * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*c284bb0fSMatt Madia  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23*c284bb0fSMatt Madia  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24*c284bb0fSMatt Madia  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25*c284bb0fSMatt Madia  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26*c284bb0fSMatt Madia  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27*c284bb0fSMatt Madia  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28*c284bb0fSMatt Madia  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29*c284bb0fSMatt Madia  */
30*c284bb0fSMatt Madia 
31*c284bb0fSMatt Madia 
32a0795c6fSMarcus Overhagen // DiagramItemGroup.cpp
33a0795c6fSMarcus Overhagen 
34595c89bcSAxel Dörfler /*! \class DiagramItemGroup.
35595c89bcSAxel Dörfler 	\brief Basic class for managing and accessing DiagramItem objects.
36595c89bcSAxel Dörfler 
37595c89bcSAxel Dörfler 	Objects of this class can manage one or more of the DiagramItem
38595c89bcSAxel Dörfler 	type M_BOX, M_WIRE and M_ENDPOINT. Many methods let you specify
39595c89bcSAxel Dörfler 	which type of item you want to deal with.
40595c89bcSAxel Dörfler */
41595c89bcSAxel Dörfler 
42a0795c6fSMarcus Overhagen #include "DiagramItemGroup.h"
43a0795c6fSMarcus Overhagen #include "DiagramItem.h"
44a0795c6fSMarcus Overhagen 
45a0795c6fSMarcus Overhagen #include <Region.h>
46a0795c6fSMarcus Overhagen 
47a0795c6fSMarcus Overhagen __USE_CORTEX_NAMESPACE
48a0795c6fSMarcus Overhagen 
49a0795c6fSMarcus Overhagen #include <Debug.h>
50a0795c6fSMarcus Overhagen #define D_METHOD(x) //PRINT (x)
51a0795c6fSMarcus Overhagen 
52a0795c6fSMarcus Overhagen 
DiagramItemGroup(uint32 acceptedTypes,bool multiSelection)53595c89bcSAxel Dörfler DiagramItemGroup::DiagramItemGroup(uint32 acceptedTypes, bool multiSelection)
54595c89bcSAxel Dörfler 	:fBoxes(0),
55595c89bcSAxel Dörfler 	fWires(0),
56595c89bcSAxel Dörfler 	fEndPoints(0),
57595c89bcSAxel Dörfler 	fSelection(0),
58595c89bcSAxel Dörfler 	fTypes(acceptedTypes),
59595c89bcSAxel Dörfler 	fItemAlignment(1.0, 1.0),
60595c89bcSAxel Dörfler 	fMultiSelection(multiSelection),
61595c89bcSAxel Dörfler 	fLastItemUnder(0)
62a0795c6fSMarcus Overhagen {
63a0795c6fSMarcus Overhagen 	D_METHOD(("DiagramItemGroup::DiagramItemGroup()\n"));
64595c89bcSAxel Dörfler 	fSelection = new BList(1);
65a0795c6fSMarcus Overhagen }
66a0795c6fSMarcus Overhagen 
67595c89bcSAxel Dörfler 
~DiagramItemGroup()68a0795c6fSMarcus Overhagen DiagramItemGroup::~DiagramItemGroup()
69a0795c6fSMarcus Overhagen {
70a0795c6fSMarcus Overhagen 	D_METHOD(("DiagramItemGroup::~DiagramItemGroup()\n"));
71595c89bcSAxel Dörfler 
72c8fe1746SKarsten Heimrich 	int32 count = 0;
73595c89bcSAxel Dörfler 	if (fWires && (fTypes & DiagramItem::M_WIRE)) {
74c8fe1746SKarsten Heimrich 		count = fWires->CountItems();
758f30a89dSKarsten Heimrich 		for (int32 i = 0; i < count; ++i)
768f30a89dSKarsten Heimrich 			delete static_cast<DiagramItem*>(fWires->ItemAt(i));
77595c89bcSAxel Dörfler 		delete fWires;
78a0795c6fSMarcus Overhagen 	}
79595c89bcSAxel Dörfler 
80c8fe1746SKarsten Heimrich 	if (fBoxes && (fTypes & DiagramItem::M_BOX)) {
81c8fe1746SKarsten Heimrich 		count = fBoxes->CountItems();
828f30a89dSKarsten Heimrich 		for (int32 i = 0; i < count; ++i)
838f30a89dSKarsten Heimrich 			delete static_cast<DiagramItem*>(fBoxes->ItemAt(i));
84c8fe1746SKarsten Heimrich 		delete fBoxes;
85c8fe1746SKarsten Heimrich 	}
86c8fe1746SKarsten Heimrich 
87595c89bcSAxel Dörfler 	if (fEndPoints && (fTypes & DiagramItem::M_ENDPOINT)) {
88c8fe1746SKarsten Heimrich 		count = fEndPoints->CountItems();
898f30a89dSKarsten Heimrich 		for (int32 i = 0; i < count; ++i)
908f30a89dSKarsten Heimrich 			delete static_cast<DiagramItem*>(fEndPoints->ItemAt(i));
91595c89bcSAxel Dörfler 		delete fEndPoints;
92a0795c6fSMarcus Overhagen 	}
93c8fe1746SKarsten Heimrich 
94c8fe1746SKarsten Heimrich 	if (fSelection)
95c8fe1746SKarsten Heimrich 		delete fSelection;
96a0795c6fSMarcus Overhagen }
97a0795c6fSMarcus Overhagen 
98a0795c6fSMarcus Overhagen 
99595c89bcSAxel Dörfler //	#pragma mark - item accessors
100595c89bcSAxel Dörfler 
101595c89bcSAxel Dörfler 
1025680c33eSIngo Weinhold /*! Returns the number of items in the group (optionally only those
1035680c33eSIngo Weinhold 	of the given type \param whichType)
1045680c33eSIngo Weinhold */
105595c89bcSAxel Dörfler uint32
CountItems(uint32 whichType) const106595c89bcSAxel Dörfler DiagramItemGroup::CountItems(uint32 whichType) const
107a0795c6fSMarcus Overhagen {
108595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::CountItems()\n"));
109a0795c6fSMarcus Overhagen 	uint32 count = 0;
110595c89bcSAxel Dörfler 	if (whichType & fTypes) {
111595c89bcSAxel Dörfler 		if (whichType & DiagramItem::M_BOX) {
112595c89bcSAxel Dörfler 			if (fBoxes)
113595c89bcSAxel Dörfler 				count += fBoxes->CountItems();
114595c89bcSAxel Dörfler 		}
115595c89bcSAxel Dörfler 
116595c89bcSAxel Dörfler 		if (whichType & DiagramItem::M_WIRE) {
117595c89bcSAxel Dörfler 			if (fWires)
118595c89bcSAxel Dörfler 				count += fWires->CountItems();
119595c89bcSAxel Dörfler 		}
120595c89bcSAxel Dörfler 
121595c89bcSAxel Dörfler 		if (whichType & DiagramItem::M_ENDPOINT) {
122595c89bcSAxel Dörfler 			if (fEndPoints)
123595c89bcSAxel Dörfler 				count += fEndPoints->CountItems();
124a0795c6fSMarcus Overhagen 		}
125a0795c6fSMarcus Overhagen 	}
126595c89bcSAxel Dörfler 
127a0795c6fSMarcus Overhagen 	return count;
128a0795c6fSMarcus Overhagen }
129a0795c6fSMarcus Overhagen 
130595c89bcSAxel Dörfler 
131595c89bcSAxel Dörfler /*! Returns a pointer to the item in the lists which is
132595c89bcSAxel Dörfler 	at the given index; if none is found, this function
133595c89bcSAxel Dörfler 	returns 0
134595c89bcSAxel Dörfler */
135595c89bcSAxel Dörfler DiagramItem*
ItemAt(uint32 index,uint32 whichType) const136595c89bcSAxel Dörfler DiagramItemGroup::ItemAt(uint32 index, uint32 whichType) const
137a0795c6fSMarcus Overhagen {
138595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::ItemAt()\n"));
139595c89bcSAxel Dörfler 	if (fTypes & whichType) {
140595c89bcSAxel Dörfler 		if (whichType & DiagramItem::M_BOX) {
141595c89bcSAxel Dörfler 			if (fBoxes && (index < CountItems(DiagramItem::M_BOX)))
142595c89bcSAxel Dörfler 				return static_cast<DiagramItem *>(fBoxes->ItemAt(index));
143a0795c6fSMarcus Overhagen 			else
144595c89bcSAxel Dörfler 				index -= CountItems(DiagramItem::M_BOX);
145a0795c6fSMarcus Overhagen 		}
146595c89bcSAxel Dörfler 
147595c89bcSAxel Dörfler 		if (whichType & DiagramItem::M_WIRE) {
148595c89bcSAxel Dörfler 			if (fWires && (index < CountItems(DiagramItem::M_WIRE)))
149595c89bcSAxel Dörfler 				return static_cast<DiagramItem *>(fWires->ItemAt(index));
150a0795c6fSMarcus Overhagen 			else
151595c89bcSAxel Dörfler 				index -= CountItems(DiagramItem::M_WIRE);
152595c89bcSAxel Dörfler 		}
153595c89bcSAxel Dörfler 
154595c89bcSAxel Dörfler 		if (whichType & DiagramItem::M_ENDPOINT) {
155595c89bcSAxel Dörfler 			if (fEndPoints && (index < CountItems(DiagramItem::M_ENDPOINT)))
156595c89bcSAxel Dörfler 				return static_cast<DiagramItem *>(fEndPoints->ItemAt(index));
157a0795c6fSMarcus Overhagen 		}
158a0795c6fSMarcus Overhagen 	}
159595c89bcSAxel Dörfler 
160a0795c6fSMarcus Overhagen 	return 0;
161a0795c6fSMarcus Overhagen }
162a0795c6fSMarcus Overhagen 
163595c89bcSAxel Dörfler 
164595c89bcSAxel Dörfler /*! This function returns the first box or endpoint found that
165595c89bcSAxel Dörfler 	contains the given \param point. For connections it looks at all
166595c89bcSAxel Dörfler 	wires that 'might' contain the point and calls their method
167595c89bcSAxel Dörfler 	howCloseTo() to find the one closest to the point.
168595c89bcSAxel Dörfler 	The lists should be sorted by selection time for proper results!
169595c89bcSAxel Dörfler */
170595c89bcSAxel Dörfler DiagramItem*
ItemUnder(BPoint point)171595c89bcSAxel Dörfler DiagramItemGroup::ItemUnder(BPoint point)
172a0795c6fSMarcus Overhagen {
173595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::ItemUnder()\n"));
174595c89bcSAxel Dörfler 	if (fTypes & DiagramItem::M_BOX) {
175595c89bcSAxel Dörfler 		for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) {
176595c89bcSAxel Dörfler 			DiagramItem *item = ItemAt(i, DiagramItem::M_BOX);
1775680c33eSIngo Weinhold 			if (item->Frame().Contains(point) && (item->howCloseTo(point) == 1.0)) {
178a0795c6fSMarcus Overhagen 				// DiagramItemGroup *group = dynamic_cast<DiagramItemGroup *>(item);
179595c89bcSAxel Dörfler 				return (fLastItemUnder = item);
180a0795c6fSMarcus Overhagen 			}
181a0795c6fSMarcus Overhagen 		}
182a0795c6fSMarcus Overhagen 	}
183595c89bcSAxel Dörfler 
184595c89bcSAxel Dörfler 	if (fTypes & DiagramItem::M_WIRE) {
185a0795c6fSMarcus Overhagen 		float closest = 0.0;
186a0795c6fSMarcus Overhagen 		DiagramItem *closestItem = 0;
187595c89bcSAxel Dörfler 		for (uint32 i = 0; i < CountItems(DiagramItem::M_WIRE); i++) {
188595c89bcSAxel Dörfler 			DiagramItem *item = ItemAt(i, DiagramItem::M_WIRE);
1895680c33eSIngo Weinhold 			if (item->Frame().Contains(point)) {
190a0795c6fSMarcus Overhagen 				float howClose = item->howCloseTo(point);
191595c89bcSAxel Dörfler 				if (howClose > closest) {
192a0795c6fSMarcus Overhagen 					closestItem = item;
193a0795c6fSMarcus Overhagen 					if (howClose == 1.0)
194595c89bcSAxel Dörfler 						return (fLastItemUnder = item);
195a0795c6fSMarcus Overhagen 					closest = howClose;
196a0795c6fSMarcus Overhagen 				}
197a0795c6fSMarcus Overhagen 			}
198a0795c6fSMarcus Overhagen 		}
199595c89bcSAxel Dörfler 
200a0795c6fSMarcus Overhagen 		if (closest > 0.5)
201595c89bcSAxel Dörfler 			return (fLastItemUnder = closestItem);
202a0795c6fSMarcus Overhagen 	}
203595c89bcSAxel Dörfler 
204595c89bcSAxel Dörfler 	if (fTypes & DiagramItem::M_ENDPOINT) {
205595c89bcSAxel Dörfler 		for (uint32 i = 0; i < CountItems(DiagramItem::M_ENDPOINT); i++) {
206595c89bcSAxel Dörfler 			DiagramItem *item = ItemAt(i, DiagramItem::M_ENDPOINT);
2075680c33eSIngo Weinhold 			if (item->Frame().Contains(point) && (item->howCloseTo(point) == 1.0))
208595c89bcSAxel Dörfler 				return (fLastItemUnder = item);
209a0795c6fSMarcus Overhagen 		}
210a0795c6fSMarcus Overhagen 	}
211a0795c6fSMarcus Overhagen 
212595c89bcSAxel Dörfler 	return (fLastItemUnder = 0); // no item was found!
213595c89bcSAxel Dörfler }
214a0795c6fSMarcus Overhagen 
215595c89bcSAxel Dörfler 
216595c89bcSAxel Dörfler //	#pragma mark - item operations
217595c89bcSAxel Dörfler 
218595c89bcSAxel Dörfler 
219595c89bcSAxel Dörfler //! Adds an \param item to the group; returns true on success.
220595c89bcSAxel Dörfler bool
AddItem(DiagramItem * item)221595c89bcSAxel Dörfler DiagramItemGroup::AddItem(DiagramItem *item)
222a0795c6fSMarcus Overhagen {
223595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::AddItem()\n"));
224595c89bcSAxel Dörfler 	if (item && (fTypes & item->type())) {
225c8fe1746SKarsten Heimrich 		if (item->m_group)
226c8fe1746SKarsten Heimrich 			item->m_group->RemoveItem(item);
227c8fe1746SKarsten Heimrich 
228595c89bcSAxel Dörfler 		switch (item->type()) {
229a0795c6fSMarcus Overhagen 			case DiagramItem::M_BOX:
230595c89bcSAxel Dörfler 				if (!fBoxes)
231595c89bcSAxel Dörfler 					fBoxes = new BList();
232a0795c6fSMarcus Overhagen 				item->m_group = this;
233595c89bcSAxel Dörfler 				return fBoxes->AddItem(static_cast<void *>(item));
234595c89bcSAxel Dörfler 
235a0795c6fSMarcus Overhagen 			case DiagramItem::M_WIRE:
236595c89bcSAxel Dörfler 				if (!fWires)
237595c89bcSAxel Dörfler 					fWires = new BList();
238a0795c6fSMarcus Overhagen 				item->m_group = this;
239595c89bcSAxel Dörfler 				return fWires->AddItem(static_cast<void *>(item));
240595c89bcSAxel Dörfler 
241a0795c6fSMarcus Overhagen 			case DiagramItem::M_ENDPOINT:
242595c89bcSAxel Dörfler 				if (!fEndPoints)
243595c89bcSAxel Dörfler 					fEndPoints = new BList();
244a0795c6fSMarcus Overhagen 				item->m_group = this;
245595c89bcSAxel Dörfler 				return fEndPoints->AddItem(static_cast<void *>(item));
246a0795c6fSMarcus Overhagen 		}
247a0795c6fSMarcus Overhagen 	}
248595c89bcSAxel Dörfler 
249a0795c6fSMarcus Overhagen 	return false;
250a0795c6fSMarcus Overhagen }
251a0795c6fSMarcus Overhagen 
252595c89bcSAxel Dörfler 
253595c89bcSAxel Dörfler //! Removes an \param item from the group; returns true on success.
254595c89bcSAxel Dörfler bool
RemoveItem(DiagramItem * item)255595c89bcSAxel Dörfler DiagramItemGroup::RemoveItem(DiagramItem* item)
256a0795c6fSMarcus Overhagen {
257595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::RemoveItem()\n"));
258595c89bcSAxel Dörfler 	if (item && (fTypes & item->type())) {
259a0795c6fSMarcus Overhagen 		// reset the lastItemUnder-pointer if it pointed to this item
260595c89bcSAxel Dörfler 		if (fLastItemUnder == item)
261595c89bcSAxel Dörfler 			fLastItemUnder = 0;
262595c89bcSAxel Dörfler 
263a0795c6fSMarcus Overhagen 		// remove it from the selection list if it was selected
264a0795c6fSMarcus Overhagen 		if (item->isSelected())
265595c89bcSAxel Dörfler 			fSelection->RemoveItem(static_cast<void *>(item));
266595c89bcSAxel Dörfler 
267a0795c6fSMarcus Overhagen 		// try to remove the item from its list
268595c89bcSAxel Dörfler 		switch (item->type()) {
269a0795c6fSMarcus Overhagen 			case DiagramItem::M_BOX:
270595c89bcSAxel Dörfler 				if (fBoxes) {
271a0795c6fSMarcus Overhagen 					item->m_group = 0;
272595c89bcSAxel Dörfler 					return fBoxes->RemoveItem(static_cast<void *>(item));
273a0795c6fSMarcus Overhagen 				}
274595c89bcSAxel Dörfler 				break;
275595c89bcSAxel Dörfler 
276a0795c6fSMarcus Overhagen 			case DiagramItem::M_WIRE:
277595c89bcSAxel Dörfler 				if (fWires) {
278a0795c6fSMarcus Overhagen 					item->m_group = 0;
279595c89bcSAxel Dörfler 					return fWires->RemoveItem(static_cast<void *>(item));
280a0795c6fSMarcus Overhagen 				}
281595c89bcSAxel Dörfler 				break;
282595c89bcSAxel Dörfler 
283a0795c6fSMarcus Overhagen 			case DiagramItem::M_ENDPOINT:
284595c89bcSAxel Dörfler 				if (fEndPoints) {
285a0795c6fSMarcus Overhagen 					item->m_group = 0;
286595c89bcSAxel Dörfler 					return fEndPoints->RemoveItem(static_cast<void *>(item));
287a0795c6fSMarcus Overhagen 				}
288a0795c6fSMarcus Overhagen 		}
289a0795c6fSMarcus Overhagen 	}
290595c89bcSAxel Dörfler 
291a0795c6fSMarcus Overhagen 	return false;
292a0795c6fSMarcus Overhagen }
293a0795c6fSMarcus Overhagen 
294595c89bcSAxel Dörfler 
295595c89bcSAxel Dörfler /*! Performs a quicksort on a list of items with the provided
296595c89bcSAxel Dörfler 	compare function (one is already defined in the DiagramItem
297595c89bcSAxel Dörfler 	implementation); can't handle more than one item type at a
298595c89bcSAxel Dörfler 	time!
299595c89bcSAxel Dörfler */
300595c89bcSAxel Dörfler void
SortItems(uint32 whichType,int (* compareFunc)(const void *,const void *))301595c89bcSAxel Dörfler DiagramItemGroup::SortItems(uint32 whichType,
302a0795c6fSMarcus Overhagen 	int (*compareFunc)(const void *, const void *))
303a0795c6fSMarcus Overhagen {
304595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::SortItems()\n"));
305595c89bcSAxel Dörfler 	if ((whichType != DiagramItem::M_ANY) && (fTypes & whichType)) {
306595c89bcSAxel Dörfler 		switch (whichType) {
307a0795c6fSMarcus Overhagen 			case DiagramItem::M_BOX:
308595c89bcSAxel Dörfler 				if (fBoxes)
309595c89bcSAxel Dörfler 					fBoxes->SortItems(compareFunc);
310a0795c6fSMarcus Overhagen 				break;
311595c89bcSAxel Dörfler 
312a0795c6fSMarcus Overhagen 			case DiagramItem::M_WIRE:
313595c89bcSAxel Dörfler 				if (fWires)
314595c89bcSAxel Dörfler 					fWires->SortItems(compareFunc);
315a0795c6fSMarcus Overhagen 				break;
316595c89bcSAxel Dörfler 
317a0795c6fSMarcus Overhagen 			case DiagramItem::M_ENDPOINT:
318595c89bcSAxel Dörfler 				if (fEndPoints)
319595c89bcSAxel Dörfler 					fEndPoints->SortItems(compareFunc);
320a0795c6fSMarcus Overhagen 				break;
321a0795c6fSMarcus Overhagen 		}
322a0795c6fSMarcus Overhagen 	}
323a0795c6fSMarcus Overhagen }
324a0795c6fSMarcus Overhagen 
325595c89bcSAxel Dörfler 
3265680c33eSIngo Weinhold /*! Fires a Draw() command at all items of a specific type that
327595c89bcSAxel Dörfler 	intersect with the \param updateRect;
328595c89bcSAxel Dörfler 	items are drawn in reverse order; they should be sorted by
329595c89bcSAxel Dörfler 	selection time before this function gets called, so that
330595c89bcSAxel Dörfler 	the more recently selected item are drawn above others.
331595c89bcSAxel Dörfler */
332595c89bcSAxel Dörfler void
DrawItems(BRect updateRect,uint32 whichType,BRegion * updateRegion)333595c89bcSAxel Dörfler DiagramItemGroup::DrawItems(BRect updateRect, uint32 whichType, BRegion* updateRegion)
334a0795c6fSMarcus Overhagen {
335595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::DrawItems()\n"));
336595c89bcSAxel Dörfler 	if (whichType & DiagramItem::M_WIRE) {
337595c89bcSAxel Dörfler 		for (int32 i = CountItems(DiagramItem::M_WIRE) - 1; i >= 0; i--) {
338595c89bcSAxel Dörfler 			DiagramItem *item = ItemAt(i, DiagramItem::M_WIRE);
3395680c33eSIngo Weinhold 			if (item->Frame().Intersects(updateRect))
3405680c33eSIngo Weinhold 				item->Draw(updateRect);
341a0795c6fSMarcus Overhagen 		}
342a0795c6fSMarcus Overhagen 	}
343595c89bcSAxel Dörfler 
344595c89bcSAxel Dörfler 	if (whichType & DiagramItem::M_BOX) {
345595c89bcSAxel Dörfler 		for (int32 i = CountItems(DiagramItem::M_BOX) - 1; i >= 0; i--) {
346595c89bcSAxel Dörfler 			DiagramItem *item = ItemAt(i, DiagramItem::M_BOX);
3475680c33eSIngo Weinhold 			if (item && item->Frame().Intersects(updateRect)) {
3485680c33eSIngo Weinhold 				item->Draw(updateRect);
349a0795c6fSMarcus Overhagen 				if (updateRegion)
3505680c33eSIngo Weinhold 					updateRegion->Exclude(item->Frame());
351a0795c6fSMarcus Overhagen 			}
352a0795c6fSMarcus Overhagen 		}
353a0795c6fSMarcus Overhagen 	}
354595c89bcSAxel Dörfler 
355595c89bcSAxel Dörfler 	if (whichType & DiagramItem::M_ENDPOINT) {
356595c89bcSAxel Dörfler 		for (int32 i = CountItems(DiagramItem::M_ENDPOINT) - 1; i >= 0; i--) {
357595c89bcSAxel Dörfler 			DiagramItem *item = ItemAt(i, DiagramItem::M_ENDPOINT);
3585680c33eSIngo Weinhold 			if (item && item->Frame().Intersects(updateRect))
3595680c33eSIngo Weinhold 				item->Draw(updateRect);
360a0795c6fSMarcus Overhagen 		}
361a0795c6fSMarcus Overhagen 	}
362a0795c6fSMarcus Overhagen }
363a0795c6fSMarcus Overhagen 
364595c89bcSAxel Dörfler 
365595c89bcSAxel Dörfler /*!	Returns in outRegion the \param region of items that lay "over" the given
366595c89bcSAxel Dörfler 	DiagramItem in \param which; returns false if no items are above or the item
367595c89bcSAxel Dörfler 	doesn't exist.
368595c89bcSAxel Dörfler */
369595c89bcSAxel Dörfler bool
GetClippingAbove(DiagramItem * which,BRegion * region)370595c89bcSAxel Dörfler DiagramItemGroup::GetClippingAbove(DiagramItem *which, BRegion *region)
371a0795c6fSMarcus Overhagen {
372595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::GetClippingAbove()\n"));
373a0795c6fSMarcus Overhagen 	bool found = false;
374595c89bcSAxel Dörfler 	if (which && region) {
375595c89bcSAxel Dörfler 		switch (which->type()) {
376a0795c6fSMarcus Overhagen 			case DiagramItem::M_BOX:
377a0795c6fSMarcus Overhagen 			{
378595c89bcSAxel Dörfler 				int32 index = fBoxes->IndexOf(which);
379595c89bcSAxel Dörfler 				if (index >= 0) { // the item was found
3805680c33eSIngo Weinhold 					BRect r = which->Frame();
381595c89bcSAxel Dörfler 					for (int32 i = 0; i < index; i++) {
382595c89bcSAxel Dörfler 						DiagramItem *item = ItemAt(i, DiagramItem::M_BOX);
3835680c33eSIngo Weinhold 						if (item && item->Frame().Intersects(r)) {
3845680c33eSIngo Weinhold 							region->Include(item->Frame() & r);
385a0795c6fSMarcus Overhagen 							found = true;
386a0795c6fSMarcus Overhagen 						}
387a0795c6fSMarcus Overhagen 					}
388a0795c6fSMarcus Overhagen 				}
389a0795c6fSMarcus Overhagen 				break;
390a0795c6fSMarcus Overhagen 			}
391595c89bcSAxel Dörfler 
392a0795c6fSMarcus Overhagen 			case DiagramItem::M_WIRE:
393a0795c6fSMarcus Overhagen 			{
3945680c33eSIngo Weinhold 				BRect r = which->Frame();
395595c89bcSAxel Dörfler 				for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) {
396595c89bcSAxel Dörfler 					DiagramItem *item = ItemAt(i, DiagramItem::M_BOX);
3975680c33eSIngo Weinhold 					if (item && item->Frame().Intersects(r)) {
3985680c33eSIngo Weinhold 						region->Include(item->Frame() & r);
399a0795c6fSMarcus Overhagen 						found = true;
400a0795c6fSMarcus Overhagen 					}
401a0795c6fSMarcus Overhagen 				}
402a0795c6fSMarcus Overhagen 				break;
403a0795c6fSMarcus Overhagen 			}
404a0795c6fSMarcus Overhagen 		}
405a0795c6fSMarcus Overhagen 	}
406595c89bcSAxel Dörfler 
407a0795c6fSMarcus Overhagen 	return found;
408a0795c6fSMarcus Overhagen }
409a0795c6fSMarcus Overhagen 
410a0795c6fSMarcus Overhagen 
411595c89bcSAxel Dörfler //	#pragma mark - selection accessors
412595c89bcSAxel Dörfler 
413595c89bcSAxel Dörfler 
414595c89bcSAxel Dörfler /*!	Returns the type of DiagramItems in the current selection
415595c89bcSAxel Dörfler 	(currently only one type at a time is supported!)
416595c89bcSAxel Dörfler */
417595c89bcSAxel Dörfler uint32
SelectedType() const418595c89bcSAxel Dörfler DiagramItemGroup::SelectedType() const
419a0795c6fSMarcus Overhagen {
420595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::SelectedType()\n"));
421595c89bcSAxel Dörfler 	if (CountSelectedItems() > 0)
422595c89bcSAxel Dörfler 		return SelectedItemAt(0)->type();
423595c89bcSAxel Dörfler 
424a0795c6fSMarcus Overhagen 	return 0;
425a0795c6fSMarcus Overhagen }
426a0795c6fSMarcus Overhagen 
427595c89bcSAxel Dörfler 
428595c89bcSAxel Dörfler //!	Returns the number of items in the current selection
429595c89bcSAxel Dörfler uint32
CountSelectedItems() const430595c89bcSAxel Dörfler DiagramItemGroup::CountSelectedItems() const
431a0795c6fSMarcus Overhagen {
432595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::CountSelectedItems()\n"));
433595c89bcSAxel Dörfler 	if (fSelection)
434595c89bcSAxel Dörfler 		return fSelection->CountItems();
435595c89bcSAxel Dörfler 
436a0795c6fSMarcus Overhagen 	return 0;
437a0795c6fSMarcus Overhagen }
438a0795c6fSMarcus Overhagen 
439595c89bcSAxel Dörfler 
440595c89bcSAxel Dörfler /*!	Returns a pointer to the item in the list which is
441595c89bcSAxel Dörfler 	at the given \param index; if none is found, this function
442595c89bcSAxel Dörfler 	returns 0
443595c89bcSAxel Dörfler */
444595c89bcSAxel Dörfler DiagramItem*
SelectedItemAt(uint32 index) const445595c89bcSAxel Dörfler DiagramItemGroup::SelectedItemAt(uint32 index) const
446a0795c6fSMarcus Overhagen {
447595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::SelectedItemAt()\n"));
448595c89bcSAxel Dörfler 	if (fSelection)
449595c89bcSAxel Dörfler 		return static_cast<DiagramItem *>(fSelection->ItemAt(index));
450595c89bcSAxel Dörfler 
451a0795c6fSMarcus Overhagen 	return 0;
452a0795c6fSMarcus Overhagen }
453a0795c6fSMarcus Overhagen 
454a0795c6fSMarcus Overhagen 
455595c89bcSAxel Dörfler //	#pragma mark - selection related operations
456595c89bcSAxel Dörfler 
457595c89bcSAxel Dörfler 
458595c89bcSAxel Dörfler /*!	Selects an item, optionally replacing the complete former
459595c89bcSAxel Dörfler 	selection. If the type of the item to be selected differs
460595c89bcSAxel Dörfler 	from the type of items currently selected, this methods
461595c89bcSAxel Dörfler 	automatically replaces the former selection
462595c89bcSAxel Dörfler */
463595c89bcSAxel Dörfler bool
SelectItem(DiagramItem * which,bool deselectOthers)464595c89bcSAxel Dörfler DiagramItemGroup::SelectItem(DiagramItem* which, bool deselectOthers)
465a0795c6fSMarcus Overhagen {
466595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::SelectItem()\n"));
467a0795c6fSMarcus Overhagen 	bool selectionChanged = false;
468595c89bcSAxel Dörfler 	if (which && !which->isSelected() && which->isSelectable()) {
469a0795c6fSMarcus Overhagen 		// check if the item's type is the same as of the other
470a0795c6fSMarcus Overhagen 		// selected items
471595c89bcSAxel Dörfler 		if (fMultiSelection) {
472595c89bcSAxel Dörfler 			if (which->type() != SelectedType())
473a0795c6fSMarcus Overhagen 				deselectOthers = true;
474a0795c6fSMarcus Overhagen 		}
475a0795c6fSMarcus Overhagen 
476a0795c6fSMarcus Overhagen 		// check if the former selection has to be deselected
477595c89bcSAxel Dörfler 		if (deselectOthers || !fMultiSelection) {
478595c89bcSAxel Dörfler 			while (CountSelectedItems() > 0)
479595c89bcSAxel Dörfler 				DeselectItem(SelectedItemAt(0));
480a0795c6fSMarcus Overhagen 		}
481a0795c6fSMarcus Overhagen 
482a0795c6fSMarcus Overhagen 		// select the item
483595c89bcSAxel Dörfler 		if (deselectOthers || CountSelectedItems() == 0)
484a0795c6fSMarcus Overhagen 			which->select();
485a0795c6fSMarcus Overhagen 		else
486a0795c6fSMarcus Overhagen 			which->selectAdding();
487595c89bcSAxel Dörfler 
488595c89bcSAxel Dörfler 		fSelection->AddItem(which);
489a0795c6fSMarcus Overhagen 		selectionChanged = true;
490a0795c6fSMarcus Overhagen 	}
491a0795c6fSMarcus Overhagen 
492a0795c6fSMarcus Overhagen 	// resort the lists if necessary
493595c89bcSAxel Dörfler 	if (selectionChanged) {
494595c89bcSAxel Dörfler 		SortItems(which->type(), compareSelectionTime);
495595c89bcSAxel Dörfler 		SortSelectedItems(compareSelectionTime);
496a0795c6fSMarcus Overhagen 		return true;
497a0795c6fSMarcus Overhagen 	}
498595c89bcSAxel Dörfler 
499a0795c6fSMarcus Overhagen 	return false;
500a0795c6fSMarcus Overhagen }
501a0795c6fSMarcus Overhagen 
502595c89bcSAxel Dörfler 
503595c89bcSAxel Dörfler //!	Simply deselects one item
504595c89bcSAxel Dörfler bool
DeselectItem(DiagramItem * which)505595c89bcSAxel Dörfler DiagramItemGroup::DeselectItem(DiagramItem* which)
506a0795c6fSMarcus Overhagen {
507595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::DeselectItem()\n"));
508595c89bcSAxel Dörfler 	if (which && which->isSelected()) {
509595c89bcSAxel Dörfler 		fSelection->RemoveItem(which);
510a0795c6fSMarcus Overhagen 		which->deselect();
511595c89bcSAxel Dörfler 		SortItems(which->type(), compareSelectionTime);
512595c89bcSAxel Dörfler 		SortSelectedItems(compareSelectionTime);
513a0795c6fSMarcus Overhagen 		return true;
514a0795c6fSMarcus Overhagen 	}
515595c89bcSAxel Dörfler 
516a0795c6fSMarcus Overhagen 	return false;
517a0795c6fSMarcus Overhagen }
518a0795c6fSMarcus Overhagen 
519595c89bcSAxel Dörfler 
520595c89bcSAxel Dörfler //! Selects all items of the given \param itemType
521595c89bcSAxel Dörfler bool
SelectAll(uint32 itemType)522595c89bcSAxel Dörfler DiagramItemGroup::SelectAll(uint32 itemType)
523a0795c6fSMarcus Overhagen {
524595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::SelectAll()\n"));
525a0795c6fSMarcus Overhagen 	bool selectionChanged = false;
526595c89bcSAxel Dörfler 	if (fTypes & itemType) {
527595c89bcSAxel Dörfler 		for (uint32 i = 0; i < CountItems(itemType); i++) {
528595c89bcSAxel Dörfler 			if (SelectItem(ItemAt(i, itemType), false))
529a0795c6fSMarcus Overhagen 				selectionChanged = true;
530a0795c6fSMarcus Overhagen 		}
531a0795c6fSMarcus Overhagen 	}
532595c89bcSAxel Dörfler 
533a0795c6fSMarcus Overhagen 	return selectionChanged;
534a0795c6fSMarcus Overhagen }
535a0795c6fSMarcus Overhagen 
536595c89bcSAxel Dörfler 
537595c89bcSAxel Dörfler //! Deselects all items of the given \param itemType
538595c89bcSAxel Dörfler bool
DeselectAll(uint32 itemType)539595c89bcSAxel Dörfler DiagramItemGroup::DeselectAll(uint32 itemType)
540a0795c6fSMarcus Overhagen {
541595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::DeselectAll()\n"));
542a0795c6fSMarcus Overhagen 	bool selectionChanged = false;
543595c89bcSAxel Dörfler 	if (fTypes & itemType) {
544595c89bcSAxel Dörfler 		for (uint32 i = 0; i < CountItems(itemType); i++) {
545595c89bcSAxel Dörfler 			if (DeselectItem(ItemAt(i, itemType)))
546a0795c6fSMarcus Overhagen 				selectionChanged = true;
547a0795c6fSMarcus Overhagen 		}
548a0795c6fSMarcus Overhagen 	}
549595c89bcSAxel Dörfler 
550a0795c6fSMarcus Overhagen 	return selectionChanged;
551a0795c6fSMarcus Overhagen }
552a0795c6fSMarcus Overhagen 
553595c89bcSAxel Dörfler 
554595c89bcSAxel Dörfler /*!	Performs a quicksort on the list of selected items with the
555595c89bcSAxel Dörfler 	provided compare function (one is already defined in the DiagramItem
556595c89bcSAxel Dörfler 	implementation)
557595c89bcSAxel Dörfler */
558595c89bcSAxel Dörfler void
SortSelectedItems(int (* compareFunc)(const void *,const void *))559595c89bcSAxel Dörfler DiagramItemGroup::SortSelectedItems(int (*compareFunc)(const void *, const void *))
560a0795c6fSMarcus Overhagen {
561595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::SortSelectedItems()\n"));
562595c89bcSAxel Dörfler 	fSelection->SortItems(compareFunc);
563a0795c6fSMarcus Overhagen }
564a0795c6fSMarcus Overhagen 
565595c89bcSAxel Dörfler 
566595c89bcSAxel Dörfler /*!	Moves all selected items by a given amount, taking
567595c89bcSAxel Dörfler 	item alignment into account; in updateRegion the areas
568595c89bcSAxel Dörfler 	that still require updating by the caller are returned
569595c89bcSAxel Dörfler */
570595c89bcSAxel Dörfler void
DragSelectionBy(float x,float y,BRegion * updateRegion)571595c89bcSAxel Dörfler DiagramItemGroup::DragSelectionBy(float x, float y, BRegion* updateRegion)
572a0795c6fSMarcus Overhagen {
573595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::DragSelectionBy()\n"));
574595c89bcSAxel Dörfler 	if (SelectedType() == DiagramItem::M_BOX) {
575595c89bcSAxel Dörfler 		Align(&x, &y);
576595c89bcSAxel Dörfler 		if ((x != 0) || (y != 0)) {
577595c89bcSAxel Dörfler 			for (int32 i = CountSelectedItems() - 1; i >= 0; i--) {
578595c89bcSAxel Dörfler 				DiagramItem *item = dynamic_cast<DiagramItem *>(SelectedItemAt(i));
579a0795c6fSMarcus Overhagen 				if (item->isDraggable())
5805680c33eSIngo Weinhold 					item->MoveBy(x, y, updateRegion);
581a0795c6fSMarcus Overhagen 			}
582a0795c6fSMarcus Overhagen 		}
583a0795c6fSMarcus Overhagen 	}
584a0795c6fSMarcus Overhagen }
585595c89bcSAxel Dörfler 
586595c89bcSAxel Dörfler 
587595c89bcSAxel Dörfler //!	Removes all selected items from the group
588595c89bcSAxel Dörfler void
RemoveSelection()589595c89bcSAxel Dörfler DiagramItemGroup::RemoveSelection()
590595c89bcSAxel Dörfler {
591595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::RemoveSelection()\n"));
592595c89bcSAxel Dörfler 	for (uint32 i = 0; i < CountSelectedItems(); i++)
593595c89bcSAxel Dörfler 		RemoveItem(SelectedItemAt(i));
594a0795c6fSMarcus Overhagen }
595a0795c6fSMarcus Overhagen 
596a0795c6fSMarcus Overhagen 
597595c89bcSAxel Dörfler //	#pragma mark - alignment related accessors & operations
598a0795c6fSMarcus Overhagen 
599595c89bcSAxel Dörfler 
600595c89bcSAxel Dörfler void
GetItemAlignment(float * horizontal,float * vertical)601595c89bcSAxel Dörfler DiagramItemGroup::GetItemAlignment(float *horizontal, float *vertical)
602a0795c6fSMarcus Overhagen {
603595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::GetItemAlignment()\n"));
604a0795c6fSMarcus Overhagen 	if (horizontal)
605595c89bcSAxel Dörfler 		*horizontal = fItemAlignment.x;
606a0795c6fSMarcus Overhagen 	if (vertical)
607595c89bcSAxel Dörfler 		*vertical = fItemAlignment.y;
608a0795c6fSMarcus Overhagen }
609a0795c6fSMarcus Overhagen 
610595c89bcSAxel Dörfler 
611595c89bcSAxel Dörfler //! Align a given point(\param x, \param y) to the current grid
612595c89bcSAxel Dörfler void
Align(float * x,float * y) const613595c89bcSAxel Dörfler DiagramItemGroup::Align(float *x, float *y) const
614a0795c6fSMarcus Overhagen {
615595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::Align()\n"));
616595c89bcSAxel Dörfler 	*x = ((int)*x / (int)fItemAlignment.x) * fItemAlignment.x;
617595c89bcSAxel Dörfler 	*y = ((int)*y / (int)fItemAlignment.y) * fItemAlignment.y;
618a0795c6fSMarcus Overhagen }
619a0795c6fSMarcus Overhagen 
620595c89bcSAxel Dörfler 
621595c89bcSAxel Dörfler //! Align a given \param point to the current grid
622595c89bcSAxel Dörfler BPoint
Align(BPoint point) const623595c89bcSAxel Dörfler DiagramItemGroup::Align(BPoint point) const
624a0795c6fSMarcus Overhagen {
625595c89bcSAxel Dörfler 	D_METHOD(("DiagramItemGroup::Align()\n"));
626a0795c6fSMarcus Overhagen 	float x = point.x, y = point.y;
627595c89bcSAxel Dörfler 	Align(&x, &y);
628a0795c6fSMarcus Overhagen 	return BPoint(x, y);
629a0795c6fSMarcus Overhagen }
630