xref: /haiku/src/apps/cortex/DiagramView/DiagramBox.cpp (revision 93a78ecaa45114d68952d08c4778f073515102f2)
1 // DiagramBox.cpp
2 
3 /*! \class DiagramBox
4 	DiagramItem subclass providing a basic framework for
5 	boxes in diagrams, i.e. objects that can contain various
6 	endpoints
7 */
8 
9 #include "DiagramBox.h"
10 #include "DiagramDefs.h"
11 #include "DiagramEndPoint.h"
12 #include "DiagramView.h"
13 
14 #include <Message.h>
15 #include <Messenger.h>
16 
17 __USE_CORTEX_NAMESPACE
18 
19 #include <Debug.h>
20 #define D_METHOD(x) //PRINT (x)
21 #define D_MESSAGE(x) //PRINT (x)
22 #define D_MOUSE(x) //PRINT (x)
23 #define D_DRAW(x) //PRINT (x)
24 
25 
26 //	#pragma mark -
27 
28 
29 DiagramBox::DiagramBox(BRect frame, uint32 flags)
30 	: DiagramItem(DiagramItem::M_BOX),
31 	DiagramItemGroup(DiagramItem::M_ENDPOINT),
32 	fFrame(frame),
33 	fFlags(flags)
34 {
35 	D_METHOD(("DiagramBox::DiagramBox()\n"));
36 	makeDraggable(true);
37 }
38 
39 
40 DiagramBox::~DiagramBox()
41 {
42 	D_METHOD(("DiagramBox::~DiagramBox()\n"));
43 }
44 
45 
46 //	#pragma mark -  derived from DiagramItemGroup (public)
47 
48 
49 /*! Extends the DiagramItemGroup implementation by setting
50 	the items owner and calling the attachedToDiagram() hook
51 	on it
52 */
53 bool
54 DiagramBox::AddItem(DiagramItem *item)
55 {
56 	D_METHOD(("DiagramBox::AddItem()\n"));
57 	if (item) {
58 		if (DiagramItemGroup::AddItem(item)) {
59 			if (m_view) {
60 				item->_SetOwner(m_view);
61 				item->attachedToDiagram();
62 			}
63 			return true;
64 		}
65 	}
66 	return false;
67 }
68 
69 
70 /*! Extends the DiagramItemGroup implementation by calling
71 	the detachedToDiagram() hook on the \a item
72 */
73 bool
74 DiagramBox::RemoveItem(DiagramItem *item)
75 {
76 	D_METHOD(("DiagramBox::RemoveItem()\n"));
77 	if (item) {
78 		item->detachedFromDiagram();
79 		if (DiagramItemGroup::RemoveItem(item)) {
80 			item->_SetOwner(0);
81 			return true;
82 		}
83 	}
84 	return false;
85 }
86 
87 
88 //	#pragma mark -   derived from DiagramItem (public)
89 
90 
91 /*! Prepares the drawing stack and clipping region, then
92 	calls drawBox
93 */
94 void
95 DiagramBox::Draw(BRect updateRect)
96 {
97 	D_DRAW(("DiagramBox::Draw()\n"));
98 	if (view()) {
99 		view()->PushState();
100 		{
101 			if (fFlags & M_DRAW_UNDER_ENDPOINTS) {
102 				BRegion region, clipping;
103 				region.Include(Frame());
104 				if (group()->GetClippingAbove(this, &clipping))
105 					region.Exclude(&clipping);
106 				view()->ConstrainClippingRegion(&region);
107 				DrawBox();
108 				for (uint32 i = 0; i < CountItems(); i++) {
109 					DiagramItem *item = ItemAt(i);
110 					if (region.Intersects(item->Frame()))
111 						item->Draw(item->Frame());
112 				}
113 			} else {
114 				BRegion region, clipping;
115 				region.Include(Frame());
116 				if (view()->GetClippingAbove(this, &clipping))
117 					region.Exclude(&clipping);
118 				for (uint32 i = 0; i < CountItems(); i++) {
119 					DiagramItem *item = ItemAt(i);
120 					BRect r;
121 					if (region.Intersects(r = item->Frame())) {
122 						item->Draw(r);
123 						region.Exclude(r);
124 					}
125 				}
126 				view()->ConstrainClippingRegion(&region);
127 				DrawBox();
128 			}
129 		}
130 		view()->PopState();
131 	}
132 }
133 
134 
135 /*! Is called from the parent DiagramViews MouseDown() implementation
136 	if the Box was hit; this version initiates selection and dragging
137 */
138 void
139 DiagramBox::MouseDown(BPoint point, uint32 buttons, uint32 clicks)
140 {
141 	D_MOUSE(("DiagramBox::MouseDown()\n"));
142 	DiagramItem *item = ItemUnder(point);
143 	if (item)
144 		item->MouseDown(point, buttons, clicks);
145 	else if (clicks == 1) {
146 		if (isSelectable()) {
147 			BMessage selectMsg(M_SELECTION_CHANGED);
148 			if (modifiers() & B_SHIFT_KEY)
149 				selectMsg.AddBool("replace", false);
150 			else
151 				selectMsg.AddBool("replace", true);
152 			selectMsg.AddPointer("item", reinterpret_cast<void *>(this));
153 			DiagramView* v = view();
154 			BMessenger(v).SendMessage(&selectMsg);
155 		}
156 		if (isDraggable() && (buttons == B_PRIMARY_MOUSE_BUTTON)) {
157 			BMessage dragMsg(M_BOX_DRAGGED);
158 			dragMsg.AddPointer("item", static_cast<void *>(this));
159 			dragMsg.AddPoint("offset", point - Frame().LeftTop());
160 			view()->DragMessage(&dragMsg, BRect(0.0, 0.0, -1.0, -1.0), view());
161 		}
162 	}
163 }
164 
165 
166 
167 /*!	Is called from the DiagramViews MouseMoved() when no message is being
168 	dragged, but the mouse has moved above the box
169 */
170 void
171 DiagramBox::MouseOver(BPoint point, uint32 transit)
172 {
173 	D_MOUSE(("DiagramBox::MouseOver()\n"));
174 	DiagramItem *last = _LastItemUnder();
175 	if (last && (transit == B_EXITED_VIEW)) {
176 		last->MouseOver(point, B_EXITED_VIEW);
177 		_ResetItemUnder();
178 	} else {
179 		DiagramItem *item = ItemUnder(point);
180 		if (item) {
181 			if (item != last) {
182 				if (last)
183 					last->MouseOver(point, B_EXITED_VIEW);
184 				item->MouseOver(point, B_ENTERED_VIEW);
185 			} else
186 				item->MouseOver(point, B_INSIDE_VIEW);
187 		}
188 		else if (last)
189 			last->MouseOver(point, B_EXITED_VIEW);
190 	}
191 }
192 
193 
194 /*!	Is called from the DiagramViews MouseMoved() when a message is being
195 	dragged over the DiagramBox
196 */
197 void
198 DiagramBox::MessageDragged(BPoint point, uint32 transit, const BMessage *message)
199 {
200 	D_MOUSE(("DiagramBox::MessageDragged()\n"));
201 	DiagramItem *last = _LastItemUnder();
202 	if (last && (transit == B_EXITED_VIEW)) {
203 		last->MessageDragged(point, B_EXITED_VIEW, message);
204 		_ResetItemUnder();
205 	} else {
206 		DiagramItem *item = ItemUnder(point);
207 		if (item) {
208 			if (item != last) {
209 				if (last)
210 					last->MessageDragged(point, B_EXITED_VIEW, message);
211 				item->MessageDragged(point, B_ENTERED_VIEW, message);
212 			} else
213 				item->MessageDragged(point, B_INSIDE_VIEW, message);
214 			return;
215 		} else if (last)
216 			last->MessageDragged(point, B_EXITED_VIEW, message);
217 		if (message->what == M_WIRE_DRAGGED)
218 			view()->trackWire(point);
219 	}
220 }
221 
222 
223 /*!	Is called from the DiagramViews MessageReceived() function when a
224 	message has been dropped on the DiagramBox
225 */
226 void
227 DiagramBox::MessageDropped(BPoint point, BMessage *message)
228 {
229 	D_METHOD(("DiagramBox::MessageDropped()\n"));
230 	DiagramItem *item = ItemUnder(point);
231 	if (item) {
232 		item->MessageDropped(point, message);
233 		return;
234 	}
235 }
236 
237 
238 //	#pragma mark - operations (public)
239 
240 
241 /*!	Moves the box by a given amount, and returns in updateRegion the
242 	frames of wires impacted by the move
243 */
244 void
245 DiagramBox::MoveBy(float x, float y, BRegion *wireRegion)
246 {
247 	D_METHOD(("DiagramBox::MoveBy()\n"));
248 	if (view()) {
249 		view()->PushState();
250 		{
251 			for (uint32 i = 0; i < CountItems(); i++) {
252 				DiagramEndPoint *endPoint = dynamic_cast<DiagramEndPoint *>(ItemAt(i));
253 				if (endPoint)
254 					endPoint->MoveBy(x, y, wireRegion);
255 			}
256 			if (wireRegion) {
257 				wireRegion->Include(fFrame);
258 				fFrame.OffsetBy(x, y);
259 				wireRegion->Include(fFrame);
260 			}
261 			else
262 				fFrame.OffsetBy(x, y);
263 		}
264 		view()->PopState();
265 	}
266 }
267 
268 
269 //! Resizes the boxes frame without doing any updating
270 void
271 DiagramBox::ResizeBy(float horizontal, float vertical)
272 {
273 	D_METHOD(("DiagramBox::ResizeBy()\n"));
274 	fFrame.right += horizontal;
275 	fFrame.bottom += vertical;
276 }
277 
278 
279 //	#pragma mark - internal operations (private)
280 
281 
282 //!	Is called by the DiagramView when added
283 void
284 DiagramBox::_SetOwner(DiagramView *owner)
285 {
286 	D_METHOD(("DiagramBox::_SetOwner()\n"));
287 	m_view = owner;
288 	for (uint32 i = 0; i < CountItems(DiagramItem::M_ENDPOINT); i++) {
289 		DiagramItem *item = ItemAt(i);
290 		item->_SetOwner(m_view);
291 		if (m_view)
292 			item->attachedToDiagram();
293 	}
294 }
295