1// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
2//
3//	Copyright (c) 2003, OpenBeOS
4//
5//  This software is part of the OpenBeOS distribution and is covered
6//  by the OpenBeOS license.
7//
8//
9//  File:        MediaListItem.cpp
10//  Author:      Sikosis, Jérôme Duval
11//  Description: Media Preferences
12//  Created :    June 25, 2003
13//
14// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
15#include "MediaListItem.h"
16
17#include <string.h>
18
19#include <MediaAddOn.h>
20#include <View.h>
21
22#include "MediaIcons.h"
23#include "MediaWindow.h"
24
25
26#define kITEM_MARGIN	1
27#define GREATER_THAN	-1
28#define LESS_THAN		1
29
30
31MediaIcons* MediaListItem::sIcons = NULL;
32
33
34struct MediaListItem::Renderer {
35	Renderer()
36		:
37		fTitle(NULL),
38		fPrimaryIcon(NULL),
39		fSecondaryIcon(NULL),
40		fDoubleInsets(true),
41		fSelected(false)
42	{
43	}
44
45	// The first icon added is drawn next to the label,
46	// the second is drawn to the right of the label.
47	void AddIcon(BBitmap* icon)
48	{
49		if (!fPrimaryIcon)
50			fPrimaryIcon = icon;
51		else {
52			fSecondaryIcon = fPrimaryIcon;
53			fPrimaryIcon = icon;
54		}
55	}
56
57	void SetTitle(const char* title)
58	{
59		fTitle = title;
60	}
61
62	void SetSelected(bool selected)
63	{
64		fSelected = selected;
65	}
66
67	// set whether or not to leave enough room for two icons,
68	// defaults to true.
69	void UseDoubleInset(bool doubleInset)
70	{
71		fDoubleInsets = doubleInset;
72	}
73
74	void Render(BView* onto, BRect frame, bool complete = false)
75	{
76		const rgb_color lowColor = onto->LowColor();
77		const rgb_color highColor = onto->HighColor();
78		const rgb_color kBlack = {0, 0, 0, 255};
79
80		if (fSelected || complete) {
81			if (fSelected)
82				onto->SetLowColor(tint_color(lowColor, B_DARKEN_2_TINT));
83			onto->FillRect(frame, B_SOLID_LOW);
84		}
85
86		frame.left += 4;
87		frame.top += kITEM_MARGIN;
88		BRect iconFrame(MediaIcons::IconRectAt(frame.LeftTop() + BPoint(1, 0)));
89
90		onto->SetDrawingMode(B_OP_OVER);
91		if (fPrimaryIcon && !fDoubleInsets) {
92			onto->DrawBitmap(fPrimaryIcon, iconFrame);
93			frame.left = iconFrame.right + 1;
94		} else if (fSecondaryIcon) {
95			onto->DrawBitmap(fSecondaryIcon, iconFrame);
96		}
97		iconFrame = MediaIcons::IconRectAt(iconFrame.RightTop() + BPoint(1, 0));
98
99		if (fDoubleInsets && fPrimaryIcon) {
100			onto->DrawBitmap(fPrimaryIcon, iconFrame);
101			frame.left = iconFrame.right + 1;
102		}
103
104		onto->SetDrawingMode(B_OP_COPY);
105		onto->SetHighColor(kBlack);
106
107		BFont font = be_plain_font;
108		font_height	fontInfo;
109		font.GetHeight(&fontInfo);
110		float lineHeight = fontInfo.ascent + fontInfo.descent
111			+ fontInfo.leading;
112		onto->SetFont(&font);
113		onto->MovePenTo(frame.left + 8, frame.top
114			+ ((frame.Height() - (lineHeight)) / 2)
115			+ (fontInfo.ascent + fontInfo.descent) - 1);
116		onto->DrawString(fTitle);
117
118		onto->SetHighColor(highColor);
119		onto->SetLowColor(lowColor);
120	}
121
122	float ItemWidth()
123	{
124		float width = 4.0f;
125			// left margin
126
127		float iconSpace = MediaIcons::sBounds.Width() + 1.0f;
128		if (fDoubleInsets)
129			iconSpace *= 2.0f;
130		width += iconSpace;
131		width += 8.0f;
132			// space between icons and text
133
134		width += be_plain_font->StringWidth(fTitle) + 16.0f;
135		return width;
136	}
137
138private:
139
140	const char*	fTitle;
141	BBitmap*	fPrimaryIcon;
142	BBitmap*	fSecondaryIcon;
143	bool		fDoubleInsets;
144	bool		fSelected;
145};
146
147
148MediaListItem::MediaListItem()
149	:
150	BListItem((uint32)0)
151{
152}
153
154
155void
156MediaListItem::Update(BView* owner, const BFont* font)
157{
158	// we need to override the update method so we can make sure our
159	// list item size doesn't change
160	BListItem::Update(owner, font);
161
162	float iconHeight = MediaIcons::sBounds.Height() + 1;
163	if ((Height() < iconHeight + kITEM_MARGIN * 2)) {
164		SetHeight(iconHeight + kITEM_MARGIN * 2);
165	}
166
167	Renderer renderer;
168	renderer.SetTitle(Label());
169	SetRenderParameters(renderer);
170	SetWidth(renderer.ItemWidth());
171}
172
173
174void
175MediaListItem::DrawItem(BView* owner, BRect frame, bool complete)
176{
177	Renderer renderer;
178	renderer.SetSelected(IsSelected());
179	renderer.SetTitle(Label());
180	SetRenderParameters(renderer);
181	renderer.Render(owner, frame, complete);
182}
183
184
185int
186MediaListItem::Compare(const void* itemOne, const void* itemTwo)
187{
188	MediaListItem* firstItem = *(MediaListItem**)itemOne;
189	MediaListItem* secondItem = *(MediaListItem**)itemTwo;
190
191	return firstItem->CompareWith(secondItem);
192}
193
194
195// #pragma mark - NodeListItem
196
197
198NodeListItem::NodeListItem(const dormant_node_info* node, media_type type)
199	:
200	MediaListItem(),
201	fNodeInfo(node),
202	fMediaType(type),
203	fIsDefaultInput(false),
204	fIsDefaultOutput(false)
205{
206}
207
208
209void
210NodeListItem::SetRenderParameters(MediaListItem::Renderer& renderer)
211{
212	MediaIcons::IconSet* iconSet = &Icons()->videoIcons;
213	if (fMediaType == MediaListItem::AUDIO_TYPE)
214		iconSet = &Icons()->audioIcons;
215
216	if (fIsDefaultInput)
217		renderer.AddIcon(&iconSet->inputIcon);
218	if (fIsDefaultOutput)
219		renderer.AddIcon(&iconSet->outputIcon);
220}
221
222
223const char*
224NodeListItem::Label()
225{
226	return fNodeInfo->name;
227}
228
229
230void
231NodeListItem::SetMediaType(media_type type)
232{
233	fMediaType = type;
234}
235
236
237void
238NodeListItem::SetDefaultOutput(bool isDefault)
239{
240	fIsDefaultOutput = isDefault;
241}
242
243
244void
245NodeListItem::SetDefaultInput(bool isDefault)
246{
247	fIsDefaultInput = isDefault;
248}
249
250
251void
252NodeListItem::AlterWindow(MediaWindow* window)
253{
254	window->SelectNode(fNodeInfo);
255}
256
257
258void
259NodeListItem::Accept(MediaListItem::Visitor& visitor)
260{
261	visitor.Visit(this);
262}
263
264
265int
266NodeListItem::CompareWith(MediaListItem* item)
267{
268	Comparator comparator(this);
269	item->Accept(comparator);
270	return comparator.result;
271}
272
273
274NodeListItem::Comparator::Comparator(NodeListItem* compareOthersTo)
275	:
276	result(GREATER_THAN),
277	fTarget(compareOthersTo)
278{
279}
280
281
282void
283NodeListItem::Comparator::Visit(NodeListItem* item)
284{
285	result = GREATER_THAN;
286
287	if (fTarget->Type() != item->Type() && fTarget->Type() == VIDEO_TYPE)
288		result = LESS_THAN;
289	else
290		result = strcmp(fTarget->Label(), item->Label());
291}
292
293
294void
295NodeListItem::Comparator::Visit(DeviceListItem* item)
296{
297	result = LESS_THAN;
298	if (fTarget->Type() != item->Type() && fTarget->Type() == AUDIO_TYPE)
299		result = GREATER_THAN;
300}
301
302
303void
304NodeListItem::Comparator::Visit(AudioMixerListItem* item)
305{
306	result = LESS_THAN;
307}
308
309
310// #pragma mark - DeviceListItem
311
312
313DeviceListItem::DeviceListItem(const char* title,
314	MediaListItem::media_type type)
315	:
316	MediaListItem(),
317	fTitle(title),
318	fMediaType(type)
319{
320}
321
322
323void
324DeviceListItem::Accept(MediaListItem::Visitor& visitor)
325{
326	visitor.Visit(this);
327}
328
329
330int
331DeviceListItem::CompareWith(MediaListItem* item)
332{
333	Comparator comparator(this);
334	item->Accept(comparator);
335	return comparator.result;
336}
337
338
339DeviceListItem::Comparator::Comparator(DeviceListItem* compareOthersTo)
340	:
341	result(GREATER_THAN),
342	fTarget(compareOthersTo)
343{
344}
345
346
347void
348DeviceListItem::Comparator::Visit(NodeListItem* item)
349{
350	result = GREATER_THAN;
351	if (fTarget->Type() != item->Type() && fTarget->Type() == AUDIO_TYPE)
352		result = LESS_THAN;
353}
354
355
356void
357DeviceListItem::Comparator::Visit(DeviceListItem* item)
358{
359	result = LESS_THAN;
360	if (fTarget->Type() == AUDIO_TYPE)
361		result = GREATER_THAN;
362}
363
364
365void
366DeviceListItem::Comparator::Visit(AudioMixerListItem* item)
367{
368	result = LESS_THAN;
369	if (fTarget->Type() == AUDIO_TYPE)
370		result = GREATER_THAN;
371}
372
373
374void
375DeviceListItem::SetRenderParameters(Renderer& renderer)
376{
377	renderer.AddIcon(&Icons()->devicesIcon);
378	renderer.UseDoubleInset(false);
379}
380
381
382void
383DeviceListItem::AlterWindow(MediaWindow* window)
384{
385	if (fMediaType == MediaListItem::AUDIO_TYPE)
386		window->SelectAudioSettings(fTitle);
387	else
388		window->SelectVideoSettings(fTitle);
389}
390
391
392// #pragma mark - AudioMixerListItem
393
394
395AudioMixerListItem::AudioMixerListItem(const char* title)
396	:
397	MediaListItem(),
398	fTitle(title)
399{
400}
401
402
403void
404AudioMixerListItem::AlterWindow(MediaWindow* window)
405{
406	window->SelectAudioMixer(fTitle);
407}
408
409
410void
411AudioMixerListItem::Accept(MediaListItem::Visitor& visitor)
412{
413	visitor.Visit(this);
414}
415
416
417int
418AudioMixerListItem::CompareWith(MediaListItem* item)
419{
420	Comparator comparator(this);
421	item->Accept(comparator);
422	return comparator.result;
423}
424
425
426AudioMixerListItem::Comparator::Comparator(AudioMixerListItem* compareOthersTo)
427	:
428	result(0),
429	fTarget(compareOthersTo)
430{
431}
432
433
434void
435AudioMixerListItem::Comparator::Visit(NodeListItem* item)
436{
437	result = GREATER_THAN;
438}
439
440
441void
442AudioMixerListItem::Comparator::Visit(DeviceListItem* item)
443{
444	result = GREATER_THAN;
445	if (item->Type() == AUDIO_TYPE)
446		result = LESS_THAN;
447}
448
449
450void
451AudioMixerListItem::Comparator::Visit(AudioMixerListItem* item)
452{
453	result = 0;
454}
455
456
457void
458AudioMixerListItem::SetRenderParameters(Renderer& renderer)
459{
460	renderer.AddIcon(&Icons()->mixerIcon);
461}
462