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// MediaWire.cpp
33
34#include "MediaWire.h"
35// InfoWindow
36#include "InfoWindowManager.h"
37// MediaRoutingView
38#include "MediaJack.h"
39#include "MediaRoutingDefs.h"
40#include "MediaRoutingView.h"
41// Support
42#include "cortex_ui.h"
43#include "MediaString.h"
44// TipManager
45#include "TipManager.h"
46
47// Application Kit
48#include <Application.h>
49// Interface Kit
50#include <MenuItem.h>
51#include <PopUpMenu.h>
52// Media Kit
53#include <MediaDefs.h>
54
55__USE_CORTEX_NAMESPACE
56
57#include <Debug.h>
58#define D_METHOD(x) //PRINT (x)
59#define D_DRAW(x) //PRINT (x)
60#define D_MOUSE(x) //PRINT (x)
61
62// -------------------------------------------------------- //
63// constants
64// -------------------------------------------------------- //
65
66const float MediaWire::M_WIRE_OFFSET		= 4.0;
67
68// -------------------------------------------------------- //
69// *** ctor/dtor
70// -------------------------------------------------------- //
71
72MediaWire::MediaWire(
73	Connection connection,
74	MediaJack *outputJack,
75	MediaJack *inputJack)
76	: DiagramWire(outputJack, inputJack),
77	  connection(connection)
78{
79	D_METHOD(("MediaWire::MediaWire()\n"));
80}
81
82MediaWire::MediaWire(
83	MediaJack *jack,
84	bool isStartPoint)
85	: DiagramWire(jack, isStartPoint)
86{
87	D_METHOD(("MediaWire::MediaWire(temp)\n"));
88}
89
90MediaWire::~MediaWire()
91{
92	D_METHOD(("MediaWire::~MediaWire()\n"));
93}
94
95// -------------------------------------------------------- //
96// *** derived from DiagramWire (public)
97// -------------------------------------------------------- //
98
99void MediaWire::attachedToDiagram()
100{
101	D_METHOD(("MediaWire::detachedFromDiagram()\n"));
102
103	endPointMoved(startPoint());
104	endPointMoved(endPoint());
105}
106
107void MediaWire::detachedFromDiagram()
108{
109	D_METHOD(("MediaWire::detachedFromDiagram()\n"));
110
111	// make sure we're no longer displaying a tooltip
112	TipManager *tips = TipManager::Instance();
113	tips->hideTip(view()->ConvertToScreen(Frame()));
114}
115
116BRect MediaWire::Frame() const
117{
118	D_DRAW(("MediaWire::Frame()\n"));
119	return m_frame;
120}
121
122float MediaWire::howCloseTo(
123	BPoint point) const
124{
125	D_MOUSE(("MediaWire::howCloseTo()\n"));
126	if (Frame().Contains(point))
127	{
128		BPoint sp = m_startPoint;
129		BPoint ep = m_endPoint;
130		BPoint so = m_startOffset;
131		BPoint eo = m_endOffset;
132		BRect wireFrame, startFrame, endFrame;
133		wireFrame.left = so.x < eo.x ? so.x : eo.x;
134		wireFrame.top = so.y < eo.y ? so.y : eo.y;
135		wireFrame.right = so.x > eo.x ? so.x : eo.x;
136		wireFrame.bottom = so.y > eo.y ? so.y : eo.y;
137		startFrame.Set(sp.x, sp.y, so.x, so.y);
138		endFrame.Set(ep.x, ep.y, eo.x, eo.y);
139		wireFrame.InsetBy(-1.0, -1.0);
140		startFrame.InsetBy(-1.0, -1.0);
141		endFrame.InsetBy(-1.0, -1.0);
142		if ((wireFrame.Width() <= 5.0) || (wireFrame.Height() <= 5.0) || startFrame.Contains(point) || endFrame.Contains(point))
143		{
144			return 1.0;
145		}
146		else
147		{
148			float length, result;
149			length = sqrt(pow(eo.x - so.x, 2) + pow(eo.y - so.y, 2));
150 			result = ((so.y - point.y) * (eo.x - so.x)) - ((so.x - point.x) * (eo.y - so.y));
151			result = 3.0 - fabs(result / length);
152			return result;
153		}
154	}
155	return 0.0;
156}
157
158void MediaWire::drawWire()
159{
160	D_DRAW(("MediaWire::drawWire()\n"));
161
162	rgb_color border = isSelected() ? M_BLUE_COLOR : M_DARK_GRAY_COLOR;
163	rgb_color fill = isSelected() ? M_LIGHT_BLUE_COLOR : M_LIGHT_GRAY_COLOR;
164	view()->SetPenSize(3.0);
165	view()->BeginLineArray(3);
166		view()->AddLine(m_startPoint, m_startOffset, border);
167		view()->AddLine(m_startOffset, m_endOffset, border);
168		view()->AddLine(m_endOffset, m_endPoint, border);
169	view()->EndLineArray();
170	view()->SetPenSize(1.0);
171	view()->BeginLineArray(3);
172		view()->AddLine(m_startPoint, m_startOffset, fill);
173		view()->AddLine(m_startOffset, m_endOffset, fill);
174		view()->AddLine(m_endOffset, m_endPoint, fill);
175	view()->EndLineArray();
176}
177
178void MediaWire::MouseDown(
179	BPoint point,
180	uint32 buttons,
181	uint32 clicks)
182{
183	D_MOUSE(("MediaWire::MouseDown()\n"));
184	_inherited::MouseDown(point, buttons, clicks);
185
186	switch (buttons)
187	{
188		case B_SECONDARY_MOUSE_BUTTON:
189		{
190			if (clicks == 1)
191			{
192				showContextMenu(point);
193			}
194		}
195	}
196}
197
198void MediaWire::MouseOver(
199	BPoint point,
200	uint32 transit)
201{
202	D_MOUSE(("MediaWire::MouseOver()\n"));
203
204	if (isDragging())
205	{
206		return;
207	}
208	switch (transit)
209	{
210		case B_ENTERED_VIEW:
211		{
212			TipManager *tips = TipManager::Instance();
213			BString tipText = MediaString::getStringFor(connection.format(), false);
214			tips->showTip(tipText.String(), view()->ConvertToScreen(Frame()),
215						  TipManager::LEFT_OFFSET_FROM_POINTER, BPoint(12.0, 8.0));
216			be_app->SetCursor(M_CABLE_CURSOR);
217			break;
218		}
219		case B_EXITED_VIEW:
220		{
221			be_app->SetCursor(B_HAND_CURSOR);
222			TipManager *tips = TipManager::Instance();
223			tips->hideTip(view()->ConvertToScreen(Frame()));
224			break;
225		}
226	}
227}
228
229void MediaWire::selected()
230{
231	D_METHOD(("MediaWire::selected()\n"));
232	if (startPoint())
233	{
234		MediaJack *outputJack = static_cast<MediaJack *>(startPoint());
235		outputJack->select();
236	}
237	if (endPoint())
238	{
239		MediaJack *inputJack = static_cast<MediaJack *>(endPoint());
240		inputJack->select();
241	}
242}
243
244void MediaWire::deselected()
245{
246	D_METHOD(("MediaWire::deselected()\n"));
247	if (startPoint())
248	{
249		MediaJack *outputJack = static_cast<MediaJack *>(startPoint());
250		outputJack->deselect();
251	}
252	if (endPoint())
253	{
254		MediaJack *inputJack = static_cast<MediaJack *>(endPoint());
255		inputJack->deselect();
256	}
257}
258
259void MediaWire::endPointMoved(
260	DiagramEndPoint *which)
261{
262	if (which == startPoint())
263	{
264		m_startPoint = startConnectionPoint();
265		switch (dynamic_cast<MediaRoutingView *>(view())->getLayout())
266		{
267			case MediaRoutingView::M_ICON_VIEW:
268			{
269				m_startOffset = m_startPoint + BPoint(M_WIRE_OFFSET, 0.0);
270				break;
271			}
272			case MediaRoutingView::M_MINI_ICON_VIEW:
273			{
274				m_startOffset = m_startPoint + BPoint(0.0, M_WIRE_OFFSET);
275				break;
276			}
277		}
278		m_frame.left = m_startPoint.x < m_endOffset.x ? m_startPoint.x - 2.0: m_endOffset.x - 2.0;
279		m_frame.top = m_startPoint.y < m_endOffset.y ? m_startPoint.y - 2.0 : m_endOffset.y - 2.0;
280		m_frame.right = m_startOffset.x > m_endPoint.x ? m_startOffset.x + 2.0 : m_endPoint.x + 2.0;
281		m_frame.bottom = m_startOffset.y > m_endPoint.y ? m_startOffset.y + 2.0 : m_endPoint.y + 2.0;
282	}
283	else if (which == endPoint())
284	{
285		m_endPoint = endConnectionPoint();
286		switch (dynamic_cast<MediaRoutingView *>(view())->getLayout())
287		{
288			case MediaRoutingView::M_ICON_VIEW:
289			{
290				m_endOffset = m_endPoint - BPoint(M_WIRE_OFFSET, 0.0);
291				break;
292			}
293			case MediaRoutingView::M_MINI_ICON_VIEW:
294			{
295				m_endOffset = m_endPoint - BPoint(0.0, M_WIRE_OFFSET);
296				break;
297			}
298		}
299		m_frame.left = m_startPoint.x < m_endOffset.x ? m_startPoint.x - 2.0: m_endOffset.x - 2.0;
300		m_frame.top = m_startPoint.y < m_endOffset.y ? m_startPoint.y - 2.0 : m_endOffset.y - 2.0;
301		m_frame.right = m_startOffset.x > m_endPoint.x ? m_startOffset.x + 2.0 : m_endPoint.x + 2.0;
302		m_frame.bottom = m_startOffset.y > m_endPoint.y ? m_startOffset.y + 2.0 : m_endPoint.y + 2.0;
303	}
304}
305
306// -------------------------------------------------------- //
307// *** internal operations (protected)
308// -------------------------------------------------------- //
309
310void MediaWire::showContextMenu(
311	BPoint point)
312{
313	D_METHOD(("MediaWire::showContextMenu()\n"));
314
315	BPopUpMenu *menu = new BPopUpMenu("MediaWire PopUp", false, false, B_ITEMS_IN_COLUMN);
316	menu->SetFont(be_plain_font);
317	BMenuItem *item;
318
319	// add the "Get Info" item
320	media_output output;
321	connection.getOutput(&output);
322	BMessage *message = new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED);
323	message->AddData("connection", B_RAW_TYPE,
324					 reinterpret_cast<const void *>(&output), sizeof(output));
325	menu->AddItem(item = new BMenuItem("Get info", message, 'I'));
326
327	// add the "Disconnect" item
328	menu->AddItem(item = new BMenuItem("Disconnect", new BMessage(MediaRoutingView::M_DELETE_SELECTION), 'T'));
329	if (connection.flags() & Connection::LOCKED)
330	{
331		item->SetEnabled(false);
332	}
333
334	menu->SetTargetForItems(view());
335	view()->ConvertToScreen(&point);
336	point -= BPoint(1.0, 1.0);
337	menu->Go(point, true, true, true);
338}
339
340// END -- MediaWire.cpp --
341