ardour
region_view.cc
Go to the documentation of this file.
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 <algorithm>
22 
23 #include <gtkmm.h>
24 
25 #include <gtkmm2ext/gtk_ui.h>
26 
27 #include "ardour/playlist.h"
28 #include "ardour/session.h"
29 
30 #include "canvas/polygon.h"
31 #include "canvas/debug.h"
32 #include "canvas/pixbuf.h"
33 #include "canvas/text.h"
34 #include "canvas/line.h"
35 #include "canvas/utils.h"
36 #include "canvas/colors.h"
37 
38 #include "ardour_ui.h"
39 #include "global_signals.h"
40 #include "streamview.h"
41 #include "region_view.h"
42 #include "automation_region_view.h"
43 #include "route_time_axis.h"
44 #include "public_editor.h"
45 #include "region_editor.h"
46 #include "ghostregion.h"
47 #include "route_time_axis.h"
48 #include "ui_config.h"
49 #include "utils.h"
50 #include "rgb_macros.h"
51 #include "gui_thread.h"
52 
53 #include "i18n.h"
54 
55 using namespace std;
56 using namespace ARDOUR;
57 using namespace ARDOUR_UI_UTILS;
58 using namespace PBD;
59 using namespace Editing;
60 using namespace Gtk;
61 using namespace ArdourCanvas;
62 
63 static const int32_t sync_mark_width = 9;
64 
65 PBD::Signal1<void,RegionView*> RegionView::RegionViewGoingAway;
66 
67 RegionView::RegionView (ArdourCanvas::Container* parent,
68  TimeAxisView& tv,
70  double spu,
71  uint32_t basic_color,
72  bool automation)
73  : TimeAxisViewItem (r->name(), *parent, tv, spu, basic_color, r->position(), r->length(), false, automation,
74  (automation ? TimeAxisViewItem::ShowFrame :
76  TimeAxisViewItem::ShowNameHighlight| TimeAxisViewItem::ShowFrame)))
77  , _region (r)
78  , sync_mark(0)
79  , sync_line(0)
80  , editor(0)
81  , current_visible_sync_position(0.0)
82  , valid(false)
83  , _enable_display(false)
84  , _pixel_width(1.0)
85  , in_destructor(false)
86  , wait_for_data(false)
87  , _silence_text (0)
88 {
89  GhostRegion::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&RegionView::remove_ghost, this, _1), gui_context());
90 }
91 
93  : sigc::trackable(other)
94  , TimeAxisViewItem (other)
95  , _silence_text (0)
96 {
97  /* derived concrete type will call init () */
98 
99  _region = other._region;
101  valid = false;
102  _pixel_width = other._pixel_width;
103 
104  GhostRegion::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&RegionView::remove_ghost, this, _1), gui_context());
105 }
106 
108  : sigc::trackable(other)
109  , TimeAxisViewItem (other)
110  , _silence_text (0)
111 {
112  /* this is a pseudo-copy constructor used when dragging regions
113  around on the canvas.
114  */
115 
116  /* derived concrete type will call init () */
117 
118  _region = other_region;
120  valid = false;
121  _pixel_width = other._pixel_width;
122 
123  GhostRegion::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&RegionView::remove_ghost, this, _1), gui_context());
124 }
125 
126 RegionView::RegionView (ArdourCanvas::Container* parent,
127  TimeAxisView& tv,
129  double spu,
130  uint32_t basic_color,
131  bool recording,
132  TimeAxisViewItem::Visibility visibility)
133  : TimeAxisViewItem (r->name(), *parent, tv, spu, basic_color, r->position(), r->length(), recording, false, visibility)
134  , _region (r)
135  , sync_mark(0)
136  , sync_line(0)
137  , editor(0)
138  , current_visible_sync_position(0.0)
139  , valid(false)
140  , _enable_display(false)
141  , _pixel_width(1.0)
142  , in_destructor(false)
143  , wait_for_data(false)
144  , _silence_text (0)
145 {
146 }
147 
148 void
150 {
151  editor = 0;
152  valid = true;
153  in_destructor = false;
154  wait_for_data = wfd;
155  sync_mark = 0;
156  sync_line = 0;
157  sync_mark = 0;
158  sync_line = 0;
159 
160  if (name_highlight) {
161  name_highlight->set_data ("regionview", this);
163  }
164 
165  if (frame_handle_start) {
166  frame_handle_start->set_data ("regionview", this);
167  frame_handle_start->set_data ("isleft", (void*) 1);
168  frame_handle_start->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_frame_handle_event), frame_handle_start, this));
169  frame_handle_start->raise_to_top();
170  }
171 
172  if (frame_handle_end) {
173  frame_handle_end->set_data ("regionview", this);
174  frame_handle_end->set_data ("isleft", (void*) 0);
175  frame_handle_end->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_frame_handle_event), frame_handle_end, this));
176  frame_handle_end->raise_to_top();
177  }
178 
179  if (name_text) {
180  name_text->set_data ("regionview", this);
181  name_text->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_region_view_name_event), name_text, this));
182  }
183 
184  if (wfd) {
185  _enable_display = true;
186  }
187 
189 
190  _region->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&RegionView::region_changed, this, _1), gui_context());
191 
192  set_colors ();
193 
194  ColorsChanged.connect (sigc::mem_fun (*this, &RegionView::color_handler));
195 
196  /* XXX sync mark drag? */
197 }
198 
200 {
201  in_destructor = true;
202 
203  for (vector<GhostRegion*>::iterator g = ghosts.begin(); g != ghosts.end(); ++g) {
204  delete *g;
205  }
206 
207  for (list<ArdourCanvas::Rectangle*>::iterator i = _coverage_frames.begin (); i != _coverage_frames.end (); ++i) {
208  delete *i;
209  }
210 
212 
213  delete editor;
214 }
215 
216 bool
218 {
219  if (!in_destructor) {
220  return trackview.editor().canvas_region_view_event (event, group, this);
221  }
222  return false;
223 }
224 
225 void
226 RegionView::set_silent_frames (const AudioIntervalResult& silences, double /*threshold*/)
227 {
228  framecnt_t shortest = max_framecnt;
229 
230  /* remove old silent frames */
232 
233  if (silences.empty()) {
234  return;
235  }
236 
237  uint32_t const color = ARDOUR_UI::config()->color_mod ("silence", "silence");
238 
239  for (AudioIntervalResult::const_iterator i = silences.begin(); i != silences.end(); ++i) {
240 
241  ArdourCanvas::Rectangle* cr = new ArdourCanvas::Rectangle (group);
242  cr->set_ignore_events (true);
243  _silent_frames.push_back (cr);
244 
245  /* coordinates for the rect are relative to the regionview origin */
246 
247  cr->set_x0 (trackview.editor().sample_to_pixel (i->first - _region->start()));
248  cr->set_x1 (trackview.editor().sample_to_pixel (i->second - _region->start()));
249  cr->set_y0 (1);
250  cr->set_y1 (_height - 2);
251  cr->set_outline (false);
252  cr->set_fill_color (color);
253 
254  shortest = min (shortest, i->second - i->first);
255  }
256 
257  /* Find shortest audible segment */
258  framecnt_t shortest_audible = max_framecnt;
259 
260  framecnt_t s = _region->start();
261  for (AudioIntervalResult::const_iterator i = silences.begin(); i != silences.end(); ++i) {
262  framecnt_t const dur = i->first - s;
263  if (dur > 0) {
264  shortest_audible = min (shortest_audible, dur);
265  }
266 
267  s = i->second;
268  }
269 
270  framecnt_t const dur = _region->start() + _region->length() - 1 - s;
271  if (dur > 0) {
272  shortest_audible = min (shortest_audible, dur);
273  }
274 
275  _silence_text = new ArdourCanvas::Text (group);
276  _silence_text->set_ignore_events (true);
277  _silence_text->set_font_description (get_font_for_style (N_("SilenceText")));
278  _silence_text->set_color (ARDOUR_UI::config()->color ("silence text"));
279 
280  /* both positions are relative to the region start offset in source */
281 
282  _silence_text->set_x_position (trackview.editor().sample_to_pixel (silences.front().first - _region->start()) + 10.0);
283  _silence_text->set_y_position (20.0);
284 
285  double ms = (float) shortest/_region->session().frame_rate();
286 
287  /* ms are now in seconds */
288 
289  char const * sunits;
290 
291  if (ms >= 60.0) {
292  sunits = _("minutes");
293  ms /= 60.0;
294  } else if (ms < 1.0) {
295  sunits = _("msecs");
296  ms *= 1000.0;
297  } else {
298  sunits = _("secs");
299  }
300 
301  string text = string_compose (ngettext ("%1 silent segment", "%1 silent segments", silences.size()), silences.size())
302  + ", "
303  + string_compose (_("shortest = %1 %2"), ms, sunits);
304 
305  if (shortest_audible != max_framepos) {
306  /* ms are now in seconds */
307  double ma = (float) shortest_audible / _region->session().frame_rate();
308  char const * aunits;
309 
310  if (ma >= 60.0) {
311  aunits = _("minutes");
312  ma /= 60.0;
313  } else if (ma < 1.0) {
314  aunits = _("msecs");
315  ma *= 1000.0;
316  } else {
317  aunits = _("secs");
318  }
319 
320  text += string_compose (_("\n (shortest audible segment = %1 %2)"), ma, aunits);
321  }
322 
323  _silence_text->set (text);
324 }
325 
326 void
328 {
329  for (list<ArdourCanvas::Rectangle*>::iterator i = _silent_frames.begin (); i != _silent_frames.end (); ++i) {
330  (*i)->hide ();
331  }
332  _silence_text->hide();
333 }
334 
335 void
337 {
338  for (list<ArdourCanvas::Rectangle*>::iterator i = _silent_frames.begin (); i != _silent_frames.end (); ++i) {
339  delete *i;
340  }
341  _silent_frames.clear ();
342 
343  delete _silence_text;
344  _silence_text = 0;
345 }
346 
347 gint
348 RegionView::_lock_toggle (ArdourCanvas::Item*, GdkEvent* ev, void* arg)
349 {
350  switch (ev->type) {
351  case GDK_BUTTON_RELEASE:
352  static_cast<RegionView*>(arg)->lock_toggle ();
353  return TRUE;
354  break;
355  default:
356  break;
357  }
358  return FALSE;
359 }
360 
361 void
363 {
365 }
366 
367 void
369 {
370  ENSURE_GUI_THREAD (*this, &RegionView::region_changed, what_changed);
371 
372  if (what_changed.contains (ARDOUR::bounds_change)) {
373  region_resized (what_changed);
375  }
376  if (what_changed.contains (ARDOUR::Properties::muted)) {
377  region_muted ();
378  }
379  if (what_changed.contains (ARDOUR::Properties::opaque)) {
380  region_opacity ();
381  }
382  if (what_changed.contains (ARDOUR::Properties::name)) {
383  region_renamed ();
384  }
385  if (what_changed.contains (ARDOUR::Properties::sync_position)) {
387  }
388  if (what_changed.contains (ARDOUR::Properties::locked)) {
389  region_locked ();
390  }
391  if (what_changed.contains (ARDOUR::Properties::locked)) {
392  /* name will show locked status */
393  region_renamed ();
394  }
395 }
396 
397 void
399 {
400  /* name will show locked status */
401  region_renamed ();
402 }
403 
404 void
406 {
407  double unit_length;
408 
409  if (what_changed.contains (ARDOUR::Properties::position)) {
410  set_position (_region->position(), 0);
411  }
412 
413  PropertyChange s_and_l;
414  s_and_l.add (ARDOUR::Properties::start);
416 
417  if (what_changed.contains (s_and_l)) {
418 
419  set_duration (_region->length(), 0);
420 
421  unit_length = _region->length() / samples_per_pixel;
422 
423  for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
424 
425  (*i)->set_duration (unit_length);
426 
427  }
428  }
429 }
430 
431 void
433 {
436 }
437 
438 void
440 {
441  set_frame_color ();
442  region_renamed ();
443 }
444 
445 void
447 {
448  set_frame_color ();
449 }
450 
451 void
453 {
454  _region->raise_to_top ();
455 }
456 
457 void
459 {
461 }
462 
463 bool
464 RegionView::set_position (framepos_t pos, void* /*src*/, double* ignored)
465 {
466  double delta;
467  bool ret;
468 
469  if (!(ret = TimeAxisViewItem::set_position (pos, this, &delta))) {
470  return false;
471  }
472 
473  if (ignored) {
474  *ignored = delta;
475  }
476 
477  if (delta) {
478  for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
479  (*i)->group->move (ArdourCanvas::Duple (delta, 0.0));
480  }
481  }
482 
483  return ret;
484 }
485 
486 void
488 {
490 
491  for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
492  (*i)->set_samples_per_pixel (fpp);
493  (*i)->set_duration (_region->length() / fpp);
494  }
495 
497 }
498 
499 bool
501 {
502  if (!TimeAxisViewItem::set_duration (frames, src)) {
503  return false;
504  }
505 
506  for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
507  (*i)->set_duration (_region->length() / samples_per_pixel);
508  }
509 
510  return true;
511 }
512 
513 void
515 {
518 }
519 
520 void
522 {
523  if (sync_mark) {
524  ArdourCanvas::Color c = ARDOUR_UI::config()->color ("sync mark");
525  sync_mark->set_fill_color (c);
526  sync_mark->set_outline_color (c);
527  sync_line->set_outline_color (c);
528  }
529 }
530 
531 uint32_t
533 {
534  ArdourCanvas::Color f = TimeAxisViewItem::get_fill_color();
535  char const *modname;
536 
537  if (_region->opaque()) {
538  modname = "opaque region base";
539  } else {
540  modname = "transparent region base";
541  }
542 
543  return HSV(f).mod (ARDOUR_UI::config()->modifier (modname)).color ();
544 }
545 
546 void
548 {
549  if (editor == 0) {
551  }
552 
553  editor->present ();
554  editor->show_all();
555 }
556 
557 void
559 {
560  if (editor) {
561  editor->hide_all ();
562  }
563 }
564 
565 std::string
567 {
568  std::string str;
569 
570  // XXX nice to have some good icons for this
571 
572  if (_region->locked()) {
573  str += '>';
574  str += _region->name();
575  str += '<';
576  } else if (_region->position_locked()) {
577  str += '{';
578  str += _region->name();
579  str += '}';
580  } else if (_region->video_locked()) {
581  str += '[';
582  str += _region->name();
583  str += ']';
584  } else {
585  str = _region->name();
586  }
587 
588  if (_region->muted()) {
589  str = string ("!") + str;
590  }
591 
592  return str;
593 }
594 
595 void
597 {
598  std::string str = make_name ();
599 
600  set_item_name (str, this);
601  set_name_text (str);
603 }
604 
605 void
607 {
608  int sync_dir;
609  framecnt_t sync_offset;
610 
611  sync_offset = _region->sync_offset (sync_dir);
612 
613  if (sync_offset == 0) {
614  /* no need for a sync mark */
615  if (sync_mark) {
616  sync_mark->hide();
617  sync_line->hide ();
618  }
619  return;
620  }
621 
622  if (!sync_mark) {
623 
624  /* points set below */
625 
626  sync_mark = new ArdourCanvas::Polygon (group);
627  CANVAS_DEBUG_NAME (sync_mark, string_compose ("sync mark for %1", get_item_name()));
628  sync_line = new ArdourCanvas::Line (group);
629  CANVAS_DEBUG_NAME (sync_line, string_compose ("sync mark for %1", get_item_name()));
630 
632  }
633 
634  /* this has to handle both a genuine change of position, a change of samples_per_pixel
635  and a change in the bounds of the _region->
636  */
637 
638  if (sync_offset == 0) {
639 
640  /* no sync mark - its the start of the region */
641 
642  sync_mark->hide();
643  sync_line->hide ();
644 
645  } else {
646 
647  if ((sync_dir < 0) || ((sync_dir > 0) && (sync_offset > _region->length()))) {
648 
649  /* no sync mark - its out of the bounds of the region */
650 
651  sync_mark->hide();
652  sync_line->hide ();
653 
654  } else {
655 
656  /* lets do it */
657 
658  Points points;
659 
660  //points = sync_mark->property_points().get_value();
661 
662  double offset = sync_offset / samples_per_pixel;
663  points.push_back (ArdourCanvas::Duple (offset - ((sync_mark_width-1)/2), 1));
664  points.push_back (ArdourCanvas::Duple (offset + ((sync_mark_width-1)/2), 1));
665  points.push_back (ArdourCanvas::Duple (offset, sync_mark_width - 1));
666  points.push_back (ArdourCanvas::Duple (offset - ((sync_mark_width-1)/2), 1));
667  sync_mark->set (points);
668  sync_mark->show ();
669 
670  sync_line->set (ArdourCanvas::Duple (offset, 0), ArdourCanvas::Duple (offset, trackview.current_height() - NAME_HIGHLIGHT_SIZE));
671  sync_line->show ();
672  }
673  }
674 }
675 
676 void
677 RegionView::move (double x_delta, double y_delta)
678 {
679  if (!_region->can_move() || (x_delta == 0 && y_delta == 0)) {
680  return;
681  }
682 
683  /* items will not prevent Item::move() moving
684  * them to a negative x-axis coordinate, which
685  * is legal, but we don't want that here.
686  */
687 
688  ArdourCanvas::Item *item = get_canvas_group ();
689 
690  if (item->position().x + x_delta < 0) {
691  x_delta = -item->position().x; /* move it to zero */
692  }
693 
694  item->move (ArdourCanvas::Duple (x_delta, y_delta));
695 
696  /* note: ghosts never leave their tracks so y_delta for them is always zero */
697 
698  for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
699  (*i)->group->move (ArdourCanvas::Duple (x_delta, 0.0));
700  }
701 }
702 
703 void
705 {
706  for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
707  if (&(*i)->trackview == &tv) {
708  delete *i;
709  break;
710  }
711  }
712 }
713 
714 void
716 {
717  if (in_destructor) {
718  return;
719  }
720 
721  for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
722  if (*i == ghost) {
723  ghosts.erase (i);
724  break;
725  }
726  }
727 }
728 
729 void
731 {
733 
734  if (sync_line) {
735  Points points;
736  int sync_dir;
737  framecnt_t sync_offset;
738  sync_offset = _region->sync_offset (sync_dir);
739  double offset = sync_offset / samples_per_pixel;
740 
741  sync_line->set (
742  ArdourCanvas::Duple (offset, 0),
743  ArdourCanvas::Duple (offset, h - NAME_HIGHLIGHT_SIZE)
744  );
745  }
746 
747  for (list<ArdourCanvas::Rectangle*>::iterator i = _coverage_frames.begin(); i != _coverage_frames.end(); ++i) {
748  (*i)->set_y1 (h + 1);
749  }
750 
751  for (list<ArdourCanvas::Rectangle*>::iterator i = _silent_frames.begin(); i != _silent_frames.end(); ++i) {
752  (*i)->set_y1 (h + 1);
753  }
754 
755 }
756 
759 void
761 {
762  /* remove old coverage frames */
763  for (list<ArdourCanvas::Rectangle*>::iterator i = _coverage_frames.begin (); i != _coverage_frames.end (); ++i) {
764  delete *i;
765  }
766 
767  _coverage_frames.clear ();
768 
769  if (d != Stacked) {
770  /* don't do coverage frames unless we're in stacked mode */
771  return;
772  }
773 
775  if (!pl) {
776  return;
777  }
778 
780  framepos_t t = position;
781  framepos_t const end = _region->last_frame ();
782 
783  ArdourCanvas::Rectangle* cr = 0;
784  bool me = false;
785 
786  /* the color that will be used to show parts of regions that will not be heard */
787  uint32_t const non_playing_color = ARDOUR_UI::config()->color_mod ("covered region", "covered region base");
788 
789  while (t < end) {
790 
791  t++;
792 
793  /* is this region is on top at time t? */
794  bool const new_me = (pl->top_unmuted_region_at (t) == _region);
795 
796  /* finish off any old rect, if required */
797  if (cr && me != new_me) {
798  cr->set_x1 (trackview.editor().sample_to_pixel (t - position));
799  }
800 
801  /* start off any new rect, if required */
802  if (cr == 0 || me != new_me) {
803  cr = new ArdourCanvas::Rectangle (group);
804  _coverage_frames.push_back (cr);
805  cr->set_x0 (trackview.editor().sample_to_pixel (t - position));
806  cr->set_y0 (1);
807  cr->set_y1 (_height + 1);
808  cr->set_outline (false);
809  cr->set_ignore_events (true);
810  if (new_me) {
811  cr->set_fill_color (UINT_RGBA_CHANGE_A (non_playing_color, 0));
812  } else {
813  cr->set_fill_color (non_playing_color);
814  }
815  }
816 
817  t = pl->find_next_region_boundary (t, 1);
818  me = new_me;
819  }
820 
821  if (cr) {
822  /* finish off the last rectangle */
823  cr->set_x1 (trackview.editor().sample_to_pixel (end - position));
824  }
825 
826  if (frame_handle_start) {
827  frame_handle_start->raise_to_top ();
828  }
829 
830  if (frame_handle_end) {
831  frame_handle_end->raise_to_top ();
832  }
833 
834  if (name_highlight) {
835  name_highlight->raise_to_top ();
836  }
837 
838  if (name_text) {
839  name_text->raise_to_top ();
840  }
841 }
842 
843 bool
844 RegionView::trim_front (framepos_t new_bound, bool no_overlap)
845 {
846  if (_region->locked()) {
847  return false;
848  }
849 
850  RouteTimeAxisView& rtv = dynamic_cast<RouteTimeAxisView&> (trackview);
851  double const speed = rtv.track()->speed ();
852 
853  framepos_t const pre_trim_first_frame = _region->first_frame();
854 
855  _region->trim_front ((framepos_t) (new_bound * speed));
856 
857  if (no_overlap) {
858  // Get the next region on the left of this region and shrink/expand it.
860  boost::shared_ptr<Region> region_left = playlist->find_next_region (pre_trim_first_frame, End, 0);
861 
862  bool regions_touching = false;
863 
864  if (region_left != 0 && (pre_trim_first_frame == region_left->last_frame() + 1)) {
865  regions_touching = true;
866  }
867 
868  // Only trim region on the left if the first frame has gone beyond the left region's last frame.
869  if (region_left != 0 && (region_left->last_frame() > _region->first_frame() || regions_touching)) {
870  region_left->trim_end (_region->first_frame() - 1);
871  }
872  }
873 
875 
876  return (pre_trim_first_frame != _region->first_frame()); //return true if we actually changed something
877 }
878 
879 bool
880 RegionView::trim_end (framepos_t new_bound, bool no_overlap)
881 {
882  if (_region->locked()) {
883  return false;
884  }
885 
886  RouteTimeAxisView& rtv = dynamic_cast<RouteTimeAxisView&> (trackview);
887  double const speed = rtv.track()->speed ();
888 
889  framepos_t const pre_trim_last_frame = _region->last_frame();
890 
891  _region->trim_end ((framepos_t) (new_bound * speed));
892 
893  if (no_overlap) {
894  // Get the next region on the right of this region and shrink/expand it.
896  boost::shared_ptr<Region> region_right = playlist->find_next_region (pre_trim_last_frame, Start, 1);
897 
898  bool regions_touching = false;
899 
900  if (region_right != 0 && (pre_trim_last_frame == region_right->first_frame() - 1)) {
901  regions_touching = true;
902  }
903 
904  // Only trim region on the right if the last frame has gone beyond the right region's first frame.
905  if (region_right != 0 && (region_right->first_frame() < _region->last_frame() || regions_touching)) {
906  region_right->trim_front (_region->last_frame() + 1);
907  }
908 
910 
911  } else {
913  }
914 
915  return (pre_trim_last_frame != _region->last_frame()); //return true if we actually changed something
916 }
917 
918 
919 void
921 {
922  if (_region->locked()) {
923  return;
924  }
925 
927 }
928 
929 
930 void
932 {
933  if (_region->locked()) {
934  return;
935  }
936  _region->move_start (distance);
938 }
939 
946 {
948 
949  /* x is region relative, convert it to global absolute frames */
950  framepos_t const session_frame = x + _region->position();
951 
952  /* try a snap in either direction */
953  framepos_t frame = session_frame;
954  editor.snap_to (frame, RoundNearest);
955 
956  /* if we went off the beginning of the region, snap forwards */
957  if (frame < _region->position ()) {
958  frame = session_frame;
959  editor.snap_to (frame, RoundUpAlways);
960  }
961 
962  /* back to region relative */
963  return frame - _region->position();
964 }
virtual void resume_property_changes()
Definition: stateful.cc:302
ArdourCanvas::Item * get_canvas_group()
ArdourCanvas::Color color(const std::string &, bool *failed=0) const
Definition: ui_config.cc:567
void set_silent_frames(const ARDOUR::AudioIntervalResult &, double threshold)
Definition: region_view.cc:226
virtual void set_height(double h)
static PBD::Signal1< void, RegionView * > RegionViewGoingAway
Definition: region_view.h:100
void trim_front(framepos_t new_position)
Definition: region.cc:746
void remove_ghost_in(TimeAxisView &)
Definition: region_view.cc:704
virtual bool canvas_region_view_name_event(GdkEvent *event, ArdourCanvas::Item *, RegionView *)=0
virtual void region_resized(const PBD::PropertyChange &)
Definition: region_view.cc:405
PublicEditor & editor() const
bool in_destructor
Definition: region_view.h:172
PBD::Signal1< void, const PropertyChange & > PropertyChanged
Definition: stateful.h:87
boost::shared_ptr< ARDOUR::Region > _region
Definition: region_view.h:159
virtual bool canvas_region_view_name_highlight_event(GdkEvent *event, ArdourCanvas::Item *, RegionView *)=0
#define ngettext(Msgid1, Msgid2, N)
Definition: gettext.h:61
virtual bool canvas_frame_handle_event(GdkEvent *event, ArdourCanvas::Item *, RegionView *)=0
Session & session() const
Definition: ardour_ui.h:130
LIBARDOUR_API PBD::PropertyDescriptor< std::string > name
Pango::FontDescription get_font_for_style(std::string widgetname)
ArdourCanvas::Polygon * sync_mark
polgyon for sync position
Definition: region_view.h:161
virtual void color_handler()
Definition: region_view.h:157
void move_start(frameoffset_t distance)
Definition: region.cc:701
bool _enable_display
see StreamView::redisplay_diskstream()
Definition: region_view.h:170
bool trim_end(framepos_t, bool)
Definition: region_view.cc:880
std::list< std::pair< frameoffset_t, frameoffset_t > > AudioIntervalResult
Definition: types.h:83
Always round up, even if on a division.
Definition: types.h:225
virtual uint32_t get_fill_color() const
Representation of the interface of the Editor class.
TimeAxisView & trackview
void drop_silent_frames()
Definition: region_view.cc:336
tuple f
Definition: signals.py:35
Definition: Beats.hpp:239
virtual std::string get_item_name() const
virtual double sample_to_pixel(framepos_t frame) const =0
ArdourCanvas::Text * name_text
ArdourCanvas::Rectangle * name_highlight
std::string make_name() const
Definition: region_view.cc:566
guint modifier
virtual void set_samples_per_pixel(double)
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
uint32_t current_height() const
framecnt_t frame_rate() const
Definition: session.h:365
Round to nearest.
Definition: types.h:224
#define ENSURE_GUI_THREAD(obj, method,...)
Definition: gui_thread.h:34
#define invalidator(x)
Definition: gui_thread.h:40
bool can_move() const
Definition: region.h:171
#define UINT_RGBA_CHANGE_A(x, a)
Definition: rgb_macros.h:64
virtual void update_coverage_frames(LayerDisplay)
Definition: region_view.cc:760
void raise_to_top()
Definition: region.cc:1112
std::list< ArdourCanvas::Rectangle * > _coverage_frames
Definition: region_view.h:182
bool set_position(framepos_t pos, void *src, double *delta=0)
Definition: region_view.cc:464
#define _(Text)
Definition: i18n.h:11
void trim_end(framepos_t new_position)
Definition: region.cc:836
void region_opacity()
Definition: region_view.cc:446
void move(double xdelta, double ydelta)
Definition: region_view.cc:677
virtual void snap_to(framepos_t &first, ARDOUR::RoundMode direction=ARDOUR::RoundNearest, bool for_mark=false)=0
double current_visible_sync_position
Definition: region_view.h:167
double _pixel_width
Definition: region_view.h:171
static const int32_t sync_mark_width
Definition: region_view.cc:63
bool canvas_group_event(GdkEvent *)
Definition: region_view.cc:217
int64_t framecnt_t
Definition: types.h:76
void set_item_name(std::string, void *)
bool video_locked() const
Definition: region.h:166
boost::shared_ptr< ARDOUR::Region > region() const
Definition: region_view.h:66
void lower_to_bottom()
Definition: region_view.cc:458
void raise_to_top()
Definition: region_view.cc:452
virtual void init(bool wait_for_data)
Definition: region_view.cc:149
bool valid
see StreamView::redisplay_diskstream()
Definition: region_view.h:169
virtual bool set_duration(framecnt_t, void *)
Definition: amp.h:29
ARDOUR::frameoffset_t snap_frame_to_frame(ARDOUR::frameoffset_t) const
Definition: region_view.cc:945
bool position_locked() const
Definition: region.h:165
ARDOUR::Session * session() const
Definition: axis_view.h:52
bool muted() const
Definition: region.h:162
LIBARDOUR_API PBD::PropertyDescriptor< bool > locked
Definition: region.cc:51
boost::shared_ptr< ARDOUR::Track > track() const
Definition: route_ui.cc:1738
virtual bool canvas_region_view_event(GdkEvent *event, ArdourCanvas::Item *, RegionView *)=0
#define gui_context()
Definition: gui_thread.h:36
virtual void set_frame_color()
Definition: enums.h:36
virtual void region_renamed()
Definition: region_view.cc:596
LIBARDOUR_API PBD::PropertyDescriptor< bool > opaque
Definition: region.cc:50
virtual void thaw_after_trim()
Definition: region_view.cc:920
frameoffset_t sync_offset(int &dir) const
Definition: region.cc:1041
void lock_toggle()
Definition: region_view.cc:362
int64_t framepos_t
Definition: types.h:66
ArdourCanvas::Rectangle * frame_handle_start
`frame' (fade) handle for the start of the item, or 0
static gint _lock_toggle(ArdourCanvas::Item *, GdkEvent *, void *)
Definition: region_view.cc:348
uint32_t get_fill_color() const
Definition: region_view.cc:532
virtual void region_muted()
Definition: region_view.cc:439
virtual void set_sync_mark_color()
Definition: region_view.cc:521
void move_contents(ARDOUR::frameoffset_t)
Definition: region_view.cc:931
int64_t frameoffset_t
Definition: types.h:71
RegionView(ArdourCanvas::Container *parent, TimeAxisView &time_view, boost::shared_ptr< ARDOUR::Region > region, double samples_per_pixel, uint32_t base_color, bool automation=false)
Definition: region_view.cc:67
virtual void show_region_editor()
Definition: region_view.cc:547
virtual bool set_position(framepos_t, void *, double *delta=0)
virtual void reset_width_dependent_items(double pixel_width)
Definition: region_view.cc:432
void set_name_text(const std::string &)
void hide_silent_frames()
Definition: region_view.cc:327
framepos_t position() const
Definition: region.h:112
void remove_ghost(GhostRegion *)
Definition: region_view.cc:715
bool trim_front(framepos_t, bool)
Definition: region_view.cc:844
static PublicEditor & instance()
virtual void reset_width_dependent_items(double)
virtual bool set_duration(framecnt_t, void *)
Definition: region_view.cc:500
const char * name
bool locked() const
Definition: region.h:164
ArdourCanvas::Rectangle * frame
virtual void set_height(double)
Definition: region_view.cc:730
ArdourCanvas::Color color_mod(std::string const &color, std::string const &modifier) const
Definition: ui_config.cc:555
std::string name() const
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
Definition: region.cc:65
static UIConfiguration * config()
Definition: ardour_ui.h:188
virtual void set_colors()
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > sync_position
Definition: region.cc:66
std::list< ArdourCanvas::Rectangle * > _silent_frames
Definition: region_view.h:186
std::vector< GhostRegion * > ghosts
Definition: region_view.h:176
virtual void set_samples_per_pixel(double)
Definition: region_view.cc:487
sigc::signal< void > ColorsChanged
Definition: debug.h:30
virtual void region_changed(const PBD::PropertyChange &)
Definition: region_view.cc:368
void region_locked()
Definition: region_view.cc:398
ArdourCanvas::Rectangle * frame_handle_end
`frame' (fade) handle for the end of the item, or 0
bool opaque() const
Definition: region.h:163
ArdourCanvas::Container * group
LayerDisplay
Definition: enums.h:34
bool contains(PropertyDescriptor< T > p) const
framecnt_t length() const
Definition: region.h:114
static const framepos_t max_framepos
Definition: types.h:78
void region_sync_changed()
Definition: region_view.cc:606
framepos_t first_frame() const
Definition: region.h:141
void lower_to_bottom()
Definition: region.cc:1121
framepos_t start() const
Definition: region.h:113
bool wait_for_data
Definition: region_view.h:174
static const framecnt_t max_framecnt
Definition: types.h:79
LIBGTKMM2EXT_API int pixel_width(const std::string &str, Pango::FontDescription &font)
void hide_region_editor()
Definition: region_view.cc:558
static PBD::Signal1< void, GhostRegion * > CatchDeletion
Definition: ghostregion.h:58
ArdourCanvas::Text * _silence_text
Definition: region_view.h:192
LIBARDOUR_API PBD::PropertyDescriptor< bool > muted
Definition: region.cc:49
ArdourCanvas::Line * sync_line
polgyon for sync position
Definition: region_view.h:162
void add(PropertyID id)
virtual void set_colors()
Definition: region_view.cc:514
LIBARDOUR_API PBD::PropertyChange bounds_change
Definition: globals.cc:150
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
#define N_(Text)
Definition: i18n.h:12
RegionEditor * editor
Definition: region_view.h:164
void set_locked(bool yn)
Definition: region.cc:980
boost::shared_ptr< ARDOUR::Playlist > playlist() const
Definition: region.h:251
static double NAME_HIGHLIGHT_SIZE
framepos_t last_frame() const
Definition: region.h:142
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > length
Definition: region.cc:64
double speed() const
Definition: track.cc:759
LIBARDOUR_API PBD::PropertyDescriptor< bool > color
Definition: route_group.cc:50