Remove unused variable and the accessor methods for it from ARDOUR_UI
[ardour.git] / gtk2_ardour / region_view.cc
1 /*
2     Copyright (C) 2001-2006 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 <cmath>
21 #include <cassert>
22 #include <algorithm>
23
24 #include <gtkmm.h>
25
26 #include <gtkmm2ext/gtk_ui.h>
27 #include <pbd/stacktrace.h>
28
29 #include <ardour/playlist.h>
30 #include <ardour/audioregion.h>
31 #include <ardour/audiosource.h>
32 #include <ardour/audio_diskstream.h>
33
34 #include "streamview.h"
35 #include "region_view.h"
36 #include "route_time_axis.h"
37 #include "simplerect.h"
38 #include "simpleline.h"
39 #include "waveview.h"
40 #include "public_editor.h"
41 #include "region_editor.h"
42 #include "ghostregion.h"
43 #include "route_time_axis.h"
44 #include "utils.h"
45 #include "rgb_macros.h"
46 #include "gui_thread.h"
47
48 #include "i18n.h"
49
50 using namespace sigc;
51 using namespace ARDOUR;
52 using namespace PBD;
53 using namespace Editing;
54 using namespace ArdourCanvas;
55
56 static const int32_t sync_mark_width = 9;
57
58 sigc::signal<void,RegionView*> RegionView::RegionViewGoingAway;
59
60 RegionView::RegionView (ArdourCanvas::Group* parent, 
61                         TimeAxisView&        tv,
62                         boost::shared_ptr<ARDOUR::Region> r,
63                         double               spu,
64                         Gdk::Color&          basic_color)
65         : TimeAxisViewItem (r->name(), *parent, tv, spu, basic_color, r->position(), r->length(),
66                             TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowNameText|
67                                                           TimeAxisViewItem::ShowNameHighlight|
68                                                           TimeAxisViewItem::ShowFrame))
69           , _region (r)
70           , sync_mark(0)
71           , editor(0)
72           , current_visible_sync_position(0.0)
73           , valid(false)
74           , _pixel_width(1.0)
75           , in_destructor(false)
76           , wait_for_data(false)
77 {
78 }
79
80 RegionView::RegionView (const RegionView& other)
81         : TimeAxisViewItem (other)
82 {
83         /* derived concrete type will call init () */
84
85         _region = other._region;
86         editor = other.editor;
87         current_visible_sync_position = other.current_visible_sync_position;
88         valid = false;
89         _pixel_width = other._pixel_width;
90 }
91
92 RegionView::RegionView (ArdourCanvas::Group*         parent, 
93                         TimeAxisView&                tv,
94                         boost::shared_ptr<ARDOUR::Region> r,
95                         double                       spu,
96                         Gdk::Color&                  basic_color,
97                         TimeAxisViewItem::Visibility visibility)
98         : TimeAxisViewItem (r->name(), *parent, tv, spu, basic_color, r->position(), r->length(), visibility)
99         , _region (r)
100         , sync_mark(0)
101         , editor(0)
102         , current_visible_sync_position(0.0)
103         , valid(false)
104         , _pixel_width(1.0)
105         , in_destructor(false)
106         , wait_for_data(false)
107 {
108 }
109
110 void
111 RegionView::init (Gdk::Color& basic_color, bool wfd)
112 {
113         valid         = true;
114         in_destructor = false;
115         wait_for_data = wfd;
116
117         compute_colors (basic_color);
118
119         name_highlight->set_data ("regionview", this);
120
121         if (name_text) {
122                 name_text->set_data ("regionview", this);
123         }
124
125         /* an equilateral triangle */
126
127         ArdourCanvas::Points shape;
128         shape.push_back (Gnome::Art::Point (-((sync_mark_width-1)/2), 1));
129         shape.push_back (Gnome::Art::Point ((sync_mark_width - 1)/2, 1));
130         shape.push_back (Gnome::Art::Point (0, sync_mark_width - 1));
131         shape.push_back (Gnome::Art::Point (-((sync_mark_width-1)/2), 1));
132
133         sync_mark =  new ArdourCanvas::Polygon (*group);
134         sync_mark->property_points() = shape;
135         sync_mark->property_fill_color_rgba() = fill_color;
136         sync_mark->hide();
137
138         reset_width_dependent_items ((double) _region->length() / samples_per_unit);
139
140         set_y_position_and_height (0, trackview.height);
141
142         _region->StateChanged.connect (mem_fun(*this, &RegionView::region_changed));
143
144         group->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_region_view_event), group, this));
145         name_highlight->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_region_view_name_highlight_event), name_highlight, this));
146
147         set_colors ();
148
149         ColorChanged.connect (mem_fun (*this, &RegionView::color_handler));
150
151         /* XXX sync mark drag? */
152 }
153
154 RegionView::~RegionView ()
155 {
156         in_destructor = true;
157
158         for (vector<GhostRegion*>::iterator g = ghosts.begin(); g != ghosts.end(); ++g) {
159                 delete *g;
160         }
161
162         if (editor) {
163                 delete editor;
164         }
165 }
166
167 gint
168 RegionView::_lock_toggle (ArdourCanvas::Item* item, GdkEvent* ev, void* arg)
169 {
170         switch (ev->type) {
171         case GDK_BUTTON_RELEASE:
172                 static_cast<RegionView*>(arg)->lock_toggle ();
173                 return TRUE;
174                 break;
175         default:
176                 break;
177         } 
178         return FALSE;
179 }
180
181 void
182 RegionView::lock_toggle ()
183 {
184         _region->set_locked (!_region->locked());
185 }
186
187 void
188 RegionView::region_changed (Change what_changed)
189 {
190         ENSURE_GUI_THREAD (bind (mem_fun(*this, &RegionView::region_changed), what_changed));
191
192         if (what_changed & BoundsChanged) {
193                 region_resized (what_changed);
194                 region_sync_changed ();
195         }
196         if (what_changed & Region::MuteChanged) {
197                 region_muted ();
198         }
199         if (what_changed & Region::OpacityChanged) {
200                 region_opacity ();
201         }
202         if (what_changed & ARDOUR::NameChanged) {
203                 region_renamed ();
204         }
205         if (what_changed & Region::SyncOffsetChanged) {
206                 region_sync_changed ();
207         }
208         if (what_changed & Region::LayerChanged) {
209                 region_layered ();
210         }
211         if (what_changed & Region::LockChanged) {
212                 region_locked ();
213         }
214 }
215
216 void
217 RegionView::region_locked ()
218 {
219         /* name will show locked status */
220         region_renamed ();
221 }
222
223 void
224 RegionView::region_resized (Change what_changed)
225 {
226         double unit_length;
227
228         if (what_changed & ARDOUR::PositionChanged) {
229                 set_position (_region->position(), 0);
230         }
231
232         if (what_changed & Change (StartChanged|LengthChanged)) {
233
234                 set_duration (_region->length(), 0);
235
236                 unit_length = _region->length() / samples_per_unit;
237                 
238                 for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
239
240                         (*i)->set_duration (unit_length);
241
242                 }
243         }
244 }
245
246 void
247 RegionView::reset_width_dependent_items (double pixel_width)
248 {
249         TimeAxisViewItem::reset_width_dependent_items (pixel_width);
250         _pixel_width = pixel_width;
251 }
252
253 void
254 RegionView::region_layered ()
255 {
256         RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*>(&get_time_axis_view());
257         assert(rtv);
258         rtv->view()->region_layered (this);
259 }
260         
261 void
262 RegionView::region_muted ()
263 {
264         set_frame_color ();
265         region_renamed ();
266 }
267
268 void
269 RegionView::region_opacity ()
270 {
271         set_frame_color ();
272 }
273
274 void
275 RegionView::raise ()
276 {
277         _region->raise ();
278 }
279
280 void
281 RegionView::raise_to_top ()
282 {
283         _region->raise_to_top ();
284 }
285
286 void
287 RegionView::lower ()
288 {
289         _region->lower ();
290 }
291
292 void
293 RegionView::lower_to_bottom ()
294 {
295         _region->lower_to_bottom ();
296 }
297
298 bool
299 RegionView::set_position (nframes_t pos, void* src, double* ignored)
300 {
301         double delta;
302         bool ret;
303
304         if (!(ret = TimeAxisViewItem::set_position (pos, this, &delta))) {
305                 return false;
306         }
307
308         if (ignored) {
309                 *ignored = delta;
310         }
311
312         if (delta) {
313                 for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
314                         (*i)->group->move (delta, 0.0);
315                 }
316         }
317
318         return ret;
319 }
320
321 void
322 RegionView::set_samples_per_unit (gdouble spu)
323 {
324         TimeAxisViewItem::set_samples_per_unit (spu);
325
326         for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
327                 (*i)->set_samples_per_unit (spu);
328                 (*i)->set_duration (_region->length() / samples_per_unit);
329         }
330
331         region_sync_changed ();
332 }
333
334 bool
335 RegionView::set_duration (nframes_t frames, void *src)
336 {
337         if (!TimeAxisViewItem::set_duration (frames, src)) {
338                 return false;
339         }
340         
341         for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
342                 (*i)->set_duration (_region->length() / samples_per_unit);
343         }
344
345         return true;
346 }
347
348 void
349 RegionView::compute_colors (Gdk::Color& basic_color)
350 {
351         TimeAxisViewItem::compute_colors (basic_color);
352 }
353
354 void
355 RegionView::set_colors ()
356 {
357         TimeAxisViewItem::set_colors ();
358         
359         if (sync_mark) {
360                 sync_mark->property_fill_color_rgba() = fill_color;
361         }
362 }
363
364 void
365 RegionView::set_frame_color ()
366 {
367         if (_region->opaque()) {
368                 fill_opacity = 130;
369         } else {
370                 fill_opacity = 60;
371         }
372
373         TimeAxisViewItem::set_frame_color ();
374 }
375
376 void
377 RegionView::fake_set_opaque (bool yn)
378 {
379        if (yn) {
380                fill_opacity = 130;
381        } else {
382                fill_opacity = 60;
383        }
384
385        TimeAxisViewItem::set_frame_color ();
386 }
387
388 void
389 RegionView::hide_region_editor()
390 {
391         if (editor) {
392                 editor->hide_all ();
393         }
394 }
395
396 Glib::ustring
397 RegionView::make_name () const
398 {
399         Glib::ustring str;
400
401         // XXX nice to have some good icons for this
402
403         if (_region->locked()) {
404                 str += '>';
405                 str += _region->name();
406                 str += '<';
407         } else if (_region->position_locked()) {
408                 str += '{';
409                 str += _region->name();
410                 str += '}';
411         } else {
412                 str = _region->name();
413         }
414
415         if (_region->muted()) {
416                 str = string ("!") + str;
417         }
418
419         return str;
420 }
421
422 void
423 RegionView::region_renamed ()
424 {
425         Glib::ustring str = make_name ();
426
427         set_item_name (str, this);
428         set_name_text (str);
429         reset_width_dependent_items (_pixel_width);
430 }
431
432 void
433 RegionView::region_sync_changed ()
434 {
435         if (sync_mark == 0) {
436                 return;
437         }
438
439         int sync_dir;
440         nframes_t sync_offset;
441
442         sync_offset = _region->sync_offset (sync_dir);
443
444         /* this has to handle both a genuine change of position, a change of samples_per_unit,
445            and a change in the bounds of the _region->
446          */
447
448         if (sync_offset == 0) {
449
450                 /* no sync mark - its the start of the region */
451
452                 sync_mark->hide();
453
454         } else {
455
456                 if ((sync_dir < 0) || ((sync_dir > 0) && (sync_offset > _region->length()))) { 
457
458                         /* no sync mark - its out of the bounds of the region */
459
460                         sync_mark->hide();
461
462                 } else {
463
464                         /* lets do it */
465
466                         Points points;
467                         
468                         //points = sync_mark->property_points().get_value();
469                         
470                         double offset = sync_offset / samples_per_unit;
471                         points.push_back (Gnome::Art::Point (offset - ((sync_mark_width-1)/2), 1));
472                         points.push_back (Gnome::Art::Point (offset + ((sync_mark_width-1)/2), 1));
473                         points.push_back (Gnome::Art::Point (offset, sync_mark_width - 1));
474                         points.push_back (Gnome::Art::Point (offset - ((sync_mark_width-1)/2), 1));     
475                         sync_mark->property_points().set_value (points);
476                         sync_mark->show();
477
478                 }
479         }
480 }
481
482 void
483 RegionView::move (double x_delta, double y_delta)
484 {
485         if (!_region->can_move() || (x_delta == 0 && y_delta == 0)) {
486                 return;
487         }
488
489         get_canvas_group()->move (x_delta, y_delta);
490
491         /* note: ghosts never leave their tracks so y_delta for them is always zero */
492
493         for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
494                 (*i)->group->move (x_delta, 0.0);
495         }
496 }
497
498 void
499 RegionView::remove_ghost (GhostRegion* ghost)
500 {
501         if (in_destructor) {
502                 return;
503         }
504
505         for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
506                 if (*i == ghost) {
507                         ghosts.erase (i);
508                         break;
509                 }
510         }
511 }
512
513 uint32_t
514 RegionView::get_fill_color ()
515 {
516         return fill_color;
517 }
518