remove "New Return" menu option from processor box; make return toggle processor...
[ardour.git] / gtk2_ardour / ghostregion.cc
1 /*
2     Copyright (C) 2000-2007 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "evoral/Note.hpp"
21 #include "ardour_ui.h"
22 #include "automation_time_axis.h"
23 #include "canvas-hit.h"
24 #include "canvas-note.h"
25 #include "ghostregion.h"
26 #include "midi_streamview.h"
27 #include "midi_time_axis.h"
28 #include "rgb_macros.h"
29 #include "simplerect.h"
30 #include "waveview.h"
31
32 using namespace std;
33 using namespace Editing;
34 using namespace ArdourCanvas;
35 using namespace ARDOUR;
36
37 GhostRegion::GhostRegion (ArdourCanvas::Group* parent, TimeAxisView& tv, TimeAxisView& source_tv, double initial_pos)
38         : trackview (tv)
39         , source_trackview (source_tv)
40 {
41         group = new ArdourCanvas::Group (*parent);
42         group->property_x() = initial_pos;
43         group->property_y() = 0.0;
44
45         base_rect = new ArdourCanvas::SimpleRect (*group);
46         base_rect->property_x1() = (double) 0.0;
47         base_rect->property_y1() = (double) 0.0;
48         base_rect->property_y2() = (double) trackview.current_height();
49         base_rect->property_outline_what() = (guint32) 0;
50
51         if (!is_automation_ghost()) {
52                 base_rect->hide();
53         }
54
55         GhostRegion::set_colors();
56
57         /* the parent group of a ghostregion is a dedicated group for ghosts,
58            so the new ghost would want to get to the top of that group*/
59         group->raise_to_top ();
60 }
61
62 GhostRegion::~GhostRegion ()
63 {
64         GoingAway (this);
65         delete base_rect;
66         delete group;
67 }
68
69 void
70 GhostRegion::set_duration (double units)
71 {
72         base_rect->property_x2() = units;
73 }
74
75 void
76 GhostRegion::set_height ()
77 {
78         base_rect->property_y2() = (double) trackview.current_height();
79 }
80
81 void
82 GhostRegion::set_colors ()
83 {
84         if (is_automation_ghost()) {
85                 base_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_GhostTrackBase.get();
86                 base_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_GhostTrackBase.get();
87         }
88 }
89
90 guint
91 GhostRegion::source_track_color(unsigned char alpha) {
92         Gdk::Color color = source_trackview.color();
93         unsigned char r,g,b ;
94         r = color.get_red()/256;
95         g = color.get_green()/256;
96         b = color.get_blue()/256;
97         return RGBA_TO_UINT(r, g, b, alpha);
98 }
99
100 bool
101 GhostRegion::is_automation_ghost() {
102         return (dynamic_cast<AutomationTimeAxisView*>(&trackview)) != 0;
103 }
104
105 AudioGhostRegion::AudioGhostRegion(TimeAxisView& tv, TimeAxisView& source_tv, double initial_unit_pos)
106         : GhostRegion(tv.ghost_group(), tv, source_tv, initial_unit_pos) {
107 }
108
109 void
110 AudioGhostRegion::set_samples_per_unit (double spu)
111 {
112         for (vector<WaveView*>::iterator i = waves.begin(); i != waves.end(); ++i) {
113                 (*i)->property_samples_per_unit() = spu;
114         }
115 }
116
117 void
118 AudioGhostRegion::set_height ()
119 {
120         gdouble ht;
121         vector<WaveView*>::iterator i;
122         uint32_t n;
123
124         GhostRegion::set_height();
125
126         ht = ((trackview.current_height()) / (double) waves.size());
127
128         for (n = 0, i = waves.begin(); i != waves.end(); ++i, ++n) {
129                 gdouble yoff = n * ht;
130                 (*i)->property_height() = ht;
131                 (*i)->property_y() = yoff;
132         }
133 }
134
135 void
136 AudioGhostRegion::set_colors ()
137 {
138         GhostRegion::set_colors();
139         guint fill_color;
140
141         if (is_automation_ghost()) {
142                 fill_color = ARDOUR_UI::config()->canvasvar_GhostTrackWaveFill.get();
143         }
144         else {
145                 fill_color = source_track_color(200);
146         }
147
148         for (uint32_t n=0; n < waves.size(); ++n) {
149                 waves[n]->property_wave_color() = ARDOUR_UI::config()->canvasvar_GhostTrackWave.get();
150                 waves[n]->property_fill_color() = fill_color;
151                 waves[n]->property_clip_color() = ARDOUR_UI::config()->canvasvar_GhostTrackWaveClip.get();
152                 waves[n]->property_zero_color() = ARDOUR_UI::config()->canvasvar_GhostTrackZeroLine.get();
153         }
154 }
155
156 /*
157  * This is the general constructor, and is called when the destination timeaxisview doesn't have
158  * a midistreamview. But what to do when positioning the midi ghost here? For example, there is
159  * no range controller in these tracks. maybe show the whole range.
160  */
161 MidiGhostRegion::MidiGhostRegion(TimeAxisView& tv, TimeAxisView& source_tv, double initial_unit_pos)
162         : GhostRegion(tv.ghost_group(), tv, source_tv, initial_unit_pos)
163 {
164
165         base_rect->lower_to_bottom();
166 }
167
168 MidiGhostRegion::MidiGhostRegion(MidiStreamView& msv, TimeAxisView& source_tv, double initial_unit_pos)
169         : GhostRegion(msv.midi_underlay_group, msv.trackview(), source_tv, initial_unit_pos)
170 {
171         base_rect->lower_to_bottom();
172 }
173
174 MidiGhostRegion::~MidiGhostRegion()
175 {
176         //clear_events();
177 }
178
179 MidiGhostRegion::Event::Event(ArdourCanvas::CanvasNoteEvent* e)
180         : event(e)
181 {
182 }
183
184 MidiGhostRegion::Note::Note(ArdourCanvas::CanvasNote* n, ArdourCanvas::Group* g)
185         : Event(n)
186 {
187         rect = new ArdourCanvas::SimpleRect(*g, n->x1(), n->y1(), n->x2(), n->y2());
188 }
189
190 MidiGhostRegion::Note::~Note()
191 {
192         //delete rect;
193 }
194
195 void
196 MidiGhostRegion::Note::x_changed()
197 {
198         rect->property_x1() = event->x1();
199         rect->property_x2() = event->x2();
200 }
201
202 MidiGhostRegion::Hit::Hit(ArdourCanvas::CanvasHit* h, ArdourCanvas::Group*)
203         : Event(h)
204 {
205         cerr << "Hit ghost item does not work yet" << endl;
206 }
207
208 MidiGhostRegion::Hit::~Hit()
209 {
210 }
211
212 void
213 MidiGhostRegion::Hit::x_changed()
214 {
215 }
216
217 void
218 MidiGhostRegion::set_samples_per_unit (double /*spu*/)
219 {
220 }
221
222 MidiStreamView*
223 MidiGhostRegion::midi_view()
224 {
225         MidiTimeAxisView* mtv;
226
227         if ((mtv = dynamic_cast<MidiTimeAxisView*>(&trackview)) != 0) {
228                 return mtv->midi_view();
229         }
230         else {
231                 return 0;
232         }
233 }
234
235 void
236 MidiGhostRegion::set_height()
237 {
238         GhostRegion::set_height();
239         update_range();
240 }
241
242 void
243 MidiGhostRegion::set_colors()
244 {
245         MidiGhostRegion::Note* note;
246         guint fill = source_track_color(200);
247
248         GhostRegion::set_colors();
249
250         for (EventList::iterator it = events.begin(); it != events.end(); ++it) {
251                 if ((note = dynamic_cast<MidiGhostRegion::Note*>(*it)) != 0) {
252                         note->rect->property_fill_color_rgba() = fill;
253                         note->rect->property_outline_color_rgba() =  ARDOUR_UI::config()->canvasvar_GhostTrackMidiOutline.get();
254                 }
255         }
256 }
257
258 void
259 MidiGhostRegion::update_range()
260 {
261         MidiStreamView* mv = midi_view();
262
263         if (!mv) {
264                 return;
265         }
266
267         MidiGhostRegion::Note* note;
268         uint8_t note_num;
269         double y;
270
271         for (EventList::iterator it = events.begin(); it != events.end(); ++it) {
272                 if ((note = dynamic_cast<MidiGhostRegion::Note*>(*it)) != 0) {
273                         note_num = note->event->note()->note();
274
275                         if (note_num < mv->lowest_note() || note_num > mv->highest_note()) {
276                                 note->rect->hide();
277                         }
278                         else {
279                                 note->rect->show();
280                                 y = mv->note_to_y(note_num);
281                                 note->rect->property_y1() = y;
282                                 note->rect->property_y2() = y + mv->note_height();
283                         }
284                 }
285         }
286 }
287
288 void
289 MidiGhostRegion::add_note(ArdourCanvas::CanvasNote* n)
290 {
291         Note* note = new Note(n, group);
292         events.push_back(note);
293
294         note->rect->property_fill_color_rgba() = source_track_color(200);
295         note->rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_GhostTrackMidiOutline.get();
296
297         MidiStreamView* mv = midi_view();
298
299         if (mv) {
300                 const uint8_t note_num = n->note()->note();
301
302                 if (note_num < mv->lowest_note() || note_num > mv->highest_note()) {
303                         note->rect->hide();
304                 } else {
305                         const double y = mv->note_to_y(note_num);
306                         note->rect->property_y1() = y;
307                         note->rect->property_y2() = y + mv->note_height();
308                 }
309         }
310 }
311
312 void
313 MidiGhostRegion::add_hit(ArdourCanvas::CanvasHit* /*h*/)
314 {
315         //events.push_back(new Hit(h, group));
316 }
317
318 void
319 MidiGhostRegion::clear_events()
320 {
321         for (EventList::iterator it = events.begin(); it != events.end(); ++it) {
322                 delete *it;
323         }
324
325         events.clear();
326 }
327