X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fmidi_channel_selector.cc;h=1da8fd9c0059dfcc9e5179a067d0dde9c8a02014;hb=cf52d6e4b40111eb04b244ec054055a4ec15dbe0;hp=6bed5d1f95b0fb1d6735f58b6a99a4305b118bb9;hpb=accc73a8c15ce9b86db269a52a132a88e9f17da2;p=ardour.git diff --git a/gtk2_ardour/midi_channel_selector.cc b/gtk2_ardour/midi_channel_selector.cc index 6bed5d1f95..1da8fd9c00 100644 --- a/gtk2_ardour/midi_channel_selector.cc +++ b/gtk2_ardour/midi_channel_selector.cc @@ -1,34 +1,75 @@ -#include "midi_channel_selector.h" -#include "gtkmm/separator.h" -#include "i18n.h" +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include #include +#include +#include +#include +#include +#include +#include + +#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 "pbd/i18n.h" using namespace std; +using namespace Gtk; +using namespace ARDOUR; -MidiChannelSelector::MidiChannelSelector(int no_rows, int no_columns, int start_row, int start_column) : - Gtk::Table(no_rows, no_columns, true) -{ - assert(no_rows >= 4); - assert(no_rows >= start_row + 4); - assert(no_columns >=4); - assert(no_columns >= start_column + 4); - +MidiChannelSelector::MidiChannelSelector(int n_rows, int n_columns, int start_row, int start_column) + : 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) +{ property_column_spacing() = 0; property_row_spacing() = 0; - + uint8_t channel_nr = 0; - for(int row = 0; row < 4; ++row) { - for(int column = 0; column < 4; ++column) { + for (int row = 0; row < 4; ++row) { + for (int column = 0; column < 4; ++column) { ostringstream channel; channel << int(++channel_nr); _button_labels[row][column].set_text(channel.str()); - _button_labels[row][column].set_justify(Gtk::JUSTIFY_RIGHT); + _button_labels[row][column].set_justify(JUSTIFY_RIGHT); _buttons[row][column].add(_button_labels[row][column]); _buttons[row][column].signal_toggled().connect( sigc::bind( sigc::mem_fun(this, &MidiChannelSelector::button_toggled), &_buttons[row][column], channel_nr - 1)); + _buttons[row][column].set_widget_name (X_("MidiChannelSelectorButton")); + + _buttons[row][column].signal_button_release_event().connect( + sigc::mem_fun(this, &MidiChannelSelector::was_clicked), false); int table_row = start_row + row; int table_column = start_column + column; @@ -41,55 +82,151 @@ MidiChannelSelector::~MidiChannelSelector() { } +bool +MidiChannelSelector::was_clicked (GdkEventButton*) +{ + clicked (); + return false; +} + +void +MidiChannelSelector::set_channel_colors(const uint32_t new_channel_colors[16]) +{ + for (int row = 0; row < 4; ++row) { + for (int column = 0; column < 4; ++column) { + char color_normal[8]; + char color_active[8]; + snprintf(color_normal, 8, "#%x", UINT_INTERPOLATE(new_channel_colors[row * 4 + column], 0x000000ff, 0.6)); + snprintf(color_active, 8, "#%x", new_channel_colors[row * 4 + column]); + _buttons[row][column].modify_bg(STATE_NORMAL, Gdk::Color(color_normal)); + _buttons[row][column].modify_bg(STATE_ACTIVE, Gdk::Color(color_active)); + } + } +} + +void +MidiChannelSelector::set_default_channel_color() +{ + for (int row = 0; row < 4; ++row) { + for (int column = 0; column < 4; ++column) { + _buttons[row][column].unset_fg (STATE_NORMAL); + _buttons[row][column].unset_fg (STATE_ACTIVE); + _buttons[row][column].unset_bg (STATE_NORMAL); + _buttons[row][column].unset_bg (STATE_ACTIVE); + } + } +} + SingleMidiChannelSelector::SingleMidiChannelSelector(uint8_t active_channel) : MidiChannelSelector() { - _active_button = 0; - Gtk::ToggleButton *button = &_buttons[active_channel / 4][active_channel % 4]; - button->set_active(true); - _active_button = button; + _last_active_button = 0; + ToggleButton* button = &_buttons[active_channel / 4][active_channel % 4]; _active_channel = active_channel; + button->set_active(true); + _last_active_button = button; } void -SingleMidiChannelSelector::button_toggled(Gtk::ToggleButton *button, uint8_t channel) +SingleMidiChannelSelector::button_toggled(ToggleButton* button, uint8_t channel) { - if(button->get_active()) { - if(_active_button) { - _active_button->set_active(false); + ++_recursion_counter; + if (_recursion_counter == 1) { + // if the current button is active it must + // be different from the first one + if (button->get_active()) { + if (_last_active_button) { + _last_active_button->set_active(false); + _active_channel = channel; + _last_active_button = button; + channel_selected.emit(channel); + } + } else { + // if not, the user pressed the already active button + button->set_active(true); + _active_channel = channel; } - _active_button = button; - _active_channel = channel; - channel_selected.emit(channel); - } + } + --_recursion_counter; } -MidiMultipleChannelSelector::MidiMultipleChannelSelector(uint16_t initial_selection) - : MidiChannelSelector(6, 4, 0, 0) +MidiMultipleChannelSelector::MidiMultipleChannelSelector(ChannelMode mode, uint16_t mask) + : MidiChannelSelector(4, 6, 0, 0) + , _channel_mode(mode) { - _select_all.add(*Gtk::manage(new Gtk::Label(_("All")))); + _select_all.add(*manage(new Label(_("All")))); _select_all.signal_clicked().connect( sigc::bind(sigc::mem_fun(this, &MidiMultipleChannelSelector::select_all), true)); - - _select_none.add(*Gtk::manage(new Gtk::Label(_("None")))); + + _select_none.add(*manage(new Label(_("None")))); _select_none.signal_clicked().connect( sigc::bind(sigc::mem_fun(this, &MidiMultipleChannelSelector::select_all), false)); - - _invert_selection.add(*Gtk::manage(new Gtk::Label(_("Invert")))); + + _invert_selection.add(*manage(new Label(_("Invert")))); _invert_selection.signal_clicked().connect( sigc::mem_fun(this, &MidiMultipleChannelSelector::invert_selection)); + _force_channel.add(*manage(new Label(_("Force")))); + _force_channel.signal_toggled().connect( + sigc::mem_fun(this, &MidiMultipleChannelSelector::force_channels_button_toggled)); + set_homogeneous(false); - attach(*Gtk::manage(new Gtk::HSeparator()), 0, 4, 4, 5, Gtk::FILL, Gtk::SHRINK, 0, 0); - set_col_spacing(4, -5); - attach(_select_all, 0, 2, 5, 6); - attach(_select_none, 2, 4, 5, 6); - attach(_invert_selection, 0, 4, 6, 7); - - _selected_channels = 0; - for(uint16_t i = 0; i < 16; i++) { - Gtk::ToggleButton *button = &_buttons[i / 4][i % 4]; - if(initial_selection & (1L << i)) { + attach(*manage(new VSeparator()), 4, 5, 0, 4, SHRINK, FILL, 0, 0); + //set_row_spacing(4, -5); + attach(_select_all, 5, 6, 0, 1); + attach(_select_none, 5, 6, 1, 2); + attach(_invert_selection, 5, 6, 2, 3); + attach(_force_channel, 5, 6, 3, 4); + + set_selected_channels(mask); +} + +MidiMultipleChannelSelector::~MidiMultipleChannelSelector() +{ + mode_changed.clear(); +} + +void +MidiMultipleChannelSelector::set_channel_mode(ChannelMode mode, uint16_t mask) +{ + switch (mode) { + case AllChannels: + _force_channel.set_active(false); + set_selected_channels(0xFFFF); + break; + case FilterChannels: + _force_channel.set_active(false); + set_selected_channels(mask); + break; + case ForceChannel: + _force_channel.set_active(true); + for (uint16_t i = 0; i < 16; i++) { + ToggleButton* button = &_buttons[i / 4][i % 4]; + button->set_active(i == mask); + } + } +} + +uint16_t +MidiMultipleChannelSelector::get_selected_channels() const +{ + uint16_t selected_channels = 0; + for (uint16_t i = 0; i < 16; i++) { + const ToggleButton* button = &_buttons[i / 4][i % 4]; + if (button->get_active()) { + selected_channels |= (1L << i); + } + } + + return selected_channels; +} + +void +MidiMultipleChannelSelector::set_selected_channels(uint16_t selected_channels) +{ + for (uint16_t i = 0; i < 16; i++) { + ToggleButton* button = &_buttons[i / 4][i % 4]; + if (selected_channels & (1L << i)) { button->set_active(true); } else { button->set_active(false); @@ -98,33 +235,659 @@ MidiMultipleChannelSelector::MidiMultipleChannelSelector(uint16_t initial_select } void -MidiMultipleChannelSelector::button_toggled(Gtk::ToggleButton *button, uint8_t channel) +MidiMultipleChannelSelector::button_toggled(ToggleButton */*button*/, uint8_t channel) { - _selected_channels = _selected_channels ^ (1L << channel); - selection_changed.emit(_selected_channels); + ++_recursion_counter; + if (_recursion_counter == 1) { + if (_channel_mode == ForceChannel) { + mode_changed.emit(_channel_mode, channel); + set_selected_channels(1 << channel); + } else { + mode_changed.emit(_channel_mode, get_selected_channels()); + } + } + --_recursion_counter; } -void +void +MidiMultipleChannelSelector::force_channels_button_toggled() +{ + if (_force_channel.get_active()) { + _channel_mode = ForceChannel; + bool found_first_active = false; + // leave only the first button enabled + uint16_t active_channel = 0; + for (int i = 0; i <= 15; i++) { + ToggleButton* button = &_buttons[i / 4][i % 4]; + if (button->get_active()) { + if (found_first_active) { + ++_recursion_counter; + button->set_active(false); + --_recursion_counter; + } else { + found_first_active = true; + active_channel = i; + } + } + } + + if (!found_first_active) { + _buttons[0][0].set_active(true); + } + + _select_all.set_sensitive(false); + _select_none.set_sensitive(false); + _invert_selection.set_sensitive(false); + mode_changed.emit(_channel_mode, active_channel); + } else { + _channel_mode = FilterChannels; + _select_all.set_sensitive(true); + _select_none.set_sensitive(true); + _invert_selection.set_sensitive(true); + mode_changed.emit(FilterChannels, get_selected_channels()); + } +} + +void MidiMultipleChannelSelector::select_all(bool on) { - for(uint16_t i = 0; i < 16; i++) { - Gtk::ToggleButton *button = &_buttons[i / 4][i % 4]; + if (_channel_mode == ForceChannel) + return; + + ++_recursion_counter; + for (uint16_t i = 0; i < 16; i++) { + ToggleButton* button = &_buttons[i / 4][i % 4]; button->set_active(on); } - selection_changed.emit(_selected_channels); + --_recursion_counter; + mode_changed.emit(_channel_mode, get_selected_channels()); } -void +void MidiMultipleChannelSelector::invert_selection(void) { - for(uint16_t i = 0; i < 16; i++) { - Gtk::ToggleButton *button = &_buttons[i / 4][i % 4]; - if(button->get_active()) { + if (_channel_mode == ForceChannel) + return; + + ++_recursion_counter; + for (uint16_t i = 0; i < 16; i++) { + ToggleButton* button = &_buttons[i / 4][i % 4]; + if (button->get_active()) { button->set_active(false); } else { button->set_active(true); } } - selection_changed.emit(_selected_channels); + --_recursion_counter; + mode_changed.emit(_channel_mode, get_selected_channels()); +} + +/*-----------------------------------------*/ + +MidiChannelSelectorWindow::MidiChannelSelectorWindow (boost::shared_ptr mt) + : 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_mode_changed (); + capture_mode_changed (); + + 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() +{ +} + +void +MidiChannelSelectorWindow::build () +{ + VBox* vpacker; + HBox* capture_controls; + HBox* playback_controls; + Button* b; + Label* l; + + vpacker = manage (new VBox); + vpacker->set_spacing (6); + vpacker->set_border_width (12); + + l = manage (new Label (string_compose (("%1: %2"), _("MIDI Channel Control"), track->name()))); + l->set_use_markup (true); + l->set_alignment (0.5, 0.0); + + vpacker->pack_start (*l, true, true); + + l = manage (new Label (string_compose ("%1", _("Inbound")))); + l->set_use_markup (true); + vpacker->pack_start (*l); + + + vpacker->pack_start (capture_all_button); + capture_all_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), AllChannels)); + + vpacker->pack_start (capture_filter_button); + capture_filter_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), FilterChannels)); + + 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_box); + + 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_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_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_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_controls); + + l = manage (new Label (string_compose ("%1", _("Playback")))); + l->set_use_markup (true); + vpacker->pack_start (*l); + + 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_filter_button); + playback_filter_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), FilterChannels)); + + 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_mask_box); + + 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_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_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_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_controls); + + add (*vpacker); +} + +void +MidiChannelSelectorWindow::fill_playback_mask () +{ + if (track->get_playback_channel_mode() == FilterChannels) { + track->set_playback_channel_mask (0xffff); + } +} + +void +MidiChannelSelectorWindow::zero_playback_mask () +{ + if (track->get_playback_channel_mode() == FilterChannels) { + track->set_playback_channel_mask (0); + } +} + +void +MidiChannelSelectorWindow::invert_playback_mask () +{ + if (track->get_playback_channel_mode() == FilterChannels) { + track->set_playback_channel_mask (~track->get_playback_channel_mask()); + } +} + +void +MidiChannelSelectorWindow::fill_capture_mask () +{ + if (track->get_capture_channel_mode() == FilterChannels) { + track->set_capture_channel_mask (0xffff); + } +} + +void +MidiChannelSelectorWindow::zero_capture_mask () +{ + if (track->get_capture_channel_mode() == FilterChannels) { + track->set_capture_channel_mask (0); + } +} + +void +MidiChannelSelectorWindow::invert_capture_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) +{ + 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<set_active (i == (PBD::ffs (mask) - 1)); + } + break; + } +} + +void +MidiChannelSelectorWindow::set_capture_selected_channels (uint16_t 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<set_active (i == (PBD::ffs (mask) - 1)); + } + break; + } +} + +void +MidiChannelSelectorWindow::playback_mask_changed () +{ + set_playback_selected_channels (track->get_playback_channel_mask()); +} + +void +MidiChannelSelectorWindow::capture_mask_changed () +{ + set_capture_selected_channels (track->get_capture_channel_mask()); +} + +void +MidiChannelSelectorWindow::playback_mode_changed () +{ + uint32_t first_channel = 0; + ChannelMode mode = track->get_playback_channel_mode(); + + switch (mode) { + case AllChannels: + 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::iterator i = playback_mask_controls.begin(); i != playback_mask_controls.end(); ++i) { + (*i)->set_sensitive (false); + } + playback_all_button.set_active (); + break; + + case FilterChannels: + if (last_drawn_playback_mode == ForceChannel) { + playback_buttons.clear (); + } else if (last_drawn_playback_mode == AllChannels) { + for (vector::iterator i = playback_buttons.begin(); i != playback_buttons.end(); ++i) { + (*i)->set_sensitive (true); + } + } + for (vector::iterator i = playback_mask_controls.begin(); i != playback_mask_controls.end(); ++i) { + (*i)->set_sensitive (true); + } + playback_filter_button.set_active (); + break; + + case ForceChannel: + 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::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::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 () +{ + uint32_t first_channel = 0; + ChannelMode mode = track->get_capture_channel_mode(); + + switch (mode) { + case AllChannels: + 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::iterator i = capture_mask_controls.begin(); i != capture_mask_controls.end(); ++i) { + (*i)->set_sensitive (false); + } + capture_all_button.set_active (); + break; + + case FilterChannels: + if (last_drawn_capture_mode == ForceChannel) { + capture_buttons.clear (); + } else if (last_drawn_capture_mode == AllChannels) { + for (vector::iterator i = capture_buttons.begin(); i != capture_buttons.end(); ++i) { + (*i)->set_sensitive (true); + } + } + for (vector::iterator i = capture_mask_controls.begin(); i != capture_mask_controls.end(); ++i) { + (*i)->set_sensitive (true); + } + capture_filter_button.set_active (); + break; + + case ForceChannel: + 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::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::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()) { + switch (track->get_playback_channel_mode()) { + case AllChannels: + break; + case FilterChannels: + track->set_playback_channel_mask (track->get_playback_channel_mask() | (1<set_playback_channel_mask (1<get_playback_channel_mode() == FilterChannels) { + track->set_playback_channel_mask (track->get_playback_channel_mask() & ~(1<get_active()) { + switch (track->get_capture_channel_mode()) { + case AllChannels: + break; + case FilterChannels: + track->set_capture_channel_mask (track->get_capture_channel_mask() | (1<set_capture_channel_mask (1<get_capture_channel_mode() == FilterChannels) { + track->set_capture_channel_mask (track->get_capture_channel_mask() & ~(1<set_capture_channel_mode (AllChannels, track->get_capture_channel_mask()); + } + break; + case FilterChannels: + if (capture_filter_button.get_active()) { + track->set_capture_channel_mode (FilterChannels, track->get_capture_channel_mask()); + } + break; + case ForceChannel: + if (capture_force_button.get_active()) { + track->set_capture_channel_mode (ForceChannel, track->get_capture_channel_mask()); + } + break; + } +} + +void +MidiChannelSelectorWindow::playback_mode_toggled (ChannelMode mode) +{ + /* this is called twice for every radio button change. the first time + 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 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()) { + track->set_playback_channel_mode (AllChannels, track->get_playback_channel_mask()); + } + break; + case FilterChannels: + if (playback_filter_button.get_active()) { + track->set_playback_channel_mode (FilterChannels, track->get_playback_channel_mask()); + } + break; + case ForceChannel: + if (playback_force_button.get_active()) { + track->set_playback_channel_mode (ForceChannel, track->get_playback_channel_mask()); + } + break; + } +} + +void +MidiChannelSelectorWindow::set_channel_colors (const uint32_t new_channel_colors[16]) +{ + for (uint32_t n = 0; n < 16; ++n) { + + 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]); + + playback_buttons[n]->modify_bg(STATE_NORMAL, Gdk::Color(color_normal)); + playback_buttons[n]->modify_bg(STATE_ACTIVE, Gdk::Color(color_active)); + + capture_buttons[n]->modify_bg(STATE_NORMAL, Gdk::Color(color_normal)); + capture_buttons[n]->modify_bg(STATE_ACTIVE, Gdk::Color(color_active)); + } +} + +void +MidiChannelSelectorWindow::set_default_channel_color() +{ + for (uint32_t n = 0; n < 16; ++n) { + playback_buttons[n]->unset_fg (STATE_NORMAL); + playback_buttons[n]->unset_bg (STATE_NORMAL); + playback_buttons[n]->unset_fg (STATE_ACTIVE); + playback_buttons[n]->unset_bg (STATE_ACTIVE); + + capture_buttons[n]->unset_fg (STATE_NORMAL); + capture_buttons[n]->unset_bg (STATE_NORMAL); + capture_buttons[n]->unset_fg (STATE_ACTIVE); + capture_buttons[n]->unset_bg (STATE_ACTIVE); + } +}