ardour
editor_regions.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000-2005 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 <cstdlib>
21 #include <cmath>
22 #include <algorithm>
23 #include <string>
24 #include <sstream>
25 
26 #include "pbd/basename.h"
27 #include "pbd/enumwriter.h"
28 
29 #include "ardour/audioregion.h"
30 #include "ardour/audiofilesource.h"
32 #include "ardour/region_factory.h"
33 #include "ardour/session.h"
34 #include "ardour/profile.h"
35 
36 #include "gtkmm2ext/choice.h"
37 #include "gtkmm2ext/treeutils.h"
38 
39 #include "audio_clock.h"
40 #include "editor.h"
41 #include "editing.h"
42 #include "keyboard.h"
43 #include "ardour_ui.h"
44 #include "gui_thread.h"
45 #include "actions.h"
46 #include "region_view.h"
47 #include "utils.h"
48 #include "editor_regions.h"
49 #include "editor_drag.h"
50 #include "main_clock.h"
51 
52 #include "i18n.h"
53 
54 using namespace std;
55 using namespace ARDOUR;
56 using namespace ARDOUR_UI_UTILS;
57 using namespace PBD;
58 using namespace Gtk;
59 using namespace Glib;
60 using namespace Editing;
62 
63 struct ColumnInfo {
64  int index;
65  const char* label;
66  const char* tooltip;
67 };
68 
70  : EditorComponent (e)
71  , old_focus (0)
72  , name_editable (0)
73  , _menu (0)
74  , _show_automatic_regions (true)
75  , ignore_region_list_selection_change (false)
76  , ignore_selected_region_change (false)
77  , _no_redisplay (false)
78  , _sort_type ((Editing::RegionListSortType) 0)
79  , expanded (false)
80 {
81  _display.set_size_request (100, -1);
82  _display.set_rules_hint (true);
83  _display.set_name ("EditGroupList");
84 
85  /* Try to prevent single mouse presses from initiating edits.
86  This relies on a hack in gtktreeview.c:gtk_treeview_button_press()
87  */
88  _display.set_data ("mouse-edits-require-mod1", (gpointer) 0x1);
89 
90  _model = TreeStore::create (_columns);
91  _model->set_sort_func (0, sigc::mem_fun (*this, &EditorRegions::sorter));
92  _model->set_sort_column (0, SORT_ASCENDING);
93 
94  _display.set_model (_model);
95 
96  _display.append_column ("", _columns.name);
97  _display.append_column ("", _columns.position);
98  _display.append_column ("", _columns.end);
99  _display.append_column ("", _columns.length);
100  _display.append_column ("", _columns.sync);
101  _display.append_column ("", _columns.fadein);
102  _display.append_column ("", _columns.fadeout);
103  _display.append_column ("", _columns.locked);
104  _display.append_column ("", _columns.glued);
105  _display.append_column ("", _columns.muted);
106  _display.append_column ("", _columns.opaque);
107 
108  TreeViewColumn* col;
109  Gtk::Label* l;
110 
111  ColumnInfo ci[] = {
112  { 0, _("Region"), _("Region name, with number of channels in []'s") },
113  { 1, _("Position"), _("Position of start of region") },
114  { 2, _("End"), _("Position of end of region") },
115  { 3, _("Length"), _("Length of the region") },
116  { 4, _("Sync"), _("Position of region sync point, relative to start of the region") },
117  { 5, _("Fade In"), _("Length of region fade-in (units: secondary clock), () if disabled") },
118  { 6, _("Fade Out"), _("Length of region fade-out (units: secondary clock), () if disabled") },
119  { 7, S_("Lock|L"), _("Region position locked?") },
120  { 8, S_("Gain|G"), _("Region position glued to Bars|Beats time?") },
121  { 9, S_("Mute|M"), _("Region muted?") },
122  { 10, S_("Opaque|O"), _("Region opaque (blocks regions below it from being heard)?") },
123  { -1, 0, 0 }
124  };
125 
126  for (int i = 0; ci[i].index >= 0; ++i) {
127  col = _display.get_column (ci[i].index);
128  l = manage (new Label (ci[i].label));
129  ARDOUR_UI::instance()->set_tip (*l, ci[i].tooltip);
130  col->set_widget (*l);
131  l->show ();
132 
133  if (ci[i].index > 6) {
134  col->set_expand (false);
135  col->set_alignment (ALIGN_CENTER);
136  }
137  }
138 
139  _display.set_headers_visible (true);
140  _display.set_rules_hint ();
141 
142  /* show path as the row tooltip */
143  _display.set_tooltip_column (14); /* path */
144 
145  CellRendererText* region_name_cell = dynamic_cast<CellRendererText*>(_display.get_column_cell_renderer (0));
146  region_name_cell->property_editable() = true;
147  region_name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRegions::name_edit));
148  region_name_cell->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRegions::name_editing_started));
149 
150  _display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRegions::selection_filter));
151 
152  TreeViewColumn* tv_col = _display.get_column(0);
153  CellRendererText* renderer = dynamic_cast<CellRendererText*>(_display.get_column_cell_renderer (0));
154  tv_col->add_attribute(renderer->property_text(), _columns.name);
155  tv_col->add_attribute(renderer->property_foreground_gdk(), _columns.color_);
156  tv_col->set_expand (true);
157 
158  CellRendererToggle* locked_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (7));
159  locked_cell->property_activatable() = true;
160  locked_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRegions::locked_changed));
161 
162  TreeViewColumn* locked_col = _display.get_column (7);
163  locked_col->add_attribute (locked_cell->property_visible(), _columns.property_toggles_visible);
164 
165  CellRendererToggle* glued_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (8));
166  glued_cell->property_activatable() = true;
167  glued_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRegions::glued_changed));
168 
169  TreeViewColumn* glued_col = _display.get_column (8);
170  glued_col->add_attribute (glued_cell->property_visible(), _columns.property_toggles_visible);
171 
172  CellRendererToggle* muted_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (9));
173  muted_cell->property_activatable() = true;
174  muted_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRegions::muted_changed));
175 
176  TreeViewColumn* muted_col = _display.get_column (9);
177  muted_col->add_attribute (muted_cell->property_visible(), _columns.property_toggles_visible);
178 
179  CellRendererToggle* opaque_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (10));
180  opaque_cell->property_activatable() = true;
181  opaque_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRegions::opaque_changed));
182 
183  TreeViewColumn* opaque_col = _display.get_column (10);
184  opaque_col->add_attribute (opaque_cell->property_visible(), _columns.property_toggles_visible);
185 
186  _display.get_selection()->set_mode (SELECTION_MULTIPLE);
187  _display.add_object_drag (_columns.region.index(), "regions");
188 
189  /* setup DnD handling */
190 
191  list<TargetEntry> region_list_target_table;
192 
193  region_list_target_table.push_back (TargetEntry ("text/plain"));
194  region_list_target_table.push_back (TargetEntry ("text/uri-list"));
195  region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
196 
197  _display.add_drop_targets (region_list_target_table);
198  _display.signal_drag_data_received().connect (sigc::mem_fun(*this, &EditorRegions::drag_data_received));
199 
200  _scroller.add (_display);
201  _scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
202 
203  _display.signal_button_press_event().connect (sigc::mem_fun(*this, &EditorRegions::button_press), false);
204  _change_connection = _display.get_selection()->signal_changed().connect (sigc::mem_fun(*this, &EditorRegions::selection_changed));
205 
206  _scroller.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRegions::key_press), false);
207  _scroller.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRegions::focus_in), false);
208  _scroller.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRegions::focus_out));
209 
210  _display.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRegions::enter_notify), false);
211  _display.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRegions::leave_notify), false);
212 
213  // _display.signal_popup_menu().connect (sigc::bind (sigc::mem_fun (*this, &Editor::show__display_context_menu), 1, 0));
214 
215  //ARDOUR_UI::instance()->secondary_clock.mode_changed.connect (sigc::mem_fun(*this, &Editor::redisplay_regions));
219 
222 }
223 
224 bool
225 EditorRegions::focus_in (GdkEventFocus*)
226 {
227  Window* win = dynamic_cast<Window*> (_scroller.get_toplevel ());
228 
229  if (win) {
230  old_focus = win->get_focus ();
231  } else {
232  old_focus = 0;
233  }
234 
235  name_editable = 0;
236 
237  /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
238  return true;
239 }
240 
241 bool
242 EditorRegions::focus_out (GdkEventFocus*)
243 {
244  if (old_focus) {
245  old_focus->grab_focus ();
246  old_focus = 0;
247  }
248 
249  name_editable = 0;
250 
251  return false;
252 }
253 
254 bool
255 EditorRegions::enter_notify (GdkEventCrossing*)
256 {
257  if (name_editable) {
258  return true;
259  }
260 
261  /* arm counter so that ::selection_filter() will deny selecting anything for the
262  next two attempts to change selection status.
263  */
264  _scroller.grab_focus ();
265  Keyboard::magic_widget_grab_focus ();
266  return false;
267 }
268 
269 bool
270 EditorRegions::leave_notify (GdkEventCrossing*)
271 {
272  if (old_focus) {
273  old_focus->grab_focus ();
274  old_focus = 0;
275  }
276 
277  Keyboard::magic_widget_drop_focus ();
278  return false;
279 }
280 
281 void
283 {
284  SessionHandlePtr::set_session (s);
285  redisplay ();
286 }
287 
288 void
290 {
291  if (!region || !_session) {
292  return;
293  }
294 
295  string str;
296  TreeModel::Row row;
297  Gdk::Color c;
298  bool missing_source = boost::dynamic_pointer_cast<SilentFileSource>(region->source()) != NULL;
299 
300  if (!_show_automatic_regions && region->automatic()) {
301  return;
302  }
303 
304  if (region->hidden()) {
305 
306  TreeModel::iterator iter = _model->get_iter ("0");
307  TreeModel::Row parent;
308 
309  if (!iter) {
310  parent = *(_model->append());
311  parent[_columns.name] = _("Hidden");
312  boost::shared_ptr<Region> proxy = parent[_columns.region];
313  proxy.reset ();
314  } else {
315  string s = (*iter)[_columns.name];
316  if (s != _("Hidden")) {
317  parent = *(_model->insert(iter));
318  parent[_columns.name] = _("Hidden");
319  boost::shared_ptr<Region> proxy = parent[_columns.region];
320  proxy.reset ();
321  } else {
322  parent = *iter;
323  }
324  }
325 
326  row = *(_model->append (parent.children()));
327 
328  } else if (region->whole_file()) {
329 
330  TreeModel::iterator i;
331  TreeModel::Children rows = _model->children();
332 
333  for (i = rows.begin(); i != rows.end(); ++i) {
335 
336  if (rr && region->region_list_equivalent (rr)) {
337  return;
338  }
339  }
340 
341  row = *(_model->append());
342 
343  if (missing_source) {
344  // c.set_rgb(65535,0,0); // FIXME: error color from style
345  set_color_from_rgba (c, ARDOUR_UI::config()->color ("region list missing source"));
346 
347  } else if (region->automatic()){
348  // c.set_rgb(0,65535,0); // FIXME: error color from style
349  set_color_from_rgba (c, ARDOUR_UI::config()->color ("region list automatic"));
350 
351  } else {
352  set_color_from_rgba (c, ARDOUR_UI::config()->color ("region list whole file"));
353  }
354 
355  row[_columns.color_] = c;
356 
357  if (region->source()->name()[0] == '/') { // external file
358 
359  if (region->whole_file()) {
360 
362  str = ".../";
363 
364  if (afs) {
365  str = region_name_from_path (afs->path(), region->n_channels() > 1);
366  } else {
367  str += region->source()->name();
368  }
369 
370  } else {
371  str = region->name();
372  }
373 
374  } else {
375  str = region->name();
376  }
377 
378  if (region->n_channels() > 1) {
379  std::stringstream foo;
380  foo << region->n_channels ();
381  str += " [";
382  str += foo.str();
383  str += "]";
384  }
385 
386  row[_columns.name] = str;
387  row[_columns.region] = region;
388  row[_columns.property_toggles_visible] = false;
389 
390  if (missing_source) {
391  row[_columns.path] = _("(MISSING) ") + region->source()->name();
392 
393  } else {
395  if (fs) {
396  row[_columns.path] = fs->path();
397  } else {
398  row[_columns.path] = region->source()->name();
399  }
400  }
401 
402  region_row_map.insert(pair<boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::RowReference>(region, TreeRowReference(_model, TreePath (row))) );
403  parent_regions_sources_map.insert(pair<string, Gtk::TreeModel::RowReference>(region->source_string(), TreeRowReference(_model, TreePath (row))) );
404 
405  return;
406 
407  } else {
408  // find parent node, add as new child
409  TreeModel::iterator i;
410 
411  boost::unordered_map<string, Gtk::TreeModel::RowReference>::iterator it;
412 
413  it = parent_regions_sources_map.find (region->source_string());
414 
415  if (it != parent_regions_sources_map.end()){
416 
417  TreeModel::iterator j = _model->get_iter ((*it).second.get_path());
418 
419  TreeModel::iterator ii;
420  TreeModel::Children subrows = (*j).children();
421 
422  /* XXXX: should we be accounting for all regions? */
423  /*
424  for (ii = subrows.begin(); ii != subrows.end(); ++ii) {
425  boost::shared_ptr<Region> rr = (*ii)[_columns.region];
426 
427  if (region->region_list_equivalent (rr)) {
428  return;
429  }
430  }
431  */
432 
433  row = *(_model->insert (subrows.end()));
434 
435  } else {
436  row = *(_model->append());
437  }
438 
440  }
441 
442  row[_columns.region] = region;
443 
444  region_row_map.insert(pair<boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::RowReference>(region, TreeRowReference(_model, TreePath (row))) );
445 
446  populate_row(region, (*row));
447 }
448 
449 void
451 {
452  vector<string> choices;
453  string prompt;
454 
455  if (!_session) {
456  return;
457  }
458 
459  prompt = _("Do you really want to remove unused regions?"
460  "\n(This is destructive and cannot be undone)");
461 
462  choices.push_back (_("No, do nothing."));
463  choices.push_back (_("Yes, remove."));
464 
465  Gtkmm2ext::Choice prompter (_("Remove unused regions"), prompt, choices);
466 
467  if (prompter.run () == 1) {
468  _no_redisplay = true;
470  _no_redisplay = false;
471  redisplay ();
472  }
473 }
474 
475 void
477 {
478  PropertyChange our_interests;
479 
480  our_interests.add (ARDOUR::Properties::name);
481  our_interests.add (ARDOUR::Properties::position);
482  our_interests.add (ARDOUR::Properties::length);
483  our_interests.add (ARDOUR::Properties::start);
484  our_interests.add (ARDOUR::Properties::locked);
486  our_interests.add (ARDOUR::Properties::muted);
487  our_interests.add (ARDOUR::Properties::opaque);
488  our_interests.add (ARDOUR::Properties::fade_in);
489  our_interests.add (ARDOUR::Properties::fade_out);
490  our_interests.add (ARDOUR::Properties::fade_in_active);
492 
493  if (what_changed.contains (our_interests)) {
494 
495  if (last_row != 0) {
496 
497  TreeModel::iterator j = _model->get_iter (last_row.get_path());
499 
500  if (c == r) {
501  populate_row (r, (*j));
502 
503  if (what_changed.contains (ARDOUR::Properties::hidden)) {
504  redisplay ();
505  }
506 
507  return;
508  }
509  }
510 
511  RegionRowMap::iterator it;
512 
513  it = region_row_map.find (r);
514 
515  if (it != region_row_map.end()){
516 
517  TreeModel::iterator j = _model->get_iter ((*it).second.get_path());
519 
520  if (c == r) {
521  populate_row (r, (*j));
522 
523  if (what_changed.contains (ARDOUR::Properties::hidden)) {
524  redisplay ();
525  }
526 
527  return;
528  }
529  }
530  }
531 
532  if (what_changed.contains (ARDOUR::Properties::hidden)) {
533  redisplay ();
534  }
535 }
536 
537 void
539 {
541  return;
542  }
543 
545 
546  if (_display.get_selection()->count_selected_rows() > 0) {
547 
548  TreeIter iter;
549  TreeView::Selection::ListHandle_Path rows = _display.get_selection()->get_selected_rows ();
550 
552 
553  for (TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); i != rows.end(); ++i) {
554 
555  if ((iter = _model->get_iter (*i))) {
556 
557  boost::shared_ptr<Region> region = (*iter)[_columns.region];
558 
559  // they could have clicked on a row that is just a placeholder, like "Hidden"
560  // although that is not allowed by our selection filter. check it anyway
561  // since we need a region ptr.
562 
563  if (region) {
564 
565  _change_connection.block (true);
567  _change_connection.block (false);
568  }
569  }
570 
571  }
572  } else {
574  }
575 
577 }
578 
579 void
581 {
582  for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
583 
584  boost::shared_ptr<Region> r ((*i)->region());
585 
586  RegionRowMap::iterator it;
587 
588  it = region_row_map.find (r);
589 
590  if (it != region_row_map.end()){
591  TreeModel::iterator j = _model->get_iter ((*it).second.get_path());
592  _display.get_selection()->select(*j);
593  }
594  }
595 }
596 
597 void
599 {
600  if (_no_redisplay || !_session) {
601  return;
602  }
603 
604  bool tree_expanded = false;
605 
606  /* If the list was expanded prior to rebuilding, expand it again afterwards */
607  if (toggle_full_action()->get_active()) {
608  tree_expanded = true;
609  }
610 
611  _display.set_model (Glib::RefPtr<Gtk::TreeStore>(0));
612  _model->clear ();
613  _model->set_sort_column (-2, SORT_ASCENDING); //Disable sorting to gain performance
614 
615 
616  region_row_map.clear();
618 
619  /* now add everything we have, via a temporary list used to help with sorting */
620 
622 
623  for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
624 
625  if ( i->second->whole_file()) {
626  /* add automatic regions first so that children can find their parents as we add them */
627  add_region (i->second);
628  continue;
629  }
630 
631  tmp_region_list.push_front (i->second);
632  }
633 
634  for (list<boost::shared_ptr<Region> >::iterator r = tmp_region_list.begin(); r != tmp_region_list.end(); ++r) {
635  add_region (*r);
636  }
637 
638  _model->set_sort_column (0, SORT_ASCENDING); // renabale sorting
639  _display.set_model (_model);
640 
641  tmp_region_list.clear();
642 
643  if (tree_expanded) {
644  _display.expand_all();
645  }
646 }
647 
648 void
650 {
651  if (!region || !_session) {
652  return;
653  }
654 
655  RegionRowMap::iterator it;
656 
657  it = region_row_map.find (region);
658 
659  if (it != region_row_map.end()){
660 
661  TreeModel::iterator j = _model->get_iter ((*it).second.get_path());
662  populate_row(region, (*j));
663  }
664 }
665 
666 void
668 {
669  if (!_session) {
670  return;
671  }
672 
673  RegionRowMap::iterator i;
674 
675  for (i = region_row_map.begin(); i != region_row_map.end(); ++i) {
676 
677  TreeModel::iterator j = _model->get_iter ((*i).second.get_path());
678 
680 
681  if (!region->automatic()) {
682  populate_row(region, (*j));
683  }
684  }
685 }
686 
687 void
688 EditorRegions::format_position (framepos_t pos, char* buf, size_t bufsize, bool onoff)
689 {
690  Timecode::BBT_Time bbt;
691  Timecode::Time timecode;
692 
693  if (pos < 0) {
694  error << string_compose (_("EditorRegions::format_position: negative timecode position: %1"), pos) << endmsg;
695  snprintf (buf, bufsize, "invalid");
696  return;
697  }
698 
699  switch (ARDOUR_UI::instance()->secondary_clock->mode ()) {
700  case AudioClock::BBT:
701  _session->tempo_map().bbt_time (pos, bbt);
702  if (onoff) {
703  snprintf (buf, bufsize, "%03d|%02d|%04d" , bbt.bars, bbt.beats, bbt.ticks);
704  } else {
705  snprintf (buf, bufsize, "(%03d|%02d|%04d)" , bbt.bars, bbt.beats, bbt.ticks);
706  }
707  break;
708 
709  case AudioClock::MinSec:
710  framepos_t left;
711  int hrs;
712  int mins;
713  float secs;
714 
715  left = pos;
716  hrs = (int) floor (left / (_session->frame_rate() * 60.0f * 60.0f));
717  left -= (framecnt_t) floor (hrs * _session->frame_rate() * 60.0f * 60.0f);
718  mins = (int) floor (left / (_session->frame_rate() * 60.0f));
719  left -= (framecnt_t) floor (mins * _session->frame_rate() * 60.0f);
720  secs = left / (float) _session->frame_rate();
721  if (onoff) {
722  snprintf (buf, bufsize, "%02d:%02d:%06.3f", hrs, mins, secs);
723  } else {
724  snprintf (buf, bufsize, "(%02d:%02d:%06.3f)", hrs, mins, secs);
725  }
726  break;
727 
728  case AudioClock::Frames:
729  if (onoff) {
730  snprintf (buf, bufsize, "%" PRId64, pos);
731  } else {
732  snprintf (buf, bufsize, "(%" PRId64 ")", pos);
733  }
734  break;
735 
737  default:
738  _session->timecode_time (pos, timecode);
739  if (onoff) {
740  snprintf (buf, bufsize, "%02d:%02d:%02d:%02d", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
741  } else {
742  snprintf (buf, bufsize, "(%02d:%02d:%02d:%02d)", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
743  }
744  break;
745  }
746 }
747 
748 void
749 EditorRegions::populate_row (boost::shared_ptr<Region> region, TreeModel::Row const &row)
750 {
752  //uint32_t used = _session->playlists->region_use_count (region);
753  /* Presently a region is only used once so let's save on the sequential scan to determine use count */
754  uint32_t used = 1;
755 
756  populate_row_position (region, row, used);
757  populate_row_end (region, row, used);
758  populate_row_sync (region, row, used);
759  populate_row_fade_in (region, row, used, audioregion);
760  populate_row_fade_out (region, row, used, audioregion);
761  populate_row_locked (region, row, used);
762  populate_row_glued (region, row, used);
763  populate_row_muted (region, row, used);
764  populate_row_opaque (region, row, used);
765  populate_row_length (region, row);
766  populate_row_source (region, row);
767  populate_row_name (region, row);
768  populate_row_used (region, row, used);
769 }
770 
771 #if 0
772  if (audioRegion && fades_in_seconds) {
773 
774  framepos_t left;
775  int mins;
776  int millisecs;
777 
778  left = audioRegion->fade_in()->back()->when;
779  mins = (int) floor (left / (_session->frame_rate() * 60.0f));
780  left -= (framepos_t) floor (mins * _session->frame_rate() * 60.0f);
781  millisecs = (int) floor ((left * 1000.0f) / _session->frame_rate());
782 
783  if (audioRegion->fade_in()->back()->when >= _session->frame_rate()) {
784  sprintf (fadein_str, "%01dM %01dmS", mins, millisecs);
785  } else {
786  sprintf (fadein_str, "%01dmS", millisecs);
787  }
788 
789  left = audioRegion->fade_out()->back()->when;
790  mins = (int) floor (left / (_session->frame_rate() * 60.0f));
791  left -= (framepos_t) floor (mins * _session->frame_rate() * 60.0f);
792  millisecs = (int) floor ((left * 1000.0f) / _session->frame_rate());
793 
794  if (audioRegion->fade_out()->back()->when >= _session->frame_rate()) {
795  sprintf (fadeout_str, "%01dM %01dmS", mins, millisecs);
796  } else {
797  sprintf (fadeout_str, "%01dmS", millisecs);
798  }
799  }
800 #endif
801 
802 void
803 EditorRegions::populate_row_used (boost::shared_ptr<Region>, TreeModel::Row const& row, uint32_t used)
804 {
805  char buf[8];
806  snprintf (buf, sizeof (buf), "%4d" , used);
807  row[_columns.used] = buf;
808 }
809 
810 void
812 {
813  char buf[16];
814  format_position (region->length(), buf, sizeof (buf));
815  row[_columns.length] = buf;
816 }
817 
818 void
819 EditorRegions::populate_row_end (boost::shared_ptr<Region> region, TreeModel::Row const &row, uint32_t used)
820 {
821  if (region->whole_file()) {
822  row[_columns.end] = "";
823  } else if (used > 1) {
824  row[_columns.end] = _("Mult.");
825  } else if (region->last_frame() >= region->first_frame()) {
826  char buf[16];
827  format_position (region->last_frame(), buf, sizeof (buf));
828  row[_columns.end] = buf;
829  } else {
830  row[_columns.end] = "empty";
831  }
832 }
833 
834 void
835 EditorRegions::populate_row_position (boost::shared_ptr<Region> region, TreeModel::Row const &row, uint32_t used)
836 {
837  if (region->whole_file()) {
838  row[_columns.position] = "";
839  } else if (used > 1) {
840  row[_columns.position] = _("Mult.");
841  } else {
842  char buf[16];
843  format_position (region->position(), buf, sizeof (buf));
844  row[_columns.position] = buf;
845  }
846 }
847 
848 void
849 EditorRegions::populate_row_sync (boost::shared_ptr<Region> region, TreeModel::Row const &row, uint32_t used)
850 {
851  if (region->whole_file()) {
852  row[_columns.sync] = "";
853  } else if (used > 1) {
854  row[_columns.sync] = _("Mult."); /* translators: a short phrase for "multiple" as in "many" */
855  } else {
856  if (region->sync_position() == region->position()) {
857  row[_columns.sync] = _("Start");
858  } else if (region->sync_position() == (region->last_frame())) {
859  row[_columns.sync] = _("End");
860  } else {
861  char buf[16];
862  format_position (region->sync_position(), buf, sizeof (buf));
863  row[_columns.sync] = buf;
864  }
865  }
866 }
867 
868 void
869 EditorRegions::populate_row_fade_in (boost::shared_ptr<Region> region, TreeModel::Row const &row, uint32_t used, boost::shared_ptr<AudioRegion> audioregion)
870 {
871  if (!audioregion || region->whole_file()) {
872  row[_columns.fadein] = "";
873  } else {
874  if (used > 1) {
875  row[_columns.fadein] = _("Multiple");
876  } else {
877  char buf[32];
878  format_position (audioregion->fade_in()->back()->when, buf, sizeof (buf), audioregion->fade_in_active());
879  row[_columns.fadein] = buf;
880  }
881  }
882 }
883 
884 void
885 EditorRegions::populate_row_fade_out (boost::shared_ptr<Region> region, TreeModel::Row const &row, uint32_t used, boost::shared_ptr<AudioRegion> audioregion)
886 {
887  if (!audioregion || region->whole_file()) {
888  row[_columns.fadeout] = "";
889  } else {
890  if (used > 1) {
891  row[_columns.fadeout] = _("Multiple");
892  } else {
893  char buf[32];
894  format_position (audioregion->fade_out()->back()->when, buf, sizeof (buf), audioregion->fade_out_active());
895  row[_columns.fadeout] = buf;
896  }
897  }
898 }
899 
900 void
901 EditorRegions::populate_row_locked (boost::shared_ptr<Region> region, TreeModel::Row const &row, uint32_t used)
902 {
903  if (region->whole_file()) {
904  row[_columns.locked] = false;
905  } else if (used > 1) {
906  row[_columns.locked] = false;
907  } else {
908  row[_columns.locked] = region->locked();
909  }
910 }
911 
912 void
913 EditorRegions::populate_row_glued (boost::shared_ptr<Region> region, TreeModel::Row const &row, uint32_t used)
914 {
915  if (region->whole_file() || used > 1) {
916  row[_columns.glued] = false;
917  } else {
918  if (region->position_lock_style() == MusicTime) {
919  row[_columns.glued] = true;
920  } else {
921  row[_columns.glued] = false;
922  }
923  }
924 }
925 
926 void
927 EditorRegions::populate_row_muted (boost::shared_ptr<Region> region, TreeModel::Row const &row, uint32_t used)
928 {
929  if (region->whole_file() || used > 1) {
930  row[_columns.muted] = false;
931  } else {
932  row[_columns.muted] = region->muted();
933  }
934 }
935 
936 void
937 EditorRegions::populate_row_opaque (boost::shared_ptr<Region> region, TreeModel::Row const &row, uint32_t used)
938 {
939  if (region->whole_file() || used > 1) {
940  row[_columns.opaque] = false;
941  } else {
942  row[_columns.opaque] = region->opaque();
943  }
944 }
945 
946 void
948 {
949  if (region->n_channels() > 1) {
950  row[_columns.name] = string_compose("%1 [%2]", region->name(), region->n_channels());
951  } else {
952  row[_columns.name] = region->name();
953  }
954 }
955 
956 void
958 {
959  if (boost::dynamic_pointer_cast<SilentFileSource>(region->source())) {
960  row[_columns.path] = _("MISSING ") + region->source()->name();
961  } else {
962  row[_columns.path] = region->source()->name();
963  }
964 }
965 
966 void
968 {
970  redisplay ();
971 }
972 
973 void
975 {
976  set_full (toggle_full_action()->get_active ());
977 }
978 
979 void
981 {
982  if (f) {
983  _display.expand_all ();
984  expanded = true;
985  } else {
986  _display.collapse_all ();
987  expanded = false;
988  }
989 }
990 
991 void
992 EditorRegions::show_context_menu (int button, int time)
993 {
994  if (_menu == 0) {
995  _menu = dynamic_cast<Menu*> (ActionManager::get_widget ("/RegionListMenu"));
996  }
997 
998  if (_display.get_selection()->count_selected_rows() > 0) {
1000  } else {
1002  }
1003 
1004  /* Enable the "Show" option if any selected regions are hidden, and vice versa for "Hide" */
1005 
1006  bool have_shown = false;
1007  bool have_hidden = false;
1008 
1009  TreeView::Selection::ListHandle_Path rows = _display.get_selection()->get_selected_rows ();
1010  for (TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); i != rows.end(); ++i) {
1011  TreeIter t = _model->get_iter (*i);
1013  if (r) {
1014  if (r->hidden ()) {
1015  have_hidden = true;
1016  } else {
1017  have_shown = true;
1018  }
1019  }
1020  }
1021 
1022  hide_action()->set_sensitive (have_shown);
1023  show_action()->set_sensitive (have_hidden);
1024 
1025  _menu->popup (button, time);
1026 }
1027 
1028 bool
1029 EditorRegions::key_press (GdkEventKey* ev)
1030 {
1031  TreeViewColumn *col;
1032 
1033  switch (ev->keyval) {
1034  case GDK_Tab:
1035  case GDK_ISO_Left_Tab:
1036 
1037  if (name_editable) {
1038  name_editable->editing_done ();
1039  name_editable = 0;
1040  }
1041 
1042  col = _display.get_column (0); // select&focus on name column
1043 
1044  if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1046  } else {
1048  }
1049 
1050  return true;
1051  break;
1052 
1053  default:
1054  break;
1055  }
1056 
1057  return false;
1058 }
1059 
1060 bool
1061 EditorRegions::button_press (GdkEventButton *ev)
1062 {
1064  TreeIter iter;
1065  TreeModel::Path path;
1066  TreeViewColumn* column;
1067  int cellx;
1068  int celly;
1069 
1070  if (_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1071  if ((iter = _model->get_iter (path))) {
1072  region = (*iter)[_columns.region];
1073  }
1074  }
1075 
1076  if (Keyboard::is_context_menu_event (ev)) {
1077  show_context_menu (ev->button, ev->time);
1078  return false;
1079  }
1080 
1081  if (region != 0 && Keyboard::is_button2_event (ev)) {
1082  // start/stop audition
1083  if (!Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1084  _editor->consider_auditioning (region);
1085  }
1086  return true;
1087  }
1088 
1089  return false;
1090 }
1091 
1092 int
1093 EditorRegions::sorter (TreeModel::iterator a, TreeModel::iterator b)
1094 {
1095  int cmp = 0;
1096 
1099 
1100  /* handle rows without regions, like "Hidden" */
1101 
1102  if (r1 == 0) {
1103  return -1;
1104  }
1105 
1106  if (r2 == 0) {
1107  return 1;
1108  }
1109 
1112 
1113  if (region1 == 0 || region2 == 0) {
1114  std::string s1;
1115  std::string s2;
1116  switch (_sort_type) {
1117  case ByName:
1118  s1 = (*a)[_columns.name];
1119  s2 = (*b)[_columns.name];
1120  return (s1.compare (s2));
1121  default:
1122  return 0;
1123  }
1124  }
1125 
1126  switch (_sort_type) {
1127  case ByName:
1128  cmp = region1->name().compare(region2->name());
1129  break;
1130 
1131  case ByLength:
1132  cmp = region1->length() - region2->length();
1133  break;
1134 
1135  case ByPosition:
1136  cmp = region1->position() - region2->position();
1137  break;
1138 
1139  case ByTimestamp:
1140  cmp = region1->source()->timestamp() - region2->source()->timestamp();
1141  break;
1142 
1143  case ByStartInFile:
1144  cmp = region1->start() - region2->start();
1145  break;
1146 
1147  case ByEndInFile:
1148  // cerr << "Compare " << (region1->start() + region1->length()) << " and " << (region2->start() + region2->length()) << endl;
1149  cmp = (region1->start() + region1->length()) - (region2->start() + region2->length());
1150  break;
1151 
1152  case BySourceFileName:
1153  cmp = region1->source()->name().compare(region2->source()->name());
1154  break;
1155 
1156  case BySourceFileLength:
1157  cmp = region1->source_length(0) - region2->source_length(0);
1158  break;
1159 
1160  case BySourceFileCreationDate:
1161  cmp = region1->source()->timestamp() - region2->source()->timestamp();
1162  break;
1163 
1164  case BySourceFileFS:
1165  if (region1->source()->name() == region2->source()->name()) {
1166  cmp = region1->name().compare(region2->name());
1167  } else {
1168  cmp = region1->source()->name().compare(region2->source()->name());
1169  }
1170  break;
1171  }
1172 
1173  // cerr << "Comparison on " << enum_2_string (_sort_type) << " gives " << cmp << endl;
1174 
1175  if (cmp < 0) {
1176  return -1;
1177  } else if (cmp > 0) {
1178  return 1;
1179  } else {
1180  return 0;
1181  }
1182 }
1183 
1184 void
1186 {
1187  if (type != _sort_type || force) {
1188  _sort_type = type;
1189  _model->set_sort_func (0, (sigc::mem_fun (*this, &EditorRegions::sorter)));
1190  }
1191 }
1192 
1193 void
1195 {
1196  _model->set_sort_column (0, up ? SORT_ASCENDING : SORT_DESCENDING);
1197 }
1198 
1199 void
1201 {
1202  Glib::RefPtr<TreeSelection> selection = _display.get_selection();
1203  TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1204  TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1205 
1206  if (selection->count_selected_rows() == 0 || _session == 0) {
1207  return;
1208  }
1209 
1210  for (; i != rows.end(); ++i) {
1211  TreeIter iter;
1212 
1213  if ((iter = _model->get_iter (*i))) {
1214 
1215  /* some rows don't have a region associated with them, but can still be
1216  selected (XXX maybe prevent them from being selected)
1217  */
1218 
1220 
1221  if (r) {
1222  sl (r);
1223  }
1224  }
1225  }
1226 }
1227 
1228 
1229 void
1230 EditorRegions::drag_data_received (const RefPtr<Gdk::DragContext>& context,
1231  int x, int y,
1232  const SelectionData& data,
1233  guint info, guint time)
1234 {
1235  vector<string> paths;
1236 
1237  if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1238  /* something is being dragged over the region list */
1239  _editor->_drags->abort ();
1240  _display.on_drag_data_received (context, x, y, data, info, time);
1241  return;
1242  }
1243 
1244  if (_editor->convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
1245  framepos_t pos = 0;
1246  bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
1247 
1248  if (Profile->get_sae() || ARDOUR_UI::config()->get_only_copy_imported_files() || copy) {
1249  _editor->do_import (paths, Editing::ImportDistinctFiles, Editing::ImportAsRegion, SrcBest, pos);
1250  } else {
1251  _editor->do_embed (paths, Editing::ImportDistinctFiles, ImportAsRegion, pos);
1252  }
1253  context->drag_finish (true, false, time);
1254  }
1255 }
1256 
1257 bool
1258 EditorRegions::selection_filter (const RefPtr<TreeModel>& model, const TreeModel::Path& path, bool already_selected)
1259 {
1260  /* not possible to select rows that do not represent regions, like "Hidden" */
1261 
1262  if (already_selected) {
1263  /* deselecting anything is OK with us */
1264  return true;
1265  }
1266 
1267  TreeModel::iterator iter = model->get_iter (path);
1268 
1269  if (iter) {
1271  if (!r) {
1272  return false;
1273  }
1274  }
1275 
1276  return true;
1277 }
1278 
1279 void
1280 EditorRegions::name_editing_started (CellEditable* ce, const Glib::ustring&)
1281 {
1282  name_editable = ce;
1283 
1284  /* give it a special name */
1285 
1286  Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1287 
1288  if (e) {
1289  e->set_name (X_("RegionNameEditorEntry"));
1290  }
1291 }
1292 
1293 void
1294 EditorRegions::name_edit (const std::string& path, const std::string& new_text)
1295 {
1296  name_editable = 0;
1297 
1299  TreeIter iter;
1300 
1301  if ((iter = _model->get_iter (path))) {
1302  region = (*iter)[_columns.region];
1303  (*iter)[_columns.name] = new_text;
1304  }
1305 
1306  /* now mapover everything */
1307 
1308  if (region) {
1309  vector<RegionView*> equivalents;
1310  _editor->get_regions_corresponding_to (region, equivalents, false);
1311 
1312  for (vector<RegionView*>::iterator i = equivalents.begin(); i != equivalents.end(); ++i) {
1313  if (new_text != (*i)->region()->name()) {
1314  (*i)->region()->set_name (new_text);
1315  }
1316  }
1317  }
1318 
1319 }
1320 
1324 {
1325  list<boost::shared_ptr<Region> > regions;
1326  TreeView* source;
1327  _display.get_object_drag_data (regions, &source);
1328 
1329  if (regions.empty()) {
1330  return boost::shared_ptr<Region> ();
1331  }
1332 
1333  assert (regions.size() == 1);
1334  return regions.front ();
1335 }
1336 
1337 void
1339 {
1340  _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1341  _model->clear ();
1342  _display.set_model (_model);
1343 
1344  /* Clean up the maps */
1345  region_row_map.clear();
1347 }
1348 
1351 {
1352  Glib::RefPtr<TreeSelection> selected = _display.get_selection();
1353 
1354  if (selected->count_selected_rows() != 1) {
1355  return boost::shared_ptr<Region> ();
1356  }
1357 
1358  TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1359 
1360  /* only one row selected, so rows.begin() is it */
1361 
1362  TreeIter iter = _model->get_iter (*rows.begin());
1363 
1364  if (!iter) {
1365  return boost::shared_ptr<Region> ();
1366  }
1367 
1368  return (*iter)[_columns.region];
1369 }
1370 
1371 void
1373 
1374  _display.set_model (Glib::RefPtr<Gtk::TreeStore>(0));
1375  _model->set_sort_column (-2, SORT_ASCENDING); //Disable sorting to gain performance
1376 
1377 }
1378 
1379 void
1381 
1382  _model->set_sort_column (0, SORT_ASCENDING); // renabale sorting
1383  _display.set_model (_model);
1384 
1385  if (toggle_full_action()->get_active()) {
1386  _display.expand_all();
1387  }
1388 }
1389 
1390 void
1391 EditorRegions::locked_changed (std::string const & path)
1392 {
1393  TreeIter i = _model->get_iter (path);
1394  if (i) {
1396  if (region) {
1397  region->set_locked (!(*i)[_columns.locked]);
1398  }
1399  }
1400 }
1401 
1402 void
1403 EditorRegions::glued_changed (std::string const & path)
1404 {
1405  TreeIter i = _model->get_iter (path);
1406  if (i) {
1408  if (region) {
1409  /* `glued' means MusicTime, and we're toggling here */
1411  }
1412  }
1413 
1414 }
1415 
1416 void
1417 EditorRegions::muted_changed (std::string const & path)
1418 {
1419  TreeIter i = _model->get_iter (path);
1420  if (i) {
1422  if (region) {
1423  region->set_muted (!(*i)[_columns.muted]);
1424  }
1425  }
1426 
1427 }
1428 
1429 void
1430 EditorRegions::opaque_changed (std::string const & path)
1431 {
1432  TreeIter i = _model->get_iter (path);
1433  if (i) {
1435  if (region) {
1436  region->set_opaque (!(*i)[_columns.opaque]);
1437  }
1438  }
1439 
1440 }
1441 
1442 XMLNode &
1444 {
1445  XMLNode* node = new XMLNode (X_("RegionList"));
1446 
1447  node->add_property (X_("sort-type"), enum_2_string (_sort_type));
1448 
1449  RefPtr<Action> act = ActionManager::get_action (X_("RegionList"), X_("SortAscending"));
1450  bool const ascending = RefPtr<RadioAction>::cast_dynamic(act)->get_active ();
1451  node->add_property (X_("sort-ascending"), ascending ? "yes" : "no");
1452  node->add_property (X_("show-all"), toggle_full_action()->get_active() ? "yes" : "no");
1453  node->add_property (X_("show-automatic-regions"), _show_automatic_regions ? "yes" : "no");
1454 
1455  return *node;
1456 }
1457 
1458 void
1460 {
1461  bool changed = false;
1462 
1463  if (node.name() != X_("RegionList")) {
1464  return;
1465  }
1466 
1467  XMLProperty const * p = node.property (X_("sort-type"));
1468 
1469  if (p) {
1471 
1472  if (_sort_type != t) {
1473  changed = true;
1474  }
1475 
1476  reset_sort_type (t, true);
1477  RefPtr<RadioAction> ract = sort_type_action (t);
1478  ract->set_active ();
1479  }
1480 
1481  p = node.property (X_("sort-ascending"));
1482 
1483  if (p) {
1484  bool const yn = string_is_affirmative (p->value ());
1485  SortType old_sort_type;
1486  int old_sort_column;
1487 
1488  _model->get_sort_column_id (old_sort_column, old_sort_type);
1489 
1490  if (old_sort_type != (yn ? SORT_ASCENDING : SORT_DESCENDING)) {
1491  changed = true;
1492  }
1493 
1494  reset_sort_direction (yn);
1495  RefPtr<Action> act;
1496 
1497  if (yn) {
1498  act = ActionManager::get_action (X_("RegionList"), X_("SortAscending"));
1499  } else {
1500  act = ActionManager::get_action (X_("RegionList"), X_("SortDescending"));
1501  }
1502 
1503  RefPtr<RadioAction>::cast_dynamic(act)->set_active ();
1504  }
1505 
1506  p = node.property (X_("show-all"));
1507  if (p) {
1508  bool const yn = string_is_affirmative (p->value ());
1509 
1510  if (expanded != yn) {
1511  changed = true;
1512  }
1513 
1514  set_full (yn);
1515  toggle_full_action()->set_active (yn);
1516  }
1517 
1518  p = node.property (X_("show-automatic-regions"));
1519  if (p) {
1520  bool const yn = string_is_affirmative (p->value ());
1521 
1522  if (yn != _show_automatic_regions) {
1524  toggle_show_auto_regions_action()->set_active (yn);
1525  changed = true;
1526  }
1527  }
1528 
1529  if (changed) {
1530  redisplay ();
1531  }
1532 }
1533 
1534 RefPtr<RadioAction>
1536 {
1537  const char* action = 0;
1538 
1539  switch (t) {
1540  case Editing::ByName:
1541  action = X_("SortByRegionName");
1542  break;
1543  case Editing::ByLength:
1544  action = X_("SortByRegionLength");
1545  break;
1546  case Editing::ByPosition:
1547  action = X_("SortByRegionPosition");
1548  break;
1549  case Editing::ByTimestamp:
1550  action = X_("SortByRegionTimestamp");
1551  break;
1552  case Editing::ByStartInFile:
1553  action = X_("SortByRegionStartinFile");
1554  break;
1555  case Editing::ByEndInFile:
1556  action = X_("SortByRegionEndinFile");
1557  break;
1558  case Editing::BySourceFileName:
1559  action = X_("SortBySourceFileName");
1560  break;
1561  case Editing::BySourceFileLength:
1562  action = X_("SortBySourceFileLength");
1563  break;
1564  case Editing::BySourceFileCreationDate:
1565  action = X_("SortBySourceFileCreationDate");
1566  break;
1567  case Editing::BySourceFileFS:
1568  action = X_("SortBySourceFilesystem");
1569  break;
1570  default:
1571  fatal << string_compose (_("programming error: %1: %2"), "EditorRegions: impossible sort type", (int) t) << endmsg;
1572  abort(); /*NOTREACHED*/
1573  }
1574 
1575  RefPtr<Action> act = ActionManager::get_action (X_("RegionList"), action);
1576  assert (act);
1577 
1578  return RefPtr<RadioAction>::cast_dynamic (act);
1579 }
1580 
1581 RefPtr<Action>
1583 {
1584  return ActionManager::get_action (X_("RegionList"), X_("rlHide"));
1585 
1586 }
1587 
1588 RefPtr<Action>
1590 {
1591  return ActionManager::get_action (X_("RegionList"), X_("rlShow"));
1592 }
1593 
1594 RefPtr<Action>
1596 {
1597  return ActionManager::get_action (X_("RegionList"), X_("removeUnusedRegions"));
1598 }
1599 
1600 RefPtr<ToggleAction>
1602 {
1603  Glib::RefPtr<Action> act = ActionManager::get_action (X_("RegionList"), X_("rlShowAll"));
1604  assert (act);
1605  return Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1606 }
1607 
1608 RefPtr<ToggleAction>
1610 {
1611  Glib::RefPtr<Action> act = ActionManager::get_action (X_("RegionList"), X_("rlShowAuto"));
1612  assert (act);
1613  return Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1614 }
void get_regions_corresponding_to(boost::shared_ptr< ARDOUR::Region > region, std::vector< RegionView * > &regions, bool src_comparison)
Definition: editor.cc:5004
Gtk::TreeModelColumn< Gdk::Color > color_
std::map< PBD::ID, boost::shared_ptr< Region > > RegionMap
void do_import(std::vector< std::string > paths, Editing::ImportDisposition disposition, Editing::ImportMode mode, ARDOUR::SrcQuality quality, framepos_t &pos, boost::shared_ptr< ARDOUR::PluginInfo > instrument=boost::shared_ptr< ARDOUR::PluginInfo >())
void populate_row_glued(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row, uint32_t used)
Gtk::TreeModelColumn< std::string > used
LIBPBD_API Transmitter fatal
LIBGTKMM2EXT_API Gtk::Widget * get_widget(const char *name)
Definition: actions.cc:366
void update_all_rows()
LIBARDOUR_API PBD::PropertyDescriptor< bool > fade_out_active
Definition: audioregion.cc:65
void region_changed(boost::shared_ptr< ARDOUR::Region >, PBD::PropertyChange const &)
void clear_regions()
Definition: selection.cc:159
void show_context_menu(int button, int time)
Gtk::TreeModelColumn< std::string > path
void populate_row(boost::shared_ptr< ARDOUR::Region >, Gtk::TreeModel::Row const &)
void reset_sort_type(Editing::RegionListSortType, bool)
bool get_sae() const
Definition: profile.h:48
void bbt_time(framepos_t when, Timecode::BBT_Time &)
Definition: tempo.cc:1168
const std::string & value() const
Definition: xml++.h:159
void populate_row_sync(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row, uint32_t used)
LIBARDOUR_API PBD::PropertyDescriptor< bool > hidden
Definition: route_group.h:50
bool focus_out(GdkEventFocus *)
#define enum_2_string(e)
Definition: enumwriter.h:97
Glib::RefPtr< Gtk::TreeStore > _model
Gtkmm2ext::DnDTreeView< boost::shared_ptr< ARDOUR::Region > > _display
Definition: ardour_ui.h:130
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
LIBARDOUR_API PBD::PropertyDescriptor< std::string > name
boost::shared_ptr< AutomationList > fade_in()
Definition: audioregion.h:87
const std::string & name() const
Definition: xml++.h:104
Gtk::TreeModelColumn< bool > locked
void set_full(bool)
sigc::signal< void > mode_changed
Definition: audio_clock.h:93
TempoMap & tempo_map()
Definition: session.h:596
bool enter_notify(GdkEventCrossing *)
LIBGTKMM2EXT_API Glib::RefPtr< Gtk::Action > get_action(const char *group, const char *name)
Definition: actions.cc:406
Gtk::TreeModelColumn< std::string > end
void populate_row_position(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row, uint32_t used)
Gtk::TreeModelColumn< std::string > fadeout
int sorter(Gtk::TreeModel::iterator, Gtk::TreeModel::iterator)
boost::shared_ptr< AutomationList > fade_out()
Definition: audioregion.h:89
void drag_data_received(Glib::RefPtr< Gdk::DragContext > const &, gint, gint, Gtk::SelectionData const &, guint, guint)
void get_object_drag_data(std::list< DataType > &l, Gtk::TreeView **source)
Definition: dndtreeview.h:145
void add_drop_targets(std::list< Gtk::TargetEntry > &)
Definition: dndtreeview.cc:47
tuple f
Definition: signals.py:35
Definition: Beats.hpp:239
void populate_row_name(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row)
LIBPBD_API Transmitter error
PBD::ScopedConnection editor_thaw_connection
bool leave_notify(GdkEventCrossing *)
bool whole_file() const
Definition: region.h:169
void freeze_tree_model()
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
boost::shared_ptr< Source > source(uint32_t n=0) const
Definition: region.h:258
bool key_press(GdkEventKey *)
bool button_press(GdkEventButton *)
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
Gtk::TreeModelColumn< boost::shared_ptr< ARDOUR::Region > > region
void update_row(boost::shared_ptr< ARDOUR::Region >)
Gtk::TreeModelColumn< bool > muted
Glib::RefPtr< Gtk::ToggleAction > toggle_show_auto_regions_action() const
framecnt_t frame_rate() const
Definition: session.h:365
void reset_sort_direction(bool)
bool fade_in_active() const
Definition: audioregion.h:84
framepos_t sync_position() const
Definition: region.cc:1082
void toggle_show_auto_regions()
boost::shared_ptr< ARDOUR::Region > get_single_selection()
Gtk::ScrolledWindow _scroller
void add_region(boost::shared_ptr< ARDOUR::Region >)
void name_edit(const std::string &, const std::string &)
Glib::RefPtr< Gtk::Action > hide_action() const
void populate_row_source(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row)
MainClock * secondary_clock
Definition: ardour_ui.h:230
void populate_row_opaque(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row, uint32_t used)
bool ignore_region_list_selection_change
void populate_row_used(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row, uint32_t used)
#define _(Text)
Definition: i18n.h:11
LIBGTKMM2EXT_API void set_sensitive(std::vector< Glib::RefPtr< Gtk::Action > > &actions, bool)
Gtk::TreeModelColumn< std::string > sync
void set_selected_regionview_from_region_list(boost::shared_ptr< ARDOUR::Region > region, Selection::Operation op=Selection::Set)
LIBGTKMM2EXT_API uint64_t Keyboard
Definition: debug.cc:23
#define X_(Text)
Definition: i18n.h:13
int64_t framecnt_t
Definition: types.h:76
Gtk::Widget * old_focus
int convert_drop_to_paths(std::vector< std::string > &paths, const Glib::RefPtr< Gdk::DragContext > &context, gint x, gint y, const Gtk::SelectionData &data, guint info, guint time)
Definition: editor.cc:3246
XMLProperty * property(const char *)
Definition: xml++.cc:413
void locked_changed(std::string const &)
std::vector< Glib::RefPtr< Gtk::Action > > region_list_selection_sensitive_actions
Definition: actions.cc:51
#define string_2_enum(str, e)
Definition: enumwriter.h:98
Gtk::TreeModelColumn< bool > opaque
const char * label
void set_color_from_rgba(Gdk::Color &, uint32_t)
Definition: utils.cc:276
void populate_row_fade_in(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row, uint32_t used, boost::shared_ptr< ARDOUR::AudioRegion >)
bool string_is_affirmative(const std::string &str)
Definition: convert.cc:282
void on_drag_data_received(const Glib::RefPtr< Gdk::DragContext > &context, int x, int y, const Gtk::SelectionData &selection_data, guint info, guint time)
Definition: dndtreeview.h:116
bool fade_out_active() const
Definition: audioregion.h:85
Definition: amp.h:29
void remove_unused_regions()
std::list< boost::shared_ptr< ARDOUR::Region > > tmp_region_list
void muted_changed(std::string const &)
bool muted() const
Definition: region.h:162
LIBARDOUR_API PBD::PropertyDescriptor< bool > locked
Definition: region.cc:51
bool selection_filter(const Glib::RefPtr< Gtk::TreeModel > &model, const Gtk::TreeModel::Path &path, bool yn)
void opaque_changed(std::string const &)
#define gui_context()
Definition: gui_thread.h:36
void set_session(ARDOUR::Session *)
bool automatic() const
Definition: region.h:168
LIBARDOUR_API PBD::PropertyDescriptor< boost::shared_ptr< AutomationList > > fade_out
Definition: audioregion.cc:69
void add_object_drag(int column, std::string type_name)
Definition: dndtreeview.cc:58
EditorRegions(Editor *)
LIBARDOUR_API PBD::PropertyDescriptor< boost::shared_ptr< AutomationList > > fade_in
Definition: audioregion.cc:67
RegionSourceMap parent_regions_sources_map
PBD::Signal0< void > EditorFreeze
Definition: editor.h:1577
Gtk::TreeModelColumn< std::string > length
LIBARDOUR_API PBD::PropertyDescriptor< bool > opaque
Definition: region.cc:50
bool _show_automatic_regions
PBD::ScopedConnection check_new_region_connection
Gtk::TreeModelColumn< bool > glued
void do_embed(std::vector< std::string > paths, Editing::ImportDisposition disposition, Editing::ImportMode mode, framepos_t &pos, boost::shared_ptr< ARDOUR::PluginInfo > instrument=boost::shared_ptr< ARDOUR::PluginInfo >())
std::string source_string() const
Definition: region.cc:1456
int64_t framepos_t
Definition: types.h:66
sigc::connection _change_connection
bool region_list_equivalent(boost::shared_ptr< const Region >) const
Definition: region.cc:1356
Glib::RefPtr< Gtk::ToggleAction > toggle_full_action() const
static PBD::Signal1< void, boost::shared_ptr< Region > > CheckNewRegion
const char * tooltip
bool _region_selection_change_updates_region_list
Definition: editor.h:2198
void format_position(ARDOUR::framepos_t pos, char *buf, size_t bufsize, bool onoff=true)
Gtk::TreeModel::RowReference last_row
LIBARDOUR_API PBD::PropertyDescriptor< bool > regions
Definition: playlist.cc:51
void set_state(const XMLNode &)
LIBPBD_API Transmitter info
PositionLockStyle position_lock_style() const
Definition: region.h:178
void populate_row_fade_out(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row, uint32_t used, boost::shared_ptr< ARDOUR::AudioRegion >)
LIBARDOUR_API RuntimeProfile * Profile
Definition: globals.cc:120
void set_muted(bool yn)
Definition: region.cc:962
framecnt_t source_length(uint32_t n) const
Definition: region.cc:1511
framepos_t position() const
Definition: region.h:112
void set_tip(Gtk::Widget &w, const gchar *tip)
void populate_row_muted(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row, uint32_t used)
LIBGTKMM2EXT_API void treeview_select_next(Gtk::TreeView &view, Glib::RefPtr< Gtk::TreeModel > model, Gtk::TreeViewColumn *col)
XMLProperty * add_property(const char *name, const std::string &value)
void set_selected(RegionSelection &)
void selection_changed()
const std::string & path() const
Definition: file_source.h:49
bool locked() const
Definition: region.h:164
void set_opaque(bool yn)
Definition: region.cc:971
Definition: editor.h:134
uint32_t n_channels() const
Definition: region.h:259
void abort()
Definition: editor_drag.cc:95
PBD::ScopedConnection region_property_connection
Definition: xml++.h:95
std::string name() const
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
Definition: region.cc:65
static UIConfiguration * config()
Definition: ardour_ui.h:188
PBD::Signal0< void > EditorThaw
Definition: editor.h:1578
Gtk::TreeModelColumn< std::string > fadein
void name_editing_started(Gtk::CellEditable *, const Glib::ustring &)
Definition: debug.h:30
void populate_row_length(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row)
Selection & get_selection() const
Definition: editor.h:244
Gtk::TreeModelColumn< bool > property_toggles_visible
Gtk::Menu * _menu
#define S_(Text)
Definition: i18n.h:18
bool opaque() const
Definition: region.h:163
void consider_auditioning(boost::shared_ptr< ARDOUR::Region >)
Definition: editor.cc:5440
bool contains(PropertyDescriptor< T > p) const
framecnt_t length() const
Definition: region.h:114
void selection_mapover(sigc::slot< void, boost::shared_ptr< ARDOUR::Region > >)
void populate_row_end(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row, uint32_t used)
boost::shared_ptr< ARDOUR::Region > get_dragged_region()
framepos_t first_frame() const
Definition: region.h:141
void timecode_time(Timecode::Time &)
void set_position_lock_style(PositionLockStyle ps)
Definition: region.cc:543
Gtk::TreeModelColumn< std::string > name
ControlEvent * back()
framepos_t start() const
Definition: region.h:113
LIBARDOUR_API PBD::PropertyDescriptor< PositionLockStyle > position_lock_style
Definition: region.cc:72
XMLNode & get_state() const
RegionRowMap region_row_map
DragManager * _drags
Definition: editor.h:1481
void glued_changed(std::string const &)
Gtk::TreeModelColumn< std::string > position
Glib::RefPtr< Gtk::Action > show_action() const
#define MISSING_INVALIDATOR
Definition: event_loop.h:86
PBD::ScopedConnection editor_freeze_connection
int64_t framepos_t
static PBD::Signal2< void, boost::shared_ptr< ARDOUR::Region >, const PBD::PropertyChange & > RegionPropertyChanged
Definition: region.h:95
Gtk::CellEditable * name_editable
Glib::RefPtr< Gtk::Action > remove_unused_regions_action() const
LIBARDOUR_API PBD::PropertyDescriptor< bool > muted
Definition: region.cc:49
LIBARDOUR_API std::string region_name_from_path(std::string path, bool strip_channels, bool add_channel_suffix=false, uint32_t total=0, uint32_t this_one=0)
Editing::RegionListSortType _sort_type
bool focus_in(GdkEventFocus *)
ARDOUR::Session * _session
void add(PropertyID id)
LIBARDOUR_API PBD::PropertyDescriptor< bool > fade_in_active
Definition: audioregion.cc:64
LIBGTKMM2EXT_API void treeview_select_previous(Gtk::TreeView &view, Glib::RefPtr< Gtk::TreeModel > model, Gtk::TreeViewColumn *col)
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
void populate_row_locked(boost::shared_ptr< ARDOUR::Region > region, Gtk::TreeModel::Row const &row, uint32_t used)
void set_locked(bool yn)
Definition: region.cc:980
Glib::RefPtr< Gtk::RadioAction > sort_type_action(Editing::RegionListSortType) const
RegionListSortType
Definition: editing.h:77
framepos_t last_frame() const
Definition: region.h:142
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > length
Definition: region.cc:64
LIBARDOUR_API PBD::PropertyDescriptor< bool > color
Definition: route_group.cc:50
bool hidden() const
Definition: region.h:161