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.
23 #include "midi_channel_selector.h"
24 #include "gtkmm/separator.h"
26 #include "rgb_macros.h"
30 using namespace ARDOUR;
32 MidiChannelSelector::MidiChannelSelector(int n_rows, int n_columns, int start_row, int start_column)
33 : Table(n_rows, n_columns, true)
34 , _recursion_counter(0)
36 n_rows = std::max(4, n_rows);
37 n_rows = std::max(4, start_row + 4);
38 n_columns = std::max(4, n_columns);
39 n_columns = std::max(4, start_column + 4);
41 property_column_spacing() = 0;
42 property_row_spacing() = 0;
44 uint8_t channel_nr = 0;
45 for (int row = 0; row < 4; ++row) {
46 for (int column = 0; column < 4; ++column) {
47 ostringstream channel;
48 channel << int(++channel_nr);
49 _button_labels[row][column].set_text(channel.str());
50 _button_labels[row][column].set_justify(JUSTIFY_RIGHT);
51 _buttons[row][column].add(_button_labels[row][column]);
52 _buttons[row][column].signal_toggled().connect(
54 sigc::mem_fun(this, &MidiChannelSelector::button_toggled),
55 &_buttons[row][column],
57 _buttons[row][column].set_widget_name (X_("MidiChannelSelectorButton"));
59 _buttons[row][column].signal_button_release_event().connect(
60 sigc::mem_fun(this, &MidiChannelSelector::was_clicked), false);
62 int table_row = start_row + row;
63 int table_column = start_column + column;
64 attach(_buttons[row][column], table_column, table_column + 1, table_row, table_row + 1);
69 MidiChannelSelector::~MidiChannelSelector()
74 MidiChannelSelector::was_clicked (GdkEventButton*)
81 MidiChannelSelector::set_channel_colors(const uint32_t new_channel_colors[16])
83 for (int row = 0; row < 4; ++row) {
84 for (int column = 0; column < 4; ++column) {
87 snprintf(color_normal, 8, "#%x", UINT_INTERPOLATE(new_channel_colors[row * 4 + column], 0x000000ff, 0.6));
88 snprintf(color_active, 8, "#%x", new_channel_colors[row * 4 + column]);
89 _buttons[row][column].modify_bg(STATE_NORMAL, Gdk::Color(color_normal));
90 _buttons[row][column].modify_bg(STATE_ACTIVE, Gdk::Color(color_active));
96 MidiChannelSelector::set_default_channel_color()
98 for (int row = 0; row < 4; ++row) {
99 for (int column = 0; column < 4; ++column) {
100 _buttons[row][column].unset_fg (STATE_NORMAL);
101 _buttons[row][column].unset_fg (STATE_ACTIVE);
102 _buttons[row][column].unset_bg (STATE_NORMAL);
103 _buttons[row][column].unset_bg (STATE_ACTIVE);
108 SingleMidiChannelSelector::SingleMidiChannelSelector(uint8_t active_channel)
109 : MidiChannelSelector()
111 _last_active_button = 0;
112 ToggleButton* button = &_buttons[active_channel / 4][active_channel % 4];
113 _active_channel = active_channel;
114 button->set_active(true);
115 _last_active_button = button;
119 SingleMidiChannelSelector::button_toggled(ToggleButton* button, uint8_t channel)
121 ++_recursion_counter;
122 if (_recursion_counter == 1) {
123 // if the current button is active it must
124 // be different from the first one
125 if (button->get_active()) {
126 if (_last_active_button) {
127 _last_active_button->set_active(false);
128 _active_channel = channel;
129 _last_active_button = button;
130 channel_selected.emit(channel);
133 // if not, the user pressed the already active button
134 button->set_active(true);
135 _active_channel = channel;
138 --_recursion_counter;
141 MidiMultipleChannelSelector::MidiMultipleChannelSelector(ChannelMode mode, uint16_t mask)
142 : MidiChannelSelector(4, 6, 0, 0)
143 , _channel_mode(mode)
145 _select_all.add(*manage(new Label(_("All"))));
146 _select_all.signal_clicked().connect(
147 sigc::bind(sigc::mem_fun(this, &MidiMultipleChannelSelector::select_all), true));
149 _select_none.add(*manage(new Label(_("None"))));
150 _select_none.signal_clicked().connect(
151 sigc::bind(sigc::mem_fun(this, &MidiMultipleChannelSelector::select_all), false));
153 _invert_selection.add(*manage(new Label(_("Invert"))));
154 _invert_selection.signal_clicked().connect(
155 sigc::mem_fun(this, &MidiMultipleChannelSelector::invert_selection));
157 _force_channel.add(*manage(new Label(_("Force"))));
158 _force_channel.signal_toggled().connect(
159 sigc::mem_fun(this, &MidiMultipleChannelSelector::force_channels_button_toggled));
161 set_homogeneous(false);
162 attach(*manage(new VSeparator()), 4, 5, 0, 4, SHRINK, FILL, 0, 0);
163 //set_row_spacing(4, -5);
164 attach(_select_all, 5, 6, 0, 1);
165 attach(_select_none, 5, 6, 1, 2);
166 attach(_invert_selection, 5, 6, 2, 3);
167 attach(_force_channel, 5, 6, 3, 4);
169 set_selected_channels(mask);
172 MidiMultipleChannelSelector::~MidiMultipleChannelSelector()
174 mode_changed.clear();
178 MidiMultipleChannelSelector::set_channel_mode(ChannelMode mode, uint16_t mask)
182 _force_channel.set_active(false);
183 set_selected_channels(0xFFFF);
186 _force_channel.set_active(false);
187 set_selected_channels(mask);
190 _force_channel.set_active(true);
191 for (uint16_t i = 0; i < 16; i++) {
192 ToggleButton* button = &_buttons[i / 4][i % 4];
193 button->set_active(i == mask);
199 MidiMultipleChannelSelector::get_selected_channels() const
201 uint16_t selected_channels = 0;
202 for (uint16_t i = 0; i < 16; i++) {
203 const ToggleButton* button = &_buttons[i / 4][i % 4];
204 if (button->get_active()) {
205 selected_channels |= (1L << i);
209 return selected_channels;
213 MidiMultipleChannelSelector::set_selected_channels(uint16_t selected_channels)
215 for (uint16_t i = 0; i < 16; i++) {
216 ToggleButton* button = &_buttons[i / 4][i % 4];
217 if (selected_channels & (1L << i)) {
218 button->set_active(true);
220 button->set_active(false);
226 MidiMultipleChannelSelector::button_toggled(ToggleButton */*button*/, uint8_t channel)
228 ++_recursion_counter;
229 if (_recursion_counter == 1) {
230 if (_channel_mode == ForceChannel) {
231 mode_changed.emit(_channel_mode, channel);
232 set_selected_channels(1 << channel);
234 mode_changed.emit(_channel_mode, get_selected_channels());
237 --_recursion_counter;
241 MidiMultipleChannelSelector::force_channels_button_toggled()
243 if (_force_channel.get_active()) {
244 _channel_mode = ForceChannel;
245 bool found_first_active = false;
246 // leave only the first button enabled
247 uint16_t active_channel = 0;
248 for (int i = 0; i <= 15; i++) {
249 ToggleButton* button = &_buttons[i / 4][i % 4];
250 if (button->get_active()) {
251 if (found_first_active) {
252 ++_recursion_counter;
253 button->set_active(false);
254 --_recursion_counter;
256 found_first_active = true;
262 if (!found_first_active) {
263 _buttons[0][0].set_active(true);
266 _select_all.set_sensitive(false);
267 _select_none.set_sensitive(false);
268 _invert_selection.set_sensitive(false);
269 mode_changed.emit(_channel_mode, active_channel);
271 _channel_mode = FilterChannels;
272 _select_all.set_sensitive(true);
273 _select_none.set_sensitive(true);
274 _invert_selection.set_sensitive(true);
275 mode_changed.emit(FilterChannels, get_selected_channels());
280 MidiMultipleChannelSelector::select_all(bool on)
282 if (_channel_mode == ForceChannel)
285 ++_recursion_counter;
286 for (uint16_t i = 0; i < 16; i++) {
287 ToggleButton* button = &_buttons[i / 4][i % 4];
288 button->set_active(on);
290 --_recursion_counter;
291 mode_changed.emit(_channel_mode, get_selected_channels());
295 MidiMultipleChannelSelector::invert_selection(void)
297 if (_channel_mode == ForceChannel)
300 ++_recursion_counter;
301 for (uint16_t i = 0; i < 16; i++) {
302 ToggleButton* button = &_buttons[i / 4][i % 4];
303 if (button->get_active()) {
304 button->set_active(false);
306 button->set_active(true);
309 --_recursion_counter;
310 mode_changed.emit(_channel_mode, get_selected_channels());