2 Copyright (C) 2008 Paul Davis
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "midi_channel_selector.h"
22 #include "gtkmm/separator.h"
28 using namespace ARDOUR;
30 MidiChannelSelector::MidiChannelSelector(int no_rows, int no_columns, int start_row, int start_column) : Table(no_rows, no_columns, true)
31 , _recursion_counter(0)
34 assert(no_rows >= start_row + 4);
35 assert(no_columns >=4);
36 assert(no_columns >= start_column + 4);
38 property_column_spacing() = 0;
39 property_row_spacing() = 0;
41 uint8_t channel_nr = 0;
42 for (int row = 0; row < 4; ++row) {
43 for (int column = 0; column < 4; ++column) {
44 ostringstream channel;
45 channel << int(++channel_nr);
46 _button_labels[row][column].set_text(channel.str());
47 _button_labels[row][column].set_justify(JUSTIFY_RIGHT);
48 _buttons[row][column].add(_button_labels[row][column]);
49 _buttons[row][column].signal_toggled().connect(
51 mem_fun(this, &MidiChannelSelector::button_toggled),
52 &_buttons[row][column],
55 int table_row = start_row + row;
56 int table_column = start_column + column;
57 attach(_buttons[row][column], table_column, table_column + 1, table_row, table_row + 1);
62 MidiChannelSelector::~MidiChannelSelector()
66 SingleMidiChannelSelector::SingleMidiChannelSelector(uint8_t active_channel)
67 : MidiChannelSelector()
69 _last_active_button = 0;
70 ToggleButton* button = &_buttons[active_channel / 4][active_channel % 4];
71 _active_channel = active_channel;
72 button->set_active(true);
73 _last_active_button = button;
77 SingleMidiChannelSelector::button_toggled(ToggleButton* button, uint8_t channel)
80 if (_recursion_counter == 1) {
81 // if the current button is active it must
82 // be different from the first one
83 if (button->get_active()) {
84 if (_last_active_button) {
85 _last_active_button->set_active(false);
86 _active_channel = channel;
87 _last_active_button = button;
88 channel_selected.emit(channel);
91 // if not, the user pressed the already active button
92 button->set_active(true);
93 _active_channel = channel;
99 MidiMultipleChannelSelector::MidiMultipleChannelSelector(ChannelMode mode, uint16_t mask)
100 : MidiChannelSelector(4, 6, 0, 0)
101 , _channel_mode(mode)
103 _select_all.add(*manage(new Label(_("All"))));
104 _select_all.signal_clicked().connect(
105 bind(mem_fun(this, &MidiMultipleChannelSelector::select_all), true));
107 _select_none.add(*manage(new Label(_("None"))));
108 _select_none.signal_clicked().connect(
109 bind(mem_fun(this, &MidiMultipleChannelSelector::select_all), false));
111 _invert_selection.add(*manage(new Label(_("Invert"))));
112 _invert_selection.signal_clicked().connect(
113 mem_fun(this, &MidiMultipleChannelSelector::invert_selection));
115 _force_channel.add(*manage(new Label(_("Force"))));
116 _force_channel.signal_toggled().connect(
117 mem_fun(this, &MidiMultipleChannelSelector::force_channels_button_toggled));
119 set_homogeneous(false);
120 attach(*manage(new VSeparator()), 4, 5, 0, 4, SHRINK, FILL, 0, 0);
121 //set_row_spacing(4, -5);
122 attach(_select_all, 5, 6, 0, 1);
123 attach(_select_none, 5, 6, 1, 2);
124 attach(_invert_selection, 5, 6, 2, 3);
125 attach(_force_channel, 5, 6, 3, 4);
127 set_selected_channels(mask);
130 MidiMultipleChannelSelector::~MidiMultipleChannelSelector()
132 mode_changed.clear();
136 MidiMultipleChannelSelector::set_channel_mode(ChannelMode mode, uint8_t mask)
140 _force_channel.set_active(false);
141 set_selected_channels(0xFFFF);
144 _force_channel.set_active(false);
145 set_selected_channels(mask);
148 _force_channel.set_active(true);
149 for (uint16_t i = 0; i < 16; i++) {
150 ToggleButton* button = &_buttons[i / 4][i % 4];
151 button->set_active(i == mask);
157 MidiMultipleChannelSelector::get_selected_channels() const
159 uint16_t selected_channels = 0;
160 for (uint16_t i = 0; i < 16; i++) {
161 const ToggleButton* button = &_buttons[i / 4][i % 4];
162 if (button->get_active()) {
163 selected_channels |= (1L << i);
167 return selected_channels;
171 MidiMultipleChannelSelector::set_selected_channels(uint16_t selected_channels)
173 for (uint16_t i = 0; i < 16; i++) {
174 ToggleButton* button = &_buttons[i / 4][i % 4];
175 if (selected_channels & (1L << i)) {
176 button->set_active(true);
178 button->set_active(false);
184 MidiMultipleChannelSelector::button_toggled(ToggleButton *button, uint8_t channel)
186 ++_recursion_counter;
187 if (_recursion_counter == 1) {
188 if (_channel_mode == ForceChannel) {
189 mode_changed.emit(_channel_mode, channel);
190 set_selected_channels(1 << channel);
192 mode_changed.emit(_channel_mode, get_selected_channels());
195 --_recursion_counter;
199 MidiMultipleChannelSelector::force_channels_button_toggled()
201 if (_force_channel.get_active()) {
202 _channel_mode = ForceChannel;
203 bool found_first_active = false;
204 // leave only the first button enabled
205 uint16_t active_channel = 0;
206 for (int i = 0; i <= 15; i++) {
207 ToggleButton* button = &_buttons[i / 4][i % 4];
208 if (button->get_active()) {
209 if (found_first_active) {
210 ++_recursion_counter;
211 button->set_active(false);
212 --_recursion_counter;
214 found_first_active = true;
220 if (!found_first_active) {
221 _buttons[0][0].set_active(true);
224 _select_all.set_sensitive(false);
225 _select_none.set_sensitive(false);
226 _invert_selection.set_sensitive(false);
227 mode_changed.emit(_channel_mode, active_channel);
229 _channel_mode = FilterChannels;
230 _select_all.set_sensitive(true);
231 _select_none.set_sensitive(true);
232 _invert_selection.set_sensitive(true);
233 mode_changed.emit(FilterChannels, get_selected_channels());
238 MidiMultipleChannelSelector::select_all(bool on)
240 if (_channel_mode == ForceChannel)
243 ++_recursion_counter;
244 for (uint16_t i = 0; i < 16; i++) {
245 ToggleButton* button = &_buttons[i / 4][i % 4];
246 button->set_active(on);
248 --_recursion_counter;
249 mode_changed.emit(_channel_mode, get_selected_channels());
253 MidiMultipleChannelSelector::invert_selection(void)
255 if (_channel_mode == ForceChannel)
258 ++_recursion_counter;
259 for (uint16_t i = 0; i < 16; i++) {
260 ToggleButton* button = &_buttons[i / 4][i % 4];
261 if (button->get_active()) {
262 button->set_active(false);
264 button->set_active(true);
267 --_recursion_counter;
268 mode_changed.emit(_channel_mode, get_selected_channels());