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// MediaJack.cpp
33// c.lenz 10oct99
34
35#include "MediaJack.h"
36// MediaRoutingView
37#include "MediaRoutingDefs.h"
38#include "MediaRoutingView.h"
39#include "MediaWire.h"
40// InfoWindow
41#include "InfoWindowManager.h"
42// Support
43#include "cortex_ui.h"
44#include "MediaString.h"
45// TipManager
46#include "TipManager.h"
47
48// Application Kit
49#include <Application.h>
50// Interface Kit
51#include <Bitmap.h>
52#include <MenuItem.h>
53#include <PopUpMenu.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
66float MediaJack::M_DEFAULT_WIDTH				= 5.0;
67float MediaJack::M_DEFAULT_HEIGHT				= 10.0;
68const float MediaJack::M_DEFAULT_GAP			= 5.0;
69const int32 MediaJack::M_MAX_ABBR_LENGTH		= 3;
70
71// -------------------------------------------------------- //
72// *** ctor/dtor
73// -------------------------------------------------------- //
74
75MediaJack::MediaJack(
76	media_input input)
77	: DiagramEndPoint(BRect(0.0, 0.0, M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT)),
78	  m_jackType(M_INPUT),
79	  m_bitmap(0),
80	  m_index(input.destination.id),
81	  m_node(input.node),
82	  m_source(input.source),
83	  m_destination(input.destination),
84	  m_format(input.format),
85	  m_label(input.name),
86	  m_abbreviation("")
87{
88	D_METHOD(("MediaJack::MediaJack()\n"));
89	makeSelectable(false);
90	if (m_label == "")
91		m_label = "Input";
92	_updateAbbreviation();
93}
94
95MediaJack::MediaJack(
96	media_output output)
97	: DiagramEndPoint(BRect(0.0, 0.0, M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT)),
98	  m_jackType(M_OUTPUT),
99	  m_bitmap(0),
100	  m_index(output.source.id),
101	  m_node(output.node),
102	  m_source(output.source),
103	  m_destination(output.destination),
104	  m_format(output.format),
105	  m_label(output.name),
106	  m_abbreviation("")
107{
108	D_METHOD(("MediaJack::MediaJack()\n"));
109	makeSelectable(false);
110	if (m_label == "")
111		m_label = "Output";
112	_updateAbbreviation();
113}
114
115MediaJack::~MediaJack()
116{
117	D_METHOD(("MediaJack::~MediaJack()\n"));
118	delete m_bitmap;
119}
120
121// -------------------------------------------------------- //
122// *** accessors
123// -------------------------------------------------------- //
124
125status_t MediaJack::getInput(
126	media_input *input) const
127{
128	D_METHOD(("MediaJack::getInput()\n"));
129	if (isInput())
130	{
131		input->node = m_node;
132		input->source = m_source;
133		input->destination = m_destination;
134		input->format = m_format;
135		strlcpy(input->name, m_label.String(), B_MEDIA_NAME_LENGTH);
136		return B_OK;
137	}
138	return B_ERROR;
139}
140
141status_t MediaJack::getOutput(
142	media_output *output) const
143{
144	D_METHOD(("MediaJack::getOutput()\n"));
145	if (isOutput())
146	{
147		output->node = m_node;
148		output->source = m_source;
149		output->destination = m_destination;
150		output->format = m_format;
151		strlcpy(output->name, m_label.String(), B_MEDIA_NAME_LENGTH);
152		return B_OK;
153	}
154	return B_ERROR;
155}
156
157// -------------------------------------------------------- //
158// *** derived from DiagramEndPoint (public)
159// -------------------------------------------------------- //
160
161void MediaJack::attachedToDiagram()
162{
163	D_METHOD(("MediaJack::attachedToDiagram()\n"));
164	_updateBitmap();
165}
166
167void MediaJack::detachedFromDiagram()
168{
169	D_METHOD(("MediaJack::detachedFromDiagram()\n"));
170
171	// make sure we're no longer displaying a tooltip
172	TipManager *tips = TipManager::Instance();
173	tips->hideTip(view()->ConvertToScreen(Frame()));
174}
175
176void MediaJack::drawEndPoint()
177{
178	D_DRAW(("MediaJack::drawEndPoint()\n"));
179
180	if (m_bitmap)
181	{
182		view()->DrawBitmap(m_bitmap, Frame().LeftTop());
183	}
184}
185
186BPoint MediaJack::connectionPoint() const
187{
188	D_METHOD(("MediaJack::connectionPoint()\n"));
189
190	switch (dynamic_cast<MediaRoutingView *>(view())->getLayout())
191	{
192		case MediaRoutingView::M_ICON_VIEW:
193		{
194			if (isInput())
195			{
196				return BPoint(Frame().left - 1.0, Frame().top + Frame().Height() / 2.0);
197			}
198			else if (isOutput())
199			{
200				return BPoint(Frame().right + 1.0, Frame().top + Frame().Height() / 2.0);
201			}
202			break;
203		}
204		case MediaRoutingView::M_MINI_ICON_VIEW:
205		{
206			if (isInput())
207			{
208				return BPoint(Frame().left + Frame().Width() / 2.0, Frame().top - 1.0);
209			}
210			else if (isOutput())
211			{
212				return BPoint(Frame().left + Frame().Width() / 2.0, Frame().bottom + 1.0);
213			}
214			break;
215		}
216	}
217	return BPoint(-1.0, -1.0);
218}
219
220bool MediaJack::connectionRequested(
221	DiagramEndPoint *which)
222{
223	D_METHOD(("MediaJack::connectionRequested()\n"));
224
225	MediaJack *otherJack = dynamic_cast<MediaJack *>(which);
226	if (otherJack && (otherJack->m_jackType != m_jackType) && !isConnected())
227	{
228		return true;
229	}
230	return false;
231}
232
233void MediaJack::MouseDown(
234	BPoint point,
235	uint32 buttons,
236	uint32 clicks)
237{
238	D_MOUSE(("MediaJack::MouseOver()\n"));
239
240	// if connected, redirect to the wire
241	if (isConnected())
242	{
243		dynamic_cast<MediaWire *>(wire())->MouseDown(point, buttons, clicks);
244		return;
245	}
246
247	// else we handle the mouse event ourselves
248	switch (buttons)
249	{
250		case B_SECONDARY_MOUSE_BUTTON:
251		{
252			showContextMenu(point);
253			break;
254		}
255		default:
256		{
257			DiagramEndPoint::MouseDown(point, buttons, clicks);
258		}
259	}
260}
261
262void MediaJack::MouseOver(
263	BPoint point,
264	uint32 transit)
265{
266	D_MOUSE(("MediaJack::MouseOver()\n"));
267	switch (transit)
268	{
269		case B_ENTERED_VIEW:
270		{
271			be_app->SetCursor(M_CABLE_CURSOR);
272			TipManager *tips = TipManager::Instance();
273			BString tipText = m_label.String();
274			tipText << " (" << MediaString::getStringFor(m_format.type) << ")";
275			tips->showTip(tipText.String(),view()->ConvertToScreen(Frame()),
276						  TipManager::LEFT_OFFSET_FROM_POINTER, BPoint(12.0, 8.0));
277			break;
278		}
279		case B_EXITED_VIEW:
280		{
281			if (!view()->isWireTracking())
282			{
283				be_app->SetCursor(B_HAND_CURSOR);
284			}
285			break;
286		}
287	}
288}
289
290void MediaJack::MessageDragged(
291	BPoint point,
292	uint32 transit,
293	const BMessage *message)
294{
295	D_MOUSE(("MediaJack::MessageDragged()\n"));
296	switch (transit)
297	{
298		case B_ENTERED_VIEW:
299		{
300			be_app->SetCursor(M_CABLE_CURSOR);
301			break;
302		}
303		case B_EXITED_VIEW:
304		{
305			if (!view()->isWireTracking())
306			{
307				be_app->SetCursor(B_HAND_CURSOR);
308			}
309			break;
310		}
311	}
312	DiagramEndPoint::MessageDragged(point, transit, message);
313}
314
315void MediaJack::selected()
316{
317	D_METHOD(("MediaJack::selected()\n"));
318	_updateBitmap();
319	view()->Invalidate(Frame());
320}
321
322void MediaJack::deselected()
323{
324	D_METHOD(("MediaJack::deselected()\n"));
325	_updateBitmap();
326	view()->Invalidate(Frame());
327}
328
329void MediaJack::connected()
330{
331	D_METHOD(("MediaJack::connected()\n"));
332	_updateBitmap();
333	view()->Invalidate(Frame());
334}
335
336void MediaJack::disconnected()
337{
338	D_METHOD(("MediaJack::disconnected()\n"));
339	_updateBitmap();
340	view()->Invalidate(Frame());
341}
342
343// -------------------------------------------------------- //
344// *** operations (public)
345// -------------------------------------------------------- //
346
347void MediaJack::layoutChanged(
348	int32 layout)
349{
350	D_METHOD(("MediaJack::layoutChanged\n"));
351	resizeTo(M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT);
352	_updateBitmap();
353}
354
355void MediaJack::setPosition(
356	float offset,
357	float leftTopBoundary,
358	float rightBottomBoundary,
359	BRegion *updateRegion)
360{
361	D_METHOD(("MediaJack::setPosition\n"));
362	switch (dynamic_cast<MediaRoutingView *>(view())->getLayout())
363	{
364		case MediaRoutingView::M_ICON_VIEW:
365		{
366			if (isInput())
367			{
368				moveTo(BPoint(leftTopBoundary, offset), updateRegion);
369			}
370			else if (isOutput())
371			{
372				moveTo(BPoint(rightBottomBoundary - Frame().Width(), offset), updateRegion);
373			}
374			break;
375		}
376		case MediaRoutingView::M_MINI_ICON_VIEW:
377		{
378			if (isInput())
379			{
380				moveTo(BPoint(offset, leftTopBoundary), updateRegion);
381			}
382			else if (isOutput())
383			{
384				moveTo(BPoint(offset, rightBottomBoundary - Frame().Height()), updateRegion);
385			}
386			break;
387		}
388	}
389}
390
391// -------------------------------------------------------- //
392// *** internal methods (private)
393// -------------------------------------------------------- //
394
395void MediaJack::_updateBitmap()
396{
397	D_METHOD(("MediaJack::_updateBitmap()\n"));
398
399	if (m_bitmap)
400	{
401		delete m_bitmap;
402	}
403	BBitmap *tempBitmap = new BBitmap(Frame().OffsetToCopy(0.0, 0.0), B_CMAP8, true);
404	tempBitmap->Lock();
405	{
406		BView *tempView = new BView(tempBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
407		tempBitmap->AddChild(tempView);
408		tempView->SetOrigin(0.0, 0.0);
409
410		MediaRoutingView* mediaView = dynamic_cast<MediaRoutingView*>(view());
411		int32 layout = mediaView ? mediaView->getLayout() : MediaRoutingView::M_ICON_VIEW;
412
413		_drawInto(tempView, tempView->Bounds(), layout);
414
415		tempView->Sync();
416		tempBitmap->RemoveChild(tempView);
417		delete tempView;
418	}
419	tempBitmap->Unlock();
420	m_bitmap = new BBitmap(tempBitmap);
421	delete tempBitmap;
422}
423
424void MediaJack::_drawInto(
425	BView *target,
426	BRect targetRect,
427	int32 layout)
428{
429	D_METHOD(("MediaJack::_drawInto()\n"));
430
431	bool selected = isConnecting() || isSelected();
432	switch (layout)
433	{
434		case MediaRoutingView::M_ICON_VIEW:
435		{
436			if (isInput())
437			{
438				BRect r;
439				BPoint p;
440
441				// fill rect
442				r = targetRect;
443				target->SetLowColor(M_GRAY_COLOR);
444				r.left += 2.0;
445				target->FillRect(r, B_SOLID_LOW);
446
447				// draw connection point
448				r = targetRect;
449				p.Set(0.0, Frame().Height() / 2.0 - 2.0);
450				target->BeginLineArray(4);
451				{
452					target->AddLine(r.LeftTop(),
453									p,
454									M_DARK_GRAY_COLOR);
455					target->AddLine(r.LeftTop() + BPoint(1.0, 0.0),
456									p + BPoint(1.0, 0.0),
457									M_LIGHT_GRAY_COLOR);
458					target->AddLine(p + BPoint(0.0, 5.0),
459									r.LeftBottom(),
460									M_DARK_GRAY_COLOR);
461					target->AddLine(p + BPoint(1.0, 5.0),
462									r.LeftBottom() + BPoint(1.0, 0.0),
463									M_LIGHT_GRAY_COLOR);
464				}
465				target->EndLineArray();
466
467				if (isConnected() || isConnecting())
468				{
469					target->BeginLineArray(11);
470					{
471						target->AddLine(p, p, M_DARK_GRAY_COLOR);
472						target->AddLine(p + BPoint(0.0, 4.0), p + BPoint(0.0, 4.0), M_DARK_GRAY_COLOR);
473						target->AddLine(p + BPoint(1.0, 0.0), p + BPoint(4.0, 0.0), M_DARK_GRAY_COLOR);
474						target->AddLine(p + BPoint(1.0, 4.0), p + BPoint(4.0, 4.0), M_LIGHT_GRAY_COLOR);
475						target->AddLine(p + BPoint(4.0, 1.0), p + BPoint(4.0, 3.0), M_LIGHT_GRAY_COLOR);
476						target->AddLine(p + BPoint(0.0, 1.0), p + BPoint(2.0, 1.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
477						target->AddLine(p + BPoint(3.0, 1.0), p + BPoint(3.0, 1.0), M_MED_GRAY_COLOR);
478						target->AddLine(p + BPoint(0.0, 2.0), p + BPoint(2.0, 2.0), selected ? M_LIGHT_BLUE_COLOR : M_LIGHT_GRAY_COLOR);
479						target->AddLine(p + BPoint(3.0, 2.0), p + BPoint(3.0, 2.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
480						target->AddLine(p + BPoint(0.0, 3.0), p + BPoint(2.0, 3.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
481						target->AddLine(p + BPoint(3.0, 3.0), p + BPoint(3.0, 3.0), M_MED_GRAY_COLOR);
482					}
483					target->EndLineArray();
484				}
485				else
486				{
487					target->BeginLineArray(7);
488					{
489						target->AddLine(p, p + BPoint(0.0, 4.0), M_DARK_GRAY_COLOR);
490						target->AddLine(p + BPoint(1.0, 0.0), p + BPoint(4.0, 0.0), M_DARK_GRAY_COLOR);
491						target->AddLine(p + BPoint(1.0, 4.0), p + BPoint(4.0, 4.0), M_LIGHT_GRAY_COLOR);
492						target->AddLine(p + BPoint(4.0, 1.0), p + BPoint(4.0, 3.0), M_LIGHT_GRAY_COLOR);
493						target->AddLine(p + BPoint(1.0, 1.0), p + BPoint(3.0, 1.0), M_MED_GRAY_COLOR);
494						target->AddLine(p + BPoint(1.0, 2.0), p + BPoint(3.0, 2.0), M_MED_GRAY_COLOR);
495						target->AddLine(p + BPoint(1.0, 3.0), p + BPoint(3.0, 3.0), M_MED_GRAY_COLOR);
496					}
497					target->EndLineArray();
498				}
499
500				// draw abbreviation string
501				BFont font(be_plain_font);
502				font_height fh;
503				font.SetSize(font.Size() - 2.0);
504				font.GetHeight(&fh);
505				p.x += 7.0;
506				p.y = (Frame().Height() / 2.0) + (fh.ascent / 2.0);
507				target->SetFont(&font);
508				target->SetDrawingMode(B_OP_OVER);
509				target->SetHighColor((isConnected() || isConnecting()) ?
510									  M_MED_GRAY_COLOR :
511									  M_DARK_GRAY_COLOR);
512				target->DrawString(m_abbreviation.String(), p);
513			}
514			else if (isOutput())
515			{
516				BRect r;
517				BPoint p;
518
519				// fill rect
520				r = targetRect;
521				target->SetLowColor(M_GRAY_COLOR);
522				r.right -= 2.0;
523				target->FillRect(r, B_SOLID_LOW);
524
525				// draw connection point
526				r = targetRect;
527				p.Set(targetRect.right - 4.0, Frame().Height() / 2.0 - 2.0);
528				target->BeginLineArray(4);
529				{
530					target->AddLine(r.RightTop(),
531									p + BPoint(4.0, 0.0),
532									M_DARK_GRAY_COLOR);
533					target->AddLine(r.RightTop() + BPoint(-1.0, 0.0),
534									p + BPoint(3.0, 0.0),
535									M_MED_GRAY_COLOR);
536					target->AddLine(p + BPoint(4.0, 5.0),
537									r.RightBottom(),
538									M_DARK_GRAY_COLOR);
539					target->AddLine(p + BPoint(3.0, 5.0),
540									r.RightBottom() + BPoint(-1.0, 0.0),
541									M_MED_GRAY_COLOR);
542				}
543				target->EndLineArray();
544
545				if (isConnected() || isConnecting())
546				{
547					target->BeginLineArray(11);
548					target->AddLine(p + BPoint(4.0, 0.0), p + BPoint(4.0, 0.0), M_DARK_GRAY_COLOR);
549					target->AddLine(p + BPoint(4.0, 4.0), p + BPoint(4.0, 4.0), M_DARK_GRAY_COLOR);
550					target->AddLine(p, p + BPoint(3.0, 0.0), M_DARK_GRAY_COLOR);
551					target->AddLine(p + BPoint(0.0, 1.0), p + BPoint(0.0, 3.0), M_DARK_GRAY_COLOR);
552					target->AddLine(p + BPoint(0.0, 4.0), p + BPoint(3.0, 4.0), M_LIGHT_GRAY_COLOR);
553					target->AddLine(p + BPoint(1.0, 1.0), p + BPoint(1.0, 1.0), M_MED_GRAY_COLOR);
554					target->AddLine(p + BPoint(2.0, 1.0), p + BPoint(4.0, 1.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
555					target->AddLine(p + BPoint(1.0, 2.0), p + BPoint(1.0, 2.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
556					target->AddLine(p + BPoint(2.0, 2.0), p + BPoint(4.0, 2.0), selected ? M_LIGHT_BLUE_COLOR : M_LIGHT_GRAY_COLOR);
557					target->AddLine(p + BPoint(1.0, 3.0), p + BPoint(1.0, 3.0), M_MED_GRAY_COLOR);
558					target->AddLine(p + BPoint(2.0, 3.0), p + BPoint(4.0, 3.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
559					target->EndLineArray();
560				}
561				else
562				{
563					target->BeginLineArray(7);
564					target->AddLine(p + BPoint(4.0, 0.0), p + BPoint(4.0, 4.0), M_DARK_GRAY_COLOR);
565					target->AddLine(p, p + BPoint(3.0, 0.0), M_DARK_GRAY_COLOR);
566					target->AddLine(p + BPoint(0.0, 1.0), p + BPoint(0.0, 3.0), M_DARK_GRAY_COLOR);
567					target->AddLine(p + BPoint(0.0, 4.0), p + BPoint(3.0, 4.0), M_LIGHT_GRAY_COLOR);
568					target->AddLine(p + BPoint(1.0, 1.0), p + BPoint(3.0, 1.0), M_MED_GRAY_COLOR);
569					target->AddLine(p + BPoint(1.0, 2.0), p + BPoint(3.0, 2.0), M_MED_GRAY_COLOR);
570					target->AddLine(p + BPoint(1.0, 3.0), p + BPoint(3.0, 3.0), M_MED_GRAY_COLOR);
571					target->EndLineArray();
572				}
573
574				// draw abbreviation string
575				BFont font(be_plain_font);
576				font_height fh;
577				font.SetSize(font.Size() - 2.0);
578				font.GetHeight(&fh);
579				p.x -= font.StringWidth(m_abbreviation.String()) + 2.0;
580				p.y = (Frame().Height() / 2.0) + (fh.ascent / 2.0);
581				target->SetFont(&font);
582				target->SetDrawingMode(B_OP_OVER);
583				target->SetHighColor((isConnected() || isConnecting()) ?
584									  M_MED_GRAY_COLOR :
585									  M_DARK_GRAY_COLOR);
586				target->DrawString(m_abbreviation.String(), p);
587			}
588			break;
589		}
590		case MediaRoutingView::M_MINI_ICON_VIEW:
591		{
592			if (isInput())
593			{
594				BRect r;
595				BPoint p;
596
597				// fill rect
598				r = targetRect;
599				target->SetLowColor(M_GRAY_COLOR);
600				r.top += 2.0;
601				target->FillRect(r, B_SOLID_LOW);
602
603				// draw connection point
604				r = targetRect;
605				p.Set(Frame().Width() / 2.0 - 2.0, 0.0);
606				target->BeginLineArray(4);
607				{
608					target->AddLine(r.LeftTop(),
609									p,
610									M_DARK_GRAY_COLOR);
611					target->AddLine(r.LeftTop() + BPoint(0.0, 1.0),
612									p + BPoint(0.0, 1.0),
613									M_LIGHT_GRAY_COLOR);
614					target->AddLine(p + BPoint(5.0, 0.0),
615									r.RightTop(),
616									M_DARK_GRAY_COLOR);
617					target->AddLine(p + BPoint(5.0, 1.0),
618									r.RightTop() + BPoint(0.0, 1.0),
619									M_LIGHT_GRAY_COLOR);
620				}
621				target->EndLineArray();
622				if (isConnected() || isConnecting())
623				{
624					target->BeginLineArray(11);
625					target->AddLine(p, p, M_DARK_GRAY_COLOR);
626					target->AddLine(p + BPoint(4.0, 0.0), p + BPoint(4.0, 0.0), M_DARK_GRAY_COLOR);
627					target->AddLine(p + BPoint(0.0, 1.0), p + BPoint(0.0, 4.0), M_DARK_GRAY_COLOR);
628					target->AddLine(p + BPoint(4.0, 1.0), p + BPoint(4.0, 4.0), M_LIGHT_GRAY_COLOR);
629					target->AddLine(p + BPoint(1.0, 4.0), p + BPoint(3.0, 4.0), M_LIGHT_GRAY_COLOR);
630					target->AddLine(p + BPoint(1.0, 0.0), p + BPoint(1.0, 2.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
631					target->AddLine(p + BPoint(1.0, 3.0), p + BPoint(1.0, 3.0), M_MED_GRAY_COLOR);
632					target->AddLine(p + BPoint(2.0, 0.0), p + BPoint(2.0, 2.0), selected ? M_LIGHT_BLUE_COLOR : M_LIGHT_GRAY_COLOR);
633					target->AddLine(p + BPoint(2.0, 3.0), p + BPoint(2.0, 3.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
634					target->AddLine(p + BPoint(3.0, 0.0), p + BPoint(3.0, 2.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
635					target->AddLine(p + BPoint(3.0, 3.0), p + BPoint(3.0, 3.0), M_MED_GRAY_COLOR);
636					target->EndLineArray();
637				}
638				else
639				{
640					target->BeginLineArray(7);
641					target->AddLine(p, p + BPoint(4.0, 0.0), M_DARK_GRAY_COLOR);
642					target->AddLine(p + BPoint(0.0, 1.0), p + BPoint(0.0, 4.0), M_DARK_GRAY_COLOR);
643					target->AddLine(p + BPoint(4.0, 1.0), p + BPoint(4.0, 4.0), M_LIGHT_GRAY_COLOR);
644					target->AddLine(p + BPoint(1.0, 4.0), p + BPoint(3.0, 4.0), M_LIGHT_GRAY_COLOR);
645					target->AddLine(p + BPoint(1.0, 1.0), p + BPoint(1.0, 3.0), M_MED_GRAY_COLOR);
646					target->AddLine(p + BPoint(2.0, 1.0), p + BPoint(2.0, 3.0), M_MED_GRAY_COLOR);
647					target->AddLine(p + BPoint(3.0, 1.0), p + BPoint(3.0, 3.0), M_MED_GRAY_COLOR);
648					target->EndLineArray();
649				}
650			}
651			else if (isOutput())
652			{
653				BRect r = targetRect;
654				BPoint p;
655
656				// fill rect
657				r = targetRect;
658				target->SetLowColor(M_GRAY_COLOR);
659				r.bottom -= 2.0;
660				target->FillRect(r, B_SOLID_LOW);
661
662				// draw connection point
663				r = targetRect;
664				p.Set(Frame().Width() / 2.0 - 2.0, targetRect.bottom - 4.0);
665				target->BeginLineArray(4);
666				{
667					target->AddLine(r.LeftBottom(),
668									p + BPoint(0.0, 4.0),
669									M_DARK_GRAY_COLOR);
670					target->AddLine(r.LeftBottom() + BPoint(0.0, -1.0),
671									p + BPoint(0.0, 3.0),
672									M_MED_GRAY_COLOR);
673					target->AddLine(p + BPoint(5.0, 4.0),
674									r.RightBottom(),
675									M_DARK_GRAY_COLOR);
676					target->AddLine(p + BPoint(5.0, 3.0),
677									r.RightBottom() + BPoint(0.0, -1.0),
678									M_MED_GRAY_COLOR);
679				}
680				target->EndLineArray();
681				if (isConnected() || isConnecting())
682				{
683					target->BeginLineArray(11);
684					target->AddLine(p + BPoint(0.0, 4.0), p + BPoint(0.0, 4.0), M_DARK_GRAY_COLOR);
685					target->AddLine(p + BPoint(4.0, 4.0), p + BPoint(4.0, 4.0), M_DARK_GRAY_COLOR);
686					target->AddLine(p, p + BPoint(0.0, 3.0), M_DARK_GRAY_COLOR);
687					target->AddLine(p + BPoint(1.0, 0.0), p + BPoint(3.0, 0.0), M_DARK_GRAY_COLOR);
688					target->AddLine(p + BPoint(4.0, 0.0), p + BPoint(4.0, 3.0), M_LIGHT_GRAY_COLOR);
689					target->AddLine(p + BPoint(1.0, 1.0), p + BPoint(1.0, 1.0), M_MED_GRAY_COLOR);
690					target->AddLine(p + BPoint(1.0, 2.0), p + BPoint(1.0, 4.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
691					target->AddLine(p + BPoint(2.0, 1.0), p + BPoint(2.0, 1.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
692					target->AddLine(p + BPoint(2.0, 2.0), p + BPoint(2.0, 4.0), selected ? M_LIGHT_BLUE_COLOR : M_LIGHT_GRAY_COLOR);
693					target->AddLine(p + BPoint(3.0, 1.0), p + BPoint(3.0, 1.0), M_MED_GRAY_COLOR);
694					target->AddLine(p + BPoint(3.0, 2.0), p + BPoint(3.0, 4.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
695					target->EndLineArray();
696				}
697				else
698				{
699					target->BeginLineArray(7);
700					target->AddLine(p + BPoint(0.0, 4.0), p + BPoint(4.0, 4.0), M_DARK_GRAY_COLOR);
701					target->AddLine(p, p + BPoint(0.0, 3.0), M_DARK_GRAY_COLOR);
702					target->AddLine(p + BPoint(1.0, 0.0), p + BPoint(3.0, 0.0), M_DARK_GRAY_COLOR);
703					target->AddLine(p + BPoint(4.0, 0.0), p + BPoint(4.0, 3.0), M_LIGHT_GRAY_COLOR);
704					target->AddLine(p + BPoint(1.0, 1.0), p + BPoint(1.0, 3.0), M_MED_GRAY_COLOR);
705					target->AddLine(p + BPoint(2.0, 1.0), p + BPoint(2.0, 3.0), M_MED_GRAY_COLOR);
706					target->AddLine(p + BPoint(3.0, 1.0), p + BPoint(3.0, 3.0), M_MED_GRAY_COLOR);
707					target->EndLineArray();
708				}
709			}
710			break;
711		}
712	}
713}
714
715void MediaJack::_updateAbbreviation()
716{
717	D_METHOD(("MediaJack::_updateAbbreviation()\n"));
718
719	int32 offset;
720	m_abbreviation = "";
721	m_abbreviation += m_label[0];
722	offset = m_label.FindFirst(" ") + 1;
723	if ((offset > 1) && (offset < m_label.CountChars() - 1))
724		m_abbreviation += m_label[offset];
725	else
726		m_abbreviation += m_label[1];
727	offset = m_label.CountChars() - 1;
728	m_abbreviation += m_label[offset];
729}
730
731// -------------------------------------------------------- //
732// *** internal operations (protected)
733// -------------------------------------------------------- //
734
735void MediaJack::showContextMenu(
736	BPoint point)
737{
738	D_METHOD(("MediaJack::showContextMenu()\n"));
739
740	BPopUpMenu *menu = new BPopUpMenu("MediaJack PopUp", false, false, B_ITEMS_IN_COLUMN);
741	menu->SetFont(be_plain_font);
742	BMenuItem *item;
743
744	// add the "Get Info" item
745	if (isInput())
746	{
747		media_input input;
748		getInput(&input);
749		BMessage *message = new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED);
750		message->AddData("input", B_RAW_TYPE,
751						 reinterpret_cast<const void *>(&input), sizeof(input));
752		menu->AddItem(item = new BMenuItem("Get info", message));
753	}
754	else if (isOutput())
755	{
756		media_output output;
757		getOutput(&output);
758		BMessage *message = new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED);
759		message->AddData("output", B_RAW_TYPE,
760						 reinterpret_cast<const void *>(&output), sizeof(output));
761		menu->AddItem(item = new BMenuItem("Get info", message));
762	}
763
764	menu->SetTargetForItems(view());
765	view()->ConvertToScreen(&point);
766	point -= BPoint(1.0, 1.0);
767	menu->Go(point, true, true, true);
768}
769
770// -------------------------------------------------------- //
771// *** sorting methods (friend)
772// -------------------------------------------------------- //
773
774int __CORTEX_NAMESPACE__ compareTypeAndID(
775	const void *lValue,
776	const void *rValue)
777{
778	int retValue = 0;
779	const MediaJack *lJack = *(reinterpret_cast<MediaJack * const*>(reinterpret_cast<void * const*>(lValue)));
780	const MediaJack *rJack = *(reinterpret_cast<MediaJack * const*>(reinterpret_cast<void * const*>(rValue)));
781	if (lJack && rJack)
782	{
783		if (lJack->m_jackType < lJack->m_jackType)
784		{
785			return -1;
786		}
787		if (lJack->m_jackType == lJack->m_jackType)
788		{
789			if (lJack->m_index < rJack->m_index)
790			{
791				return -1;
792			}
793			else
794			{
795				return 1;
796			}
797		}
798		else if (lJack->m_jackType > rJack->m_jackType)
799		{
800			retValue = 1;
801		}
802	}
803	return retValue;
804}
805
806// END -- LiveNodeView.cpp --
807