More changes in the UI to try and make things neater.

This abandons the combo box approach an instead partially reverts to the popup.
We now display a suffix after the stream title saying " on <device>" or " from <device>"
where the <device> part looks like a hyperlink and, when clicked, shows the popup to change the device.

If there is only one device available, we suppress the whole thing and thus avoid confusion.
This commit is contained in:
Colin Guthrie 2009-06-13 19:15:02 +01:00
parent e71562619a
commit 02b316fcba
11 changed files with 254 additions and 213 deletions

View File

@ -86,9 +86,6 @@ MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade:
sourceOutputTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSourceOutputTypeComboBoxChanged)); sourceOutputTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSourceOutputTypeComboBoxChanged));
sinkTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSinkTypeComboBoxChanged)); sinkTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSinkTypeComboBoxChanged));
sourceTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSourceTypeComboBoxChanged)); sourceTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSourceTypeComboBoxChanged));
sinkTree = Gtk::ListStore::create(deviceColumns);
sourceTree = Gtk::ListStore::create(deviceColumns);
} }
MainWindow* MainWindow::create() { MainWindow* MainWindow::create() {
@ -179,34 +176,6 @@ void MainWindow::updateCard(const pa_card_info &info) {
updateDeviceVisibility(); updateDeviceVisibility();
} }
void MainWindow::rebuildSinkCombo() {
uint32_t idx = 0;
Gtk::TreeModel::Row row;
sinkTree->clear();
sinkTreeIndexes.clear();
/*
row = *(sinkTree->append());
idx++;
row[deviceColumns.index] = -1;
row[deviceColumns.name] = "Default Output";
*/
for (std::map<uint32_t, SinkWidget*>::iterator i = sinkWidgets.begin(); i != sinkWidgets.end(); ++i) {
Gtk::TreeModel::Row row = *(sinkTree->append());
sinkTreeIndexes[i->first] = idx++;
row[deviceColumns.index] = i->first;
row[deviceColumns.name] = i->second->description.c_str();
}
/* Force a redraw of the dropdown combo due to the model change. */
for (std::map<uint32_t, SinkInputWidget*>::iterator i = sinkInputWidgets.begin(); i != sinkInputWidgets.end(); ++i) {
SinkInputWidget* w = i->second;
w->setSinkIndex(w->sinkIndex());
}
}
void MainWindow::updateSink(const pa_sink_info &info) { void MainWindow::updateSink(const pa_sink_info &info) {
SinkWidget *w; SinkWidget *w;
bool is_new = false; bool is_new = false;
@ -250,7 +219,6 @@ void MainWindow::updateSink(const pa_sink_info &info) {
w->updating = false; w->updating = false;
rebuildSinkCombo();
if (is_new) if (is_new)
updateDeviceVisibility(); updateDeviceVisibility();
} }
@ -356,34 +324,6 @@ void MainWindow::createMonitorStreamForSinkInput(uint32_t sink_input_idx, uint32
} }
} }
void MainWindow::rebuildSourceCombo() {
uint32_t idx = 0;
Gtk::TreeModel::Row row;
sourceTree->clear();
sourceTreeIndexes.clear();
/*
row = *(sourceTree->append());
idx++;
row[deviceColumns.index] = -1;
row[deviceColumns.name] = "Default Input";
*/
for (std::map<uint32_t, SourceWidget*>::iterator i = sourceWidgets.begin(); i != sourceWidgets.end(); ++i) {
Gtk::TreeModel::Row row = *(sourceTree->append());
sourceTreeIndexes[i->first] = idx++;
row[deviceColumns.index] = i->first;
row[deviceColumns.name] = i->second->description.c_str();
}
/* Force a redraw of the dropdown combo due to the model change. */
for (std::map<uint32_t, SourceOutputWidget*>::iterator i = sourceOutputWidgets.begin(); i != sourceOutputWidgets.end(); ++i) {
SourceOutputWidget* w = i->second;
w->setSourceIndex(w->sourceIndex());
}
}
void MainWindow::updateSource(const pa_source_info &info) { void MainWindow::updateSource(const pa_source_info &info) {
SourceWidget *w; SourceWidget *w;
bool is_new = false; bool is_new = false;
@ -428,7 +368,6 @@ void MainWindow::updateSource(const pa_source_info &info) {
w->updating = false; w->updating = false;
rebuildSourceCombo();
if (is_new) if (is_new)
updateDeviceVisibility(); updateDeviceVisibility();
} }
@ -737,6 +676,14 @@ void MainWindow::reallyUpdateDeviceVisibility() {
for (std::map<uint32_t, SinkInputWidget*>::iterator i = sinkInputWidgets.begin(); i != sinkInputWidgets.end(); ++i) { for (std::map<uint32_t, SinkInputWidget*>::iterator i = sinkInputWidgets.begin(); i != sinkInputWidgets.end(); ++i) {
SinkInputWidget* w = i->second; SinkInputWidget* w = i->second;
if (sinkWidgets.size() > 1) {
w->directionLabel->show();
w->deviceButton->show();
} else {
w->directionLabel->hide();
w->deviceButton->hide();
}
if (showSinkInputType == SINK_INPUT_ALL || w->type == showSinkInputType) { if (showSinkInputType == SINK_INPUT_ALL || w->type == showSinkInputType) {
w->show(); w->show();
is_empty = false; is_empty = false;
@ -757,6 +704,14 @@ void MainWindow::reallyUpdateDeviceVisibility() {
for (std::map<uint32_t, SourceOutputWidget*>::iterator i = sourceOutputWidgets.begin(); i != sourceOutputWidgets.end(); ++i) { for (std::map<uint32_t, SourceOutputWidget*>::iterator i = sourceOutputWidgets.begin(); i != sourceOutputWidgets.end(); ++i) {
SourceOutputWidget* w = i->second; SourceOutputWidget* w = i->second;
if (sourceWidgets.size() > 1) {
w->directionLabel->show();
w->deviceButton->show();
} else {
w->directionLabel->hide();
w->deviceButton->hide();
}
if (showSourceOutputType == SOURCE_OUTPUT_ALL || w->type == showSourceOutputType) { if (showSourceOutputType == SOURCE_OUTPUT_ALL || w->type == showSourceOutputType) {
w->show(); w->show();
is_empty = false; is_empty = false;
@ -848,7 +803,6 @@ void MainWindow::removeSink(uint32_t index) {
delete sinkWidgets[index]; delete sinkWidgets[index];
sinkWidgets.erase(index); sinkWidgets.erase(index);
rebuildSinkCombo();
updateDeviceVisibility(); updateDeviceVisibility();
} }
@ -858,7 +812,6 @@ void MainWindow::removeSource(uint32_t index) {
delete sourceWidgets[index]; delete sourceWidgets[index];
sourceWidgets.erase(index); sourceWidgets.erase(index);
rebuildSourceCombo();
updateDeviceVisibility(); updateDeviceVisibility();
} }

View File

@ -91,31 +91,8 @@ public:
Glib::ustring defaultSinkName, defaultSourceName; Glib::ustring defaultSinkName, defaultSourceName;
class DeviceColumns : public Gtk::TreeModel::ColumnRecord
{
public:
DeviceColumns()
{ add(index); add(name); }
Gtk::TreeModelColumn<uint32_t> index;
Gtk::TreeModelColumn<Glib::ustring> name;
};
DeviceColumns deviceColumns;
Glib::RefPtr<Gtk::ListStore> sinkTree;
std::map<uint32_t, uint32_t> sinkTreeIndexes;
Glib::RefPtr<Gtk::ListStore> sourceTree;
std::map<uint32_t, uint32_t> sourceTreeIndexes;
protected: protected:
virtual void on_realize(); virtual void on_realize();
private:
void rebuildSinkCombo();
void rebuildSourceCombo();
}; };

View File

@ -498,7 +498,6 @@ Monitors</property>
<widget class="GtkImage" id="iconImage"> <widget class="GtkImage" id="iconImage">
<property name="visible">True</property> <property name="visible">True</property>
<property name="stock">gtk-missing-image</property> <property name="stock">gtk-missing-image</property>
<property name="icon-size">4</property>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -508,6 +507,7 @@ Monitors</property>
<child> <child>
<widget class="GtkHBox" id="hbox12"> <widget class="GtkHBox" id="hbox12">
<property name="visible">True</property> <property name="visible">True</property>
<property name="spacing">2</property>
<child> <child>
<widget class="GtkLabel" id="boldNameLabel"> <widget class="GtkLabel" id="boldNameLabel">
<property name="visible">True</property> <property name="visible">True</property>
@ -524,12 +524,42 @@ Monitors</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="label" translatable="yes">Stream Title</property> <property name="label" translatable="yes">Stream Title</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="ellipsize">middle</property>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
<child>
<widget class="GtkLabel" id="directionLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="xpad">4</property>
<property name="label" translatable="yes">direction</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkEventBox" id="deviceButton">
<property name="visible">True</property>
<child>
<widget class="GtkLabel" id="deviceLabel">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;a href=""&gt;Device&lt;/a&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="position">3</property>
</packing>
</child>
</widget> </widget>
<packing> <packing>
<property name="position">1</property> <property name="position">1</property>
@ -582,6 +612,26 @@ Monitors</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
<child>
<widget class="GtkButton" id="terminateButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip" translatable="yes">Terminate stream</property>
<child>
<widget class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="stock">gtk-delete</property>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -612,52 +662,6 @@ Monitors</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
<child>
<widget class="GtkHBox" id="streamControlHBox">
<property name="visible">True</property>
<child>
<widget class="GtkLabel" id="directionLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">direction</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="deviceCombo">
<property name="visible">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="terminateButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip" translatable="yes">Terminate stream</property>
<child>
<widget class="GtkImage" id="image2">
<property name="visible">True</property>
<property name="stock">gtk-delete</property>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -702,7 +706,6 @@ Monitors</property>
<widget class="GtkImage" id="iconImage"> <widget class="GtkImage" id="iconImage">
<property name="visible">True</property> <property name="visible">True</property>
<property name="stock">gtk-missing-image</property> <property name="stock">gtk-missing-image</property>
<property name="icon-size">4</property>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -947,7 +950,6 @@ Monitors</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="stock">gtk-missing-image</property> <property name="stock">gtk-missing-image</property>
<property name="icon-size">4</property>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>

View File

@ -32,7 +32,8 @@ RoleWidget::RoleWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade:
StreamWidget(cobject, x) { StreamWidget(cobject, x) {
lockToggleButton->hide(); lockToggleButton->hide();
streamControlHBox->hide(); directionLabel->hide();
deviceButton->hide();
} }
RoleWidget* RoleWidget::create() { RoleWidget* RoleWidget::create() {
@ -48,9 +49,6 @@ void RoleWidget::onMuteToggleButton() {
executeVolumeUpdate(); executeVolumeUpdate();
} }
void RoleWidget::onDeviceChange() {
}
void RoleWidget::executeVolumeUpdate() { void RoleWidget::executeVolumeUpdate() {
pa_ext_stream_restore_info info; pa_ext_stream_restore_info info;

View File

@ -33,7 +33,6 @@ public:
Glib::ustring role; Glib::ustring role;
Glib::ustring device; Glib::ustring device;
virtual void onDeviceChange();
virtual void onMuteToggleButton(); virtual void onMuteToggleButton();
virtual void executeVolumeUpdate(); virtual void executeVolumeUpdate();
}; };

View File

@ -32,13 +32,13 @@ SinkInputWidget::SinkInputWidget(BaseObjectType* cobject, const Glib::RefPtr<Gno
StreamWidget(cobject, x), StreamWidget(cobject, x),
mpMainWindow(NULL) { mpMainWindow(NULL) {
directionLabel->set_label(_("<i>Playing on </i> ")); gchar *txt;
directionLabel->set_label(txt = g_markup_printf_escaped("<i>%s</i>", _("on")));
g_free(txt);
} }
void SinkInputWidget::init(MainWindow* mainWindow) { void SinkInputWidget::init(MainWindow* mainWindow) {
mpMainWindow = mainWindow; mpMainWindow = mainWindow;
deviceCombo->set_model(mpMainWindow->sinkTree);
deviceCombo->pack_start(mpMainWindow->deviceColumns.name);
} }
SinkInputWidget* SinkInputWidget::create(MainWindow* mainWindow) { SinkInputWidget* SinkInputWidget::create(MainWindow* mainWindow) {
@ -49,12 +49,22 @@ SinkInputWidget* SinkInputWidget::create(MainWindow* mainWindow) {
return w; return w;
} }
SinkInputWidget::~SinkInputWidget(void) {
clearMenu();
}
void SinkInputWidget::setSinkIndex(uint32_t idx) { void SinkInputWidget::setSinkIndex(uint32_t idx) {
mSinkIndex = idx; mSinkIndex = idx;
mSuppressDeviceChange = true; gchar *txt;
deviceCombo->set_active(mpMainWindow->sinkTreeIndexes[idx]); if (mpMainWindow->sinkWidgets.count(idx)) {
mSuppressDeviceChange = false; SinkWidget *w = mpMainWindow->sinkWidgets[idx];
txt = g_markup_printf_escaped("<a href=\"\">%s</a>", w->description.c_str());
}
else
txt = g_markup_printf_escaped("<a href=\"\">%s</a>", _("Unknown output"));
deviceLabel->set_label(txt);
g_free(txt);
} }
uint32_t SinkInputWidget::sinkIndex() { uint32_t SinkInputWidget::sinkIndex() {
@ -97,27 +107,50 @@ void SinkInputWidget::onKill() {
pa_operation_unref(o); pa_operation_unref(o);
} }
void SinkInputWidget::onDeviceChange() { void SinkInputWidget::clearMenu() {
Gtk::TreeModel::iterator iter; while (!sinkMenuItems.empty()) {
std::map<uint32_t, SinkMenuItem*>::iterator i = sinkMenuItems.begin();
delete i->second;
sinkMenuItems.erase(i);
}
}
if (updating || mSuppressDeviceChange) void SinkInputWidget::buildMenu() {
for (std::map<uint32_t, SinkWidget*>::iterator i = mpMainWindow->sinkWidgets.begin(); i != mpMainWindow->sinkWidgets.end(); ++i) {
SinkMenuItem *m;
sinkMenuItems[i->second->index] = m = new SinkMenuItem(this, i->second->description.c_str(), i->second->index, i->second->index == mSinkIndex);
menu.append(m->menuItem);
}
menu.show_all();
}
void SinkInputWidget::SinkMenuItem::onToggle() {
if (widget->updating)
return; return;
iter = deviceCombo->get_active(); if (!menuItem.get_active())
if (iter) return;
{
Gtk::TreeModel::Row row = *iter;
if (row)
{
pa_operation* o;
uint32_t sink_index = row[mpMainWindow->deviceColumns.index];
if (!(o = pa_context_move_sink_input_by_index(get_context(), index, sink_index, NULL, NULL))) { /*if (!mpMainWindow->sinkWidgets.count(widget->index))
return;*/
pa_operation* o;
if (!(o = pa_context_move_sink_input_by_index(get_context(), widget->index, index, NULL, NULL))) {
show_error(_("pa_context_move_sink_input_by_index() failed")); show_error(_("pa_context_move_sink_input_by_index() failed"));
return; return;
} }
pa_operation_unref(o); pa_operation_unref(o);
} }
}
bool SinkInputWidget::onDeviceChangePopup(GdkEventButton* event) {
if (GDK_BUTTON_PRESS == event->type && 1 == event->button)
{
clearMenu();
buildMenu();
menu.popup(event->button, event->time);
return true;
}
else
return false;
} }

View File

@ -31,6 +31,7 @@ class SinkInputWidget : public StreamWidget {
public: public:
SinkInputWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x); SinkInputWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x);
static SinkInputWidget* create(MainWindow* mainWindow); static SinkInputWidget* create(MainWindow* mainWindow);
~SinkInputWidget(void);
void init(MainWindow* mainWindow); void init(MainWindow* mainWindow);
@ -40,7 +41,7 @@ public:
void setSinkIndex(uint32_t idx); void setSinkIndex(uint32_t idx);
uint32_t sinkIndex(); uint32_t sinkIndex();
virtual void executeVolumeUpdate(); virtual void executeVolumeUpdate();
virtual void onDeviceChange(); virtual bool onDeviceChangePopup(GdkEventButton*);
virtual void onMuteToggleButton(); virtual void onMuteToggleButton();
virtual void onKill(); virtual void onKill();
@ -48,6 +49,28 @@ private:
MainWindow *mpMainWindow; MainWindow *mpMainWindow;
uint32_t mSinkIndex; uint32_t mSinkIndex;
void clearMenu();
void buildMenu();
Gtk::Menu menu;
struct SinkMenuItem {
SinkMenuItem(SinkInputWidget *w, const char *label, uint32_t i, bool active) :
widget(w),
menuItem(label),
index(i) {
menuItem.set_active(active);
menuItem.set_draw_as_radio(true);
menuItem.signal_toggled().connect(sigc::mem_fun(*this, &SinkMenuItem::onToggle));
}
SinkInputWidget *widget;
Gtk::CheckMenuItem menuItem;
uint32_t index;
void onToggle();
};
std::map<uint32_t, SinkMenuItem*> sinkMenuItems;
}; };
#endif #endif

View File

@ -32,13 +32,13 @@ SourceOutputWidget::SourceOutputWidget(BaseObjectType* cobject, const Glib::RefP
StreamWidget(cobject, x), StreamWidget(cobject, x),
mpMainWindow(NULL) { mpMainWindow(NULL) {
directionLabel->set_label(_("<i>Recording from </i> ")); gchar *txt;
directionLabel->set_label(txt = g_markup_printf_escaped("<i>%s</i>", _("from")));
g_free(txt);
} }
void SourceOutputWidget::init(MainWindow* mainWindow) { void SourceOutputWidget::init(MainWindow* mainWindow) {
mpMainWindow = mainWindow; mpMainWindow = mainWindow;
deviceCombo->set_model(mpMainWindow->sourceTree);
deviceCombo->pack_start(mpMainWindow->deviceColumns.name);
} }
SourceOutputWidget* SourceOutputWidget::create(MainWindow* mainWindow) { SourceOutputWidget* SourceOutputWidget::create(MainWindow* mainWindow) {
@ -49,12 +49,22 @@ SourceOutputWidget* SourceOutputWidget::create(MainWindow* mainWindow) {
return w; return w;
} }
SourceOutputWidget::~SourceOutputWidget(void) {
clearMenu();
}
void SourceOutputWidget::setSourceIndex(uint32_t idx) { void SourceOutputWidget::setSourceIndex(uint32_t idx) {
mSourceIndex = idx; mSourceIndex = idx;
mSuppressDeviceChange = true; gchar *txt;
deviceCombo->set_active(mpMainWindow->sourceTreeIndexes[idx]); if (mpMainWindow->sourceWidgets.count(idx)) {
mSuppressDeviceChange = false; SourceWidget *w = mpMainWindow->sourceWidgets[idx];
txt = g_markup_printf_escaped("<a href=\"\">%s</a>", w->description.c_str());
}
else
txt = g_markup_printf_escaped("<a href=\"\">%s</a>", _("Unknown input"));
deviceLabel->set_label(txt);
g_free(txt);
} }
uint32_t SourceOutputWidget::sourceIndex() { uint32_t SourceOutputWidget::sourceIndex() {
@ -71,27 +81,51 @@ void SourceOutputWidget::onKill() {
pa_operation_unref(o); pa_operation_unref(o);
} }
void SourceOutputWidget::onDeviceChange() {
Gtk::TreeModel::iterator iter;
if (updating || mSuppressDeviceChange) void SourceOutputWidget::clearMenu() {
while (!sourceMenuItems.empty()) {
std::map<uint32_t, SourceMenuItem*>::iterator i = sourceMenuItems.begin();
delete i->second;
sourceMenuItems.erase(i);
}
}
void SourceOutputWidget::buildMenu() {
for (std::map<uint32_t, SourceWidget*>::iterator i = mpMainWindow->sourceWidgets.begin(); i != mpMainWindow->sourceWidgets.end(); ++i) {
SourceMenuItem *m;
sourceMenuItems[i->second->index] = m = new SourceMenuItem(this, i->second->description.c_str(), i->second->index, i->second->index == mSourceIndex);
menu.append(m->menuItem);
}
menu.show_all();
}
void SourceOutputWidget::SourceMenuItem::onToggle() {
if (widget->updating)
return; return;
iter = deviceCombo->get_active(); if (!menuItem.get_active())
if (iter) return;
{
Gtk::TreeModel::Row row = *iter;
if (row)
{
pa_operation* o;
uint32_t source_index = row[mpMainWindow->deviceColumns.index];
if (!(o = pa_context_move_source_output_by_index(get_context(), source_index, index, NULL, NULL))) { /*if (!mpMainWindow->sourceWidgets.count(widget->index))
return;*/
pa_operation* o;
if (!(o = pa_context_move_source_output_by_index(get_context(), widget->index, index, NULL, NULL))) {
show_error(_("pa_context_move_source_output_by_index() failed")); show_error(_("pa_context_move_source_output_by_index() failed"));
return; return;
} }
pa_operation_unref(o); pa_operation_unref(o);
} }
}
bool SourceOutputWidget::onDeviceChangePopup(GdkEventButton* event) {
if (GDK_BUTTON_PRESS == event->type && 1 == event->button)
{
clearMenu();
buildMenu();
menu.popup(event->button, event->time);
return true;
}
else
return false;
} }

View File

@ -31,6 +31,7 @@ class SourceOutputWidget : public StreamWidget {
public: public:
SourceOutputWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x); SourceOutputWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x);
static SourceOutputWidget* create(MainWindow* mainWindow); static SourceOutputWidget* create(MainWindow* mainWindow);
~SourceOutputWidget(void);
void init(MainWindow* mainWindow); void init(MainWindow* mainWindow);
@ -39,13 +40,35 @@ public:
uint32_t index, clientIndex; uint32_t index, clientIndex;
void setSourceIndex(uint32_t idx); void setSourceIndex(uint32_t idx);
uint32_t sourceIndex(); uint32_t sourceIndex();
virtual void onDeviceChange(); virtual bool onDeviceChangePopup(GdkEventButton*);
virtual void onKill(); virtual void onKill();
private: private:
MainWindow *mpMainWindow; MainWindow *mpMainWindow;
uint32_t mSourceIndex; uint32_t mSourceIndex;
void clearMenu();
void buildMenu();
Gtk::Menu menu;
struct SourceMenuItem {
SourceMenuItem(SourceOutputWidget *w, const char *label, uint32_t i, bool active) :
widget(w),
menuItem(label),
index(i) {
menuItem.set_active(active);
menuItem.set_draw_as_radio(true);
menuItem.signal_toggled().connect(sigc::mem_fun(*this, &SourceMenuItem::onToggle));
}
SourceOutputWidget *widget;
Gtk::CheckMenuItem menuItem;
uint32_t index;
void onToggle();
};
std::map<uint32_t, SourceMenuItem*> sourceMenuItems;
}; };
#endif #endif

View File

@ -27,19 +27,18 @@
/*** StreamWidget ***/ /*** StreamWidget ***/
StreamWidget::StreamWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) : StreamWidget::StreamWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) :
MinimalStreamWidget(cobject, x), MinimalStreamWidget(cobject, x) {
mSuppressDeviceChange(false) {
x->get_widget("lockToggleButton", lockToggleButton); x->get_widget("lockToggleButton", lockToggleButton);
x->get_widget("muteToggleButton", muteToggleButton); x->get_widget("muteToggleButton", muteToggleButton);
x->get_widget("deviceCombo", deviceCombo);
x->get_widget("terminateButton", terminateButton); x->get_widget("terminateButton", terminateButton);
x->get_widget("directionLabel", directionLabel); x->get_widget("directionLabel", directionLabel);
x->get_widget("streamControlHBox", streamControlHBox); x->get_widget("deviceButton", deviceButton);
x->get_widget("deviceLabel", deviceLabel);
deviceCombo->signal_changed().connect( sigc::mem_fun(*this, &StreamWidget::onDeviceChange));
terminateButton->signal_clicked().connect(sigc::mem_fun(*this, &StreamWidget::onKill)); terminateButton->signal_clicked().connect(sigc::mem_fun(*this, &StreamWidget::onKill));
muteToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &StreamWidget::onMuteToggleButton)); muteToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &StreamWidget::onMuteToggleButton));
deviceButton->signal_button_press_event().connect(sigc::mem_fun(*this, &StreamWidget::onDeviceChangePopup));
for (unsigned i = 0; i < PA_CHANNELS_MAX; i++) for (unsigned i = 0; i < PA_CHANNELS_MAX; i++)
channelWidgets[i] = NULL; channelWidgets[i] = NULL;
@ -109,3 +108,7 @@ bool StreamWidget::timeoutEvent() {
void StreamWidget::executeVolumeUpdate() { void StreamWidget::executeVolumeUpdate() {
} }
bool StreamWidget::onDeviceChangePopup(GdkEventButton*) {
return false;
}

View File

@ -38,7 +38,8 @@ public:
Gtk::ToggleButton *lockToggleButton, *muteToggleButton; Gtk::ToggleButton *lockToggleButton, *muteToggleButton;
Gtk::Button *terminateButton; Gtk::Button *terminateButton;
Gtk::Label *directionLabel; Gtk::Label *directionLabel;
Gtk::HBox *streamControlHBox; Gtk::EventBox *deviceButton;
Gtk::Label *deviceLabel;
pa_channel_map channelMap; pa_channel_map channelMap;
pa_cvolume volume; pa_cvolume volume;
@ -46,7 +47,7 @@ public:
ChannelWidget *channelWidgets[PA_CHANNELS_MAX]; ChannelWidget *channelWidgets[PA_CHANNELS_MAX];
virtual void onMuteToggleButton(); virtual void onMuteToggleButton();
virtual void onDeviceChange() = 0; virtual bool onDeviceChangePopup(GdkEventButton*);
virtual void onKill(); virtual void onKill();
sigc::connection timeoutConnection; sigc::connection timeoutConnection;
@ -54,11 +55,6 @@ public:
bool timeoutEvent(); bool timeoutEvent();
virtual void executeVolumeUpdate(); virtual void executeVolumeUpdate();
protected:
Gtk::ComboBox *deviceCombo;
bool mSuppressDeviceChange;
}; };
#endif #endif