Some more copy-editing. Make 'make mono regions' option sensitive to the region...
[ardour.git] / gtk2_ardour / canvas-note-event.cc
1 /*
2     Copyright (C) 2007 Paul Davis
3     Author: Dave Robillard
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 <iostream>
21 #include "canvas-note-event.h"
22 #include "midi_region_view.h"
23 #include "public_editor.h"
24 #include "editing_syms.h"
25 #include "keyboard.h"
26
27 using namespace std;
28 using ARDOUR::MidiModel;
29
30 namespace Gnome {
31 namespace Canvas {
32
33 /// dividing the hue circle in 16 parts, hand adjusted for equal look, courtesy Thorsten Wilms
34 const uint32_t CanvasNoteEvent::midi_channel_colors[16] = {
35           0xd32d2dff,  0xd36b2dff,  0xd3972dff,  0xd3d12dff,
36           0xa0d32dff,  0x7dd32dff,  0x2dd45eff,  0x2dd3c4ff,
37           0x2da5d3ff,  0x2d6fd3ff,  0x432dd3ff,  0x662dd3ff,
38           0x832dd3ff,  0xa92dd3ff,  0xd32dbfff,  0xd32d67ff
39         };
40
41 CanvasNoteEvent::CanvasNoteEvent(MidiRegionView& region, Item* item,
42                 const boost::shared_ptr<NoteType> note)
43         : _region(region)
44         , _item(item)
45         , _text(0)
46         , _channel_selector_widget()
47         , _state(None)
48         , _note(note)
49         , _selected(false)
50         , _valid (true)
51 {
52 }
53
54 CanvasNoteEvent::~CanvasNoteEvent()
55 {
56         cerr << "Destroying CNE @ " << this << endl;
57
58         if (_text) {
59                 _text->hide();
60                 delete _text;
61         }
62
63         delete _channel_selector_widget;
64 }
65
66 void
67 CanvasNoteEvent::invalidate ()
68 {
69         _valid = false;
70 }
71
72 void
73 CanvasNoteEvent::validate ()
74 {
75         _valid = true;
76 }
77
78 void
79 CanvasNoteEvent::show_velocity()
80 {
81         if (!_text) {
82                 _text = new InteractiveText(*(_item->property_parent()), this);
83         }
84         _text->property_x() = (x1() + x2()) /2;
85         _text->property_y() = (y1() + y2()) /2;
86         ostringstream velo(ios::ate);
87         velo << int(_note->velocity());
88         _text->property_text() = velo.str();
89         _text->property_justification() = Gtk::JUSTIFY_CENTER;
90         _text->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiNoteVelocityText.get();
91         _text->show();
92         _text->raise_to_top();
93 }
94
95 void
96 CanvasNoteEvent::hide_velocity()
97 {
98         if (_text) {
99                 _text->hide();
100                 delete _text;
101                 _text = 0;
102         }
103 }
104
105 void
106 CanvasNoteEvent::on_channel_selection_change(uint16_t selection)
107 {
108         // make note change its color if its channel is not marked active
109         if ( (selection & (1 << _note->channel())) == 0 ) {
110                 set_fill_color(ARDOUR_UI::config()->canvasvar_MidiNoteInactiveChannel.get());
111                 set_outline_color(calculate_outline(ARDOUR_UI::config()->canvasvar_MidiNoteInactiveChannel.get()));
112         } else {
113                 // set the color according to the notes selection state
114                 selected(_selected);
115         }
116         // this forces the item to update..... maybe slow...
117         _item->hide();
118         _item->show();
119 }
120
121 void
122 CanvasNoteEvent::on_channel_change(uint8_t channel)
123 {
124         _region.note_selected(this, true);
125         hide_channel_selector();
126         _region.change_channel(channel);
127 }
128
129 void
130 CanvasNoteEvent::show_channel_selector(void)
131 {
132         if (_channel_selector_widget == 0) {
133                 cerr << "Note has channel: " << int(_note->channel()) << endl;
134                 SingleMidiChannelSelector* _channel_selector = new SingleMidiChannelSelector(_note->channel());
135                 _channel_selector->show_all();
136                 _channel_selector->channel_selected.connect(
137                         sigc::mem_fun(this, &CanvasNoteEvent::on_channel_change));
138
139                 _channel_selector_widget = new Widget(*(_item->property_parent()),
140                                 x1(),
141                                 y2() + 2,
142                                 (Gtk::Widget &) *_channel_selector);
143
144                 _channel_selector_widget->hide();
145                 _channel_selector_widget->property_height() = 100;
146                 _channel_selector_widget->property_width() = 100;
147                 _channel_selector_widget->raise_to_top();
148                 _channel_selector_widget->show();
149         } else {
150                 hide_channel_selector();
151         }
152 }
153
154 void
155 CanvasNoteEvent::hide_channel_selector(void)
156 {
157         if (_channel_selector_widget) {
158                 _channel_selector_widget->hide();
159                 delete _channel_selector_widget;
160                 _channel_selector_widget = 0;
161         }
162 }
163
164 void
165 CanvasNoteEvent::selected(bool selected)
166 {
167         if (!_note) {
168                 return;
169         } else if (selected) {
170                 set_fill_color(UINT_INTERPOLATE(base_color(),
171                                 ARDOUR_UI::config()->canvasvar_MidiNoteSelected.get(), 0.5));
172                 set_outline_color(calculate_outline(
173                                 ARDOUR_UI::config()->canvasvar_MidiNoteSelected.get()));
174         } else {
175                 set_fill_color(base_color());
176                 set_outline_color(calculate_outline(base_color()));
177         }
178
179         _selected = selected;
180 }
181
182 #define SCALE_USHORT_TO_UINT8_T(x) ((x) / 257)
183
184 uint32_t
185 CanvasNoteEvent::base_color()
186 {
187         using namespace ARDOUR;
188
189         ColorMode mode = _region.color_mode();
190
191         const uint8_t min_opacity = 15;
192         uint8_t       opacity = std::max(min_opacity, uint8_t(_note->velocity() + _note->velocity()));
193
194         switch (mode) {
195         case TrackColor:
196                 {
197                         Gdk::Color color = _region.midi_stream_view()->get_region_color();
198                         return RGBA_TO_UINT(
199                                         SCALE_USHORT_TO_UINT8_T(color.get_red()),
200                                         SCALE_USHORT_TO_UINT8_T(color.get_green()),
201                                         SCALE_USHORT_TO_UINT8_T(color.get_blue()),
202                                         opacity);
203                 }
204
205         case ChannelColors:
206                 return UINT_RGBA_CHANGE_A(CanvasNoteEvent::midi_channel_colors[_note->channel()],
207                                                   opacity);
208
209         default:
210                 return meter_style_fill_color(_note->velocity());
211         };
212
213         return 0;
214 }
215
216 bool
217 CanvasNoteEvent::on_event(GdkEvent* ev)
218 {
219         PublicEditor& editor (_region.get_time_axis_view().editor());
220
221         if (!editor.internal_editing()) {
222                 return false;
223         }
224
225         switch (ev->type) {
226         case GDK_ENTER_NOTIFY:
227                 _region.note_entered(this);
228                 //Keyboard::magic_widget_grab_focus();
229                 break;
230
231         case GDK_LEAVE_NOTIFY:
232                 //Keyboard::magic_widget_drop_focus();
233                 _region.note_left (this);
234                 if (!selected()) {
235                         hide_velocity();
236                 }
237                 break;
238
239         case GDK_BUTTON_PRESS:
240                 if (ev->button.button == 3) {
241                         show_channel_selector();
242                         return true;
243                 }
244                 break;
245
246         case GDK_BUTTON_RELEASE:
247                 if (ev->button.button == 3) {
248                         return true;
249                 }
250                 break;
251
252         default:
253                 break;
254         }
255
256         return false;
257 }
258
259 } // namespace Canvas
260 } // namespace Gnome
261