(1) extend region if needed BEFORE adding step-edit note, so that the new note ends...
[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
56                         _buttons[row][column].signal_button_release_event().connect(
57                                 sigc::mem_fun(this, &MidiChannelSelector::was_clicked), false);
58
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_bg(STATE_NORMAL);
99                         _buttons[row][column].unset_bg(STATE_ACTIVE);
100                 }
101         }
102 }
103
104 SingleMidiChannelSelector::SingleMidiChannelSelector(uint8_t active_channel)
105         : MidiChannelSelector()
106 {
107         _last_active_button = 0;
108         ToggleButton* button = &_buttons[active_channel / 4][active_channel % 4];
109         _active_channel = active_channel;
110         button->set_active(true);
111         _last_active_button = button;
112 }
113
114 void
115 SingleMidiChannelSelector::button_toggled(ToggleButton* button, uint8_t channel)
116 {
117         ++_recursion_counter;
118         if (_recursion_counter == 1) {
119                 // if the current button is active it must
120                 // be different from the first one
121                 if (button->get_active()) {
122                         if (_last_active_button) {
123                                 _last_active_button->set_active(false);
124                                 _active_channel = channel;
125                                 _last_active_button = button;
126                                 channel_selected.emit(channel);
127                         }
128                 } else {
129                         // if not, the user pressed the already active button
130                         button->set_active(true);
131                         _active_channel = channel;
132                 }
133         }
134         --_recursion_counter;
135 }
136
137 MidiMultipleChannelSelector::MidiMultipleChannelSelector(ChannelMode mode, uint16_t mask)
138         : MidiChannelSelector(4, 6, 0, 0)
139         , _channel_mode(mode)
140 {
141         _select_all.add(*manage(new Label(_("All"))));
142         _select_all.signal_clicked().connect(
143                         sigc::bind(sigc::mem_fun(this, &MidiMultipleChannelSelector::select_all), true));
144
145         _select_none.add(*manage(new Label(_("None"))));
146         _select_none.signal_clicked().connect(
147                         sigc::bind(sigc::mem_fun(this, &MidiMultipleChannelSelector::select_all), false));
148
149         _invert_selection.add(*manage(new Label(_("Invert"))));
150         _invert_selection.signal_clicked().connect(
151                         sigc::mem_fun(this, &MidiMultipleChannelSelector::invert_selection));
152
153         _force_channel.add(*manage(new Label(_("Force"))));
154         _force_channel.signal_toggled().connect(
155                         sigc::mem_fun(this, &MidiMultipleChannelSelector::force_channels_button_toggled));
156
157         set_homogeneous(false);
158         attach(*manage(new VSeparator()), 4, 5, 0, 4, SHRINK, FILL, 0, 0);
159         //set_row_spacing(4, -5);
160         attach(_select_all,       5, 6, 0, 1);
161         attach(_select_none,      5, 6, 1, 2);
162         attach(_invert_selection, 5, 6, 2, 3);
163         attach(_force_channel,    5, 6, 3, 4);
164
165         set_selected_channels(mask);
166 }
167
168 MidiMultipleChannelSelector::~MidiMultipleChannelSelector()
169 {
170         mode_changed.clear();
171 }
172
173 void
174 MidiMultipleChannelSelector::set_channel_mode(ChannelMode mode, uint16_t mask)
175 {
176         switch (mode) {
177         case AllChannels:
178                 _force_channel.set_active(false);
179                 set_selected_channels(0xFFFF);
180                 break;
181         case FilterChannels:
182                 _force_channel.set_active(false);
183                 set_selected_channels(mask);
184                 break;
185         case ForceChannel:
186                 _force_channel.set_active(true);
187                 for (uint16_t i = 0; i < 16; i++) {
188                         ToggleButton* button = &_buttons[i / 4][i % 4];
189                         button->set_active(i == mask);
190                 }
191         }
192 }
193
194 uint16_t
195 MidiMultipleChannelSelector::get_selected_channels() const
196 {
197         uint16_t selected_channels = 0;
198         for (uint16_t i = 0; i < 16; i++) {
199                 const ToggleButton* button = &_buttons[i / 4][i % 4];
200                 if (button->get_active()) {
201                         selected_channels |= (1L << i);
202                 }
203         }
204
205         return selected_channels;
206 }
207
208 void
209 MidiMultipleChannelSelector::set_selected_channels(uint16_t selected_channels)
210 {
211         for (uint16_t i = 0; i < 16; i++) {
212                 ToggleButton* button = &_buttons[i / 4][i % 4];
213                 if (selected_channels & (1L << i)) {
214                         button->set_active(true);
215                 } else {
216                         button->set_active(false);
217                 }
218         }
219 }
220
221 void
222 MidiMultipleChannelSelector::button_toggled(ToggleButton */*button*/, uint8_t channel)
223 {
224         ++_recursion_counter;
225         if (_recursion_counter == 1) {
226                 if (_channel_mode == ForceChannel) {
227                         mode_changed.emit(_channel_mode, channel);
228                         set_selected_channels(1 << channel);
229                 } else {
230                         mode_changed.emit(_channel_mode, get_selected_channels());
231                 }
232         }
233         --_recursion_counter;
234 }
235
236 void
237 MidiMultipleChannelSelector::force_channels_button_toggled()
238 {
239         if (_force_channel.get_active()) {
240                 _channel_mode = ForceChannel;
241                 bool found_first_active = false;
242                 // leave only the first button enabled
243                 uint16_t active_channel = 0;
244                 for (int i = 0; i <= 15; i++) {
245                         ToggleButton* button = &_buttons[i / 4][i % 4];
246                         if (button->get_active()) {
247                                 if (found_first_active) {
248                                         ++_recursion_counter;
249                                         button->set_active(false);
250                                         --_recursion_counter;
251                                 } else {
252                                         found_first_active = true;
253                                         active_channel = i;
254                                 }
255                         }
256                 }
257
258                 if (!found_first_active) {
259                         _buttons[0][0].set_active(true);
260                 }
261
262                 _select_all.set_sensitive(false);
263                 _select_none.set_sensitive(false);
264                 _invert_selection.set_sensitive(false);
265                 mode_changed.emit(_channel_mode, active_channel);
266         } else {
267                 _channel_mode = FilterChannels;
268                 _select_all.set_sensitive(true);
269                 _select_none.set_sensitive(true);
270                 _invert_selection.set_sensitive(true);
271                 mode_changed.emit(FilterChannels, get_selected_channels());
272         }
273 }
274
275 void
276 MidiMultipleChannelSelector::select_all(bool on)
277 {
278         if (_channel_mode == ForceChannel)
279                 return;
280
281         ++_recursion_counter;
282         for (uint16_t i = 0; i < 16; i++) {
283                 ToggleButton* button = &_buttons[i / 4][i % 4];
284                 button->set_active(on);
285         }
286         --_recursion_counter;
287         mode_changed.emit(_channel_mode, get_selected_channels());
288 }
289
290 void
291 MidiMultipleChannelSelector::invert_selection(void)
292 {
293         if (_channel_mode == ForceChannel)
294                 return;
295
296         ++_recursion_counter;
297         for (uint16_t i = 0; i < 16; i++) {
298                 ToggleButton* button = &_buttons[i / 4][i % 4];
299                 if (button->get_active()) {
300                         button->set_active(false);
301                 } else {
302                         button->set_active(true);
303                 }
304         }
305         --_recursion_counter;
306         mode_changed.emit(_channel_mode, get_selected_channels());
307 }
308