281c6f5e2d58fe866fa3531cf82a454b2a0a54b6
[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
25 using namespace std;
26 using namespace Gtk;
27 using namespace sigc;
28 using namespace ARDOUR;
29
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)
32 {       
33         assert(no_rows >= 4);
34         assert(no_rows >= start_row + 4);
35         assert(no_columns >=4);
36         assert(no_columns >= start_column + 4);
37         
38         property_column_spacing() = 0;
39         property_row_spacing() = 0;
40         
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(
50                                 bind(
51                                         mem_fun(this, &MidiChannelSelector::button_toggled),
52                                         &_buttons[row][column],
53                                         channel_nr - 1));
54
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);
58                 }
59         }
60 }
61
62 MidiChannelSelector::~MidiChannelSelector()
63 {
64 }
65
66 SingleMidiChannelSelector::SingleMidiChannelSelector(uint8_t active_channel)
67         : MidiChannelSelector()
68 {
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;
74 }
75
76 void
77 SingleMidiChannelSelector::button_toggled(ToggleButton* button, uint8_t channel)
78 {       
79         ++_recursion_counter;
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);
89                         }
90                 } else {
91                         // if not, the user pressed the already active button
92                         button->set_active(true);
93                         _active_channel = channel;
94                 }
95         }
96         --_recursion_counter;
97 }
98
99 MidiMultipleChannelSelector::MidiMultipleChannelSelector(ChannelMode mode, uint16_t mask)
100         : MidiChannelSelector(4, 6, 0, 0)
101         , _channel_mode(mode)
102 {
103         _select_all.add(*manage(new Label(_("All"))));
104         _select_all.signal_clicked().connect(
105                         bind(mem_fun(this, &MidiMultipleChannelSelector::select_all), true));
106         
107         _select_none.add(*manage(new Label(_("None"))));
108         _select_none.signal_clicked().connect(
109                         bind(mem_fun(this, &MidiMultipleChannelSelector::select_all), false));
110         
111         _invert_selection.add(*manage(new Label(_("Invert"))));
112         _invert_selection.signal_clicked().connect(
113                         mem_fun(this, &MidiMultipleChannelSelector::invert_selection));
114         
115         _force_channel.add(*manage(new Label(_("Force"))));
116         _force_channel.signal_toggled().connect(
117                         mem_fun(this, &MidiMultipleChannelSelector::force_channels_button_toggled));
118
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);
126         
127         set_selected_channels(mask);
128 }
129
130 MidiMultipleChannelSelector::~MidiMultipleChannelSelector()
131 {
132         mode_changed.clear();
133 }
134
135 void
136 MidiMultipleChannelSelector::set_channel_mode(ChannelMode mode, uint8_t mask)
137 {
138         switch (mode) {
139         case AllChannels:
140                 _force_channel.set_active(false);
141                 set_selected_channels(0xFFFF);
142                 break;
143         case FilterChannels:
144                 _force_channel.set_active(false);
145                 set_selected_channels(mask);
146                 break;
147         case ForceChannel:
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);
152                 }
153         }
154 }
155
156 const uint16_t 
157 MidiMultipleChannelSelector::get_selected_channels() const 
158
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);
164                 } 
165         }
166         
167         return selected_channels; 
168 }
169
170 void 
171 MidiMultipleChannelSelector::set_selected_channels(uint16_t selected_channels)
172 {
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);
177                 } else {
178                         button->set_active(false);
179                 }
180         }
181 }
182
183 void
184 MidiMultipleChannelSelector::button_toggled(ToggleButton *button, uint8_t channel)
185 {
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);
191                 } else {
192                         mode_changed.emit(_channel_mode, get_selected_channels());
193                 }
194         }
195         --_recursion_counter;
196 }
197
198 void 
199 MidiMultipleChannelSelector::force_channels_button_toggled()
200 {
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;
213                                 } else {
214                                         found_first_active = true;
215                                         active_channel = i;
216                                 }
217                         } 
218                 }
219                 
220                 if (!found_first_active) {
221                         _buttons[0][0].set_active(true);
222                 }
223                 
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);
228         } else {
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());
234         }
235 }
236
237 void 
238 MidiMultipleChannelSelector::select_all(bool on)
239 {
240         if (_channel_mode == ForceChannel)
241                 return;
242
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);
247         }
248         --_recursion_counter;
249         mode_changed.emit(_channel_mode, get_selected_channels());
250 }
251
252 void 
253 MidiMultipleChannelSelector::invert_selection(void)
254 {
255         if (_channel_mode == ForceChannel)
256                 return;
257
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);
263                 } else {
264                         button->set_active(true);
265                 }
266         }
267         --_recursion_counter;
268         mode_changed.emit(_channel_mode, get_selected_channels());
269 }
270