Author: yourpalal Date: 2011-01-05 21:47:17 +0100 (Wed, 05 Jan 2011) New Revision: 40127 Changeset: http://dev.haiku-os.org/changeset/40127 Modified: haiku/trunk/src/preferences/media/Media.cpp haiku/trunk/src/preferences/media/MediaListItem.cpp haiku/trunk/src/preferences/media/MediaListItem.h haiku/trunk/src/preferences/media/MediaViews.cpp haiku/trunk/src/preferences/media/MediaViews.h haiku/trunk/src/preferences/media/MediaWindow.cpp haiku/trunk/src/preferences/media/MediaWindow.h Log: 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 Modified: haiku/trunk/src/preferences/media/Media.cpp =================================================================== --- haiku/trunk/src/preferences/media/Media.cpp 2011-01-05 20:05:09 UTC (rev 40126) +++ haiku/trunk/src/preferences/media/Media.cpp 2011-01-05 20:47:17 UTC (rev 40127) @@ -57,8 +57,8 @@ } } + MediaListItem::SetIcons(&fIcons); fWindow = new MediaWindow(rect); - MediaListItem::SetIcons(&fIcons); be_roster->StartWatching(BMessenger(this)); } Modified: haiku/trunk/src/preferences/media/MediaListItem.cpp =================================================================== --- haiku/trunk/src/preferences/media/MediaListItem.cpp 2011-01-05 20:05:09 UTC (rev 40126) +++ haiku/trunk/src/preferences/media/MediaListItem.cpp 2011-01-05 20:47:17 UTC (rev 40127) @@ -174,11 +174,10 @@ // #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 @@ 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,43 +234,58 @@ } -int -NodeListItem::CompareWith(MediaListItem* item) +void +NodeListItem::Accept(MediaListItem::Visitor& visitor) { - return item->CompareWith(this) * -1; + visitor.Visit(this); } int -NodeListItem::CompareWith(NodeListItem* item) +NodeListItem::CompareWith(MediaListItem* item) { - if (fMediaType != item->fMediaType) - return fMediaType == AUDIO_TYPE ? GREATER_THAN : LESS_THAN; + Comparator comparator(this); + item->Accept(comparator); + return comparator.result; +} - if (fIsAudioMixer != item->fIsAudioMixer) - return fIsAudioMixer ? GREATER_THAN : LESS_THAN; - return strcmp(Label(), item->Label()); +NodeListItem::Comparator::Comparator(NodeListItem* compareOthersTo) + : + result(GREATER_THAN), + fTarget(compareOthersTo) +{ } -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; +} + + // #pragma mark - DeviceListItem @@ -290,39 +299,58 @@ } +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; +} + + +void DeviceListItem::SetRenderParameters(Renderer& renderer) { renderer.AddIcon(&Icons()->devicesIcon); @@ -358,33 +386,50 @@ } +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; } Modified: haiku/trunk/src/preferences/media/MediaListItem.h =================================================================== --- haiku/trunk/src/preferences/media/MediaListItem.h 2011-01-05 20:05:09 UTC (rev 40126) +++ haiku/trunk/src/preferences/media/MediaListItem.h 2011-01-05 20:47:17 UTC (rev 40127) @@ -44,9 +44,6 @@ 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,17 +51,21 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); Modified: haiku/trunk/src/preferences/media/MediaViews.cpp =================================================================== --- haiku/trunk/src/preferences/media/MediaViews.cpp 2011-01-05 20:05:09 UTC (rev 40126) +++ haiku/trunk/src/preferences/media/MediaViews.cpp 2011-01-05 20:47:17 UTC (rev 40127) @@ -12,248 +12,287 @@ // Created : June 25, 2003 // // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ - - #include "MediaViews.h" +#include <AutoDeleter.h> #include <Box.h> #include <Button.h> #include <Catalog.h> +#include <CheckBox.h> #include <Deskbar.h> #include <Entry.h> -#include <GridView.h> -#include <GroupView.h> +#include <LayoutBuilder.h> #include <Locale.h> #include <MediaAddOn.h> #include <MediaRoster.h> #include <MenuField.h> #include <PopUpMenu.h> -#include <SpaceLayoutItem.h> #include <String.h> +#include <StringView.h> #include <TextView.h> +#include <assert.h> #include <stdio.h> +#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("<none>")); 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("<none>")); 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("<none>")); - 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(MEDIA_DEFAULT_OUTPUT_CHANGE); + _PopulateMenu(fOutputMenu, list, message); +} - 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))); - } +void +SettingsView::SetDefaultInput(const dormant_node_info* info) +{ + _ClearMenuSelection(fInputMenu); + NodeMenuItem* item = _FindNodeItem(fInputMenu, info); + if (item) + item->SetMarked(true); } void -SettingsView::SetDefault(dormant_node_info &info, bool isInput, int32 outputID) +SettingsView::SetDefaultOutput(const dormant_node_info* info) { - BMenu* menu = isInput ? fInputMenu : fOutputMenu; + _ClearMenuSelection(fOutputMenu); + NodeMenuItem* item = _FindNodeItem(fOutputMenu, info); + if (item) + item->SetMarked(true); +} - for (int32 i = 0; i < menu->CountItems(); i++) { - SettingsItem* item = static_cast<SettingsItem*>(menu->ItemAt(i)); - if (item->fInfo && item->fInfo->addon == info.addon - && item->fInfo->flavor_id == info.flavor_id) { - 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<NodeMenuItem*>(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<NodeMenuItem*>(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); +} - 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::RestartRequired(bool required) +{ + if (required) + fRestartView->Show(); + else + fRestartView->Hide(); +} + + +MediaWindow* +SettingsView::_MediaWindow() const +{ + return static_cast<MediaWindow*>(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<NodeMenuItem*>(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; } -SettingsItem::SettingsItem(dormant_node_info* info, BMessage* message, - char shortcut, uint32 modifiers) +void +SettingsView::_ClearMenuSelection(BMenu* menu) +{ + for (int32 i = 0; i < menu->CountItems(); i++) { + BMenuItem* item = menu->ItemAt(i); + item->SetMarked(false); + } +} + + +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 @@ status_t -SettingsItem::Invoke(BMessage* message) +NodeMenuItem::Invoke(BMessage* message) { if (IsMarked()) return B_OK; @@ -271,27 +310,330 @@ } -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); [... truncated: 1065 lines follow ...]