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