xref: /haiku/src/apps/cortex/DiagramView/DiagramEndPoint.cpp (revision 323b65468e5836bb27a5e373b14027d902349437)
1 /*
2  * Copyright (c) 1999-2000, Eric Moon.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions, and the following disclaimer.
11  *
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.
15  *
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.
18  *
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.
29  */
30 
31 
32 // DiagramEndPoint.cpp
33 
34 #include "DiagramEndPoint.h"
35 #include "DiagramDefs.h"
36 #include "DiagramWire.h"
37 #include "DiagramView.h"
38 
39 #include <Message.h>
40 #include <Messenger.h>
41 __USE_CORTEX_NAMESPACE
42 
43 #include <Debug.h>
44 #define D_METHOD(x) //PRINT (x)
45 #define D_MESSAGE(x) //PRINT (x)
46 #define D_MOUSE(x) //PRINT (x)
47 
48 // -------------------------------------------------------- //
49 // *** ctor/dtor
50 // -------------------------------------------------------- //
51 
52 DiagramEndPoint::DiagramEndPoint(
53 	BRect frame)
54 	: DiagramItem(DiagramItem::M_ENDPOINT),
55 	  m_frame(frame),
56 	  m_wire(0),
57 	  m_connected(false),
58 	  m_connecting(false)
59 {
60 	D_METHOD(("DiagramEndPoint::DiagramEndPoint()\n"));
61 	makeDraggable(true);
62 }
63 
64 DiagramEndPoint::~DiagramEndPoint()
65 {
66 	D_METHOD(("DiagramEndPoint::~DiagramEndPoint()\n"));
67 }
68 
69 // -------------------------------------------------------- //
70 // *** hook functions
71 // -------------------------------------------------------- //
72 
73 BPoint DiagramEndPoint::connectionPoint() const
74 {
75 	D_METHOD(("DiagramEndPoint::connectionPoint()\n"));
76 	return BPoint(Frame().left + Frame().Height() / 2.0, Frame().top + Frame().Width() / 2.0);
77 }
78 
79 bool DiagramEndPoint::connectionRequested(
80 	DiagramEndPoint *fromWhich)
81 {
82 	D_METHOD(("DiagramEndPoint::connectionRequested()\n"));
83 	if (!isConnected())
84 	{
85 		return true;
86 	}
87 	return false;
88 }
89 
90 // -------------------------------------------------------- //
91 // *** derived from DiagramItem
92 // -------------------------------------------------------- //
93 
94 void DiagramEndPoint::Draw(
95 	BRect updateRect)
96 {
97 	D_METHOD(("DiagramEndPoint::Draw()\n"));
98 	if (view())
99 	{
100 		view()->PushState();
101 		{
102 			BRegion region;
103 			region.Include(Frame() & updateRect);
104 			view()->ConstrainClippingRegion(&region);
105 			drawEndPoint();
106 		}
107 		view()->PopState();
108 	}
109 }
110 
111 void DiagramEndPoint::MouseDown(
112 	BPoint point,
113 	uint32 buttons,
114 	uint32 clicks)
115 {
116 	D_MOUSE(("DiagramEndPoint::MouseDown()\n"));
117 	if (clicks == 1)
118 	{
119 		if (isSelectable())
120 		{
121 			BMessage selectMsg(M_SELECTION_CHANGED);
122 			if (modifiers() & B_SHIFT_KEY)
123 			{
124 				selectMsg.AddBool("replace", false);
125 			}
126 			else
127 			{
128 				selectMsg.AddBool("replace", true);
129 			}
130 			selectMsg.AddPointer("item", reinterpret_cast<void *>(this));
131 			DiagramView* v = view();
132 			BMessenger(v).SendMessage(&selectMsg);
133 		}
134 		if (isDraggable() && (buttons == B_PRIMARY_MOUSE_BUTTON))
135 		{
136 			BMessage dragMsg(M_WIRE_DRAGGED);
137 			dragMsg.AddPointer("from", static_cast<void *>(this));
138 			view()->DragMessage(&dragMsg, BRect(0.0, 0.0, -1.0, -1.0), view());
139 			view()->MessageDragged(point, B_INSIDE_VIEW, &dragMsg);
140 		}
141 	}
142 }
143 
144 void DiagramEndPoint::MessageDragged(
145 	BPoint point,
146 	uint32 transit,
147 	const BMessage *message)
148 {
149 	D_MOUSE(("DiagramEndPoint::MessageDragged()\n"));
150 	switch (message->what)
151 	{
152 		case M_WIRE_DRAGGED:
153 		{
154 			D_MESSAGE(("DiagramEndPoint::MessageDragged(M_WIRE_DRAGGED)\n"));
155 			switch (transit)
156 			{
157 				case B_INSIDE_VIEW:
158 				{
159 					//PRINT((" -> transit: B_INSIDE_VIEW\n"));
160 					// this is a WORK-AROUND caused by the unreliability
161 					// of BViews DragMessage() routine !!
162 					if (isConnecting())
163 					{
164 						break;
165 					}
166 					else if (isConnected())
167 					{
168 						view()->trackWire(point);
169 					}
170 					/* this should be enough in theory:
171 					if (!isConnecting())
172 					{
173 						view()->trackWire(point);
174 					}
175 					//break;*/
176 				}
177 				case B_ENTERED_VIEW:
178 				{
179 					//PRINT((" -> transit: B_ENTERED_VIEW\n"));
180 					DiagramEndPoint *endPoint;
181 					if ((message->FindPointer("from", reinterpret_cast<void **>(&endPoint)) == B_OK)
182 					 && (endPoint != this))
183 					{
184 						if (connectionRequested(endPoint))
185 						{
186 							view()->trackWire(connectionPoint());
187 							if (!isConnecting())
188 							{
189 								m_connecting = true;
190 								connected();
191 							}
192 						}
193 						else
194 						{
195 							view()->trackWire(point);
196 							if (isConnecting())
197 							{
198 								m_connecting = false;
199 								disconnected();
200 							}
201 						}
202 					}
203 					break;
204 				}
205 				case B_EXITED_VIEW:
206 				{
207 					//PRINT((" -> transit: B_EXITED_VIEW\n"));
208 					if (isConnecting())
209 					{
210 						m_connecting = false;
211 						disconnected();
212 					}
213 					break;
214 				}
215 			}
216 			break;
217 		}
218 		default:
219 		{
220 			DiagramItem::MessageDragged(point, transit, message);
221 		}
222 	}
223 }
224 
225 void DiagramEndPoint::MessageDropped(
226 	BPoint point,
227 	BMessage *message)
228 {
229 	D_MESSAGE(("DiagramEndPoint::MessageDropped()\n"));
230 	switch (message->what)
231 	{
232 		case M_WIRE_DRAGGED:
233 		{
234 			D_MESSAGE(("DiagramEndPoint::MessageDropped(M_WIRE_DRAGGED)\n"));
235 			DiagramEndPoint *endPoint;
236 			if ((message->FindPointer("from", reinterpret_cast<void **>(&endPoint)) == B_OK)
237 			 && (endPoint != this))
238 			{
239 				bool success = connectionRequested(endPoint);
240 				BMessage dropMsg(M_WIRE_DROPPED);
241 				dropMsg.AddPointer("from", reinterpret_cast<void *>(endPoint));
242 				dropMsg.AddPointer("to", reinterpret_cast<void *>(this));
243 				dropMsg.AddBool("success", success);
244 				DiagramView* v = view();
245 				BMessenger(v).SendMessage(&dropMsg);
246 				if (isConnecting())
247 				{
248 					m_connecting = false;
249 					disconnected();
250 				}
251 			}
252 			return;
253 		}
254 		default:
255 		{
256 			DiagramItem::MessageDropped(point, message);
257 		}
258 	}
259 }
260 
261 // -------------------------------------------------------- //
262 // *** frame related operations
263 // -------------------------------------------------------- //
264 
265 void DiagramEndPoint::MoveBy(
266 	float x,
267 	float y,
268 	BRegion *updateRegion)
269 {
270 	D_METHOD(("DiagramEndPoint::MoveBy()\n"));
271 	if (isConnected() && m_wire && updateRegion)
272 	{
273 		updateRegion->Include(m_wire->Frame());
274 		m_frame.OffsetBy(x, y);
275 		m_wire->endPointMoved(this);
276 		updateRegion->Include(m_wire->Frame());
277 	}
278 	else
279 	{
280 		m_frame.OffsetBy(x, y);
281 		if (m_wire)
282 		{
283 			m_wire->endPointMoved(this);
284 		}
285 	}
286 }
287 
288 void DiagramEndPoint::ResizeBy(
289 	float horizontal,
290 	float vertical)
291 {
292 	D_METHOD(("DiagramEndPoint::ResizeBy()\n"));
293 	m_frame.right += horizontal;
294 	m_frame.bottom += vertical;
295 }
296 
297 // -------------------------------------------------------- //
298 // *** connection methods
299 // -------------------------------------------------------- //
300 
301 void DiagramEndPoint::connect(
302 	DiagramWire *wire)
303 {
304 	D_METHOD(("DiagramEndPoint::connect()\n"));
305 	if (!m_connected && wire)
306 	{
307 		m_connected = true;
308 		m_wire = wire;
309 		makeDraggable(false);
310 		connected();
311 	}
312 }
313 
314 void DiagramEndPoint::disconnect()
315 {
316 	D_METHOD(("DiagramEndPoint::disconnect()\n"));
317 	if (m_connected)
318 	{
319 		m_connected = false;
320 		m_wire = 0;
321 		makeDraggable(true);
322 		disconnected();
323 	}
324 }
325 
326 // END -- DiagramEndPoint.cpp --
327