Make send automation work (#4734).
[ardour.git] / gtk2_ardour / midi_channel_selector.cc
1 /*
2     Copyright (C) 2008 Paul Davis
3     Author: Hans Baier
4
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.
9
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.
14
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.
18 */
19
20 #include <sstream>
21 #include "midi_channel_selector.h"
22 #include "gtkmm/separator.h"
23 #include "i18n.h"
24 #include "rgb_macros.h"
25
26 using namespace std;
27 using namespace Gtk;
28 using namespace ARDOUR;
29
30 MidiChannelSelector::MidiChannelSelector(int n_rows, int n_columns, int start_row, int start_column)
31         : Table(n_rows, n_columns, true)
32         , _recursion_counter(0)
33 {
34         assert(n_rows >= 4);
35         assert(n_rows >= start_row + 4);
36         assert(n_columns >=4);
37         assert(n_columns >= start_column + 4);
38
39         property_column_spacing() = 0;
40         property_row_spacing() = 0;
41
42         uint8_t channel_nr = 0;
43         for (int row = 0; row < 4; ++row) {
44                 for (int column = 0; column < 4; ++column) {
45                         ostringstream channel;
46                         channel << int(++channel_nr);
47                         _button_labels[row][column].set_text(channel.str());
48                         _button_labels[row][column].set_justify(JUSTIFY_RIGHT);
49                         _buttons[row][column].add(_button_labels[row][column]);
50                         _buttons[row][column].signal_toggled().connect(
51                                 sigc::bind(
52                                         sigc::mem_fun(this, &MidiChannelSelector::button_toggled),
53                                         &_buttons[row][column],
54                                         channel_nr - 1));
55                         _buttons[row][column].set_widget_name (X_("MidiChannelSelectorButton"));
56
57                         _buttons[row][column].signal_button_release_event().connect(
58                                 sigc::mem_fun(this, &MidiChannelSelector::was_clicked), false);
59
60                         int table_row    = start_row + row;
61                         int table_column = start_column + column;
62                         attach(_buttons[row][column], table_column, table_column + 1, table_row, table_row + 1);
63                 }
64         }
65 }
66
67 MidiChannelSelector::~MidiChannelSelector()
68 {
69 }
70
71 bool
72 MidiChannelSelector::was_clicked (GdkEventButton*)
73 {
74         clicked ();
75         return false;
76 }
77
78 void
79 MidiChannelSelector::set_channel_colors(const uint32_t new_channel_colors[16])
80 {
81         for (int row = 0; row < 4; ++row) {
82                 for (int column = 0; column < 4; ++column) {
83                         char color_normal[8];
84                         char color_active[8];
85                         snprintf(color_normal, 8, "#%x", UINT_INTERPOLATE(new_channel_colors[row * 4 + column], 0x000000ff, 0.6));
86                         snprintf(color_active, 8, "#%x", new_channel_colors[row * 4 + column]);
87                         _buttons[row][column].modify_bg(STATE_NORMAL, Gdk::Color(color_normal));
88                         _buttons[row][column].modify_bg(STATE_ACTIVE, Gdk::Color(color_active));
89                 }
90         }
91 }
92
93 void
94 MidiChannelSelector::set_default_channel_color()
95 {
96         for (int row = 0; row < 4; ++row) {
97                 for (int column = 0; column < 4; ++column) {
98                         _buttons[row][column].unset_fg (STATE_NORMAL);
99                         _buttons[row][column].unset_fg (STATE_ACTIVE);
100                         _buttons[row][column].unset_bg (STATE_NORMAL);
101                         _buttons[row][column].unset_bg (STATE_ACTIVE);
102                 }
103         }
104 }
105
106 SingleMidiChannelSelector::SingleMidiChannelSelector(uint8_t active_channel)
107         : MidiChannelSelector()
108 {
109         _last_active_button = 0;
110         ToggleButton* button = &_buttons[active_channel / 4][active_channel % 4];
111         _active_channel = active_channel;
112         button->set_active(true);
113         _last_active_button = button;
114 }
115
116 void
117 SingleMidiChannelSelector::button_toggled(ToggleButton* button, uint8_t channel)
118 {
119         ++_recursion_counter;
120         if (_recursion_counter == 1) {
121                 // if the current button is active it must
122                 // be different from the first one
123                 if (button->get_active()) {
124                         if (_last_active_button) {
125                                 _last_active_button->set_active(false);
126                                 _active_channel = channel;
127                                 _last_active_button = button;
128                                 channel_selected.emit(channel);
129                         }
130                 } else {
131                         // if not, the user pressed the already active button
132                         button->set_active(true);
133                         _active_channel = channel;
134                 }
135         }
136         --_recursion_counter;
137 }
138
139 MidiMultipleChannelSelector::MidiMultipleChannelSelector(ChannelMode mode, uint16_t mask)
140         : MidiChannelSelector(4, 6, 0, 0)
141         , _channel_mode(mode)
142 {
143         _select_all.add(*manage(new Label(_("All"))));
144         _select_all.signal_clicked().connect(
145                         sigc::bind(sigc::mem_fun(this, &MidiMultipleChannelSelector::select_all), true));
146
147         _select_none.add(*manage(new Label(_("None"))));
148         _select_none.signal_clicked().connect(
149                         sigc::bind(sigc::mem_fun(this, &MidiMultipleChannelSelector::select_all), false));
150
151         _invert_selection.add(*manage(new Label(_("Invert"))));
152         _invert_selection.signal_clicked().connect(
153                         sigc::mem_fun(this, &MidiMultipleChannelSelector::invert_selection));
154
155         _force_channel.add(*manage(new Label(_("Force"))));
156         _force_channel.signal_toggled().connect(
157                         sigc::mem_fun(this, &MidiMultipleChannelSelector::force_channels_button_toggled));
158
159         set_homogeneous(false);
160         attach(*manage(new VSeparator()), 4, 5, 0, 4, SHRINK, FILL, 0, 0);
161         //set_row_spacing(4, -5);
162         attach(_select_all,       5, 6, 0, 1);
163         attach(_select_none,      5, 6, 1, 2);
164         attach(_invert_selection, 5, 6, 2, 3);
165         attach(_force_channel,    5, 6, 3, 4);
166
167         set_selected_channels(mask);
168 }
169
170 MidiMultipleChannelSelector::~MidiMultipleChannelSelector()
171 {
172         mode_changed.clear();
173 }
174
175 void
176 MidiMultipleChannelSelector::set_channel_mode(ChannelMode mode, uint16_t mask)
177 {
178         switch (mode) {
179         case AllChannels:
180                 _force_channel.set_active(false);
181                 set_selected_channels(0xFFFF);
182                 break;
183         case FilterChannels:
184                 _force_channel.set_active(false);
185                 set_selected_channels(mask);
186                 break;
187         case ForceChannel:
188                 _force_channel.set_active(true);
189                 for (uint16_t i = 0; i < 16; i++) {
190                         ToggleButton* button = &_buttons[i / 4][i % 4];
191                         button->set_active(i == mask);
192                 }
193         }
194 }
195
196 uint16_t
197 MidiMultipleChannelSelector::get_selected_channels() const
198 {
199         uint16_t selected_channels = 0;
200         for (uint16_t i = 0; i < 16; i++) {
201                 const ToggleButton* button = &_buttons[i / 4][i % 4];
202                 if (button->get_active()) {
203                         selected_channels |= (1L << i);
204                 }
205         }
206
207         return selected_channels;
208 }
209
210 void
211 MidiMultipleChannelSelector::set_selected_channels(uint16_t selected_channels)
212 {
213         for (uint16_t i = 0; i < 16; i++) {
214                 ToggleButton* button = &_buttons[i / 4][i % 4];
215                 if (selected_channels & (1L << i)) {
216                         button->set_active(true);
217                 } else {
218                         button->set_active(false);
219                 }
220         }
221 }
222
223 void
224 MidiMultipleChannelSelector::button_toggled(ToggleButton */*button*/, uint8_t channel)
225 {
226         ++_recursion_counter;
227         if (_recursion_counter == 1) {
228                 if (_channel_mode == ForceChannel) {
229                         mode_changed.emit(_channel_mode, channel);
230                         set_selected_channels(1 << channel);
231                 } else {
232                         mode_changed.emit(_channel_mode, get_selected_channels());
233                 }
234         }
235         --_recursion_counter;
236 }
237
238 void
239 MidiMultipleChannelSelector::force_channels_button_toggled()
240 {
241         if (_force_channel.get_active()) {
242                 _channel_mode = ForceChannel;
243                 bool found_first_active = false;
244                 // leave only the first button enabled
245                 uint16_t active_channel = 0;
246                 for (int i = 0; i <= 15; i++) {
247                         ToggleButton* button = &_buttons[i / 4][i % 4];
248                         if (button->get_active()) {
249                                 if (found_first_active) {
250                                         ++_recursion_counter;
251                                         button->set_active(false);
252                                         --_recursion_counter;
253                                 } else {
254                                         found_first_active = true;
255                                         active_channel = i;
256                                 }
257                         }
258                 }
259
260                 if (!found_first_active) {
261                         _buttons[0][0].set_active(true);
262                 }
263
264                 _select_all.set_sensitive(false);
265                 _select_none.set_sensitive(false);
266                 _invert_selection.set_sensitive(false);
267                 mode_changed.emit(_channel_mode, active_channel);
268         } else {
269                 _channel_mode = FilterChannels;
270                 _select_all.set_sensitive(true);
271                 _select_none.set_sensitive(true);
272                 _invert_selection.set_sensitive(true);
273                 mode_changed.emit(FilterChannels, get_selected_channels());
274         }
275 }
276
277 void
278 MidiMultipleChannelSelector::select_all(bool on)
279 {
280         if (_channel_mode == ForceChannel)
281                 return;
282
283         ++_recursion_counter;
284         for (uint16_t i = 0; i < 16; i++) {
285                 ToggleButton* button = &_buttons[i / 4][i % 4];
286                 button->set_active(on);
287         }
288         --_recursion_counter;
289         mode_changed.emit(_channel_mode, get_selected_channels());
290 }
291
292 void
293 MidiMultipleChannelSelector::invert_selection(void)
294 {
295         if (_channel_mode == ForceChannel)
296                 return;
297
298         ++_recursion_counter;
299         for (uint16_t i = 0; i < 16; i++) {
300                 ToggleButton* button = &_buttons[i / 4][i % 4];
301                 if (button->get_active()) {
302                         button->set_active(false);
303                 } else {
304                         button->set_active(true);
305                 }
306         }
307         --_recursion_counter;
308         mode_changed.emit(_channel_mode, get_selected_channels());
309 }
310