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:
parent
e71562619a
commit
02b316fcba
|
@ -86,9 +86,6 @@ MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade:
|
|||
sourceOutputTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSourceOutputTypeComboBoxChanged));
|
||||
sinkTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSinkTypeComboBoxChanged));
|
||||
sourceTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSourceTypeComboBoxChanged));
|
||||
|
||||
sinkTree = Gtk::ListStore::create(deviceColumns);
|
||||
sourceTree = Gtk::ListStore::create(deviceColumns);
|
||||
}
|
||||
|
||||
MainWindow* MainWindow::create() {
|
||||
|
@ -179,34 +176,6 @@ void MainWindow::updateCard(const pa_card_info &info) {
|
|||
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) {
|
||||
SinkWidget *w;
|
||||
bool is_new = false;
|
||||
|
@ -250,7 +219,6 @@ void MainWindow::updateSink(const pa_sink_info &info) {
|
|||
|
||||
w->updating = false;
|
||||
|
||||
rebuildSinkCombo();
|
||||
if (is_new)
|
||||
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) {
|
||||
SourceWidget *w;
|
||||
bool is_new = false;
|
||||
|
@ -428,7 +368,6 @@ void MainWindow::updateSource(const pa_source_info &info) {
|
|||
|
||||
w->updating = false;
|
||||
|
||||
rebuildSourceCombo();
|
||||
if (is_new)
|
||||
updateDeviceVisibility();
|
||||
}
|
||||
|
@ -737,6 +676,14 @@ void MainWindow::reallyUpdateDeviceVisibility() {
|
|||
for (std::map<uint32_t, SinkInputWidget*>::iterator i = sinkInputWidgets.begin(); i != sinkInputWidgets.end(); ++i) {
|
||||
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) {
|
||||
w->show();
|
||||
is_empty = false;
|
||||
|
@ -757,6 +704,14 @@ void MainWindow::reallyUpdateDeviceVisibility() {
|
|||
for (std::map<uint32_t, SourceOutputWidget*>::iterator i = sourceOutputWidgets.begin(); i != sourceOutputWidgets.end(); ++i) {
|
||||
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) {
|
||||
w->show();
|
||||
is_empty = false;
|
||||
|
@ -848,7 +803,6 @@ void MainWindow::removeSink(uint32_t index) {
|
|||
|
||||
delete sinkWidgets[index];
|
||||
sinkWidgets.erase(index);
|
||||
rebuildSinkCombo();
|
||||
updateDeviceVisibility();
|
||||
}
|
||||
|
||||
|
@ -858,7 +812,6 @@ void MainWindow::removeSource(uint32_t index) {
|
|||
|
||||
delete sourceWidgets[index];
|
||||
sourceWidgets.erase(index);
|
||||
rebuildSourceCombo();
|
||||
updateDeviceVisibility();
|
||||
}
|
||||
|
||||
|
|
|
@ -91,31 +91,8 @@ public:
|
|||
|
||||
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:
|
||||
virtual void on_realize();
|
||||
|
||||
private:
|
||||
void rebuildSinkCombo();
|
||||
void rebuildSourceCombo();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -498,7 +498,6 @@ Monitors</property>
|
|||
<widget class="GtkImage" id="iconImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
<property name="icon-size">4</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
@ -508,6 +507,7 @@ Monitors</property>
|
|||
<child>
|
||||
<widget class="GtkHBox" id="hbox12">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="boldNameLabel">
|
||||
<property name="visible">True</property>
|
||||
|
@ -524,12 +524,42 @@ Monitors</property>
|
|||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Stream Title</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="ellipsize">middle</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</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"><a href="">Device</a></property>
|
||||
<property name="use_markup">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
|
@ -582,6 +612,26 @@ Monitors</property>
|
|||
<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="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>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
@ -612,52 +662,6 @@ Monitors</property>
|
|||
<property name="position">1</property>
|
||||
</packing>
|
||||
</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>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
@ -702,7 +706,6 @@ Monitors</property>
|
|||
<widget class="GtkImage" id="iconImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
<property name="icon-size">4</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
@ -947,7 +950,6 @@ Monitors</property>
|
|||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
<property name="icon-size">4</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
|
|
@ -32,7 +32,8 @@ RoleWidget::RoleWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade:
|
|||
StreamWidget(cobject, x) {
|
||||
|
||||
lockToggleButton->hide();
|
||||
streamControlHBox->hide();
|
||||
directionLabel->hide();
|
||||
deviceButton->hide();
|
||||
}
|
||||
|
||||
RoleWidget* RoleWidget::create() {
|
||||
|
@ -48,9 +49,6 @@ void RoleWidget::onMuteToggleButton() {
|
|||
executeVolumeUpdate();
|
||||
}
|
||||
|
||||
void RoleWidget::onDeviceChange() {
|
||||
}
|
||||
|
||||
void RoleWidget::executeVolumeUpdate() {
|
||||
pa_ext_stream_restore_info info;
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ public:
|
|||
Glib::ustring role;
|
||||
Glib::ustring device;
|
||||
|
||||
virtual void onDeviceChange();
|
||||
virtual void onMuteToggleButton();
|
||||
virtual void executeVolumeUpdate();
|
||||
};
|
||||
|
|
|
@ -32,13 +32,13 @@ SinkInputWidget::SinkInputWidget(BaseObjectType* cobject, const Glib::RefPtr<Gno
|
|||
StreamWidget(cobject, x),
|
||||
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) {
|
||||
mpMainWindow = mainWindow;
|
||||
deviceCombo->set_model(mpMainWindow->sinkTree);
|
||||
deviceCombo->pack_start(mpMainWindow->deviceColumns.name);
|
||||
}
|
||||
|
||||
SinkInputWidget* SinkInputWidget::create(MainWindow* mainWindow) {
|
||||
|
@ -49,12 +49,22 @@ SinkInputWidget* SinkInputWidget::create(MainWindow* mainWindow) {
|
|||
return w;
|
||||
}
|
||||
|
||||
SinkInputWidget::~SinkInputWidget(void) {
|
||||
clearMenu();
|
||||
}
|
||||
|
||||
void SinkInputWidget::setSinkIndex(uint32_t idx) {
|
||||
mSinkIndex = idx;
|
||||
|
||||
mSuppressDeviceChange = true;
|
||||
deviceCombo->set_active(mpMainWindow->sinkTreeIndexes[idx]);
|
||||
mSuppressDeviceChange = false;
|
||||
gchar *txt;
|
||||
if (mpMainWindow->sinkWidgets.count(idx)) {
|
||||
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() {
|
||||
|
@ -97,27 +107,50 @@ void SinkInputWidget::onKill() {
|
|||
pa_operation_unref(o);
|
||||
}
|
||||
|
||||
void SinkInputWidget::onDeviceChange() {
|
||||
Gtk::TreeModel::iterator iter;
|
||||
|
||||
if (updating || mSuppressDeviceChange)
|
||||
return;
|
||||
|
||||
iter = deviceCombo->get_active();
|
||||
if (iter)
|
||||
{
|
||||
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))) {
|
||||
show_error(_("pa_context_move_sink_input_by_index() failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
pa_operation_unref(o);
|
||||
}
|
||||
}
|
||||
void SinkInputWidget::clearMenu() {
|
||||
while (!sinkMenuItems.empty()) {
|
||||
std::map<uint32_t, SinkMenuItem*>::iterator i = sinkMenuItems.begin();
|
||||
delete i->second;
|
||||
sinkMenuItems.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!menuItem.get_active())
|
||||
return;
|
||||
|
||||
/*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"));
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ class SinkInputWidget : public StreamWidget {
|
|||
public:
|
||||
SinkInputWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x);
|
||||
static SinkInputWidget* create(MainWindow* mainWindow);
|
||||
~SinkInputWidget(void);
|
||||
|
||||
void init(MainWindow* mainWindow);
|
||||
|
||||
|
@ -40,7 +41,7 @@ public:
|
|||
void setSinkIndex(uint32_t idx);
|
||||
uint32_t sinkIndex();
|
||||
virtual void executeVolumeUpdate();
|
||||
virtual void onDeviceChange();
|
||||
virtual bool onDeviceChangePopup(GdkEventButton*);
|
||||
virtual void onMuteToggleButton();
|
||||
virtual void onKill();
|
||||
|
||||
|
@ -48,6 +49,28 @@ private:
|
|||
MainWindow *mpMainWindow;
|
||||
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
|
||||
|
|
|
@ -32,13 +32,13 @@ SourceOutputWidget::SourceOutputWidget(BaseObjectType* cobject, const Glib::RefP
|
|||
StreamWidget(cobject, x),
|
||||
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) {
|
||||
mpMainWindow = mainWindow;
|
||||
deviceCombo->set_model(mpMainWindow->sourceTree);
|
||||
deviceCombo->pack_start(mpMainWindow->deviceColumns.name);
|
||||
}
|
||||
|
||||
SourceOutputWidget* SourceOutputWidget::create(MainWindow* mainWindow) {
|
||||
|
@ -49,12 +49,22 @@ SourceOutputWidget* SourceOutputWidget::create(MainWindow* mainWindow) {
|
|||
return w;
|
||||
}
|
||||
|
||||
SourceOutputWidget::~SourceOutputWidget(void) {
|
||||
clearMenu();
|
||||
}
|
||||
|
||||
void SourceOutputWidget::setSourceIndex(uint32_t idx) {
|
||||
mSourceIndex = idx;
|
||||
|
||||
mSuppressDeviceChange = true;
|
||||
deviceCombo->set_active(mpMainWindow->sourceTreeIndexes[idx]);
|
||||
mSuppressDeviceChange = false;
|
||||
gchar *txt;
|
||||
if (mpMainWindow->sourceWidgets.count(idx)) {
|
||||
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() {
|
||||
|
@ -71,27 +81,51 @@ void SourceOutputWidget::onKill() {
|
|||
pa_operation_unref(o);
|
||||
}
|
||||
|
||||
void SourceOutputWidget::onDeviceChange() {
|
||||
Gtk::TreeModel::iterator iter;
|
||||
|
||||
if (updating || mSuppressDeviceChange)
|
||||
return;
|
||||
|
||||
iter = deviceCombo->get_active();
|
||||
if (iter)
|
||||
{
|
||||
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))) {
|
||||
show_error(_("pa_context_move_source_output_by_index() failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
pa_operation_unref(o);
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
if (!menuItem.get_active())
|
||||
return;
|
||||
|
||||
/*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"));
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ class SourceOutputWidget : public StreamWidget {
|
|||
public:
|
||||
SourceOutputWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x);
|
||||
static SourceOutputWidget* create(MainWindow* mainWindow);
|
||||
~SourceOutputWidget(void);
|
||||
|
||||
void init(MainWindow* mainWindow);
|
||||
|
||||
|
@ -39,13 +40,35 @@ public:
|
|||
uint32_t index, clientIndex;
|
||||
void setSourceIndex(uint32_t idx);
|
||||
uint32_t sourceIndex();
|
||||
virtual void onDeviceChange();
|
||||
virtual bool onDeviceChangePopup(GdkEventButton*);
|
||||
virtual void onKill();
|
||||
|
||||
private:
|
||||
MainWindow *mpMainWindow;
|
||||
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
|
||||
|
|
|
@ -27,19 +27,18 @@
|
|||
|
||||
/*** StreamWidget ***/
|
||||
StreamWidget::StreamWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) :
|
||||
MinimalStreamWidget(cobject, x),
|
||||
mSuppressDeviceChange(false) {
|
||||
MinimalStreamWidget(cobject, x) {
|
||||
|
||||
x->get_widget("lockToggleButton", lockToggleButton);
|
||||
x->get_widget("muteToggleButton", muteToggleButton);
|
||||
x->get_widget("deviceCombo", deviceCombo);
|
||||
x->get_widget("terminateButton", terminateButton);
|
||||
x->get_widget("directionLabel", directionLabel);
|
||||
x->get_widget("streamControlHBox", streamControlHBox);
|
||||
|
||||
deviceCombo->signal_changed().connect( sigc::mem_fun(*this, &StreamWidget::onDeviceChange));
|
||||
x->get_widget("deviceButton", deviceButton);
|
||||
x->get_widget("deviceLabel", deviceLabel);
|
||||
|
||||
terminateButton->signal_clicked().connect(sigc::mem_fun(*this, &StreamWidget::onKill));
|
||||
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++)
|
||||
channelWidgets[i] = NULL;
|
||||
|
@ -109,3 +108,7 @@ bool StreamWidget::timeoutEvent() {
|
|||
|
||||
void StreamWidget::executeVolumeUpdate() {
|
||||
}
|
||||
|
||||
bool StreamWidget::onDeviceChangePopup(GdkEventButton*) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ public:
|
|||
Gtk::ToggleButton *lockToggleButton, *muteToggleButton;
|
||||
Gtk::Button *terminateButton;
|
||||
Gtk::Label *directionLabel;
|
||||
Gtk::HBox *streamControlHBox;
|
||||
Gtk::EventBox *deviceButton;
|
||||
Gtk::Label *deviceLabel;
|
||||
|
||||
pa_channel_map channelMap;
|
||||
pa_cvolume volume;
|
||||
|
@ -46,7 +47,7 @@ public:
|
|||
ChannelWidget *channelWidgets[PA_CHANNELS_MAX];
|
||||
|
||||
virtual void onMuteToggleButton();
|
||||
virtual void onDeviceChange() = 0;
|
||||
virtual bool onDeviceChangePopup(GdkEventButton*);
|
||||
virtual void onKill();
|
||||
|
||||
sigc::connection timeoutConnection;
|
||||
|
@ -54,11 +55,6 @@ public:
|
|||
bool timeoutEvent();
|
||||
|
||||
virtual void executeVolumeUpdate();
|
||||
|
||||
protected:
|
||||
Gtk::ComboBox *deviceCombo;
|
||||
|
||||
bool mSuppressDeviceChange;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue