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// DormantNodeListItem.cpp
33
34#include "DormantNodeListItem.h"
35// InfoWindow
36#include "InfoWindowManager.h"
37// Support
38#include "MediaIcon.h"
39// TipManager
40#include "TipManager.h"
41
42// Application Kit
43#include <Application.h>
44// Locale Kit
45#undef B_CATALOG
46#define B_CATALOG (&sCatalog)
47#include <Catalog.h>
48// Interface Kit
49#include <PopUpMenu.h>
50#include <MenuItem.h>
51// Media Kit
52#include <MediaRoster.h>
53#include <MediaAddOn.h>
54
55#undef B_TRANSLATION_CONTEXT
56#define B_TRANSLATION_CONTEXT "CortexDormantNodeListItem"
57
58__USE_CORTEX_NAMESPACE
59
60#include <Debug.h>
61#define D_ALLOC(x) //PRINT (x)		// ctor/dtor
62#define D_HOOK(x) //PRINT (x)		// BListItem impl.
63#define D_OPERATION(x) //PRINT (x)	// operations
64#define D_COMPARE(x) //PRINT (x)	// compare functions
65
66static BCatalog sCatalog("x-vnd.Cortex.DormantNodeView");
67
68// -------------------------------------------------------- //
69// constants
70// -------------------------------------------------------- //
71
72const float DormantNodeListItem::M_ICON_H_MARGIN		= 3.0;
73const float DormantNodeListItem::M_ICON_V_MARGIN		= 1.0;
74
75// -------------------------------------------------------- //
76// ctor/dtor
77// -------------------------------------------------------- //
78
79DormantNodeListItem::DormantNodeListItem(
80	const dormant_node_info &nodeInfo)
81	: m_info(nodeInfo),
82	  m_icon(0) {
83	D_ALLOC(("DormantNodeListItem::DormantNodeListItem()\n"));
84
85	m_icon = new MediaIcon(nodeInfo, B_MINI_ICON);
86}
87
88DormantNodeListItem::~DormantNodeListItem() {
89	D_ALLOC(("DormantNodeListItem::~DormantNodeListItem()\n"));
90
91	delete m_icon;
92}
93
94// -------------------------------------------------------- //
95// BListItem impl.
96// -------------------------------------------------------- //
97
98void DormantNodeListItem::DrawItem(
99	BView *owner,
100	BRect frame,
101	bool drawEverything) {
102	D_HOOK(("DormantNodeListItem::DrawItem()\n"));
103
104	// Draw icon
105	if (m_icon) {
106		BRect r = frame;
107		r.left += M_ICON_H_MARGIN;
108		r.top += (frame.Height() / 2.0) - (B_MINI_ICON / 2.0);
109		r.right = r.left + B_MINI_ICON - 1.0;
110		r.bottom = r.top + B_MINI_ICON - 1.0;
111		owner->SetDrawingMode(B_OP_OVER);
112		owner->DrawBitmap(m_icon, r.LeftTop());
113	}
114
115	// Draw label
116	BRect r = frame;
117	r.left += 2 * M_ICON_H_MARGIN + B_MINI_ICON;
118	r.top += (frame.Height() / 2.0) - (m_fontHeight.ascent / 2.0);
119	r.right = r.left + Width();
120	r.bottom = r.top + m_fontHeight.ascent + m_fontHeight.descent;
121	if (IsSelected() || drawEverything) {
122		if (IsSelected()) {
123			owner->SetHighColor(16, 64, 96, 255);
124		}
125		else {
126			owner->SetHighColor(owner->ViewColor());
127		}
128		owner->FillRect(r);
129	}
130	if (IsSelected()) {
131		owner->SetHighColor(255, 255, 255, 255);
132	}
133	else {
134		owner->SetHighColor(0, 0, 0, 0);
135	}
136	BPoint labelOffset(r.left + 1.0, r.bottom - m_fontHeight.descent);
137	owner->DrawString(m_info.name, labelOffset);
138
139	// cache the frame rect
140	m_frame = frame;
141}
142
143void DormantNodeListItem::Update(
144	BView *owner,
145	const BFont *font) {
146	D_HOOK(("DormantNodeListItem::Update()\n"));
147	BListItem::Update(owner, font);
148
149	SetWidth(font->StringWidth(m_info.name));
150	owner->GetFontHeight(&m_fontHeight);
151	float newHeight = m_fontHeight.ascent + m_fontHeight.descent + m_fontHeight.leading;
152	if (newHeight < B_MINI_ICON) {
153		newHeight = B_MINI_ICON;
154	}
155	newHeight += 2 * M_ICON_V_MARGIN;
156	if (Height() < newHeight) {
157		SetHeight(newHeight);
158	}
159}
160
161// -------------------------------------------------------- //
162// BListItem impl.
163// -------------------------------------------------------- //
164
165void DormantNodeListItem::MouseOver(
166	BView *owner,
167	BPoint point,
168	uint32 transit) {
169	D_OPERATION(("DormantNodeListItem::MouseOver()\n"));
170
171	switch (transit) {
172		case B_ENTERED_VIEW: {
173			TipManager *tips = TipManager::Instance();
174			dormant_flavor_info flavorInfo;
175			BMediaRoster *roster = BMediaRoster::CurrentRoster();
176			if (roster && roster->GetDormantFlavorInfoFor(info(), &flavorInfo) == B_OK) {
177				BString tip = flavorInfo.info;
178				if (tip == "") {
179					tip = m_info.name;
180				}
181				tips->showTip(tip.String(), owner->ConvertToScreen(m_frame));
182			}
183			break;
184		}
185		case B_EXITED_VIEW: {
186			TipManager *tips = TipManager::Instance();
187			tips->hideTip(owner->ConvertToScreen(m_frame));
188			break;
189		}
190	}
191}
192
193BRect DormantNodeListItem::getRealFrame(
194	const BFont *font) const {
195	D_OPERATION(("DormantNodeListItem::getRealFrame()\n"));
196
197	BRect r(0.0, 0.0, -1.0, -1.0);
198	if (m_frame.IsValid()) {
199		r = m_frame;
200		r.right = r.left + B_MINI_ICON + 2 * M_ICON_H_MARGIN;
201		r.right += font->StringWidth(m_info.name);
202	}
203	else {
204		r.right = font->StringWidth(m_info.name);
205		r.right += B_MINI_ICON + 2 * M_ICON_H_MARGIN + 5.0;
206		font_height fh;
207		font->GetHeight(&fh);
208		r.bottom = fh.ascent + fh.descent + fh.leading;
209		if (r.bottom < B_MINI_ICON) {
210			r.bottom = B_MINI_ICON;
211		}
212		r.bottom += 2 * M_ICON_V_MARGIN;
213		if (Height() > r.bottom) {
214			r.bottom = Height();
215		}
216	}
217	return r;
218}
219
220BBitmap *DormantNodeListItem::getDragBitmap() {
221	D_OPERATION(("DormantNodeListItem::getDragBitmap()\n"));
222
223	// Prepare Bitmap for Drag & Drop
224	BBitmap *dragBitmap = new BBitmap(m_frame.OffsetToCopy(BPoint(0.0, 0.0)), B_RGBA32, true);
225	dragBitmap->Lock(); {
226		BView *dragView = new BView(dragBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
227		dragBitmap->AddChild(dragView);
228		dragView->SetOrigin(0.0, 0.0);
229		dragView->SetHighColor(0, 0, 0, 0);
230		dragView->FillRect(dragView->Bounds());
231		dragView->SetDrawingMode(B_OP_ALPHA);
232		dragView->SetHighColor(0, 0, 0, 128);
233	    dragView->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
234		// Drawing code back again
235		if (m_icon) {
236			BRect r = dragView->Bounds();
237			r.left += M_ICON_H_MARGIN;
238			r.top += (m_frame.Height() / 2.0) - (B_MINI_ICON / 2.0);
239			r.right = r.left + B_MINI_ICON - 1.0;
240			r.bottom = r.top + B_MINI_ICON - 1.0;
241			dragView->DrawBitmap(m_icon, r.LeftTop());
242		}
243		BRect r = dragView->Bounds();
244		r.left += 2 * M_ICON_H_MARGIN + B_MINI_ICON;
245		r.top += (m_frame.Height() / 2.0) - (m_fontHeight.ascent / 2.0);
246		r.right = r.left + Width();
247		r.bottom = r.top + m_fontHeight.ascent + m_fontHeight.descent;
248		BPoint labelOffset(r.left + 1.0, r.bottom - m_fontHeight.descent);
249		dragView->DrawString(m_info.name, labelOffset);
250		dragView->Sync();
251	}
252	dragBitmap->Unlock();
253	return dragBitmap;
254}
255
256void DormantNodeListItem::showContextMenu(
257	BPoint point,
258	BView *owner) {
259	D_OPERATION(("DormantNodeListItem::showContextMenu()\n"));
260
261	BPopUpMenu *menu = new BPopUpMenu("DormantNodeListItem PopUp", false, false, B_ITEMS_IN_COLUMN);
262	menu->SetFont(be_plain_font);
263
264	// Add the "Get Info" item
265	BMessage *message = new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED);
266	menu->AddItem(new BMenuItem(B_TRANSLATE("Get info"), message));
267
268	menu->SetTargetForItems(owner);
269	owner->ConvertToScreen(&point);
270	point -= BPoint(1.0, 1.0);
271	menu->Go(point, true, true, true);
272}
273
274// -------------------------------------------------------- //
275// *** compare functions (friend)
276// -------------------------------------------------------- //
277
278int __CORTEX_NAMESPACE__ compareName(
279	const void *lValue,
280	const void *rValue) {
281	D_COMPARE(("compareSelectionTime()\n"));
282
283	int returnValue = 0;
284	const DormantNodeListItem *lItem = *(reinterpret_cast<const DormantNodeListItem* const*>
285										(reinterpret_cast<const void* const*>(lValue)));
286	const DormantNodeListItem *rItem = *(reinterpret_cast<const DormantNodeListItem* const*>
287										(reinterpret_cast<const void* const*>(rValue)));
288	BString lString = lItem->info().name;
289	lString.ToUpper();
290	BString rString = rItem->info().name;
291	rString.ToUpper();
292	if (lString < rString) {
293		returnValue = -1;
294	}
295	else if (lString > rString) {
296		returnValue = 1;
297	}
298	return returnValue;
299}
300
301int __CORTEX_NAMESPACE__ compareAddOnID(
302	const void *lValue,
303	const void *rValue) {
304	D_COMPARE(("compareAddOnID()\n"));
305
306	int returnValue = 0;
307	const DormantNodeListItem *lItem = *(reinterpret_cast<const DormantNodeListItem* const*>
308										(reinterpret_cast<const void* const*>(lValue)));
309	const DormantNodeListItem *rItem = *(reinterpret_cast<const DormantNodeListItem* const*>
310										(reinterpret_cast<const void* const*>(rValue)));
311	if (lItem->info().addon < rItem->info().addon) {
312		returnValue = -1;
313	}
314	else if (lItem->info().addon > rItem->info().addon) {
315		returnValue = 1;
316	}
317	return returnValue;
318}
319
320// END -- DormantNodeListItem.cpp --
321