xref: /haiku/src/preferences/media/MediaListItem.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
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 
31 MediaIcons* MediaListItem::sIcons = NULL;
32 
33 
34 struct 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) + 3.0f;
135 		return width;
136 	}
137 
138 private:
139 
140 	const char*	fTitle;
141 	BBitmap*	fPrimaryIcon;
142 	BBitmap*	fSecondaryIcon;
143 	bool		fDoubleInsets;
144 	bool		fSelected;
145 };
146 
147 
148 MediaListItem::MediaListItem()
149 	:
150 	BListItem((uint32)0)
151 {
152 }
153 
154 
155 void
156 MediaListItem::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 
174 void
175 MediaListItem::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 
185 int
186 MediaListItem::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 
198 NodeListItem::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 
209 void
210 NodeListItem::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 
223 const char*
224 NodeListItem::Label()
225 {
226 	return fNodeInfo->name;
227 }
228 
229 
230 void
231 NodeListItem::SetMediaType(media_type type)
232 {
233 	fMediaType = type;
234 }
235 
236 
237 void
238 NodeListItem::SetDefaultOutput(bool isDefault)
239 {
240 	fIsDefaultOutput = isDefault;
241 }
242 
243 
244 void
245 NodeListItem::SetDefaultInput(bool isDefault)
246 {
247 	fIsDefaultInput = isDefault;
248 }
249 
250 
251 void
252 NodeListItem::AlterWindow(MediaWindow* window)
253 {
254 	window->SelectNode(fNodeInfo);
255 }
256 
257 
258 void
259 NodeListItem::Accept(MediaListItem::Visitor& visitor)
260 {
261 	visitor.Visit(this);
262 }
263 
264 
265 int
266 NodeListItem::CompareWith(MediaListItem* item)
267 {
268 	Comparator comparator(this);
269 	item->Accept(comparator);
270 	return comparator.result;
271 }
272 
273 
274 NodeListItem::Comparator::Comparator(NodeListItem* compareOthersTo)
275 	:
276 	result(GREATER_THAN),
277 	fTarget(compareOthersTo)
278 {
279 }
280 
281 
282 void
283 NodeListItem::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 
294 void
295 NodeListItem::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 
303 void
304 NodeListItem::Comparator::Visit(AudioMixerListItem* item)
305 {
306 	result = LESS_THAN;
307 }
308 
309 
310 // #pragma mark - DeviceListItem
311 
312 
313 DeviceListItem::DeviceListItem(const char* title,
314 	MediaListItem::media_type type)
315 	:
316 	MediaListItem(),
317 	fTitle(title),
318 	fMediaType(type)
319 {
320 }
321 
322 
323 void
324 DeviceListItem::Accept(MediaListItem::Visitor& visitor)
325 {
326 	visitor.Visit(this);
327 }
328 
329 
330 int
331 DeviceListItem::CompareWith(MediaListItem* item)
332 {
333 	Comparator comparator(this);
334 	item->Accept(comparator);
335 	return comparator.result;
336 }
337 
338 
339 DeviceListItem::Comparator::Comparator(DeviceListItem* compareOthersTo)
340 	:
341 	result(GREATER_THAN),
342 	fTarget(compareOthersTo)
343 {
344 }
345 
346 
347 void
348 DeviceListItem::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 
356 void
357 DeviceListItem::Comparator::Visit(DeviceListItem* item)
358 {
359 	result = LESS_THAN;
360 	if (fTarget->Type() == AUDIO_TYPE)
361 		result = GREATER_THAN;
362 }
363 
364 
365 void
366 DeviceListItem::Comparator::Visit(AudioMixerListItem* item)
367 {
368 	result = LESS_THAN;
369 	if (fTarget->Type() == AUDIO_TYPE)
370 		result = GREATER_THAN;
371 }
372 
373 
374 void
375 DeviceListItem::SetRenderParameters(Renderer& renderer)
376 {
377 	renderer.AddIcon(&Icons()->devicesIcon);
378 	renderer.UseDoubleInset(false);
379 }
380 
381 
382 void
383 DeviceListItem::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 
395 AudioMixerListItem::AudioMixerListItem(const char* title)
396 	:
397 	MediaListItem(),
398 	fTitle(title)
399 {
400 }
401 
402 
403 void
404 AudioMixerListItem::AlterWindow(MediaWindow* window)
405 {
406 	window->SelectAudioMixer(fTitle);
407 }
408 
409 
410 void
411 AudioMixerListItem::Accept(MediaListItem::Visitor& visitor)
412 {
413 	visitor.Visit(this);
414 }
415 
416 
417 int
418 AudioMixerListItem::CompareWith(MediaListItem* item)
419 {
420 	Comparator comparator(this);
421 	item->Accept(comparator);
422 	return comparator.result;
423 }
424 
425 
426 AudioMixerListItem::Comparator::Comparator(AudioMixerListItem* compareOthersTo)
427 	:
428 	result(0),
429 	fTarget(compareOthersTo)
430 {
431 }
432 
433 
434 void
435 AudioMixerListItem::Comparator::Visit(NodeListItem* item)
436 {
437 	result = GREATER_THAN;
438 }
439 
440 
441 void
442 AudioMixerListItem::Comparator::Visit(DeviceListItem* item)
443 {
444 	result = GREATER_THAN;
445 	if (item->Type() == AUDIO_TYPE)
446 		result = LESS_THAN;
447 }
448 
449 
450 void
451 AudioMixerListItem::Comparator::Visit(AudioMixerListItem* item)
452 {
453 	result = 0;
454 }
455 
456 
457 void
458 AudioMixerListItem::SetRenderParameters(Renderer& renderer)
459 {
460 	renderer.AddIcon(&Icons()->mixerIcon);
461 }
462