1 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 2 // 3 // Copyright (c) 2003, OpenBeOS 4 // 5 // This software is part of the OpenBeOS 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 { 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 139 private: 140 141 const char* fTitle; 142 BBitmap* fPrimaryIcon; 143 BBitmap* fSecondaryIcon; 144 bool fDoubleInsets; 145 bool fSelected; 146 }; 147 148 149 MediaListItem::MediaListItem() 150 : 151 BListItem((uint32)0) 152 { 153 } 154 155 156 void 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 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 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 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 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* 225 NodeListItem::Label() 226 { 227 return fNodeInfo->name; 228 } 229 230 231 void 232 NodeListItem::SetMediaType(media_type type) 233 { 234 fMediaType = type; 235 } 236 237 238 void 239 NodeListItem::SetDefaultOutput(bool isDefault) 240 { 241 fIsDefaultOutput = isDefault; 242 } 243 244 245 void 246 NodeListItem::SetDefaultInput(bool isDefault) 247 { 248 fIsDefaultInput = isDefault; 249 } 250 251 252 void 253 NodeListItem::AlterWindow(MediaWindow* window) 254 { 255 window->SelectNode(fNodeInfo); 256 } 257 258 259 void 260 NodeListItem::Accept(MediaListItem::Visitor& visitor) 261 { 262 visitor.Visit(this); 263 } 264 265 266 int 267 NodeListItem::CompareWith(MediaListItem* item) 268 { 269 Comparator comparator(this); 270 item->Accept(comparator); 271 return comparator.result; 272 } 273 274 275 NodeListItem::Comparator::Comparator(NodeListItem* compareOthersTo) 276 : 277 result(GREATER_THAN), 278 fTarget(compareOthersTo) 279 { 280 } 281 282 283 void 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 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 305 NodeListItem::Comparator::Visit(AudioMixerListItem* item) 306 { 307 result = LESS_THAN; 308 } 309 310 311 void 312 NodeListItem::Comparator::Visit(MidiListItem* item) 313 { 314 result = GREATER_THAN; 315 } 316 317 318 // #pragma mark - DeviceListItem 319 320 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 332 DeviceListItem::Accept(MediaListItem::Visitor& visitor) 333 { 334 visitor.Visit(this); 335 } 336 337 338 int 339 DeviceListItem::CompareWith(MediaListItem* item) 340 { 341 Comparator comparator(this); 342 item->Accept(comparator); 343 return comparator.result; 344 } 345 346 347 DeviceListItem::Comparator::Comparator(DeviceListItem* compareOthersTo) 348 : 349 result(GREATER_THAN), 350 fTarget(compareOthersTo) 351 { 352 } 353 354 355 void 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 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 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 383 DeviceListItem::Comparator::Visit(MidiListItem* item) 384 { 385 result = LESS_THAN; 386 } 387 388 389 void 390 DeviceListItem::SetRenderParameters(Renderer& renderer) 391 { 392 renderer.AddIcon(&Icons()->devicesIcon); 393 renderer.UseDoubleInset(false); 394 } 395 396 397 void 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 410 AudioMixerListItem::AudioMixerListItem(const char* title) 411 : 412 MediaListItem(), 413 fTitle(title) 414 { 415 } 416 417 418 void 419 AudioMixerListItem::AlterWindow(MediaWindow* window) 420 { 421 window->SelectAudioMixer(fTitle); 422 } 423 424 425 void 426 AudioMixerListItem::Accept(MediaListItem::Visitor& visitor) 427 { 428 visitor.Visit(this); 429 } 430 431 432 int 433 AudioMixerListItem::CompareWith(MediaListItem* item) 434 { 435 Comparator comparator(this); 436 item->Accept(comparator); 437 return comparator.result; 438 } 439 440 441 AudioMixerListItem::Comparator::Comparator(AudioMixerListItem* compareOthersTo) 442 : 443 result(0), 444 fTarget(compareOthersTo) 445 { 446 } 447 448 449 void 450 AudioMixerListItem::Comparator::Visit(NodeListItem* item) 451 { 452 result = GREATER_THAN; 453 } 454 455 456 void 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 466 AudioMixerListItem::Comparator::Visit(AudioMixerListItem* item) 467 { 468 result = 0; 469 } 470 471 472 void 473 AudioMixerListItem::Comparator::Visit(MidiListItem* item) 474 { 475 result = GREATER_THAN; 476 } 477 478 479 void 480 AudioMixerListItem::SetRenderParameters(Renderer& renderer) 481 { 482 renderer.AddIcon(&Icons()->mixerIcon); 483 } 484 485 486 // #pragma mark - MidiListItem 487 488 MidiListItem::MidiListItem(const char* title) 489 : 490 MediaListItem(), 491 fTitle(title) 492 { 493 } 494 495 496 void 497 MidiListItem::AlterWindow(MediaWindow* window) 498 { 499 window->SelectMidiSettings(fTitle); 500 } 501 502 503 const char* 504 MidiListItem::Label() 505 { 506 return "MIDI"; 507 } 508 509 510 void 511 MidiListItem::Accept(MediaListItem::Visitor& visitor) 512 { 513 visitor.Visit(this); 514 } 515 516 517 int 518 MidiListItem::CompareWith(MediaListItem* item) 519 { 520 Comparator comparator(this); 521 item->Accept(comparator); 522 return comparator.result; 523 } 524 525 526 MidiListItem::Comparator::Comparator(MidiListItem* compareOthersTo) 527 : 528 result(0), 529 fTarget(compareOthersTo) 530 { 531 } 532 533 534 void 535 MidiListItem::Comparator::Visit(NodeListItem* item) 536 { 537 result = GREATER_THAN; 538 } 539 540 541 void 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 551 MidiListItem::Comparator::Visit(AudioMixerListItem* item) 552 { 553 result = LESS_THAN; 554 } 555 556 557 void 558 MidiListItem::Comparator::Visit(MidiListItem* item) 559 { 560 result = 0; 561 } 562 563 564 void 565 MidiListItem::SetRenderParameters(Renderer& renderer) 566 { 567 // TODO: Create a nice icon 568 renderer.AddIcon(&Icons()->mixerIcon); 569 } 570