X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fmidi_channel_selector.cc;h=c889602b8c849fb9e2d858f0bdbdece59c1c89f8;hb=fcbb78b010a53686d1c350864d731a73bd204956;hp=6fba415389c2683c7c05dca63607c628f40c57f8;hpb=7ba87f7672caf9a0ae395e895c1ca50543442636;p=ardour.git diff --git a/gtk2_ardour/midi_channel_selector.cc b/gtk2_ardour/midi_channel_selector.cc index 6fba415389..c889602b8c 100644 --- a/gtk2_ardour/midi_channel_selector.cc +++ b/gtk2_ardour/midi_channel_selector.cc @@ -1,28 +1,51 @@ +/* + Copyright (C) 2008 Paul Davis + 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 "midi_channel_selector.h" #include "gtkmm/separator.h" #include "i18n.h" -#include +#include "rgb_macros.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) + , _recursion_counter(0) +{ + assert(n_rows >= 4); + assert(n_rows >= start_row + 4); + assert(n_columns >=4); + assert(n_columns >= start_column + 4); -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); - 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( @@ -41,55 +64,142 @@ MidiChannelSelector::~MidiChannelSelector() { } +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_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(*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(*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(*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(*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,30 +208,90 @@ 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); + ++_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 +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 +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); } + --_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); } } + --_recursion_counter; + mode_changed.emit(_channel_mode, get_selected_channels()); }