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