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