re-add TLSF
[ardour.git] / gtk2_ardour / midi_channel_selector.cc
index aea9d31f03e9f19a6ad23239ba1685632cc9d555..1da8fd9c0059dfcc9e5179a067d0dde9c8a02014 100644 (file)
@@ -1,6 +1,6 @@
 /*
-    Copyright (C) 2008 Paul Davis
-    Author: Hans Baier
+    Copyright (C) 2008-2013 Paul Davis
+    Original Author: Hans Baier
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 #include <gtkmm/table.h>
 
 #include "pbd/compose.h"
+#include "pbd/ffs.h"
 
 #include "gtkmm2ext/gtk_ui.h"
 #include "gtkmm2ext/gui_thread.h"
+#include "gtkmm2ext/utils.h"
 
 #include "ardour/midi_track.h"
 
 #include "midi_channel_selector.h"
 #include "rgb_macros.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace std;
 using namespace Gtk;
 using namespace ARDOUR;
 
 MidiChannelSelector::MidiChannelSelector(int n_rows, int n_columns, int start_row, int start_column)
-       : Table(n_rows, n_columns, true)
+       : Table(std::max(4, std::max(n_rows,    start_row    + 4)),
+               std::max(4, std::max(n_columns, start_column + 4)),
+               true)
        , _recursion_counter(0)
 {
-       n_rows    = std::max(4, n_rows);
-       n_rows    = std::max(4, start_row + 4);
-       n_columns = std::max(4, n_columns);
-       n_columns = std::max(4, start_column + 4);
-
        property_column_spacing() = 0;
        property_row_spacing() = 0;
 
@@ -326,20 +325,29 @@ MidiMultipleChannelSelector::invert_selection(void)
 /*-----------------------------------------*/
 
 MidiChannelSelectorWindow::MidiChannelSelectorWindow (boost::shared_ptr<MidiTrack> mt)
-       : ArdourWindow (string_compose (_("MIDI Channel Control for %1"), mt->name()))
+       : ArdourWindow (_("MIDI Channel Control"))
        , track (mt)
+       , playback_all_button (playback_button_group, _("Playback all channels"))
+       , playback_filter_button (playback_button_group, _("Play only selected channels"))
+       , playback_force_button (playback_button_group, _("Use a single fixed channel for all playback"))
+       , capture_all_button (capture_button_group, _("Record all channels"))
+       , capture_filter_button (capture_button_group, _("Record only selected channels"))
+       , capture_force_button (capture_button_group, _("Force all channels to 1 channel"))
+       , last_drawn_capture_mode (AllChannels)
+       , last_drawn_playback_mode (AllChannels)
 {
        build ();
 
-       playback_mask_changed ();
        playback_mode_changed ();
-       capture_mask_changed ();
        capture_mode_changed ();
 
-       track->PlaybackChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mask_changed, this), gui_context());
-       track->PlaybackChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mode_changed, this), gui_context());
-       track->CaptureChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mask_changed, this), gui_context());
-       track->CaptureChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mode_changed, this), gui_context());
+       playback_mask_changed ();
+       capture_mask_changed ();
+
+       track->playback_filter().ChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mask_changed, this), gui_context());
+       track->playback_filter().ChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mode_changed, this), gui_context());
+       track->capture_filter().ChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mask_changed, this), gui_context());
+       track->capture_filter().ChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mode_changed, this), gui_context());
 }
 
 MidiChannelSelectorWindow::~MidiChannelSelectorWindow()
@@ -350,122 +358,93 @@ void
 MidiChannelSelectorWindow::build ()
 {
        VBox* vpacker;
-       HBox* capture_mask;
-       HBox* capture_mask_controls;
-       HBox* playback_mask;
-       HBox* playback_mask_controls;
+       HBox* capture_controls;
+       HBox* playback_controls;
         Button* b;
-        ToggleButton* tb;
         Label* l;
 
         vpacker = manage (new VBox);
         vpacker->set_spacing (6);
         vpacker->set_border_width (12);
 
-        l = manage (new Label (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Capture"))));
+       l = manage (new Label (string_compose (("<span size=\"larger\" weight=\"bold\">%1: %2</span>"), _("MIDI Channel Control"), track->name())));
        l->set_use_markup (true);
-        vpacker->pack_start (*l);
+       l->set_alignment (0.5, 0.0);
 
-        {
-                RadioButtonGroup group;
+       vpacker->pack_start (*l, true, true);
 
-                capture_all_button = manage (new RadioButton (group, "Record all channels"));
-                vpacker->pack_start (*capture_all_button);
-               capture_all_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), AllChannels));
+        l = manage (new Label (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Inbound"))));
+       l->set_use_markup (true);
+        vpacker->pack_start (*l);
 
-                capture_filter_button = manage (new RadioButton (group, "Record only selected channels"));
-                vpacker->pack_start (*capture_filter_button);
-               capture_filter_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), FilterChannels));
 
-                capture_force_button = manage (new RadioButton (group, "Force all channels to a single fixed channel"));
-                vpacker->pack_start (*capture_force_button);
-               capture_force_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), ForceChannel));
-        }
+       vpacker->pack_start (capture_all_button);
+       capture_all_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), AllChannels));
 
-       capture_mask = manage (new HBox);
+       vpacker->pack_start (capture_filter_button);
+       capture_filter_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), FilterChannels));
 
-        for (uint32_t n = 0; n < 16; ++n) {
-                char buf[3];
-                snprintf (buf, sizeof (buf), "%d", n+1);
-                tb = manage (new ToggleButton (buf));
-               Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to toggle recording of channel %1"), n+1));
-               capture_buttons.push_back (tb);
-               tb->set_name (X_("MidiChannelSelectorButton"));
-                capture_mask->pack_start (*tb);
-               tb->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_channel_clicked), n));
-        }
+       vpacker->pack_start (capture_force_button);
+       capture_force_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), ForceChannel));
 
-        vpacker->pack_start (*capture_mask);
+        vpacker->pack_start (capture_mask_box);
 
-       capture_mask_controls = manage (new HBox);
-       capture_mask_controls->set_spacing (6);
+       capture_controls = manage (new HBox);
+       capture_controls->set_spacing (6);
 
         b = manage (new Button (_("All")));
        Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to enable recording all channels"));
-       capture_mask_controls->pack_start (*b);
-       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::fill_capture_mask)); 
+       capture_controls->pack_start (*b);
+       capture_mask_controls.push_back (b);
+       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::fill_capture_mask));
         b = manage (new Button (_("None")));
        Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to disable recording all channels"));
-       capture_mask_controls->pack_start (*b);
-       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::zero_capture_mask)); 
+       capture_controls->pack_start (*b);
+       capture_mask_controls.push_back (b);
+       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::zero_capture_mask));
         b = manage (new Button (_("Invert")));
        Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to invert currently selected recording channels"));
-       capture_mask_controls->pack_start (*b);
-       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::invert_capture_mask)); 
+       capture_controls->pack_start (*b);
+       capture_mask_controls.push_back (b);
+       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::invert_capture_mask));
 
-        vpacker->pack_start (*capture_mask_controls);
-
-        playback_mask = manage (new HBox);
+        vpacker->pack_start (*capture_controls);
 
         l = manage (new Label (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Playback"))));
        l->set_use_markup (true);
         vpacker->pack_start (*l);
 
-        {
-                RadioButtonGroup group;
-
-                playback_all_button = manage (new RadioButton (group, "Playback all channels"));
-                vpacker->pack_start (*playback_all_button);
-               playback_all_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), AllChannels));
+       vpacker->pack_start (playback_all_button);
+       playback_all_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), AllChannels));
 
-                playback_filter_button = manage (new RadioButton (group, "Play only selected channels"));
-                vpacker->pack_start (*playback_filter_button);
-               playback_filter_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), FilterChannels));
+       vpacker->pack_start (playback_filter_button);
+       playback_filter_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), FilterChannels));
 
-                playback_force_button = manage (new RadioButton (group, "Use a single fixed channel for all playback"));
-                vpacker->pack_start (*playback_force_button);
-               playback_force_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), ForceChannel));
-        }
+       vpacker->pack_start (playback_force_button);
+       playback_force_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), ForceChannel));
 
-        for (uint32_t n = 0; n < 16; ++n) {
-                char buf[3];
-                snprintf (buf, sizeof (buf), "%d", n+1);
-                tb = manage (new ToggleButton (buf));
-               tb->set_name (X_("MidiChannelSelectorButton"));
-               playback_buttons.push_back (tb);
-                playback_mask->pack_start (*tb);
-               tb->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_channel_clicked), n));
-        }
+       vpacker->pack_start (playback_mask_box);
 
-       vpacker->pack_start (*playback_mask);
-
-       playback_mask_controls = manage (new HBox);
-       playback_mask_controls->set_spacing (6);
+       playback_controls = manage (new HBox);
+       playback_controls->set_spacing (6);
 
         b = manage (new Button (_("All")));
        Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to enable playback of all channels"));
-       playback_mask_controls->pack_start (*b);
-       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::fill_playback_mask)); 
+       playback_controls->pack_start (*b);
+       playback_mask_controls.push_back (b);
+       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::fill_playback_mask));
         b = manage (new Button (_("None")));
        Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to disable playback of all channels"));
-       playback_mask_controls->pack_start (*b);
-       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::zero_playback_mask)); 
+       playback_controls->pack_start (*b);
+       playback_mask_controls.push_back (b);
+       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::zero_playback_mask));
        b = manage (new Button (_("Invert")));
        Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to invert current selected playback channels"));
-       playback_mask_controls->pack_start (*b);
+       playback_controls->pack_start (*b);
+       playback_mask_controls.push_back (b);
        b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::invert_playback_mask));
 
-        vpacker->pack_start (*playback_mask_controls);
+        vpacker->pack_start (*playback_controls);
 
         add (*vpacker);
 }
@@ -473,52 +452,94 @@ MidiChannelSelectorWindow::build ()
 void
 MidiChannelSelectorWindow::fill_playback_mask ()
 {
-       track->set_playback_channel_mask (0xffff);
+       if (track->get_playback_channel_mode() == FilterChannels) {
+               track->set_playback_channel_mask (0xffff);
+       }
 }
 
 void
 MidiChannelSelectorWindow::zero_playback_mask ()
 {
-       track->set_playback_channel_mask (0);
+       if (track->get_playback_channel_mode() == FilterChannels) {
+               track->set_playback_channel_mask (0);
+       }
 }
 
 void
 MidiChannelSelectorWindow::invert_playback_mask ()
 {
-       track->set_playback_channel_mask (~track->get_playback_channel_mask());
+       if (track->get_playback_channel_mode() == FilterChannels) {
+               track->set_playback_channel_mask (~track->get_playback_channel_mask());
+       }
 }
 
 void
 MidiChannelSelectorWindow::fill_capture_mask ()
 {
-       track->set_capture_channel_mask (0xffff);
+       if (track->get_capture_channel_mode() == FilterChannels) {
+               track->set_capture_channel_mask (0xffff);
+       }
 }
 
 void
 MidiChannelSelectorWindow::zero_capture_mask ()
 {
-       track->set_capture_channel_mask (0);
+       if (track->get_capture_channel_mode() == FilterChannels) {
+               track->set_capture_channel_mask (0);
+       }
 }
 
 void
 MidiChannelSelectorWindow::invert_capture_mask ()
 {
-       track->set_capture_channel_mask (~track->get_capture_channel_mask());
+       if (track->get_capture_channel_mode() == FilterChannels) {
+               track->set_capture_channel_mask (~track->get_capture_channel_mask());
+       }
 }
-               
+
 void
 MidiChannelSelectorWindow::set_playback_selected_channels (uint16_t mask)
 {
-       for (uint16_t i = 0; i < 16; i++) {
-               playback_buttons[i]->set_active ((1<<i) & mask);
+       switch (track->get_playback_channel_mode()) {
+       case AllChannels:
+               /* they are insensitive, so we don't care */
+               break;
+
+       case FilterChannels:
+               for (uint16_t i = 0; i < 16; i++) {
+                       playback_buttons[i]->set_active ((1<<i) & mask);
+               }
+               break;
+
+       case ForceChannel:
+               /* only set the lowest set channel in the mask as active */
+               for (uint16_t i = 0; i < 16; i++) {
+                       playback_buttons[i]->set_active (i == (PBD::ffs (mask) - 1));
+               }
+               break;
        }
 }
 
 void
 MidiChannelSelectorWindow::set_capture_selected_channels (uint16_t mask)
 {
-       for (uint16_t i = 0; i < 16; i++) {
-               capture_buttons[i]->set_active ((1<<i) & mask);
+       switch (track->get_capture_channel_mode()) {
+       case AllChannels:
+               /* they are insensitive, so we don't care */
+               break;
+
+       case FilterChannels:
+               for (uint16_t i = 0; i < 16; i++) {
+                       capture_buttons[i]->set_active ((1<<i) & mask);
+               }
+               break;
+
+       case ForceChannel:
+               /* only set the lowest set channel in the mask as active */
+               for (uint16_t i = 0; i < 16; i++) {
+                       capture_buttons[i]->set_active (i == (PBD::ffs (mask) - 1));
+               }
+               break;
        }
 }
 
@@ -537,42 +558,221 @@ MidiChannelSelectorWindow::capture_mask_changed ()
 void
 MidiChannelSelectorWindow::playback_mode_changed ()
 {
-       switch (track->get_playback_channel_mode()) {
+       uint32_t first_channel = 0;
+       ChannelMode mode = track->get_playback_channel_mode();
+
+       switch (mode) {
        case AllChannels:
-               playback_all_button->set_active ();
+               if (last_drawn_playback_mode == ForceChannel) {
+                       /* force mode used radio buttons. not what we want,
+                        * though one could argue that we want no buttons
+                        * at since they are insensitive
+                        */
+                       playback_buttons.clear ();
+               }
+               for (vector<Widget*>::iterator i = playback_mask_controls.begin(); i != playback_mask_controls.end(); ++i) {
+                       (*i)->set_sensitive (false);
+               }
+               playback_all_button.set_active ();
                break;
+
        case FilterChannels:
-               playback_filter_button->set_active ();
+               if (last_drawn_playback_mode == ForceChannel) {
+                       playback_buttons.clear ();
+               } else if (last_drawn_playback_mode == AllChannels) {
+                       for (vector<ToggleButton*>::iterator i = playback_buttons.begin(); i != playback_buttons.end(); ++i) {
+                               (*i)->set_sensitive (true);
+                       }
+               }
+               for (vector<Widget*>::iterator i = playback_mask_controls.begin(); i != playback_mask_controls.end(); ++i) {
+                       (*i)->set_sensitive (true);
+               }
+               playback_filter_button.set_active ();
                break;
+
        case ForceChannel:
-               playback_force_button->set_active ();
+               if (last_drawn_playback_mode == AllChannels || last_drawn_playback_mode == FilterChannels) {
+                       playback_buttons.clear ();
+                       first_channel = PBD::ffs (track->get_playback_channel_mask()) - 1;
+               }
+               for (vector<Widget*>::iterator i = playback_mask_controls.begin(); i != playback_mask_controls.end(); ++i) {
+                       (*i)->set_sensitive (false);
+               }
+               playback_force_button.set_active ();
                break;
        }
+
+       if (playback_buttons.empty()) {
+
+               Gtkmm2ext::container_clear (playback_mask_box);
+
+               ToggleButton* tb;
+               RadioButtonGroup group;
+
+               for (uint32_t n = 0; n < 16; ++n) {
+                       char buf[3];
+                       snprintf (buf, sizeof (buf), "%d", n+1);
+
+                       switch (mode) {
+                       case AllChannels:
+                       case FilterChannels:
+                               tb = manage (new ToggleButton (buf));
+                               Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to toggle playback of channel %1"), n+1));
+                               break;
+                       case ForceChannel:
+                               tb = manage (new RadioButton (group, buf));
+                               tb->property_draw_indicator() = false;
+                               if (n == first_channel) {
+                                       tb->set_active (true);
+                               }
+                               Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to force all MIDI channel messages to channel %1"), n+1));
+                               break;
+                       }
+                       playback_buttons.push_back (tb);
+                       tb->set_name (X_("MidiChannelSelectorButton"));
+                       playback_mask_box.pack_start (*tb);
+                       tb->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_channel_clicked), n));
+                       tb->show ();
+
+                       if (mode == AllChannels) {
+                               tb->set_sensitive (false);
+                       }
+               }
+
+               if (mode != ForceChannel) {
+                       set_playback_selected_channels (track->get_playback_channel_mask());
+               }
+       }
+
+       if (mode == AllChannels) {
+               for (vector<ToggleButton*>::iterator i = playback_buttons.begin(); i != playback_buttons.end(); ++i) {
+                       (*i)->set_sensitive (false);
+               }
+       }
+
+       playback_mask_changed(); // update buttons
+
+       last_drawn_playback_mode = mode;
 }
 
 void
 MidiChannelSelectorWindow::capture_mode_changed ()
 {
-       switch (track->get_capture_channel_mode()) {
+       uint32_t first_channel = 0;
+       ChannelMode mode = track->get_capture_channel_mode();
+
+       switch (mode) {
        case AllChannels:
-               capture_all_button->set_active ();
+               if (last_drawn_capture_mode == ForceChannel) {
+                       /* force mode used radio buttons. not what we want,
+                        * though one could argue that we want no buttons
+                        * at since they are insensitive
+                        */
+                       capture_buttons.clear ();
+               }
+               for (vector<Widget*>::iterator i = capture_mask_controls.begin(); i != capture_mask_controls.end(); ++i) {
+                       (*i)->set_sensitive (false);
+               }
+               capture_all_button.set_active ();
                break;
+
        case FilterChannels:
-               capture_filter_button->set_active ();
+               if (last_drawn_capture_mode == ForceChannel) {
+                       capture_buttons.clear ();
+               } else if (last_drawn_capture_mode == AllChannels) {
+                       for (vector<ToggleButton*>::iterator i = capture_buttons.begin(); i != capture_buttons.end(); ++i) {
+                               (*i)->set_sensitive (true);
+                       }
+               }
+               for (vector<Widget*>::iterator i = capture_mask_controls.begin(); i != capture_mask_controls.end(); ++i) {
+                       (*i)->set_sensitive (true);
+               }
+               capture_filter_button.set_active ();
                break;
+
        case ForceChannel:
-               capture_force_button->set_active ();
+               if (last_drawn_capture_mode == AllChannels || last_drawn_capture_mode == FilterChannels) {
+                       capture_buttons.clear ();
+                       first_channel = PBD::ffs (track->get_capture_channel_mask()) - 1;
+               }
+               for (vector<Widget*>::iterator i = capture_mask_controls.begin(); i != capture_mask_controls.end(); ++i) {
+                       (*i)->set_sensitive (false);
+               }
+               capture_force_button.set_active ();
                break;
        }
+
+       if (capture_buttons.empty()) {
+
+               Gtkmm2ext::container_clear (capture_mask_box);
+
+               ToggleButton* tb;
+               RadioButtonGroup group;
+
+               for (uint32_t n = 0; n < 16; ++n) {
+                       char buf[3];
+                       snprintf (buf, sizeof (buf), "%d", n+1);
+
+                       switch (mode) {
+                       case AllChannels:
+                       case FilterChannels:
+                               tb = manage (new ToggleButton (buf));
+                               Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to toggle recording of channel %1"), n+1));
+                               break;
+                       case ForceChannel:
+                               tb = manage (new RadioButton (group, buf));
+                               tb->property_draw_indicator() = false;
+                               if (n == first_channel) {
+                                       tb->set_active (true);
+                               }
+                               Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to force all recorded channels to %1"), n+1));
+                               break;
+                       }
+                       capture_buttons.push_back (tb);
+                       tb->set_name (X_("MidiChannelSelectorButton"));
+                       capture_mask_box.pack_start (*tb);
+                       tb->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_channel_clicked), n));
+                       tb->show ();
+
+                       if (mode == AllChannels) {
+                               tb->set_sensitive (false);
+                       }
+               }
+
+               if (mode != ForceChannel) {
+                       set_capture_selected_channels (track->get_capture_channel_mask());
+               }
+       }
+
+       if (mode == AllChannels) {
+               for (vector<ToggleButton*>::iterator i = capture_buttons.begin(); i != capture_buttons.end(); ++i) {
+                       (*i)->set_sensitive (false);
+               }
+       }
+
+       capture_mask_changed (); // udpate buttons
+
+       last_drawn_capture_mode = mode;
 }
 
 void
 MidiChannelSelectorWindow::playback_channel_clicked (uint16_t n)
 {
        if (playback_buttons[n]->get_active()) {
-               track->set_playback_channel_mask (track->get_playback_channel_mask() | (1<<n));
+               switch (track->get_playback_channel_mode()) {
+               case AllChannels:
+                       break;
+               case FilterChannels:
+                       track->set_playback_channel_mask (track->get_playback_channel_mask() | (1<<n));
+                       break;
+               case ForceChannel:
+                       track->set_playback_channel_mask (1<<n);
+                       break;
+               }
        } else {
-               track->set_playback_channel_mask (track->get_playback_channel_mask() & ~(1<<n));
+               if (track->get_playback_channel_mode() == FilterChannels) {
+                       track->set_playback_channel_mask (track->get_playback_channel_mask() & ~(1<<n));
+               }
        }
 }
 
@@ -580,9 +780,20 @@ void
 MidiChannelSelectorWindow::capture_channel_clicked (uint16_t n)
 {
        if (capture_buttons[n]->get_active()) {
-               track->set_capture_channel_mask (track->get_capture_channel_mask() | (1<<n));
+               switch (track->get_capture_channel_mode()) {
+               case AllChannels:
+                       break;
+               case FilterChannels:
+                       track->set_capture_channel_mask (track->get_capture_channel_mask() | (1<<n));
+                       break;
+               case ForceChannel:
+                       track->set_capture_channel_mask (1<<n);
+                       break;
+               }
        } else {
-               track->set_capture_channel_mask (track->get_capture_channel_mask() & ~(1<<n));
+               if (track->get_capture_channel_mode() == FilterChannels) {
+                       track->set_capture_channel_mask (track->get_capture_channel_mask() & ~(1<<n));
+               }
        }
 }
 
@@ -593,27 +804,25 @@ MidiChannelSelectorWindow::capture_mode_toggled (ChannelMode mode)
           is for the button/mode that has been turned off, and the second is for the
           button/mode that has been turned on.
 
-          so we have to check the button state to know what to do.
+          so we take action only if the button is active (i.e it is the one
+          just clicked on)
        */
-          
+
        switch (mode) {
        case AllChannels:
-               if (!capture_all_button->get_active()) {
-                       return;
+               if (capture_all_button.get_active()) {
+                       track->set_capture_channel_mode (AllChannels, track->get_capture_channel_mask());
                }
-               track->set_capture_channel_mode (AllChannels, track->get_capture_channel_mask());
                break;
        case FilterChannels:
-               if (!capture_filter_button->get_active()) {
-                       return;
+               if (capture_filter_button.get_active()) {
+                       track->set_capture_channel_mode (FilterChannels, track->get_capture_channel_mask());
                }
-               track->set_capture_channel_mode (FilterChannels, track->get_capture_channel_mask());
                break;
        case ForceChannel:
-               if (!capture_force_button->get_active()) {
-                       return;
+               if (capture_force_button.get_active()) {
+                       track->set_capture_channel_mode (ForceChannel, track->get_capture_channel_mask());
                }
-               track->set_capture_channel_mode (ForceChannel, track->get_capture_channel_mask());
                break;
        }
 }
@@ -625,27 +834,25 @@ MidiChannelSelectorWindow::playback_mode_toggled (ChannelMode mode)
           is for the button/mode that has been turned off, and the second is for the
           button/mode that has been turned on.
 
-          so we have to check the button state to know what to do.
+          so we take action only if the button is active (i.e it is the one
+          just clicked on)
        */
-          
+
        switch (mode) {
        case AllChannels:
-               if (!playback_all_button->get_active()) {
-                       return;
+               if (playback_all_button.get_active()) {
+                       track->set_playback_channel_mode (AllChannels, track->get_playback_channel_mask());
                }
-               track->set_playback_channel_mode (AllChannels, track->get_playback_channel_mask());
                break;
        case FilterChannels:
-               if (!playback_filter_button->get_active()) {
-                       return;
+               if (playback_filter_button.get_active()) {
+                       track->set_playback_channel_mode (FilterChannels, track->get_playback_channel_mask());
                }
-               track->set_playback_channel_mode (FilterChannels, track->get_playback_channel_mask());
                break;
        case ForceChannel:
-               if (!playback_force_button->get_active()) {
-                       return;
+               if (playback_force_button.get_active()) {
+                       track->set_playback_channel_mode (ForceChannel, track->get_playback_channel_mask());
                }
-               track->set_playback_channel_mode (ForceChannel, track->get_playback_channel_mask());
                break;
        }
 }
@@ -657,7 +864,7 @@ MidiChannelSelectorWindow::set_channel_colors (const uint32_t new_channel_colors
 
                char color_normal[8];
                char color_active[8];
-               
+
                snprintf(color_normal, 8, "#%x", UINT_INTERPOLATE(new_channel_colors[n], 0x000000ff, 0.6));
                snprintf(color_active, 8, "#%x", new_channel_colors[n]);