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 && fPrimaryIcon) { 102 onto->DrawBitmap(fPrimaryIcon, iconFrame); 103 point.x = iconFrame.right + 1; 104 } 105 106 onto->SetDrawingMode(B_OP_COPY); 107 108 BFont font = be_plain_font; 109 font_height fontInfo; 110 font.GetHeight(&fontInfo); 111 112 onto->SetFont(&font); 113 onto->MovePenTo(point.x + 8, frame.top 114 + fontInfo.ascent + (frame.Height() 115 - ceilf(fontInfo.ascent + fontInfo.descent)) / 2.0f); 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 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 void 311 NodeListItem::Comparator::Visit(MidiListItem* item) 312 { 313 result = GREATER_THAN; 314 } 315 316 317 // #pragma mark - DeviceListItem 318 319 320 DeviceListItem::DeviceListItem(const char* title, 321 MediaListItem::media_type type) 322 : 323 MediaListItem(), 324 fTitle(title), 325 fMediaType(type) 326 { 327 } 328 329 330 void 331 DeviceListItem::Accept(MediaListItem::Visitor& visitor) 332 { 333 visitor.Visit(this); 334 } 335 336 337 int 338 DeviceListItem::CompareWith(MediaListItem* item) 339 { 340 Comparator comparator(this); 341 item->Accept(comparator); 342 return comparator.result; 343 } 344 345 346 DeviceListItem::Comparator::Comparator(DeviceListItem* compareOthersTo) 347 : 348 result(GREATER_THAN), 349 fTarget(compareOthersTo) 350 { 351 } 352 353 354 void 355 DeviceListItem::Comparator::Visit(NodeListItem* item) 356 { 357 result = GREATER_THAN; 358 if (fTarget->Type() != item->Type() && fTarget->Type() == AUDIO_TYPE) 359 result = LESS_THAN; 360 } 361 362 363 void 364 DeviceListItem::Comparator::Visit(DeviceListItem* item) 365 { 366 result = LESS_THAN; 367 if (fTarget->Type() == AUDIO_TYPE) 368 result = GREATER_THAN; 369 } 370 371 372 void 373 DeviceListItem::Comparator::Visit(AudioMixerListItem* item) 374 { 375 result = LESS_THAN; 376 if (fTarget->Type() == AUDIO_TYPE) 377 result = GREATER_THAN; 378 } 379 380 381 void 382 DeviceListItem::Comparator::Visit(MidiListItem* item) 383 { 384 result = LESS_THAN; 385 } 386 387 388 void 389 DeviceListItem::SetRenderParameters(Renderer& renderer) 390 { 391 renderer.AddIcon(&Icons()->devicesIcon); 392 renderer.UseDoubleInset(false); 393 } 394 395 396 void 397 DeviceListItem::AlterWindow(MediaWindow* window) 398 { 399 if (fMediaType == MediaListItem::AUDIO_TYPE) 400 window->SelectAudioSettings(fTitle); 401 else 402 window->SelectVideoSettings(fTitle); 403 } 404 405 406 // #pragma mark - AudioMixerListItem 407 408 409 AudioMixerListItem::AudioMixerListItem(const char* title) 410 : 411 MediaListItem(), 412 fTitle(title) 413 { 414 } 415 416 417 void 418 AudioMixerListItem::AlterWindow(MediaWindow* window) 419 { 420 window->SelectAudioMixer(fTitle); 421 } 422 423 424 void 425 AudioMixerListItem::Accept(MediaListItem::Visitor& visitor) 426 { 427 visitor.Visit(this); 428 } 429 430 431 int 432 AudioMixerListItem::CompareWith(MediaListItem* item) 433 { 434 Comparator comparator(this); 435 item->Accept(comparator); 436 return comparator.result; 437 } 438 439 440 AudioMixerListItem::Comparator::Comparator(AudioMixerListItem* compareOthersTo) 441 : 442 result(0), 443 fTarget(compareOthersTo) 444 { 445 } 446 447 448 void 449 AudioMixerListItem::Comparator::Visit(NodeListItem* item) 450 { 451 result = GREATER_THAN; 452 } 453 454 455 void 456 AudioMixerListItem::Comparator::Visit(DeviceListItem* item) 457 { 458 result = GREATER_THAN; 459 if (item->Type() == AUDIO_TYPE) 460 result = LESS_THAN; 461 } 462 463 464 void 465 AudioMixerListItem::Comparator::Visit(AudioMixerListItem* item) 466 { 467 result = 0; 468 } 469 470 471 void 472 AudioMixerListItem::Comparator::Visit(MidiListItem* item) 473 { 474 result = GREATER_THAN; 475 } 476 477 478 void 479 AudioMixerListItem::SetRenderParameters(Renderer& renderer) 480 { 481 renderer.AddIcon(&Icons()->mixerIcon); 482 } 483 484 485 // #pragma mark - MidiListItem 486 487 MidiListItem::MidiListItem(const char* title) 488 : 489 MediaListItem(), 490 fTitle(title) 491 { 492 } 493 494 495 void 496 MidiListItem::AlterWindow(MediaWindow* window) 497 { 498 window->SelectMidiSettings(fTitle); 499 } 500 501 502 const char* 503 MidiListItem::Label() 504 { 505 return "MIDI"; 506 } 507 508 509 void 510 MidiListItem::Accept(MediaListItem::Visitor& visitor) 511 { 512 visitor.Visit(this); 513 } 514 515 516 int 517 MidiListItem::CompareWith(MediaListItem* item) 518 { 519 Comparator comparator(this); 520 item->Accept(comparator); 521 return comparator.result; 522 } 523 524 525 MidiListItem::Comparator::Comparator(MidiListItem* compareOthersTo) 526 : 527 result(0), 528 fTarget(compareOthersTo) 529 { 530 } 531 532 533 void 534 MidiListItem::Comparator::Visit(NodeListItem* item) 535 { 536 result = GREATER_THAN; 537 } 538 539 540 void 541 MidiListItem::Comparator::Visit(DeviceListItem* item) 542 { 543 result = GREATER_THAN; 544 if (item->Type() == AUDIO_TYPE) 545 result = LESS_THAN; 546 } 547 548 549 void 550 MidiListItem::Comparator::Visit(AudioMixerListItem* item) 551 { 552 result = LESS_THAN; 553 } 554 555 556 void 557 MidiListItem::Comparator::Visit(MidiListItem* item) 558 { 559 result = 0; 560 } 561 562 563 void 564 MidiListItem::SetRenderParameters(Renderer& renderer) 565 { 566 // TODO: Create a nice icon 567 renderer.AddIcon(&Icons()->mixerIcon); 568 } 569