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
32 MediaIcons* MediaListItem::sIcons = NULL;
33
34
35 struct MediaListItem::Renderer {
RendererMediaListItem::Renderer36 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.
AddIconMediaListItem::Renderer48 void AddIcon(BBitmap* icon)
49 {
50 if (!fPrimaryIcon)
51 fPrimaryIcon = icon;
52 else {
53 fSecondaryIcon = fPrimaryIcon;
54 fPrimaryIcon = icon;
55 }
56 }
57
SetTitleMediaListItem::Renderer58 void SetTitle(const char* title)
59 {
60 fTitle = title;
61 }
62
SetSelectedMediaListItem::Renderer63 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.
UseDoubleInsetMediaListItem::Renderer70 void UseDoubleInset(bool doubleInset)
71 {
72 fDoubleInsets = doubleInset;
73 }
74
RenderMediaListItem::Renderer75 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
ItemWidthMediaListItem::Renderer123 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
139 private:
140
141 const char* fTitle;
142 BBitmap* fPrimaryIcon;
143 BBitmap* fSecondaryIcon;
144 bool fDoubleInsets;
145 bool fSelected;
146 };
147
148
MediaListItem()149 MediaListItem::MediaListItem()
150 :
151 BListItem((uint32)0)
152 {
153 }
154
155
156 void
Update(BView * owner,const BFont * font)157 MediaListItem::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
175 void
DrawItem(BView * owner,BRect frame,bool complete)176 MediaListItem::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
186 int
Compare(const void * itemOne,const void * itemTwo)187 MediaListItem::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
NodeListItem(const dormant_node_info * node,media_type type)199 NodeListItem::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
210 void
SetRenderParameters(MediaListItem::Renderer & renderer)211 NodeListItem::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
224 const char*
Label()225 NodeListItem::Label()
226 {
227 return fNodeInfo->name;
228 }
229
230
231 void
SetMediaType(media_type type)232 NodeListItem::SetMediaType(media_type type)
233 {
234 fMediaType = type;
235 }
236
237
238 void
SetDefaultOutput(bool isDefault)239 NodeListItem::SetDefaultOutput(bool isDefault)
240 {
241 fIsDefaultOutput = isDefault;
242 }
243
244
245 void
SetDefaultInput(bool isDefault)246 NodeListItem::SetDefaultInput(bool isDefault)
247 {
248 fIsDefaultInput = isDefault;
249 }
250
251
252 void
AlterWindow(MediaWindow * window)253 NodeListItem::AlterWindow(MediaWindow* window)
254 {
255 window->SelectNode(fNodeInfo);
256 }
257
258
259 void
Accept(MediaListItem::Visitor & visitor)260 NodeListItem::Accept(MediaListItem::Visitor& visitor)
261 {
262 visitor.Visit(this);
263 }
264
265
266 int
CompareWith(MediaListItem * item)267 NodeListItem::CompareWith(MediaListItem* item)
268 {
269 Comparator comparator(this);
270 item->Accept(comparator);
271 return comparator.result;
272 }
273
274
Comparator(NodeListItem * compareOthersTo)275 NodeListItem::Comparator::Comparator(NodeListItem* compareOthersTo)
276 :
277 result(GREATER_THAN),
278 fTarget(compareOthersTo)
279 {
280 }
281
282
283 void
Visit(NodeListItem * item)284 NodeListItem::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
295 void
Visit(DeviceListItem * item)296 NodeListItem::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
304 void
Visit(AudioMixerListItem * item)305 NodeListItem::Comparator::Visit(AudioMixerListItem* item)
306 {
307 result = LESS_THAN;
308 }
309
310
311 void
Visit(MidiListItem * item)312 NodeListItem::Comparator::Visit(MidiListItem* item)
313 {
314 result = GREATER_THAN;
315 }
316
317
318 // #pragma mark - DeviceListItem
319
320
DeviceListItem(const char * title,MediaListItem::media_type type)321 DeviceListItem::DeviceListItem(const char* title,
322 MediaListItem::media_type type)
323 :
324 MediaListItem(),
325 fTitle(title),
326 fMediaType(type)
327 {
328 }
329
330
331 void
Accept(MediaListItem::Visitor & visitor)332 DeviceListItem::Accept(MediaListItem::Visitor& visitor)
333 {
334 visitor.Visit(this);
335 }
336
337
338 int
CompareWith(MediaListItem * item)339 DeviceListItem::CompareWith(MediaListItem* item)
340 {
341 Comparator comparator(this);
342 item->Accept(comparator);
343 return comparator.result;
344 }
345
346
Comparator(DeviceListItem * compareOthersTo)347 DeviceListItem::Comparator::Comparator(DeviceListItem* compareOthersTo)
348 :
349 result(GREATER_THAN),
350 fTarget(compareOthersTo)
351 {
352 }
353
354
355 void
Visit(NodeListItem * item)356 DeviceListItem::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
364 void
Visit(DeviceListItem * item)365 DeviceListItem::Comparator::Visit(DeviceListItem* item)
366 {
367 result = LESS_THAN;
368 if (fTarget->Type() == AUDIO_TYPE)
369 result = GREATER_THAN;
370 }
371
372
373 void
Visit(AudioMixerListItem * item)374 DeviceListItem::Comparator::Visit(AudioMixerListItem* item)
375 {
376 result = LESS_THAN;
377 if (fTarget->Type() == AUDIO_TYPE)
378 result = GREATER_THAN;
379 }
380
381
382 void
Visit(MidiListItem * item)383 DeviceListItem::Comparator::Visit(MidiListItem* item)
384 {
385 result = LESS_THAN;
386 }
387
388
389 void
SetRenderParameters(Renderer & renderer)390 DeviceListItem::SetRenderParameters(Renderer& renderer)
391 {
392 renderer.AddIcon(&Icons()->devicesIcon);
393 renderer.UseDoubleInset(false);
394 }
395
396
397 void
AlterWindow(MediaWindow * window)398 DeviceListItem::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
AudioMixerListItem(const char * title)410 AudioMixerListItem::AudioMixerListItem(const char* title)
411 :
412 MediaListItem(),
413 fTitle(title)
414 {
415 }
416
417
418 void
AlterWindow(MediaWindow * window)419 AudioMixerListItem::AlterWindow(MediaWindow* window)
420 {
421 window->SelectAudioMixer(fTitle);
422 }
423
424
425 void
Accept(MediaListItem::Visitor & visitor)426 AudioMixerListItem::Accept(MediaListItem::Visitor& visitor)
427 {
428 visitor.Visit(this);
429 }
430
431
432 int
CompareWith(MediaListItem * item)433 AudioMixerListItem::CompareWith(MediaListItem* item)
434 {
435 Comparator comparator(this);
436 item->Accept(comparator);
437 return comparator.result;
438 }
439
440
Comparator(AudioMixerListItem * compareOthersTo)441 AudioMixerListItem::Comparator::Comparator(AudioMixerListItem* compareOthersTo)
442 :
443 result(0),
444 fTarget(compareOthersTo)
445 {
446 }
447
448
449 void
Visit(NodeListItem * item)450 AudioMixerListItem::Comparator::Visit(NodeListItem* item)
451 {
452 result = GREATER_THAN;
453 }
454
455
456 void
Visit(DeviceListItem * item)457 AudioMixerListItem::Comparator::Visit(DeviceListItem* item)
458 {
459 result = GREATER_THAN;
460 if (item->Type() == AUDIO_TYPE)
461 result = LESS_THAN;
462 }
463
464
465 void
Visit(AudioMixerListItem * item)466 AudioMixerListItem::Comparator::Visit(AudioMixerListItem* item)
467 {
468 result = 0;
469 }
470
471
472 void
Visit(MidiListItem * item)473 AudioMixerListItem::Comparator::Visit(MidiListItem* item)
474 {
475 result = GREATER_THAN;
476 }
477
478
479 void
SetRenderParameters(Renderer & renderer)480 AudioMixerListItem::SetRenderParameters(Renderer& renderer)
481 {
482 renderer.AddIcon(&Icons()->mixerIcon);
483 }
484
485
486 // #pragma mark - MidiListItem
487
MidiListItem(const char * title)488 MidiListItem::MidiListItem(const char* title)
489 :
490 MediaListItem(),
491 fTitle(title)
492 {
493 }
494
495
496 void
AlterWindow(MediaWindow * window)497 MidiListItem::AlterWindow(MediaWindow* window)
498 {
499 window->SelectMidiSettings(fTitle);
500 }
501
502
503 const char*
Label()504 MidiListItem::Label()
505 {
506 return "MIDI";
507 }
508
509
510 void
Accept(MediaListItem::Visitor & visitor)511 MidiListItem::Accept(MediaListItem::Visitor& visitor)
512 {
513 visitor.Visit(this);
514 }
515
516
517 int
CompareWith(MediaListItem * item)518 MidiListItem::CompareWith(MediaListItem* item)
519 {
520 Comparator comparator(this);
521 item->Accept(comparator);
522 return comparator.result;
523 }
524
525
Comparator(MidiListItem * compareOthersTo)526 MidiListItem::Comparator::Comparator(MidiListItem* compareOthersTo)
527 :
528 result(0),
529 fTarget(compareOthersTo)
530 {
531 }
532
533
534 void
Visit(NodeListItem * item)535 MidiListItem::Comparator::Visit(NodeListItem* item)
536 {
537 result = GREATER_THAN;
538 }
539
540
541 void
Visit(DeviceListItem * item)542 MidiListItem::Comparator::Visit(DeviceListItem* item)
543 {
544 result = GREATER_THAN;
545 if (item->Type() == AUDIO_TYPE)
546 result = LESS_THAN;
547 }
548
549
550 void
Visit(AudioMixerListItem * item)551 MidiListItem::Comparator::Visit(AudioMixerListItem* item)
552 {
553 result = LESS_THAN;
554 }
555
556
557 void
Visit(MidiListItem * item)558 MidiListItem::Comparator::Visit(MidiListItem* item)
559 {
560 result = 0;
561 }
562
563
564 void
SetRenderParameters(Renderer & renderer)565 MidiListItem::SetRenderParameters(Renderer& renderer)
566 {
567 // TODO: Create a nice icon
568 renderer.AddIcon(&Icons()->mixerIcon);
569 }
570