From 7afc7756306b3fd9667d03fba787e3aa8b60cab5 Mon Sep 17 00:00:00 2001 From: Alex Wilson Date: Wed, 5 Jan 2011 20:47:17 +0000 Subject: [PATCH] In Media preflet: * Modify MediaListItem to use the visitor pattern * Use the visitor pattern for comparison of MediaListItem subclassed objects * Use the visitor pattern in MediaWindow to propagate changes to NodeListItems. * Rename and/or remove some message constants * Rename SettingsItem class to NodeMenuItem * Rename Settings2Item class to ChannelMenuItem * Derive SettingsView from BGridView, and make it an abstract base class for two new classes, AudioSettingsView and VideoSettingsView. * Have the SettingsView subclasses handle messages originating from their children (for the most part). * Use a BCardLayout to hold our Audio/Video SettingsViews and our instantiated node view (when applicable). * small changes git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40127 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/preferences/media/Media.cpp | 2 +- src/preferences/media/MediaListItem.cpp | 159 ++++-- src/preferences/media/MediaListItem.h | 89 +-- src/preferences/media/MediaViews.cpp | 686 ++++++++++++++++++------ src/preferences/media/MediaViews.h | 128 ++++- src/preferences/media/MediaWindow.cpp | 375 +++++-------- src/preferences/media/MediaWindow.h | 23 +- 7 files changed, 928 insertions(+), 534 deletions(-) diff --git a/src/preferences/media/Media.cpp b/src/preferences/media/Media.cpp index 52d9213a10..3aeb3b53ed 100644 --- a/src/preferences/media/Media.cpp +++ b/src/preferences/media/Media.cpp @@ -57,8 +57,8 @@ Media::Media() } } - fWindow = new MediaWindow(rect); MediaListItem::SetIcons(&fIcons); + fWindow = new MediaWindow(rect); be_roster->StartWatching(BMessenger(this)); } diff --git a/src/preferences/media/MediaListItem.cpp b/src/preferences/media/MediaListItem.cpp index c5cf0b1998..02cb7b2740 100644 --- a/src/preferences/media/MediaListItem.cpp +++ b/src/preferences/media/MediaListItem.cpp @@ -174,11 +174,10 @@ MediaListItem::Compare(const void* itemOne, const void* itemTwo) // #pragma mark - NodeListItem -NodeListItem::NodeListItem(dormant_node_info* node, media_type type) +NodeListItem::NodeListItem(const dormant_node_info* node, media_type type) : MediaListItem(), fNodeInfo(node), - fIsAudioMixer(false), fMediaType(type), fIsDefaultInput(false), fIsDefaultOutput(false) @@ -189,19 +188,14 @@ NodeListItem::NodeListItem(dormant_node_info* node, media_type type) void NodeListItem::SetRenderParameters(MediaListItem::Renderer& renderer) { + MediaIcons::IconSet* iconSet = &Icons()->videoIcons; + if (fMediaType == MediaListItem::AUDIO_TYPE) + iconSet = &Icons()->audioIcons; - if (fIsAudioMixer) { - renderer.AddIcon(&Icons()->mixerIcon); - } else { - MediaIcons::IconSet* iconSet = &Icons()->videoIcons; - if (fMediaType == MediaListItem::AUDIO_TYPE) - iconSet = &Icons()->audioIcons; - - if (fIsDefaultInput) - renderer.AddIcon(&iconSet->inputIcon); - if (fIsDefaultOutput) - renderer.AddIcon(&iconSet->outputIcon); - } + if (fIsDefaultInput) + renderer.AddIcon(&iconSet->inputIcon); + if (fIsDefaultOutput) + renderer.AddIcon(&iconSet->outputIcon); } @@ -240,40 +234,55 @@ NodeListItem::AlterWindow(MediaWindow* window) } +void +NodeListItem::Accept(MediaListItem::Visitor& visitor) +{ + visitor.Visit(this); +} + + int NodeListItem::CompareWith(MediaListItem* item) { - return item->CompareWith(this) * -1; + Comparator comparator(this); + item->Accept(comparator); + return comparator.result; } -int -NodeListItem::CompareWith(NodeListItem* item) +NodeListItem::Comparator::Comparator(NodeListItem* compareOthersTo) + : + result(GREATER_THAN), + fTarget(compareOthersTo) { - if (fMediaType != item->fMediaType) - return fMediaType == AUDIO_TYPE ? GREATER_THAN : LESS_THAN; - - if (fIsAudioMixer != item->fIsAudioMixer) - return fIsAudioMixer ? GREATER_THAN : LESS_THAN; - - return strcmp(Label(), item->Label()); } -int -NodeListItem::CompareWith(DeviceListItem* deviceItem) +void +NodeListItem::Comparator::Visit(NodeListItem* item) { - if (fMediaType != deviceItem->Type()) - return fMediaType == AUDIO_TYPE ? GREATER_THAN : LESS_THAN; + result = GREATER_THAN; + + if (fTarget->Type() != item->Type() && fTarget->Type() == VIDEO_TYPE) + result = LESS_THAN; else - return LESS_THAN; + result = strcmp(fTarget->Label(), item->Label()); } -int -NodeListItem::CompareWith(AudioMixerListItem* item) +void +NodeListItem::Comparator::Visit(DeviceListItem* item) { - return LESS_THAN; + result = LESS_THAN; + if (fTarget->Type() != item->Type() && fTarget->Type() == AUDIO_TYPE) + result = GREATER_THAN; +} + + +void +NodeListItem::Comparator::Visit(AudioMixerListItem* item) +{ + result = LESS_THAN; } @@ -290,35 +299,54 @@ DeviceListItem::DeviceListItem(const char* title, } +void +DeviceListItem::Accept(MediaListItem::Visitor& visitor) +{ + visitor.Visit(this); +} + + int DeviceListItem::CompareWith(MediaListItem* item) { - return item->CompareWith(this) * -1; + Comparator comparator(this); + item->Accept(comparator); + return comparator.result; } -int -DeviceListItem::CompareWith(NodeListItem* item) +DeviceListItem::Comparator::Comparator(DeviceListItem* compareOthersTo) + : + result(GREATER_THAN), + fTarget(compareOthersTo) { - // let NodeListItem do the work - return item->CompareWith(this) * -1; } -int -DeviceListItem::CompareWith(DeviceListItem* item) +void +DeviceListItem::Comparator::Visit(NodeListItem* item) { - if (fMediaType == MediaListItem::AUDIO_TYPE) - return GREATER_THAN; - return LESS_THAN; + result = GREATER_THAN; + if (fTarget->Type() != item->Type() && fTarget->Type() == AUDIO_TYPE) + result = LESS_THAN; } -int -DeviceListItem::CompareWith(AudioMixerListItem* item) +void +DeviceListItem::Comparator::Visit(DeviceListItem* item) { - // let AudioMixerListItem do the work too! - return item->CompareWith(this) * -1; + result = LESS_THAN; + if (fTarget->Type() == AUDIO_TYPE) + result = GREATER_THAN; +} + + +void +DeviceListItem::Comparator::Visit(AudioMixerListItem* item) +{ + result = LESS_THAN; + if (fTarget->Type() == AUDIO_TYPE) + result = GREATER_THAN; } @@ -358,33 +386,50 @@ AudioMixerListItem::AlterWindow(MediaWindow* window) } +void +AudioMixerListItem::Accept(MediaListItem::Visitor& visitor) +{ + visitor.Visit(this); +} + + int AudioMixerListItem::CompareWith(MediaListItem* item) { - return item->CompareWith(this) * -1; + Comparator comparator(this); + item->Accept(comparator); + return comparator.result; } -int -AudioMixerListItem::CompareWith(NodeListItem* item) +AudioMixerListItem::Comparator::Comparator(AudioMixerListItem* compareOthersTo) + : + result(0), + fTarget(compareOthersTo) { - return GREATER_THAN; } -int -AudioMixerListItem::CompareWith(DeviceListItem* item) +void +AudioMixerListItem::Comparator::Visit(NodeListItem* item) { + result = GREATER_THAN; +} + + +void +AudioMixerListItem::Comparator::Visit(DeviceListItem* item) +{ + result = GREATER_THAN; if (item->Type() == AUDIO_TYPE) - return LESS_THAN; - return GREATER_THAN; + result = LESS_THAN; } -int -AudioMixerListItem::CompareWith(AudioMixerListItem* item) +void +AudioMixerListItem::Comparator::Visit(AudioMixerListItem* item) { - return 0; + result = 0; } diff --git a/src/preferences/media/MediaListItem.h b/src/preferences/media/MediaListItem.h index 591e1459db..fa71875773 100644 --- a/src/preferences/media/MediaListItem.h +++ b/src/preferences/media/MediaListItem.h @@ -44,9 +44,6 @@ public: virtual void Update(BView* owner, const BFont* font); virtual void DrawItem(BView* owner, BRect frame, bool complete = false); - - // TODO: refactor and remove this: - virtual dormant_node_info* NodeInfo() = 0; virtual const char* Label() = 0; @@ -54,16 +51,20 @@ public: static MediaIcons* Icons() {return sIcons;} static void SetIcons(MediaIcons* icons) {sIcons = icons;} - static int Compare(const void* itemOne, - const void* itemTwo); + struct Visitor { + virtual void Visit(AudioMixerListItem* item) = 0; + virtual void Visit(DeviceListItem* item) = 0; + virtual void Visit(NodeListItem* item) = 0; + }; - // use double dispatch for comparison, - // returning item->CompareWith(this) * -1 + virtual void Accept(Visitor& visitor) = 0; + + // use the visitor pattern for comparison, // -1 : < item; 0 : == item; 1 : > item virtual int CompareWith(MediaListItem* item) = 0; - virtual int CompareWith(NodeListItem* item) = 0; - virtual int CompareWith(DeviceListItem* item) = 0; - virtual int CompareWith(AudioMixerListItem* item) = 0; + + static int Compare(const void* itemOne, + const void* itemTwo); protected: struct Renderer; @@ -78,7 +79,7 @@ private: class NodeListItem : public MediaListItem { public: - NodeListItem(dormant_node_info* node, + NodeListItem(const dormant_node_info* node, media_type type); void SetMediaType(MediaListItem::media_type type); @@ -89,25 +90,32 @@ public: virtual void AlterWindow(MediaWindow* window); - // TODO: refactor and remove this: - virtual dormant_node_info* NodeInfo(){return fNodeInfo;} - virtual const char* Label(); media_type Type() {return fMediaType;} - virtual int CompareWith(MediaListItem* item); + virtual void Accept(MediaListItem::Visitor& visitor); + + struct Comparator : public MediaListItem::Visitor { + Comparator(NodeListItem* compareOthersTo); + virtual void Visit(NodeListItem* item); + virtual void Visit(DeviceListItem* item); + virtual void Visit(AudioMixerListItem* item); + + int result; + // -1 : < item; 0 : == item; 1 : > item + private: + NodeListItem* fTarget; + }; // -1 : < item; 0 : == item; 1 : > item - virtual int CompareWith(NodeListItem* item); - virtual int CompareWith(DeviceListItem* item); - virtual int CompareWith(AudioMixerListItem* item); + virtual int CompareWith(MediaListItem* item); private: virtual void SetRenderParameters(Renderer& renderer); - dormant_node_info* fNodeInfo; - bool fIsAudioMixer; + const dormant_node_info* fNodeInfo; + media_type fMediaType; bool fIsDefaultInput; bool fIsDefaultOutput; @@ -120,19 +128,24 @@ public: MediaListItem::media_type type); MediaListItem::media_type Type() {return fMediaType;} - - // TODO: refactor and remove this: - virtual dormant_node_info* NodeInfo(){return NULL;} virtual const char* Label() {return fTitle;} - virtual void AlterWindow(MediaWindow* window); + virtual void Accept(MediaListItem::Visitor& visitor); - virtual int CompareWith(MediaListItem* item); + struct Comparator : public MediaListItem::Visitor { + Comparator(DeviceListItem* compareOthersTo); + virtual void Visit(NodeListItem* item); + virtual void Visit(DeviceListItem* item); + virtual void Visit(AudioMixerListItem* item); + + int result; + // -1 : < item; 0 : == item; 1 : > item + private: + DeviceListItem* fTarget; + }; // -1 : < item; 0 : == item; 1 : > item - virtual int CompareWith(NodeListItem* item); - virtual int CompareWith(DeviceListItem* item); - virtual int CompareWith(AudioMixerListItem* item); + virtual int CompareWith(MediaListItem* item); private: virtual void SetRenderParameters(Renderer& renderer); @@ -146,19 +159,25 @@ class AudioMixerListItem : public MediaListItem { public: AudioMixerListItem(const char* title); - // TODO: refactor and remove this: - virtual dormant_node_info* NodeInfo(){return NULL;} virtual const char* Label() {return fTitle;} - virtual void AlterWindow(MediaWindow* window); + virtual void Accept(MediaListItem::Visitor& visitor); - virtual int CompareWith(MediaListItem* item); + struct Comparator : public MediaListItem::Visitor { + Comparator(AudioMixerListItem* compareOthersTo); + virtual void Visit(NodeListItem* item); + virtual void Visit(DeviceListItem* item); + virtual void Visit(AudioMixerListItem* item); + + int result; + // -1 : < item; 0 : == item; 1 : > item + private: + AudioMixerListItem* fTarget; + }; // -1 : < item; 0 : == item; 1 : > item - virtual int CompareWith(NodeListItem* item); - virtual int CompareWith(DeviceListItem* item); - virtual int CompareWith(AudioMixerListItem* item); + virtual int CompareWith(MediaListItem* item); private: virtual void SetRenderParameters(Renderer& renderer); diff --git a/src/preferences/media/MediaViews.cpp b/src/preferences/media/MediaViews.cpp index 7ea5d48474..c1a3957cab 100644 --- a/src/preferences/media/MediaViews.cpp +++ b/src/preferences/media/MediaViews.cpp @@ -12,248 +12,287 @@ // Created : June 25, 2003 // // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ - - #include "MediaViews.h" +#include #include #include #include +#include #include #include -#include -#include +#include #include #include #include #include #include -#include #include +#include #include +#include #include +#include "MediaWindow.h" + #undef B_TRANSLATE_CONTEXT #define B_TRANSLATE_CONTEXT "Media views" +#define MEDIA_DEFAULT_INPUT_CHANGE 'dich' +#define MEDIA_DEFAULT_OUTPUT_CHANGE 'doch' +#define MEDIA_SHOW_HIDE_VOLUME_CONTROL 'shvc' -SettingsView::SettingsView (bool isVideo) + +SettingsView::SettingsView() : - BView("SettingsView", B_WILL_DRAW | B_SUPPORTS_LAYOUT), - fIsVideo(isVideo) + BGridView(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING), + fRealtimeCheckBox(NULL), + fInputMenu(NULL), + fOutputMenu(NULL), + fRestartView(NULL) { - SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - - // create the default box - // input menu fInputMenu = new BPopUpMenu(B_TRANSLATE("")); fInputMenu->SetLabelFromMarked(true); - BMenuField* inputMenuField = new BMenuField("inputMenuField", - fIsVideo ? B_TRANSLATE("Video input:") - : B_TRANSLATE("Audio input:"), fInputMenu, NULL); - // output menu + // input menu fOutputMenu = new BPopUpMenu(B_TRANSLATE("")); fOutputMenu->SetLabelFromMarked(true); - BMenuField* outputMenuField = new BMenuField("outputMenuField", - fIsVideo ? B_TRANSLATE("Video output:") - : B_TRANSLATE("Audio output:"), fOutputMenu, NULL); - - // channel menu (audio only) - BMenuField* channelMenuField = NULL; - if (!fIsVideo) { - fChannelMenu = new BPopUpMenu(B_TRANSLATE("")); - fChannelMenu->SetLabelFromMarked(true); - channelMenuField = new BMenuField("channelMenuField", - B_TRANSLATE("Channel:"), fChannelMenu, NULL); - channelMenuField->SetDivider(StringWidth(B_TRANSLATE("Channel:"))+5); - } - - BBox* defaultsBox = new BBox("defaults"); - defaultsBox->SetLabel(fIsVideo ? B_TRANSLATE("Default nodes") - : B_TRANSLATE("Defaults")); - - // put our menus in a BGridView in our BBox, this way, the BBox makes sure - // we have are not blocking the label. - BGridView* defaultsGridView = new BGridView(); - defaultsBox->AddChild(defaultsGridView); - - BGridLayout* defaultsGrid = defaultsGridView->GridLayout(); - defaultsGrid->SetInsets(B_USE_DEFAULT_SPACING, 0, B_USE_DEFAULT_SPACING, - B_USE_DEFAULT_SPACING); - - BLayoutItem* labelItem = inputMenuField->CreateLabelLayoutItem(); - BLayoutItem* menuItem = inputMenuField->CreateMenuBarLayoutItem(); - defaultsGrid->AddItem(labelItem, 0, 0, 1, 1); - defaultsGrid->AddItem(menuItem, 1, 0, 3, 1); - - int32 outputMenuWidth = 3; - if (channelMenuField) { - outputMenuWidth = 1; - labelItem = channelMenuField->CreateLabelLayoutItem(); - menuItem = channelMenuField->CreateMenuBarLayoutItem(); - defaultsGrid->AddItem(labelItem, 2, 1, 1, 1); - defaultsGrid->AddItem(menuItem, 3, 1, 1, 1); - } - - labelItem = outputMenuField->CreateLabelLayoutItem(); - menuItem = outputMenuField->CreateMenuBarLayoutItem(); - defaultsGrid->AddItem(labelItem, 0, 1, 1, 1); - defaultsGrid->AddItem(menuItem, 1, 1, outputMenuWidth, 1); +} - rgb_color red_color = {222, 32, 33}; - fRestartView = new BStringView("restartStringView", - B_TRANSLATE("Restart the media server to apply changes.")); - fRestartView->SetHighColor(red_color); - defaultsBox->AddChild(fRestartView); - fRestartView->Hide(); - +BBox* +SettingsView::MakeRealtimeBox(const char* info, uint32 realtimeMask, + const char* checkBoxLabel) +{ // create the realtime box BBox* realtimeBox = new BBox("realtime"); realtimeBox->SetLabel(B_TRANSLATE("Real-time")); - BMessage* message = new BMessage(ML_ENABLE_REAL_TIME); - message->AddBool("isVideo", fIsVideo); - fRealtimeCheckBox = new BCheckBox("realtimeCheckBox", - fIsVideo ? B_TRANSLATE("Enable real-time video") - : B_TRANSLATE("Enable real-time audio"), - message); + BMessage* checkBoxMessage = new BMessage(ML_ENABLE_REAL_TIME); + checkBoxMessage->AddUInt32("flags", realtimeMask); + fRealtimeCheckBox = new BCheckBox("realtimeCheckBox", checkBoxLabel, + checkBoxMessage); - uint32 flags; + uint32 flags = 0; BMediaRoster::Roster()->GetRealtimeFlags(&flags); - if (flags & (fIsVideo ? B_MEDIA_REALTIME_VIDEO : B_MEDIA_REALTIME_AUDIO)) + if (flags & realtimeMask) fRealtimeCheckBox->SetValue(B_CONTROL_ON); BTextView* textView = new BTextView("stringView"); - textView->Insert(fIsVideo ? B_TRANSLATE( - "Enabling real-time video allows system to " - "perform video operations as fast and smoothly as possible. It " - "achieves optimum performance by using more RAM." - "\n\nOnly enable this feature if you need the lowest latency possible.") - : B_TRANSLATE( - "Enabling real-time audio allows system to record and play audio " - "as fast as possible. It achieves this performance by using more" - " CPU and RAM.\n\nOnly enable this feature if you need the lowest" - " latency possible.")); - + textView->Insert(info); textView->MakeEditable(false); textView->MakeSelectable(false); textView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - BGroupLayout* realtimeBoxLayout = new BGroupLayout(B_VERTICAL, 5); - realtimeBoxLayout->SetInsets(10,10,10,10); - realtimeBox->SetLayout(realtimeBoxLayout); + BGroupView* realtimeGroup = new BGroupView(B_VERTICAL); + BLayoutBuilder::Group<>(realtimeGroup) + .SetInsets(B_USE_DEFAULT_SPACING, 0, B_USE_DEFAULT_SPACING, + B_USE_DEFAULT_SPACING) + .Add(fRealtimeCheckBox) + .Add(textView); - realtimeBoxLayout->AddItem(BSpaceLayoutItem::CreateVerticalStrut(5)); - realtimeBoxLayout->AddView(fRealtimeCheckBox); - realtimeBoxLayout->AddView(textView); + realtimeBox->AddChild(realtimeGroup); + return realtimeBox; +} - // create the bottom line: volume in deskbar checkbox and restart button - BGroupView* bottomView = new BGroupView(B_HORIZONTAL); - BButton* restartButton = new BButton("restartButton", + +BStringView* +SettingsView::MakeRestartMessageView() +{ + // note: this ought to display at the bottom of the default box... + fRestartView = new BStringView("restartStringView", + B_TRANSLATE("Restart the media server to apply changes.")); + fRestartView->SetHighColor(ui_color(B_FAILURE_COLOR)); + // not exactly failure, but sort of. + fRestartView->Hide(); + fRestartView->SetExplicitAlignment(BAlignment(B_ALIGN_HORIZONTAL_CENTER, + B_ALIGN_VERTICAL_CENTER)); + fRestartView->SetAlignment(B_ALIGN_HORIZONTAL_CENTER); + fRestartView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); + return fRestartView; +} + + +BButton* +SettingsView::MakeRestartButton() +{ + return new BButton("restartButton", B_TRANSLATE("Restart media services"), new BMessage(ML_RESTART_MEDIA_SERVER)); +} - if (!fIsVideo) { - fVolumeCheckBox = new BCheckBox("volumeCheckBox", - B_TRANSLATE("Show volume control on Deskbar"), - new BMessage(ML_SHOW_VOLUME_CONTROL)); - bottomView->GroupLayout()->AddView(fVolumeCheckBox); - if (BDeskbar().HasItem("MediaReplicant")) - fVolumeCheckBox->SetValue(B_CONTROL_ON); - } - else{ - bottomView->GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue()); - } - bottomView->GroupLayout()->AddView(restartButton); - // compose all stuff - BGroupLayout* rootlayout = new BGroupLayout(B_VERTICAL, 5); - SetLayout(rootlayout); - rootlayout->AddView(defaultsBox); - rootlayout->AddView(realtimeBox); - rootlayout->AddView(bottomView); +void +SettingsView::AddInputNodes(NodeList& list) +{ + _EmptyMenu(fInputMenu); + + BMessage message(MEDIA_DEFAULT_INPUT_CHANGE); + _PopulateMenu(fInputMenu, list, message); } void -SettingsView::AddNodes(NodeList& list, bool isInput) +SettingsView::AddOutputNodes(NodeList& list) { - BMenu* menu = isInput ? fInputMenu : fOutputMenu; + _EmptyMenu(fOutputMenu); - for (BMenuItem* item; (item = menu->RemoveItem((int32)0)) != NULL;) - delete item; - - BMessage message(ML_DEFAULT_CHANGE); - message.AddBool("isVideo", fIsVideo); - message.AddBool("isInput", isInput); - - for (int32 i = 0; i < list.CountItems(); i++) { - dormant_node_info* info = list.ItemAt(i); - menu->AddItem(new SettingsItem(info, new BMessage(message))); - } + BMessage message(MEDIA_DEFAULT_OUTPUT_CHANGE); + _PopulateMenu(fOutputMenu, list, message); } void -SettingsView::SetDefault(dormant_node_info &info, bool isInput, int32 outputID) +SettingsView::SetDefaultInput(const dormant_node_info* info) { - BMenu* menu = isInput ? fInputMenu : fOutputMenu; + _ClearMenuSelection(fInputMenu); + NodeMenuItem* item = _FindNodeItem(fInputMenu, info); + if (item) + item->SetMarked(true); +} - for (int32 i = 0; i < menu->CountItems(); i++) { - SettingsItem* item = static_cast(menu->ItemAt(i)); - if (item->fInfo && item->fInfo->addon == info.addon - && item->fInfo->flavor_id == info.flavor_id) { - item->SetMarked(true); + +void +SettingsView::SetDefaultOutput(const dormant_node_info* info) +{ + _ClearMenuSelection(fOutputMenu); + NodeMenuItem* item = _FindNodeItem(fOutputMenu, info); + if (item) + item->SetMarked(true); +} + + +void +SettingsView::MessageReceived(BMessage* message) +{ + switch (message->what) { + case MEDIA_DEFAULT_INPUT_CHANGE: + { + int32 index; + if (message->FindInt32("index", &index)!=B_OK) + break; + NodeMenuItem* item + = static_cast(fInputMenu->ItemAt(index)); + SetDefaultInput(item->NodeInfo()); + RestartRequired(true); + } + case MEDIA_DEFAULT_OUTPUT_CHANGE: + { + int32 index; + if (message->FindInt32("index", &index)!=B_OK) + break; + NodeMenuItem* item + = static_cast(fOutputMenu->ItemAt(index)); + SetDefaultOutput(item->NodeInfo()); + RestartRequired(true); + } + case ML_ENABLE_REAL_TIME: + { + uint32 flags = 0; + if (message->FindUInt32("flags", &flags) == B_OK) + _FlipRealtimeFlag(flags); break; } } + BGridView::MessageReceived(message); +} - if (!fIsVideo && !isInput && outputID >= 0) { - BMenuItem* item; - while ((item = fChannelMenu->RemoveItem((int32)0)) != NULL) - delete item; - BMediaRoster* roster = BMediaRoster::Roster(); - media_node node; - media_node_id node_id; - status_t err; - if (roster->GetInstancesFor(info.addon, info.flavor_id, - &node_id) != B_OK) { - err = roster->InstantiateDormantNode(info, &node, - B_FLAVOR_IS_GLOBAL); - } else { - err = roster->GetNodeFor(node_id, &node); +void +SettingsView::AttachedToWindow() +{ + BMessenger thisMessenger(this); + fInputMenu->SetTargetForItems(thisMessenger); + fOutputMenu->SetTargetForItems(thisMessenger); + fRealtimeCheckBox->SetTarget(thisMessenger); +} + + +void +SettingsView::RestartRequired(bool required) +{ + if (required) + fRestartView->Show(); + else + fRestartView->Hide(); +} + + +MediaWindow* +SettingsView::_MediaWindow() const +{ + return static_cast(Window()); +} + + +void +SettingsView::_FlipRealtimeFlag(uint32 mask) +{ + // TODO: error codes + uint32 flags = 0; + BMediaRoster* roster = BMediaRoster::Roster(); + roster->GetRealtimeFlags(&flags); + if (flags & mask) + flags &= ~mask; + else + flags |= mask; + roster->SetRealtimeFlags(flags); +} + + +void +SettingsView::_EmptyMenu(BMenu* menu) +{ + while (menu->CountItems() > 0) + delete menu->RemoveItem((int32)0); +} + + +void +SettingsView::_PopulateMenu(BMenu* menu, NodeList& nodes, + const BMessage& message) +{ + for (int32 i = 0; i < nodes.CountItems(); i++) { + dormant_node_info* info = nodes.ItemAt(i); + menu->AddItem(new NodeMenuItem(info, new BMessage(message))); + } + + if (Window() != NULL) + menu->SetTargetForItems(BMessenger(this)); +} + + +NodeMenuItem* +SettingsView::_FindNodeItem(BMenu* menu, const dormant_node_info* nodeInfo) +{ + for (int32 i = 0; i < menu->CountItems(); i++) { + NodeMenuItem* item = static_cast(menu->ItemAt(i)); + const dormant_node_info* itemInfo = item->NodeInfo(); + if (itemInfo && itemInfo->addon == nodeInfo->addon + && itemInfo->flavor_id == nodeInfo->flavor_id) { + return item; } + } + return NULL; +} - if (err == B_OK) { - media_input inputs[16]; - int32 inputCount = 16; - if (roster->GetAllInputsFor(node, inputs, 16, &inputCount)==B_OK) { - BMessage message(ML_DEFAULTOUTPUT_CHANGE); - for (int32 i = 0; i < inputCount; i++) { - media_input* input = new media_input(); - memcpy(input, &inputs[i], sizeof(*input)); - item = new Settings2Item(&info, input, - new BMessage(message)); - fChannelMenu->AddItem(item); - if (inputs[i].destination.id == outputID) - item->SetMarked(true); - } - } - } +void +SettingsView::_ClearMenuSelection(BMenu* menu) +{ + for (int32 i = 0; i < menu->CountItems(); i++) { + BMenuItem* item = menu->ItemAt(i); + item->SetMarked(false); } } -SettingsItem::SettingsItem(dormant_node_info* info, BMessage* message, - char shortcut, uint32 modifiers) +NodeMenuItem::NodeMenuItem(const dormant_node_info* info, BMessage* message, + char shortcut, uint32 modifiers) : BMenuItem(info->name, message, shortcut, modifiers), fInfo(info) @@ -263,7 +302,7 @@ SettingsItem::SettingsItem(dormant_node_info* info, BMessage* message, status_t -SettingsItem::Invoke(BMessage* message) +NodeMenuItem::Invoke(BMessage* message) { if (IsMarked()) return B_OK; @@ -271,27 +310,330 @@ SettingsItem::Invoke(BMessage* message) } -Settings2Item::Settings2Item(dormant_node_info* info, media_input* input, - BMessage* message, char shortcut, uint32 modifiers) +ChannelMenuItem::ChannelMenuItem(media_input* input, BMessage* message, + char shortcut, uint32 modifiers) : BMenuItem(input->name, message, shortcut, modifiers), - fInfo(info), fInput(input) { } -Settings2Item::~Settings2Item() +ChannelMenuItem::~ChannelMenuItem() { delete fInput; } +int32 +ChannelMenuItem::DestinationID() +{ + return fInput->destination.id; +} + + +media_input* +ChannelMenuItem::Input() +{ + return fInput; +} + + status_t -Settings2Item::Invoke(BMessage* message) +ChannelMenuItem::Invoke(BMessage* message) { if (IsMarked()) return B_OK; return BMenuItem::Invoke(message); } + +AudioSettingsView::AudioSettingsView() +{ + BBox* defaultsBox = new BBox("defaults"); + defaultsBox->SetLabel(B_TRANSLATE("Defaults")); + BGridView* defaultsGridView = new BGridView(); + + BMenuField* inputMenuField = new BMenuField("inputMenuField", + B_TRANSLATE("Audio input:"), InputMenu(), NULL); + + BMenuField* outputMenuField = new BMenuField("outputMenuField", + B_TRANSLATE("Audio output:"), OutputMenu(), NULL); + + BLayoutBuilder::Grid<>(defaultsGridView) + .SetInsets(B_USE_DEFAULT_SPACING, 0, B_USE_DEFAULT_SPACING, 0) + .AddMenuField(inputMenuField, 0, 0, B_ALIGN_HORIZONTAL_UNSET, 1, 3, 1) + .AddMenuField(outputMenuField, 0, 1) + .AddMenuField(_MakeChannelMenu(), 2, 1) + .Add(MakeRestartMessageView(), 0, 2, 4, 1); + + defaultsBox->AddChild(defaultsGridView); + + const char* realtimeLabel = B_TRANSLATE("Enable real-time audio"); + const char* realtimeInfo = B_TRANSLATE( + "Enabling real-time audio allows system to record and play audio " + "as fast as possible. It achieves this performance by using more" + " CPU and RAM.\n\nOnly enable this feature if you need the lowest" + " latency possible."); + + + BLayoutBuilder::Grid<>(this) + .SetInsets(0, 0, 0, 0) + .Add(defaultsBox, 0, 0, 2, 1) + .Add(MakeRealtimeBox(realtimeInfo, B_MEDIA_REALTIME_AUDIO, + realtimeLabel), 0, 1, 2, 1) + .Add(_MakeVolumeCheckBox(),0, 2, 1, 1) + .Add(MakeRestartButton(), 1, 2, 1, 1) + .SetRowWeight(1, 10); +} + + +void +AudioSettingsView::SetDefaultChannel(int32 channelID) +{ + for (int32 i = 0; i < fChannelMenu->CountItems(); i++) { + ChannelMenuItem* item = _ChannelMenuItemAt(i); + item->SetMarked(item->DestinationID() == channelID); + } +} + + +void +AudioSettingsView::AttachedToWindow() +{ + SettingsView::AttachedToWindow(); + + BMessenger thisMessenger(this); + fChannelMenu->SetTargetForItems(thisMessenger); + fVolumeCheckBox->SetTarget(thisMessenger); +} + + +void +AudioSettingsView::MessageReceived(BMessage* message) +{ + switch (message->what) { + case ML_DEFAULT_CHANNEL_CHANGED: + { + int32 index; + if (message->FindInt32("index", &index) != B_OK) + break; + ChannelMenuItem* item = _ChannelMenuItemAt(index); + + if (item) { + BMediaRoster* roster = BMediaRoster::Roster(); + roster->SetAudioOutput(*item->Input()); + RestartRequired(true); + } else + fprintf(stderr, "ChannelMenuItem not found\n"); + } + break; + case MEDIA_SHOW_HIDE_VOLUME_CONTROL: + { + if (fVolumeCheckBox->Value() == B_CONTROL_ON) + _ShowDeskbarVolumeControl(); + else + _HideDeskbarVolumeControl(); + break; + } + + default: + SettingsView::MessageReceived(message); + } +} + + +void +AudioSettingsView::SetDefaultInput(const dormant_node_info* info) +{ + SettingsView::SetDefaultInput(info); + _MediaWindow()->UpdateInputListItem(MediaListItem::AUDIO_TYPE, info); + BMediaRoster::Roster()->SetAudioInput(*info); +} + + +void +AudioSettingsView::SetDefaultOutput(const dormant_node_info* info) +{ + SettingsView::SetDefaultOutput(info); + _MediaWindow()->UpdateOutputListItem(MediaListItem::AUDIO_TYPE, info); + _FillChannelMenu(info); + BMediaRoster::Roster()->SetAudioOutput(*info); +} + + +BMenuField* +AudioSettingsView::_MakeChannelMenu() +{ + fChannelMenu = new BPopUpMenu(B_TRANSLATE("")); + fChannelMenu->SetLabelFromMarked(true); + BMenuField* channelMenuField = new BMenuField("channelMenuField", + B_TRANSLATE("Channel:"), fChannelMenu, NULL); + return channelMenuField; +} + + +BCheckBox* +AudioSettingsView::_MakeVolumeCheckBox() +{ + fVolumeCheckBox = new BCheckBox("volumeCheckBox", + B_TRANSLATE("Show volume control on Deskbar"), + new BMessage(MEDIA_SHOW_HIDE_VOLUME_CONTROL)); + + if (BDeskbar().HasItem("MediaReplicant")) + fVolumeCheckBox->SetValue(B_CONTROL_ON); + + return fVolumeCheckBox; +} + + +void +AudioSettingsView::_FillChannelMenu(const dormant_node_info* nodeInfo) +{ + _EmptyMenu(fChannelMenu); + + BMediaRoster* roster = BMediaRoster::Roster(); + media_node node; + media_node_id node_id; + + status_t err = roster->GetInstancesFor(nodeInfo->addon, + nodeInfo->flavor_id, &node_id); + if (err != B_OK) { + err = roster->InstantiateDormantNode(*nodeInfo, &node, + B_FLAVOR_IS_GLOBAL); + } else { + err = roster->GetNodeFor(node_id, &node); + } + + if (err == B_OK) { + int32 inputCount = 4; + media_input* inputs = new media_input[inputCount]; + BPrivate::ArrayDeleter inputDeleter(inputs); + + while (true) { + int32 realInputCount = 0; + err = roster->GetAllInputsFor(node, inputs, + inputCount, &realInputCount); + if (realInputCount > inputCount) { + inputCount *= 2; + inputs = new media_input[inputCount]; + inputDeleter.SetTo(inputs); + } else { + inputCount = realInputCount; + break; + } + } + + if (err == B_OK) { + BMessage message(ML_DEFAULT_CHANNEL_CHANGED); + + for (int32 i = 0; i < inputCount; i++) { + media_input* input = new media_input(); + memcpy(input, &inputs[i], sizeof(*input)); + ChannelMenuItem* channelItem = new ChannelMenuItem(input, + new BMessage(message)); + fChannelMenu->AddItem(channelItem); + + if (channelItem->DestinationID() == 0) + channelItem->SetMarked(true); + } + } + } + + if (Window()) + fChannelMenu->SetTargetForItems(BMessenger(this)); +} + + +void +AudioSettingsView::_ShowDeskbarVolumeControl() +{ + BDeskbar deskbar; + BEntry entry("/bin/desklink", true); + int32 id; + entry_ref ref; + status_t status = entry.GetRef(&ref); + if (status == B_OK) + status = deskbar.AddItem(&ref, &id); + + if (status != B_OK) { + fprintf(stderr, B_TRANSLATE( + "Couldn't add volume control in Deskbar: %s\n"), + strerror(status)); + } +} + + +void +AudioSettingsView::_HideDeskbarVolumeControl() +{ + BDeskbar deskbar; + status_t status = deskbar.RemoveItem("MediaReplicant"); + if (status != B_OK) { + fprintf(stderr, B_TRANSLATE( + "Couldn't remove volume control in Deskbar: %s\n"), + strerror(status)); + } +} + + +ChannelMenuItem* +AudioSettingsView::_ChannelMenuItemAt(int32 index) +{ + return static_cast(fChannelMenu->ItemAt(index)); +} + + +VideoSettingsView::VideoSettingsView() +{ + BBox* defaultsBox = new BBox("defaults"); + defaultsBox->SetLabel(B_TRANSLATE("Defaults")); + BGridView* defaultsGridView = new BGridView(); + + BMenuField* inputMenuField = new BMenuField("inputMenuField", + B_TRANSLATE("Video input:"), InputMenu(), NULL); + + BMenuField* outputMenuField = new BMenuField("outputMenuField", + B_TRANSLATE("Video output:"), OutputMenu(), NULL); + + BLayoutBuilder::Grid<>(defaultsGridView) + .SetInsets(B_USE_DEFAULT_SPACING, 0, B_USE_DEFAULT_SPACING, 0) + .AddMenuField(inputMenuField, 0, 0) + .AddMenuField(outputMenuField, 0, 1) + .Add(MakeRestartMessageView(), 0, 2, 2, 1); + + defaultsBox->AddChild(defaultsGridView); + + const char* realtimeLabel = B_TRANSLATE("Enable real-time video"); + const char* realtimeInfo = B_TRANSLATE( + "Enabling real-time video allows system to " + "perform video operations as fast and smoothly as possible. It " + "achieves optimum performance by using more RAM.\n\n" + "Only enable this feature if you need the lowest latency possible."); + + BLayoutBuilder::Grid<>(this) + .SetInsets(0, 0, 0, 0) + .Add(defaultsBox, 0, 0, 2, 1) + .Add(MakeRealtimeBox(realtimeInfo, B_MEDIA_REALTIME_VIDEO, + realtimeLabel), 0, 1, 2, 1) + .Add(MakeRestartButton(), 1, 2, 1, 1) + .SetRowWeight(1, 10); +} + + +void +VideoSettingsView::SetDefaultInput(const dormant_node_info* info) +{ + SettingsView::SetDefaultInput(info); + _MediaWindow()->UpdateInputListItem(MediaListItem::VIDEO_TYPE, info); + BMediaRoster::Roster()->SetVideoInput(*info); +} + + +void +VideoSettingsView::SetDefaultOutput(const dormant_node_info* info) +{ + SettingsView::SetDefaultOutput(info); + _MediaWindow()->UpdateOutputListItem(MediaListItem::VIDEO_TYPE, info); + BMediaRoster::Roster()->SetVideoOutput(*info); +} diff --git a/src/preferences/media/MediaViews.h b/src/preferences/media/MediaViews.h index d47b0bcc59..f4f6422af4 100644 --- a/src/preferences/media/MediaViews.h +++ b/src/preferences/media/MediaViews.h @@ -14,69 +14,145 @@ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ #ifndef __MEDIAVIEWS_H__ #define __MEDIAVIEWS_H__ -#include +#include #include #include -#include -#include #include +class BBox; +class BButton; +class BCheckBox; +class BMenu; +class BMenuField; +class BStringView; + +class MediaWindow; + + const uint32 ML_RESTART_MEDIA_SERVER = 'resr'; -const uint32 ML_SHOW_VOLUME_CONTROL = 'shvc'; const uint32 ML_ENABLE_REAL_TIME = 'enrt'; -const uint32 ML_DEFAULT_CHANGE = 'dech'; -const uint32 ML_DEFAULTOUTPUT_CHANGE = 'doch'; +const uint32 ML_DEFAULT_CHANNEL_CHANGED = 'chch'; -class SettingsItem : public BMenuItem +class NodeMenuItem : public BMenuItem { public: - SettingsItem(dormant_node_info* info, + NodeMenuItem(const dormant_node_info* info, BMessage* message, char shortcut = 0, uint32 modifiers = 0); virtual status_t Invoke(BMessage* message = NULL); - dormant_node_info* fInfo; + const dormant_node_info* NodeInfo() const {return fInfo;} +private: + + const dormant_node_info* fInfo; }; -class Settings2Item : public BMenuItem +class ChannelMenuItem : public BMenuItem { public: - Settings2Item(dormant_node_info* info, - media_input* input, BMessage* message, - char shortcut = 0, uint32 modifiers = 0); - virtual ~Settings2Item(); + ChannelMenuItem(media_input* input, + BMessage* message, char shortcut = 0, + uint32 modifiers = 0); + virtual ~ChannelMenuItem(); + + int32 DestinationID(); + media_input* Input(); + virtual status_t Invoke(BMessage* message = NULL); - dormant_node_info* fInfo; +private: media_input* fInput; }; -class SettingsView : public BView +class SettingsView : public BGridView { public: typedef BObjectList NodeList; - SettingsView(bool isVideo); - void AddNodes(NodeList &nodes, bool isInput); - void SetDefault(dormant_node_info &info, - bool isInput, int32 outputID = -1); + SettingsView(); + void AddInputNodes(NodeList& nodes); + void AddOutputNodes(NodeList& nodes); + + virtual void SetDefaultInput(const dormant_node_info* info); + virtual void SetDefaultOutput(const dormant_node_info* info); + + virtual void MessageReceived(BMessage* message); + virtual void AttachedToWindow(); + + void RestartRequired(bool required); + +protected: + + BMenu* InputMenu() {return fInputMenu;} + BMenu* OutputMenu() {return fOutputMenu;} + + BBox* MakeRealtimeBox(const char* info, + uint32 realtimeMask, + const char* checkboxLabel); + BStringView* MakeRestartMessageView(); + BButton* MakeRestartButton(); + + void _EmptyMenu(BMenu* menu); + MediaWindow* _MediaWindow() const; + +private: + void _FlipRealtimeFlag(uint32 mask); + + void _PopulateMenu(BMenu* menu, NodeList& nodes, + const BMessage& message); + NodeMenuItem* _FindNodeItem(BMenu* menu, + const dormant_node_info* nodeInfo); + void _ClearMenuSelection(BMenu* menu); BCheckBox* fRealtimeCheckBox; - BCheckBox* fVolumeCheckBox; BMenu* fInputMenu; BMenu* fOutputMenu; - BMenu* fChannelMenu; - // (audio only) BStringView* fRestartView; - -private: - bool fIsVideo; }; + +class AudioSettingsView : public SettingsView +{ +public: + AudioSettingsView(); + + void SetDefaultChannel(int32 channelID); + + virtual void SetDefaultInput(const dormant_node_info* info); + virtual void SetDefaultOutput(const dormant_node_info* info); + + virtual void MessageReceived(BMessage* message); + virtual void AttachedToWindow(); + +private: + BMenuField* _MakeChannelMenu(); + BCheckBox* _MakeVolumeCheckBox(); + void _FillChannelMenu(const dormant_node_info* info); + + void _ShowDeskbarVolumeControl(); + void _HideDeskbarVolumeControl(); + + ChannelMenuItem* _ChannelMenuItemAt(int32 index); + + BMenu* fChannelMenu; + BCheckBox* fVolumeCheckBox; +}; + + +class VideoSettingsView : public SettingsView +{ +public: + VideoSettingsView(); + + virtual void SetDefaultInput(const dormant_node_info* info); + virtual void SetDefaultOutput(const dormant_node_info* info); + +}; + #endif diff --git a/src/preferences/media/MediaWindow.cpp b/src/preferences/media/MediaWindow.cpp index 70f532f9f2..6351456d4a 100644 --- a/src/preferences/media/MediaWindow.cpp +++ b/src/preferences/media/MediaWindow.cpp @@ -1,9 +1,10 @@ /* - * Copyright (c) 2003-2005, Haiku, Inc. + * Copyright (c) 2003-2010, Haiku, Inc. * Distributed under the terms of the MIT license. * * Authors: * Sikosis, Jérôme Duval + * yourpalal, Alex Wilson */ @@ -16,10 +17,11 @@ #include #include #include +#include #include #include #include -#include +#include #include #include #include @@ -44,6 +46,34 @@ const uint32 ML_SELECTED_NODE = 'MlSN'; const uint32 ML_INIT_MEDIA = 'MlIM'; +class NodeListItemUpdater : public MediaListItem::Visitor { +public: + typedef void (NodeListItem::*UpdateMethod)(bool); + + NodeListItemUpdater(NodeListItem* target, UpdateMethod action) + : + fComparator(target), + fAction(action) + { + } + + + virtual void Visit(AudioMixerListItem*){} + virtual void Visit(DeviceListItem*){} + + virtual void Visit(NodeListItem* item) + { + item->Accept(fComparator); + (item->*(fAction))(fComparator.result == 0); + } + +private: + + NodeListItem::Comparator fComparator; + UpdateMethod fAction; +}; + + MediaWindow::SmartNode::SmartNode(const BMessenger& notifyHandler) : fNode(NULL), @@ -59,17 +89,16 @@ MediaWindow::SmartNode::~SmartNode() void -MediaWindow::SmartNode::SetTo(dormant_node_info* info) +MediaWindow::SmartNode::SetTo(const dormant_node_info* info) { _FreeNode(); if (!info) return; fNode = new media_node(); - - // TODO: check error codes BMediaRoster* roster = BMediaRoster::Roster(); + // TODO: error codes media_node_id node_id; if (roster->GetInstancesFor(info->addon, info->flavor_id, &node_id) == B_OK) roster->GetNodeFor(node_id, fNode); @@ -122,7 +151,7 @@ MediaWindow::SmartNode::_FreeNode() // MediaWindow - Constructor MediaWindow::MediaWindow(BRect frame) : - BWindow (frame, B_TRANSLATE("Media"), B_TITLED_WINDOW, + BWindow(frame, B_TRANSLATE("Media"), B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), fCurrentNode(BMessenger(this)), fParamWeb(NULL), @@ -148,8 +177,6 @@ MediaWindow::~MediaWindow() { _EmptyNodeLists(); _ClearParamView(); - delete fVideoView; - delete fAudioView; char buffer[512]; BRect rect = Frame(); @@ -169,7 +196,7 @@ MediaWindow::~MediaWindow() void -MediaWindow::SelectNode(dormant_node_info* node) +MediaWindow::SelectNode(const dormant_node_info* node) { fCurrentNode.SetTo(node); _MakeParamView(); @@ -180,7 +207,7 @@ MediaWindow::SelectNode(dormant_node_info* node) void MediaWindow::SelectAudioSettings(const char* title) { - fContentView->AddChild(fAudioView); + fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fAudioView)); fTitleView->SetLabel(title); } @@ -188,7 +215,7 @@ MediaWindow::SelectAudioSettings(const char* title) void MediaWindow::SelectVideoSettings(const char* title) { - fContentView->AddChild(fVideoView); + fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fVideoView)); fTitleView->SetLabel(title); } @@ -205,6 +232,34 @@ MediaWindow::SelectAudioMixer(const char* title) } +void +MediaWindow::UpdateInputListItem(MediaListItem::media_type type, + const dormant_node_info* node) +{ + NodeListItem compareTo(node, type); + NodeListItemUpdater updater(&compareTo, &NodeListItem::SetDefaultInput); + for (int32 i = 0; i < fListView->CountItems(); i++) { + MediaListItem* item = static_cast(fListView->ItemAt(i)); + item->Accept(updater); + } + fListView->Invalidate(); +} + + +void +MediaWindow::UpdateOutputListItem(MediaListItem::media_type type, + const dormant_node_info* node) +{ + NodeListItem compareTo(node, type); + NodeListItemUpdater updater(&compareTo, &NodeListItem::SetDefaultOutput); + for (int32 i = 0; i < fListView->CountItems(); i++) { + MediaListItem* item = static_cast(fListView->ItemAt(i)); + item->Accept(updater); + } + fListView->Invalidate(); +} + + void MediaWindow::_FindNodes() { @@ -249,7 +304,8 @@ MediaWindow::_FindNodes(media_type type, uint64 kind, NodeList& into) for (int32 i = 0; i < node_info_count; i++) { PRINT(("node : %s, media_addon %i, flavor_id %i\n", - node_info[i].name, node_info[i].addon, node_info[i].flavor_id)); + node_info[i].name, (int)node_info[i].addon, + (int)node_info[i].flavor_id)); dormant_node_info* info = new dormant_node_info(); strncpy(info->name, node_info[i].name, B_MEDIA_NAME_LENGTH); @@ -263,14 +319,22 @@ MediaWindow::_FindNodes(media_type type, uint64 kind, NodeList& into) NodeListItem* MediaWindow::_FindNodeListItem(dormant_node_info* info) { + NodeListItem audioItem(info, MediaListItem::AUDIO_TYPE); + NodeListItem videoItem(info, MediaListItem::VIDEO_TYPE); + + NodeListItem::Comparator audioComparator(&audioItem); + NodeListItem::Comparator videoComparator(&videoItem); + for (int32 i = 0; i < fListView->CountItems(); i++) { MediaListItem* item = static_cast(fListView->ItemAt(i)); - dormant_node_info* itemInfo = item->NodeInfo(); - if (itemInfo && itemInfo->addon == info->addon - && itemInfo->flavor_id == info->flavor_id) { - return dynamic_cast(item); - } + item->Accept(audioComparator); + if (audioComparator.result == 0) + return static_cast(item); + + item->Accept(videoComparator); + if (videoComparator.result == 0) + return static_cast(item); } return NULL; } @@ -313,43 +377,35 @@ MediaWindow::InitWindow() scrollView->SetExplicitMaxSize(BSize(scrollWidth, B_SIZE_UNSET)); // Create the Views - fBox = new BBox("background", B_WILL_DRAW | B_FRAME_EVENTS, - B_PLAIN_BORDER); - SetLayout(new BGroupLayout(B_HORIZONTAL)); - GetLayout()->AddView(fBox); - - // StringViews fTitleView = new BSeparatorView(B_HORIZONTAL, B_FANCY_BORDER); fTitleView->SetLabel(B_TRANSLATE("Audio settings")); fTitleView->SetFont(be_bold_font); - fContentView = new BBox("contentView", B_WILL_DRAW | B_FRAME_EVENTS, - B_NO_BORDER); + fContentLayout = new BCardLayout(); + new BView("content view", 0, fContentLayout); + fContentLayout->Owner()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - fAudioView = new SettingsView(false); - fVideoView = new SettingsView(true); + fAudioView = new AudioSettingsView(); + fContentLayout->AddView(fAudioView); + + fVideoView = new VideoSettingsView(); + fContentLayout->AddView(fVideoView); // Layout all views - BGroupView* rightView = new BGroupView(B_VERTICAL, 5); - rightView->GroupLayout()->SetInsets(14, 0, 0, 0); - rightView->GroupLayout()->AddView(fTitleView); - rightView->GroupLayout()->AddView(fContentView); - - BGroupLayout* rootLayout = new BGroupLayout(B_HORIZONTAL); - rootLayout->SetInsets(14, 14, 14, 14); - fBox->SetLayout(rootLayout); - - rootLayout->AddView(scrollView); - - rootLayout->AddView(rightView); + BLayoutBuilder::Group<>(this, B_HORIZONTAL) + .SetInsets(14, 14, 14, 14) + .Add(scrollView) + .AddGroup(B_VERTICAL) + .SetInsets(14, 0, 0, 0) + .Add(fTitleView) + .Add(fContentLayout); // Start the window fInitCheck = InitMedia(true); if (fInitCheck != B_OK) { PostMessage(B_QUIT_REQUESTED); - } else { - if (IsHidden()) + } else if (IsHidden()) { Show(); } } @@ -412,10 +468,10 @@ MediaWindow::InitMedia(bool first) _AddNodeItems(fAudioOutputs, MediaListItem::AUDIO_TYPE); _AddNodeItems(fAudioInputs, MediaListItem::AUDIO_TYPE); - fAudioView->AddNodes(fAudioOutputs, false); - fAudioView->AddNodes(fAudioInputs, true); - fVideoView->AddNodes(fVideoOutputs, false); - fVideoView->AddNodes(fVideoInputs, true); + fAudioView->AddOutputNodes(fAudioOutputs); + fAudioView->AddInputNodes(fAudioInputs); + fVideoView->AddOutputNodes(fVideoOutputs); + fVideoView->AddInputNodes(fVideoInputs); // build our list view DeviceListItem* audio = new DeviceListItem(B_TRANSLATE("Audio settings"), @@ -439,43 +495,34 @@ MediaWindow::InitMedia(bool first) if (roster->GetAudioInput(&default_node) == B_OK) { roster->GetDormantNodeFor(default_node, &node_info); - NodeListItem* item = _FindNodeListItem(&node_info); - if (item) - item->SetDefaultInput(true); - fAudioView->SetDefault(node_info, true); + fAudioView->SetDefaultInput(&node_info); + // this causes our listview to be updated as well } if (roster->GetAudioOutput(&default_node, &outputID, &outputName)==B_OK) { roster->GetDormantNodeFor(default_node, &node_info); - NodeListItem* item = _FindNodeListItem(&node_info); - if (item) - item->SetDefaultOutput(true); - fAudioView->SetDefault(node_info, false, outputID); + fAudioView->SetDefaultOutput(&node_info); + fAudioView->SetDefaultChannel(outputID); + // this causes our listview to be updated as well } if (roster->GetVideoInput(&default_node)==B_OK) { roster->GetDormantNodeFor(default_node, &node_info); - NodeListItem* item = _FindNodeListItem(&node_info); - if (item) - item->SetDefaultInput(true); - fVideoView->SetDefault(node_info, true); + fVideoView->SetDefaultInput(&node_info); + // this causes our listview to be updated as well } if (roster->GetVideoOutput(&default_node)==B_OK) { roster->GetDormantNodeFor(default_node, &node_info); - NodeListItem* item = _FindNodeListItem(&node_info); - if (item) - item->SetDefaultOutput(true); - fVideoView->SetDefault(node_info, false); + fVideoView->SetDefaultOutput(&node_info); + // this causes our listview to be updated as well } if (first) { fListView->Select(fListView->IndexOf(mixer)); } else { - if (!fAudioView->fRestartView->IsHidden()) - fAudioView->fRestartView->Hide(); - if (!fVideoView->fRestartView->IsHidden()) - fVideoView->fRestartView->Hide(); + fAudioView->RestartRequired(false); + fVideoView->RestartRequired(false); if (isVideoSelected) fListView->Select(fListView->IndexOf(video)); @@ -505,15 +552,6 @@ MediaWindow::QuitRequested() } -void -MediaWindow::FrameResized (float width, float height) -{ - // This makes sure our SideBar colours down to the bottom when resized - BRect r; - r = Bounds(); -} - - // ErrorAlert -- Displays a BAlert Box with a Custom Error or Debug Message void ErrorAlert(char* errorMessage) { @@ -533,98 +571,6 @@ MediaWindow::MessageReceived(BMessage* message) case ML_INIT_MEDIA: InitMedia(false); break; - case ML_DEFAULTOUTPUT_CHANGE: - { - int32 index; - if (message->FindInt32("index", &index)!=B_OK) - break; - Settings2Item* item = static_cast( - fAudioView->fChannelMenu->ItemAt(index)); - - if (item) { - BMediaRoster* roster = BMediaRoster::Roster(); - roster->SetAudioOutput(*item->fInput); - - if (fAudioView->fRestartView->IsHidden()) - fAudioView->fRestartView->Show(); - } else - fprintf(stderr, "Settings2Item not found\n"); - } - break; - case ML_DEFAULT_CHANGE: - { - bool isVideo = true; - bool isInput = true; - if (message->FindBool("isVideo", &isVideo)!=B_OK) - break; - if (message->FindBool("isInput", &isInput)!=B_OK) - break; - int32 index; - if (message->FindInt32("index", &index)!=B_OK) - break; - SettingsView* settingsView = isVideo ? fVideoView : fAudioView; - BMenu* menu = isInput ? settingsView->fInputMenu - : settingsView->fOutputMenu; - SettingsItem* item = static_cast( - menu->ItemAt(index)); - - if (item) { - PRINT(("isVideo %i isInput %i\n", isVideo, isInput)); - BMediaRoster* roster = BMediaRoster::Roster(); - if (isVideo) { - if (isInput) - roster->SetVideoInput(*item->fInfo); - else - roster->SetVideoOutput(*item->fInfo); - } else { - if (isInput) - roster->SetAudioInput(*item->fInfo); - else { - roster->SetAudioOutput(*item->fInfo); - fAudioView->SetDefault(*item->fInfo, false, 0); - } - } - - NodeListItem* oldListItem = NULL; - MediaListItem::media_type mediaType = isVideo ? - MediaListItem::VIDEO_TYPE : MediaListItem::AUDIO_TYPE; - for (int32 j = 0; j < fListView->CountItems(); j++) { - NodeListItem* item = dynamic_cast( - fListView->ItemAt(j)); - if (!oldListItem) - continue; - if (oldListItem->Type() != mediaType) - continue; - if (isInput && !oldListItem->IsDefaultInput()) { - oldListItem = item; - break; - } else if (!isInput && oldListItem->IsDefaultOutput()) { - oldListItem = item; - break; - } - } - if (oldListItem && isInput) - oldListItem->SetDefaultInput(false); - else if (oldListItem && !isInput) - oldListItem->SetDefaultOutput(false); - else - fprintf(stderr, "oldListItem not found\n"); - - NodeListItem* listItem = _FindNodeListItem(item->fInfo); - if (listItem && isInput) - listItem->SetDefaultInput(true); - else if (listItem && !isInput) - listItem->SetDefaultOutput(true); - else - fprintf(stderr, "MediaListItem not found\n"); - fListView->Invalidate(); - - if (settingsView->fRestartView->IsHidden()) - settingsView->fRestartView->Show(); - } else - fprintf(stderr, "SettingsItem not found\n"); - } - break; case ML_RESTART_MEDIA_SERVER: { thread_id thread = spawn_thread(&MediaWindow::RestartMediaServices, @@ -635,65 +581,21 @@ MediaWindow::MessageReceived(BMessage* message) resume_thread(thread); break; } - case ML_SHOW_VOLUME_CONTROL: - { - BDeskbar deskbar; - if (fAudioView->fVolumeCheckBox->Value() == B_CONTROL_ON) { - BEntry entry("/bin/desklink", true); - int32 id; - entry_ref ref; - status_t status = entry.GetRef(&ref); - if (status == B_OK) - status = deskbar.AddItem(&ref, &id); - - if (status != B_OK) { - fprintf(stderr, B_TRANSLATE( - "Couldn't add volume control in Deskbar: %s\n"), - strerror(status)); - } - } else { - status_t status = deskbar.RemoveItem("MediaReplicant"); - if (status != B_OK) { - fprintf(stderr, B_TRANSLATE( - "Couldn't remove volume control in Deskbar: %s\n"), - strerror(status)); - } - } - break; - } - case ML_ENABLE_REAL_TIME: - { - bool isVideo = true; - if (message->FindBool("isVideo", &isVideo) != B_OK) - break; - SettingsView* settingsView = isVideo ? fVideoView : fAudioView; - uint32 flags; - uint32 realtimeFlag = isVideo - ? B_MEDIA_REALTIME_VIDEO : B_MEDIA_REALTIME_AUDIO; - BMediaRoster* roster = BMediaRoster::Roster(); - roster->GetRealtimeFlags(&flags); - if (settingsView->fRealtimeCheckBox->Value() == B_CONTROL_ON) - flags |= realtimeFlag; - else - flags &= ~realtimeFlag; - roster->SetRealtimeFlags(flags); - } - break; case B_MEDIA_WEB_CHANGED: case ML_SELECTED_NODE: - { - PRINT_OBJECT(*message); + { + PRINT_OBJECT(*message); - MediaListItem* item = static_cast( - fListView->ItemAt(fListView->CurrentSelection())); - if (!item) - break; + MediaListItem* item = static_cast( + fListView->ItemAt(fListView->CurrentSelection())); + if (!item) + break; - fCurrentNode.SetTo(NULL); - _ClearParamView(); - item->AlterWindow(this); - } + fCurrentNode.SetTo(NULL); + _ClearParamView(); + item->AlterWindow(this); break; + } case B_SOME_APP_LAUNCHED: { PRINT_OBJECT(*message); @@ -791,13 +693,18 @@ MediaWindow::UpdateProgress(int stage, const char * message, void * cookie) void MediaWindow::_ClearParamView() { - BView* child = fContentView->ChildAt(0); - if (child) - child->RemoveSelf(); - if (child != fVideoView && child != fAudioView) - delete child; - delete fParamWeb; - fParamWeb = NULL; + BLayoutItem* item = fContentLayout->VisibleItem(); + if (!item) + return; + + BView* view = item->View(); + if (view != fVideoView && view != fAudioView) { + fContentLayout->RemoveItem(item); + delete item; + delete view; + delete fParamWeb; + fParamWeb = NULL; + } } @@ -810,17 +717,16 @@ MediaWindow::_MakeParamView() fParamWeb = NULL; BMediaRoster* roster = BMediaRoster::Roster(); if (roster->GetParameterWebFor(fCurrentNode, &fParamWeb) == B_OK) { - BView* paramView = BMediaTheme::ViewFor(fParamWeb); + BRect hint(fContentLayout->Frame()); + BView* paramView = BMediaTheme::ViewFor(fParamWeb, &hint); if (paramView) { - fContentView->AddChild(paramView); - paramView->ResizeTo(1, 1); - // make sure we don't get stuck with a very large - // paramView + fContentLayout->AddView(paramView); + fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1); return; } } + _MakeEmptyParamView(); - } @@ -840,7 +746,8 @@ MediaWindow::_MakeEmptyParamView() stringView->SetExplicitAlignment(centered); stringView->SetAlignment(B_ALIGN_CENTER); - fContentView->AddChild(stringView); + fContentLayout->AddView(stringView); + fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1); rgb_color panel = stringView->LowColor(); stringView->SetHighColor(tint_color(panel, diff --git a/src/preferences/media/MediaWindow.h b/src/preferences/media/MediaWindow.h index 543f2bcd11..abbd737b07 100644 --- a/src/preferences/media/MediaWindow.h +++ b/src/preferences/media/MediaWindow.h @@ -16,7 +16,6 @@ #define __MEDIAWINDOWS_H__ -#include #include #include #include @@ -34,6 +33,7 @@ #define SETTINGS_FILE "MediaPrefs Settings" +class BCardLayout; class BSeparatorView; // struct dormant_node_info; @@ -46,15 +46,21 @@ public: status_t InitCheck(); // methods to be called by MediaListItems... - void SelectNode(dormant_node_info* node); + void SelectNode(const dormant_node_info* node); void SelectAudioSettings(const char* title); void SelectVideoSettings(const char* title); void SelectAudioMixer(const char* title); + // methods to be called by SettingsViews... + void UpdateInputListItem( + MediaListItem::media_type type, + const dormant_node_info* node); + void UpdateOutputListItem( + MediaListItem::media_type type, + const dormant_node_info* node); + virtual bool QuitRequested(); virtual void MessageReceived(BMessage* message); - virtual void FrameResized(float width, float height); - private: @@ -83,7 +89,7 @@ private: struct SmartNode { SmartNode(const BMessenger& notifyHandler); ~SmartNode(); - void SetTo(dormant_node_info* node); + void SetTo(const dormant_node_info* node); void SetTo(const media_node& node); bool IsSet(); operator media_node(); @@ -94,12 +100,11 @@ private: BMessenger fMessenger; }; - BBox* fBox; BListView* fListView; BSeparatorView* fTitleView; - BView* fContentView; - SettingsView* fAudioView; - SettingsView* fVideoView; + BCardLayout* fContentLayout; + AudioSettingsView* fAudioView; + VideoSettingsView* fVideoView; SmartNode fCurrentNode; BParameterWeb* fParamWeb;