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