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"
24 #include "rgb_macros.h"
29 using namespace ARDOUR
;
31 MidiChannelSelector::MidiChannelSelector(int n_rows
, int n_columns
, int start_row
, int start_column
)
32 : Table(n_rows
, n_columns
, true)
33 , _recursion_counter(0)
36 assert(n_rows
>= start_row
+ 4);
37 assert(n_columns
>=4);
38 assert(n_columns
>= start_column
+ 4);
40 property_column_spacing() = 0;
41 property_row_spacing() = 0;
43 uint8_t channel_nr
= 0;
44 for (int row
= 0; row
< 4; ++row
) {
45 for (int column
= 0; column
< 4; ++column
) {
46 ostringstream channel
;
47 channel
<< int(++channel_nr
);
48 _button_labels
[row
][column
].set_text(channel
.str());
49 _button_labels
[row
][column
].set_justify(JUSTIFY_RIGHT
);
50 _buttons
[row
][column
].add(_button_labels
[row
][column
]);
51 _buttons
[row
][column
].signal_toggled().connect(
53 mem_fun(this, &MidiChannelSelector::button_toggled
),
54 &_buttons
[row
][column
],
57 int table_row
= start_row
+ row
;
58 int table_column
= start_column
+ column
;
59 attach(_buttons
[row
][column
], table_column
, table_column
+ 1, table_row
, table_row
+ 1);
64 MidiChannelSelector::~MidiChannelSelector()
69 MidiChannelSelector::set_channel_colors(const uint32_t new_channel_colors
[16])
71 for (int row
= 0; row
< 4; ++row
) {
72 for (int column
= 0; column
< 4; ++column
) {
75 snprintf(color_normal
, 8, "#%x", UINT_INTERPOLATE(new_channel_colors
[row
* 4 + column
], 0x000000ff, 0.6));
76 snprintf(color_active
, 8, "#%x", new_channel_colors
[row
* 4 + column
]);
77 _buttons
[row
][column
].modify_bg(STATE_NORMAL
, Gdk::Color(color_normal
));
78 _buttons
[row
][column
].modify_bg(STATE_ACTIVE
, Gdk::Color(color_active
));
84 MidiChannelSelector::set_default_channel_color()
86 for (int row
= 0; row
< 4; ++row
) {
87 for (int column
= 0; column
< 4; ++column
) {
88 _buttons
[row
][column
].unset_bg(STATE_NORMAL
);
89 _buttons
[row
][column
].unset_bg(STATE_ACTIVE
);
94 SingleMidiChannelSelector::SingleMidiChannelSelector(uint8_t active_channel
)
95 : MidiChannelSelector()
97 _last_active_button
= 0;
98 ToggleButton
* button
= &_buttons
[active_channel
/ 4][active_channel
% 4];
99 _active_channel
= active_channel
;
100 button
->set_active(true);
101 _last_active_button
= button
;
105 SingleMidiChannelSelector::button_toggled(ToggleButton
* button
, uint8_t channel
)
107 ++_recursion_counter
;
108 if (_recursion_counter
== 1) {
109 // if the current button is active it must
110 // be different from the first one
111 if (button
->get_active()) {
112 if (_last_active_button
) {
113 _last_active_button
->set_active(false);
114 _active_channel
= channel
;
115 _last_active_button
= button
;
116 channel_selected
.emit(channel
);
119 // if not, the user pressed the already active button
120 button
->set_active(true);
121 _active_channel
= channel
;
124 --_recursion_counter
;
127 MidiMultipleChannelSelector::MidiMultipleChannelSelector(ChannelMode mode
, uint16_t mask
)
128 : MidiChannelSelector(4, 6, 0, 0)
129 , _channel_mode(mode
)
131 _select_all
.add(*manage(new Label(_("All"))));
132 _select_all
.signal_clicked().connect(
133 bind(mem_fun(this, &MidiMultipleChannelSelector::select_all
), true));
135 _select_none
.add(*manage(new Label(_("None"))));
136 _select_none
.signal_clicked().connect(
137 bind(mem_fun(this, &MidiMultipleChannelSelector::select_all
), false));
139 _invert_selection
.add(*manage(new Label(_("Invert"))));
140 _invert_selection
.signal_clicked().connect(
141 mem_fun(this, &MidiMultipleChannelSelector::invert_selection
));
143 _force_channel
.add(*manage(new Label(_("Force"))));
144 _force_channel
.signal_toggled().connect(
145 mem_fun(this, &MidiMultipleChannelSelector::force_channels_button_toggled
));
147 set_homogeneous(false);
148 attach(*manage(new VSeparator()), 4, 5, 0, 4, SHRINK
, FILL
, 0, 0);
149 //set_row_spacing(4, -5);
150 attach(_select_all
, 5, 6, 0, 1);
151 attach(_select_none
, 5, 6, 1, 2);
152 attach(_invert_selection
, 5, 6, 2, 3);
153 attach(_force_channel
, 5, 6, 3, 4);
155 set_selected_channels(mask
);
158 MidiMultipleChannelSelector::~MidiMultipleChannelSelector()
160 mode_changed
.clear();
164 MidiMultipleChannelSelector::set_channel_mode(ChannelMode mode
, uint16_t mask
)
168 _force_channel
.set_active(false);
169 set_selected_channels(0xFFFF);
172 _force_channel
.set_active(false);
173 set_selected_channels(mask
);
176 _force_channel
.set_active(true);
177 for (uint16_t i
= 0; i
< 16; i
++) {
178 ToggleButton
* button
= &_buttons
[i
/ 4][i
% 4];
179 button
->set_active(i
== mask
);
185 MidiMultipleChannelSelector::get_selected_channels() const
187 uint16_t selected_channels
= 0;
188 for (uint16_t i
= 0; i
< 16; i
++) {
189 const ToggleButton
* button
= &_buttons
[i
/ 4][i
% 4];
190 if (button
->get_active()) {
191 selected_channels
|= (1L << i
);
195 return selected_channels
;
199 MidiMultipleChannelSelector::set_selected_channels(uint16_t selected_channels
)
201 for (uint16_t i
= 0; i
< 16; i
++) {
202 ToggleButton
* button
= &_buttons
[i
/ 4][i
% 4];
203 if (selected_channels
& (1L << i
)) {
204 button
->set_active(true);
206 button
->set_active(false);
212 MidiMultipleChannelSelector::button_toggled(ToggleButton */
*button*/
, uint8_t channel
)
214 ++_recursion_counter
;
215 if (_recursion_counter
== 1) {
216 if (_channel_mode
== ForceChannel
) {
217 mode_changed
.emit(_channel_mode
, channel
);
218 set_selected_channels(1 << channel
);
220 mode_changed
.emit(_channel_mode
, get_selected_channels());
223 --_recursion_counter
;
227 MidiMultipleChannelSelector::force_channels_button_toggled()
229 if (_force_channel
.get_active()) {
230 _channel_mode
= ForceChannel
;
231 bool found_first_active
= false;
232 // leave only the first button enabled
233 uint16_t active_channel
= 0;
234 for (int i
= 0; i
<= 15; i
++) {
235 ToggleButton
* button
= &_buttons
[i
/ 4][i
% 4];
236 if (button
->get_active()) {
237 if (found_first_active
) {
238 ++_recursion_counter
;
239 button
->set_active(false);
240 --_recursion_counter
;
242 found_first_active
= true;
248 if (!found_first_active
) {
249 _buttons
[0][0].set_active(true);
252 _select_all
.set_sensitive(false);
253 _select_none
.set_sensitive(false);
254 _invert_selection
.set_sensitive(false);
255 mode_changed
.emit(_channel_mode
, active_channel
);
257 _channel_mode
= FilterChannels
;
258 _select_all
.set_sensitive(true);
259 _select_none
.set_sensitive(true);
260 _invert_selection
.set_sensitive(true);
261 mode_changed
.emit(FilterChannels
, get_selected_channels());
266 MidiMultipleChannelSelector::select_all(bool on
)
268 if (_channel_mode
== ForceChannel
)
271 ++_recursion_counter
;
272 for (uint16_t i
= 0; i
< 16; i
++) {
273 ToggleButton
* button
= &_buttons
[i
/ 4][i
% 4];
274 button
->set_active(on
);
276 --_recursion_counter
;
277 mode_changed
.emit(_channel_mode
, get_selected_channels());
281 MidiMultipleChannelSelector::invert_selection(void)
283 if (_channel_mode
== ForceChannel
)
286 ++_recursion_counter
;
287 for (uint16_t i
= 0; i
< 16; i
++) {
288 ToggleButton
* button
= &_buttons
[i
/ 4][i
% 4];
289 if (button
->get_active()) {
290 button
->set_active(false);
292 button
->set_active(true);
295 --_recursion_counter
;
296 mode_changed
.emit(_channel_mode
, get_selected_channels());