make selectability of a TimeAxisView be overridable
[ardour.git] / gtk2_ardour / time_axis_view.cc
1 /*
2     Copyright (C) 2000 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 <list>
25
26
27 #include "pbd/error.h"
28 #include "pbd/convert.h"
29 #include "pbd/stacktrace.h"
30 #include "pbd/unwind.h"
31
32 #include <gtkmm2ext/doi.h>
33 #include <gtkmm2ext/utils.h>
34 #include <gtkmm2ext/selector.h>
35
36 #include "canvas/canvas.h"
37 #include "canvas/rectangle.h"
38 #include "canvas/debug.h"
39 #include "canvas/utils.h"
40 #include "canvas/colors.h"
41
42 #include "ardour/profile.h"
43
44 #include "ardour_dialog.h"
45 #include "gui_thread.h"
46 #include "public_editor.h"
47 #include "time_axis_view.h"
48 #include "region_view.h"
49 #include "ghostregion.h"
50 #include "selection.h"
51 #include "keyboard.h"
52 #include "rgb_macros.h"
53 #include "utils.h"
54 #include "streamview.h"
55 #include "editor_drag.h"
56 #include "editor.h"
57 #include "tooltips.h"
58 #include "ui_config.h"
59
60 #include "i18n.h"
61
62 using namespace std;
63 using namespace Gtk;
64 using namespace Gdk;
65 using namespace ARDOUR;
66 using namespace ARDOUR_UI_UTILS;
67 using namespace PBD;
68 using namespace Editing;
69 using namespace ArdourCanvas;
70 using Gtkmm2ext::Keyboard;
71
72 #define TOP_LEVEL_WIDGET controls_ebox
73
74 const double trim_handle_size = 6.0; /* pixels */
75 uint32_t TimeAxisView::button_height = 0;
76 uint32_t TimeAxisView::extra_height = 0;
77 int const TimeAxisView::_max_order = 512;
78 unsigned int TimeAxisView::name_width_px = 100;
79 PBD::Signal1<void,TimeAxisView*> TimeAxisView::CatchDeletion;
80 Glib::RefPtr<Gtk::SizeGroup> TimeAxisView::controls_meters_size_group = Glib::RefPtr<Gtk::SizeGroup>();
81 Glib::RefPtr<Gtk::SizeGroup> TimeAxisView::midi_scroomer_size_group = Glib::RefPtr<Gtk::SizeGroup>();
82
83 void
84 TimeAxisView::setup_sizes()
85 {
86         name_width_px = ceilf (100.f * UIConfiguration::instance().get_ui_scale());
87 }
88
89 TimeAxisView::TimeAxisView (ARDOUR::Session* sess, PublicEditor& ed, TimeAxisView* rent, Canvas& /*canvas*/)
90         : AxisView (sess)
91         , controls_table (5, 4)
92         , controls_button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_BOTH))
93         , _name_editing (false)
94         , height (0)
95         , display_menu (0)
96         , parent (rent)
97         , selection_group (0)
98         , _ghost_group (0)
99         , _hidden (true)
100         , in_destructor (false)
101         , _size_menu (0)
102         , _canvas_display (0)
103         , _y_position (0)
104         , _editor (ed)
105         , name_entry (0)
106         , ending_name_edit (false)
107         , by_popup_menu (false)
108         , control_parent (0)
109         , _order (0)
110         , _effective_height (0)
111         , _resize_drag_start (-1)
112         , _did_resize (false)
113         , _preresize_cursor (0)
114         , _have_preresize_cursor (false)
115         , _ebox_release_can_act (true)
116 {
117         if (!controls_meters_size_group) {
118                 controls_meters_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
119         }
120         if (!midi_scroomer_size_group) {
121                 midi_scroomer_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
122         }
123         if (extra_height == 0) {
124                 compute_heights ();
125         }
126
127         _canvas_display = new ArdourCanvas::Container (ed.get_trackview_group ());
128         CANVAS_DEBUG_NAME (_canvas_display, "main for TAV");
129         _canvas_display->hide(); // reveal as needed
130
131         _canvas_separator = new ArdourCanvas::Line(_canvas_display);
132         CANVAS_DEBUG_NAME (_canvas_separator, "separator for TAV");
133         _canvas_separator->set (ArdourCanvas::Duple(0.0, 0.0), ArdourCanvas::Duple(ArdourCanvas::COORD_MAX, 0.0));
134         _canvas_separator->set_outline_color(ArdourCanvas::rgba_to_color (0, 0, 0, 1.0));
135         _canvas_separator->set_outline_width(1.0);
136         _canvas_separator->hide();
137
138         selection_group = new ArdourCanvas::Container (_canvas_display);
139         CANVAS_DEBUG_NAME (selection_group, "selection for TAV");
140         selection_group->set_data (X_("timeselection"), (void *) 1);
141         selection_group->hide();
142
143         _ghost_group = new ArdourCanvas::Container (_canvas_display);
144         CANVAS_DEBUG_NAME (_ghost_group, "ghost for TAV");
145         _ghost_group->lower_to_bottom();
146         _ghost_group->show();
147
148         name_label.set_name ("TrackLabel");
149         name_label.set_alignment (0.0, 0.5);
150         name_label.set_width_chars (12);
151         set_tooltip (name_label, _("Track/Bus name (double click to edit)"));
152
153         Gtk::Entry* an_entry = new Gtkmm2ext::FocusEntry;
154         an_entry->set_name ("EditorTrackNameDisplay");
155         Gtk::Requisition req;
156         an_entry->size_request (req);
157         name_label.set_size_request (-1, req.height);
158         name_label.set_ellipsize (Pango::ELLIPSIZE_MIDDLE);
159         delete an_entry;
160
161         name_hbox.pack_end (name_label, true, true);
162
163         // set min. track-header width if fader is not visible
164         name_hbox.set_size_request(name_width_px, -1);
165
166         name_hbox.show ();
167         name_label.show ();
168
169         controls_table.set_row_spacings (2);
170         controls_table.set_col_spacings (2);
171         controls_table.set_border_width (2);
172
173         if (ARDOUR::Profile->get_mixbus() ) {
174                 controls_table.attach (name_hbox, 4, 5, 0, 1,  Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK, 0, 0);
175         } else {
176                 controls_table.attach (name_hbox, 1, 2, 0, 1,  Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK, 0, 0);
177         }
178         controls_table.show_all ();
179         controls_table.set_no_show_all ();
180
181         controls_vbox.pack_start (controls_table, false, false);
182         controls_vbox.show ();
183
184         top_hbox.pack_start (controls_vbox, true, true);
185         top_hbox.show ();
186
187         controls_ebox.add (time_axis_hbox);
188         controls_ebox.add_events (Gdk::BUTTON_PRESS_MASK|
189                                   Gdk::BUTTON_RELEASE_MASK|
190                                   Gdk::POINTER_MOTION_MASK|
191                                   Gdk::ENTER_NOTIFY_MASK|
192                                   Gdk::LEAVE_NOTIFY_MASK|
193                                   Gdk::SCROLL_MASK);
194         controls_ebox.set_flags (CAN_FOCUS);
195
196         /* note that this handler connects *before* the default handler */
197         controls_ebox.signal_scroll_event().connect (sigc::mem_fun (*this, &TimeAxisView::controls_ebox_scroll), true);
198         controls_ebox.signal_button_press_event().connect (sigc::mem_fun (*this, &TimeAxisView::controls_ebox_button_press));
199         controls_ebox.signal_button_release_event().connect (sigc::mem_fun (*this, &TimeAxisView::controls_ebox_button_release));
200         controls_ebox.signal_motion_notify_event().connect (sigc::mem_fun (*this, &TimeAxisView::controls_ebox_motion));
201         controls_ebox.signal_leave_notify_event().connect (sigc::mem_fun (*this, &TimeAxisView::controls_ebox_leave));
202         controls_ebox.show ();
203
204         time_axis_frame.set_shadow_type (Gtk::SHADOW_NONE);
205         time_axis_frame.add(top_hbox);
206         time_axis_frame.show();
207
208         HSeparator* separator = manage (new HSeparator());
209         separator->set_name("TrackSeparator");
210         separator->set_size_request(-1, 1);
211         separator->show();
212
213         scroomer_placeholder.set_size_request (-1, -1);
214         scroomer_placeholder.show();
215         midi_scroomer_size_group->add_widget (scroomer_placeholder);
216
217         time_axis_vbox.pack_start (*separator, false, false);
218         time_axis_vbox.pack_start (time_axis_frame, true, true);
219         time_axis_vbox.show();
220         time_axis_hbox.pack_start (time_axis_vbox, true, true);
221         time_axis_hbox.show();
222         top_hbox.pack_start (scroomer_placeholder, false, false); // OR pack_end to move after meters ?
223
224         UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &TimeAxisView::color_handler));
225 }
226
227 TimeAxisView::~TimeAxisView()
228 {
229         CatchDeletion (this);
230
231         in_destructor = true;
232
233         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
234                 delete *i;
235         }
236
237         for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
238                 delete (*i)->rect; (*i)->rect=0;
239                 delete (*i)->start_trim; (*i)->start_trim = 0;
240                 delete (*i)->end_trim; (*i)->end_trim = 0;
241
242         }
243
244         for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
245                 delete (*i)->rect; (*i)->rect = 0;
246                 delete (*i)->start_trim; (*i)->start_trim = 0;
247                 delete (*i)->end_trim; (*i)->end_trim = 0;
248         }
249
250         delete selection_group;
251         selection_group = 0;
252
253         delete _canvas_display;
254         _canvas_display = 0;
255
256         delete display_menu;
257         display_menu = 0;
258
259         delete _size_menu;
260 }
261
262 void
263 TimeAxisView::hide ()
264 {
265         if (_hidden) {
266                 return;
267         }
268
269         _canvas_display->hide ();
270         _canvas_separator->hide ();
271
272         if (control_parent) {
273                 control_parent->remove (TOP_LEVEL_WIDGET);
274                 control_parent = 0;
275         }
276
277         _y_position = -1;
278         _hidden = true;
279
280         /* now hide children */
281
282         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
283                 (*i)->hide ();
284         }
285
286         /* if its hidden, it cannot be selected */
287         _editor.get_selection().remove (this);
288         /* and neither can its regions */
289         _editor.get_selection().remove_regions (this);
290
291         Hiding ();
292 }
293
294 /** Display this TimeAxisView as the nth component of the parent box, at y.
295 *
296 * @param y y position.
297 * @param nth index for this TimeAxisView, increased if this view has children.
298 * @param parent parent component.
299 * @return height of this TimeAxisView.
300 */
301 guint32
302 TimeAxisView::show_at (double y, int& nth, VBox *parent)
303 {
304         if (control_parent) {
305                 control_parent->reorder_child (TOP_LEVEL_WIDGET, nth);
306         } else {
307                 control_parent = parent;
308                 parent->pack_start (TOP_LEVEL_WIDGET, false, false);
309                 parent->reorder_child (TOP_LEVEL_WIDGET, nth);
310         }
311
312         _order = nth;
313
314         if (_y_position != y) {
315                 _canvas_display->set_y_position (y);
316                 _y_position = y;
317         }
318
319         _canvas_display->raise_to_top ();
320         _canvas_display->show ();
321
322         _hidden = false;
323
324         _effective_height = current_height ();
325
326         /* now show relevant children */
327
328         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
329                 if ((*i)->marked_for_display()) {
330                         ++nth;
331                         _effective_height += (*i)->show_at (y + _effective_height, nth, parent);
332                 } else {
333                         (*i)->hide ();
334                 }
335         }
336
337         /* put separator at the bottom of this time axis view */
338
339         _canvas_separator->set (ArdourCanvas::Duple(0, height), ArdourCanvas::Duple(ArdourCanvas::COORD_MAX, height));
340         _canvas_separator->lower_to_bottom ();
341         _canvas_separator->show ();
342
343         return _effective_height;
344 }
345
346 bool
347 TimeAxisView::controls_ebox_scroll (GdkEventScroll* ev)
348 {
349         switch (ev->direction) {
350         case GDK_SCROLL_UP:
351                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
352                         /* See Editor::_stepping_axis_view for notes on this hack */
353                         Editor& e = dynamic_cast<Editor&> (_editor);
354                         if (!e.stepping_axis_view ()) {
355                                 e.set_stepping_axis_view (this);
356                         }
357                         e.stepping_axis_view()->step_height (false);
358                         return true;
359                 }
360                 break;
361
362         case GDK_SCROLL_DOWN:
363                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
364                         /* See Editor::_stepping_axis_view for notes on this hack */
365                         Editor& e = dynamic_cast<Editor&> (_editor);
366                         if (!e.stepping_axis_view ()) {
367                                 e.set_stepping_axis_view (this);
368                         }
369                         e.stepping_axis_view()->step_height (true);
370                         return true;
371                 }
372                 break;
373
374         default:
375                 /* no handling for left/right, yet */
376                 break;
377         }
378
379         /* Just forward to the normal canvas scroll method. The coordinate
380            systems are different but since the canvas is always larger than the
381            track headers, and aligned with the trackview area, this will work.
382
383            In the not too distant future this layout is going away anyway and
384            headers will be on the canvas.
385         */
386         return _editor.canvas_scroll_event (ev, false);
387 }
388
389 bool
390 TimeAxisView::controls_ebox_button_press (GdkEventButton* event)
391 {
392         if ((event->button == 1 && event->type == GDK_2BUTTON_PRESS) || Keyboard::is_edit_event (event)) {
393                 /* see if it is inside the name label */
394                 if (name_label.is_ancestor (controls_ebox)) {
395                         int nlx;
396                         int nly;
397                         controls_ebox.translate_coordinates (name_label, event->x, event->y, nlx, nly);
398                         Gtk::Allocation a = name_label.get_allocation ();
399                         if (nlx > 0 && nlx < a.get_width() && nly > 0 && nly < a.get_height()) {
400                                 begin_name_edit ();
401                                 _ebox_release_can_act = false;
402                                 return true;
403                         }
404                 }
405
406         }
407
408         _ebox_release_can_act = true;
409
410         if (maybe_set_cursor (event->y) > 0) {
411                 _resize_drag_start = event->y_root;
412         }
413
414         return true;
415 }
416
417 void
418 TimeAxisView::idle_resize (int32_t h)
419 {
420         set_height (std::max(0, h));
421 }
422
423
424 bool
425 TimeAxisView::controls_ebox_motion (GdkEventMotion* ev)
426 {
427         if (_resize_drag_start >= 0) {
428
429                 /* (ab)use the DragManager to do autoscrolling - basically we
430                  * are pretending that the drag is taking place over the canvas
431                  * (which perhaps in the glorious future, when track headers
432                  * and the canvas are unified, will actually be true.)
433                  */
434
435                 _editor.maybe_autoscroll (false, true, true);
436
437                 /* now schedule the actual TAV resize */
438                 int32_t const delta = (int32_t) floor (ev->y_root - _resize_drag_start);
439                 _editor.add_to_idle_resize (this, delta);
440                 _resize_drag_start = ev->y_root;
441                 _did_resize = true;
442         } else {
443                 /* not dragging but ... */
444                 maybe_set_cursor (ev->y);
445         }
446
447         gdk_event_request_motions(ev);
448         return true;
449 }
450
451 bool
452 TimeAxisView::controls_ebox_leave (GdkEventCrossing*)
453 {
454         if (_have_preresize_cursor) {
455                 gdk_window_set_cursor (controls_ebox.get_window()->gobj(), _preresize_cursor);
456                 _have_preresize_cursor = false;
457         }
458         return true;
459 }
460
461 bool
462 TimeAxisView::maybe_set_cursor (int y)
463 {
464         /* XXX no Gtkmm Gdk::Window::get_cursor() */
465         Glib::RefPtr<Gdk::Window> win = controls_ebox.get_window();
466
467         if (y > (gint) floor (controls_ebox.get_height() * 0.75)) {
468
469                 /* y-coordinate in lower 25% */
470
471                 if (!_have_preresize_cursor) {
472                         _preresize_cursor = gdk_window_get_cursor (win->gobj());
473                         _have_preresize_cursor = true;
474                         win->set_cursor (Gdk::Cursor(Gdk::SB_V_DOUBLE_ARROW));
475                 }
476
477                 return 1;
478
479         } else if (_have_preresize_cursor) {
480                 gdk_window_set_cursor (win->gobj(), _preresize_cursor);
481                 _have_preresize_cursor = false;
482
483                 return -1;
484         }
485
486         return 0;
487 }
488
489 bool
490 TimeAxisView::controls_ebox_button_release (GdkEventButton* ev)
491 {
492         if (_resize_drag_start >= 0) {
493                 if (_have_preresize_cursor) {
494                         gdk_window_set_cursor (controls_ebox.get_window()->gobj(), _preresize_cursor);
495                         _preresize_cursor = 0;
496                         _have_preresize_cursor = false;
497                 }
498                 _editor.stop_canvas_autoscroll ();
499                 _resize_drag_start = -1;
500                 if (_did_resize) {
501                         _did_resize = false;
502                         // don't change selection
503                         return true;
504                 }
505         }
506
507         if (!_ebox_release_can_act) {
508                 return true;
509         }
510
511         switch (ev->button) {
512         case 1:
513                 if (selectable()) {
514                         selection_click (ev);
515                 }
516                 break;
517
518         case 3:
519                 popup_display_menu (ev->time);
520                 break;
521         }
522
523         return true;
524 }
525
526 void
527 TimeAxisView::selection_click (GdkEventButton* ev)
528 {
529         Selection::Operation op = ArdourKeyboard::selection_type (ev->state);
530         _editor.set_selected_track (*this, op, false);
531 }
532
533
534 /** Steps through the defined heights for this TrackView.
535  *  @param coarser true if stepping should decrease in size, otherwise false.
536  */
537 void
538 TimeAxisView::step_height (bool coarser)
539 {
540         static const uint32_t step = 25;
541
542         if (coarser) {
543
544                 if (height <= preset_height (HeightSmall)) {
545                         return;
546                 } else if (height <= preset_height (HeightNormal) && height > preset_height (HeightSmall)) {
547                         set_height_enum (HeightSmall);
548                 } else {
549                         set_height (height - step);
550                 }
551
552         } else {
553
554                 if (height <= preset_height(HeightSmall)) {
555                         set_height_enum (HeightNormal);
556                 } else {
557                         set_height (height + step);
558                 }
559
560         }
561 }
562
563 void
564 TimeAxisView::set_height_enum (Height h, bool apply_to_selection)
565 {
566         if (apply_to_selection) {
567                 _editor.get_selection().tracks.foreach_time_axis (boost::bind (&TimeAxisView::set_height_enum, _1, h, false));
568         } else {
569                 set_height (preset_height (h));
570         }
571 }
572
573 void
574 TimeAxisView::set_height (uint32_t h, TrackHeightMode m)
575 {
576         uint32_t lanes = 0;
577         if (m == TotalHeight) {
578                 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
579                         if ( !(*i)->hidden()) ++lanes;
580                 }
581         }
582         h /= (lanes + 1);
583
584         if (h < preset_height (HeightSmall)) {
585                 h = preset_height (HeightSmall);
586         }
587
588         TOP_LEVEL_WIDGET.property_height_request () = h;
589         height = h;
590
591         char buf[32];
592         snprintf (buf, sizeof (buf), "%u", height);
593         set_gui_property ("height", buf);
594
595         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
596                 (*i)->set_height ();
597         }
598
599         if (selection_group->visible ()) {
600                 /* resize the selection rect */
601                 show_selection (_editor.get_selection().time);
602         }
603
604         if (m != OnlySelf) {
605                 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
606                         (*i)->set_height(h, OnlySelf);
607                 }
608         }
609
610         _editor.override_visible_track_count ();
611 }
612
613 bool
614 TimeAxisView::name_entry_key_press (GdkEventKey* ev)
615 {
616         /* steal escape, tabs from GTK */
617
618         switch (ev->keyval) {
619         case GDK_Escape:
620         case GDK_ISO_Left_Tab:
621         case GDK_Tab:
622                 return true;
623         }
624         return false;
625 }
626
627 bool
628 TimeAxisView::name_entry_key_release (GdkEventKey* ev)
629 {
630         TrackViewList::iterator i;
631
632         switch (ev->keyval) {
633         case GDK_Escape:
634                 end_name_edit (RESPONSE_CANCEL);
635                 return true;
636
637         case GDK_ISO_Left_Tab:
638                 /* Shift+Tab Keys Pressed. Note that for Shift+Tab, GDK actually
639                  * generates a different ev->keyval, rather than setting
640                  * ev->state.
641                  */
642                 end_name_edit (RESPONSE_APPLY);
643                 return true;
644
645         case GDK_Tab:
646                 end_name_edit (RESPONSE_ACCEPT);
647                 return true;
648         default:
649                 break;
650         }
651
652         return false;
653 }
654
655 bool
656 TimeAxisView::name_entry_focus_out (GdkEventFocus*)
657 {
658         if (by_popup_menu) {
659                 by_popup_menu = false;
660                 return false;
661         }
662         end_name_edit (RESPONSE_OK);
663         return false;
664 }
665
666 void
667 TimeAxisView::name_entry_populate_popup (Gtk::Menu *)
668 {
669         by_popup_menu = true;
670 }
671
672 void
673 TimeAxisView::begin_name_edit ()
674 {
675         if (name_entry) {
676                 return;
677         }
678
679         if (can_edit_name()) {
680
681                 name_entry = manage (new Gtkmm2ext::FocusEntry);
682
683                 name_entry->set_width_chars(8); // min width, entry expands
684
685                 name_entry->set_name ("EditorTrackNameDisplay");
686                 name_entry->signal_key_press_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_key_press), false);
687                 name_entry->signal_key_release_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_key_release), false);
688                 name_entry->signal_focus_out_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_focus_out));
689                 name_entry->set_text (name_label.get_text());
690                 name_entry->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &TimeAxisView::end_name_edit), RESPONSE_OK));
691                 name_entry->signal_populate_popup().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_populate_popup));
692
693                 if (name_label.is_ancestor (name_hbox)) {
694                         name_hbox.remove (name_label);
695                 }
696
697                 name_hbox.pack_end (*name_entry, true, true);
698                 name_entry->show ();
699
700                 name_entry->select_region (0, -1);
701                 name_entry->set_state (STATE_SELECTED);
702                 name_entry->grab_focus ();
703                 name_entry->start_editing (0);
704         }
705 }
706
707 void
708 TimeAxisView::end_name_edit (int response)
709 {
710         if (!name_entry) {
711                 return;
712         }
713
714         if (ending_name_edit) {
715                 /* already doing this, and focus out or other event has caused
716                    us to re-enter this code.
717                 */
718                 return;
719         }
720
721         PBD::Unwinder<bool> uw (ending_name_edit, true);
722
723         bool edit_next = false;
724         bool edit_prev = false;
725
726         switch (response) {
727         case RESPONSE_CANCEL:
728                 break;
729         case RESPONSE_OK:
730                 name_entry_changed ();
731                 break;
732         case RESPONSE_ACCEPT:
733                 name_entry_changed ();
734                 edit_next = true;
735         case RESPONSE_APPLY:
736                 name_entry_changed ();
737                 edit_prev = true;
738         }
739
740         /* this will delete the name_entry. but it will also drop focus, which
741          * will cause another callback to this function, so set name_entry = 0
742          * first to ensure we don't double-remove etc. etc.
743          */
744
745         Gtk::Entry* tmp = name_entry;
746         name_entry = 0;
747         name_hbox.remove (*tmp);
748
749         /* put the name label back */
750
751         name_hbox.pack_end (name_label);
752         name_label.show ();
753
754         if (edit_next) {
755
756                 TrackViewList const & allviews = _editor.get_track_views ();
757                 TrackViewList::const_iterator i = find (allviews.begin(), allviews.end(), this);
758
759                 if (i != allviews.end()) {
760
761                         do {
762                                 if (++i == allviews.end()) {
763                                         return;
764                                 }
765
766                                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*>(*i);
767
768                                 if (rtav && (!rtav->is_track() || rtav->track()->rec_enable_control()->get_value())) {
769                                         continue;
770                                 }
771
772                                 if (!(*i)->hidden()) {
773                                         break;
774                                 }
775
776                         } while (true);
777                 }
778
779                 if ((i != allviews.end()) && (*i != this) && !(*i)->hidden()) {
780                         _editor.ensure_time_axis_view_is_visible (**i, false);
781                         (*i)->begin_name_edit ();
782                 }
783
784         } else if (edit_prev) {
785
786                 TrackViewList const & allviews = _editor.get_track_views ();
787                 TrackViewList::const_iterator i = find (allviews.begin(), allviews.end(), this);
788
789                 if (i != allviews.begin()) {
790                         do {
791                                 if (i == allviews.begin()) {
792                                         return;
793                                 }
794
795                                 --i;
796
797                                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*>(*i);
798
799                                 if (rtav && (!rtav->is_track() || rtav->track()->rec_enable_control()->get_value())) {
800                                         continue;
801                                 }
802
803                                 if (!(*i)->hidden()) {
804                                         break;
805                                 }
806
807                         } while (true);
808                 }
809
810                 if ((i != allviews.end()) && (*i != this) && !(*i)->hidden()) {
811                         _editor.ensure_time_axis_view_is_visible (**i, false);
812                         (*i)->begin_name_edit ();
813                 }
814         }
815 }
816
817 void
818 TimeAxisView::name_entry_changed ()
819 {
820 }
821
822 bool
823 TimeAxisView::can_edit_name () const
824 {
825         return true;
826 }
827
828 void
829 TimeAxisView::conditionally_add_to_selection ()
830 {
831         Selection& s (_editor.get_selection ());
832
833         if (!s.selected (this)) {
834                 _editor.set_selected_track (*this, Selection::Set);
835         }
836 }
837
838 void
839 TimeAxisView::popup_display_menu (guint32 when)
840 {
841         conditionally_add_to_selection ();
842
843         build_display_menu ();
844         display_menu->popup (1, when);
845 }
846
847 void
848 TimeAxisView::set_selected (bool yn)
849 {
850         if (can_edit_name() && name_entry && name_entry->get_visible()) {
851                 end_name_edit (RESPONSE_CANCEL);
852         }
853
854         if (yn == _selected) {
855                 return;
856         }
857
858         Selectable::set_selected (yn);
859
860         if (_selected) {
861                 time_axis_frame.set_shadow_type (Gtk::SHADOW_IN);
862                 time_axis_frame.set_name ("MixerStripSelectedFrame");
863                 controls_ebox.set_name (controls_base_selected_name);
864                 controls_vbox.set_name (controls_base_selected_name);
865                 time_axis_vbox.set_name (controls_base_selected_name);
866         } else {
867                 time_axis_frame.set_shadow_type (Gtk::SHADOW_NONE);
868                 time_axis_frame.set_name (controls_base_unselected_name);
869                 controls_ebox.set_name (controls_base_unselected_name);
870                 controls_vbox.set_name (controls_base_unselected_name);
871                 time_axis_vbox.set_name (controls_base_unselected_name);
872
873                 hide_selection ();
874
875                 /* children will be set for the yn=true case. but when deselecting
876                    the editor only has a list of top-level trackviews, so we
877                    have to do this here.
878                 */
879
880                 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
881                         (*i)->set_selected (false);
882                 }
883         }
884
885         time_axis_frame.show();
886
887 }
888
889 void
890 TimeAxisView::build_display_menu ()
891 {
892         using namespace Menu_Helpers;
893
894         delete display_menu;
895
896         display_menu = new Menu;
897         display_menu->set_name ("ArdourContextMenu");
898
899         // Just let implementing classes define what goes into the manu
900 }
901
902 void
903 TimeAxisView::set_samples_per_pixel (double fpp)
904 {
905         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
906                 (*i)->set_samples_per_pixel (fpp);
907         }
908 }
909
910 void
911 TimeAxisView::show_timestretch (framepos_t start, framepos_t end, int layers, int layer)
912 {
913         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
914                 (*i)->show_timestretch (start, end, layers, layer);
915         }
916 }
917
918 void
919 TimeAxisView::hide_timestretch ()
920 {
921         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
922                 (*i)->hide_timestretch ();
923         }
924 }
925
926 void
927 TimeAxisView::show_selection (TimeSelection& ts)
928 {
929         double x1;
930         double x2;
931         double y2;
932         SelectionRect *rect;    time_axis_frame.show();
933
934
935         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
936                 (*i)->show_selection (ts);
937         }
938
939         if (selection_group->visible ()) {
940                 while (!used_selection_rects.empty()) {
941                         free_selection_rects.push_front (used_selection_rects.front());
942                         used_selection_rects.pop_front();
943                         free_selection_rects.front()->rect->hide();
944                         free_selection_rects.front()->start_trim->hide();
945                         free_selection_rects.front()->end_trim->hide();
946                 }
947                 selection_group->hide();
948         }
949
950         selection_group->show();
951         selection_group->raise_to_top();
952
953         for (list<AudioRange>::iterator i = ts.begin(); i != ts.end(); ++i) {
954                 framepos_t start, end;
955                 framecnt_t cnt;
956
957                 start = (*i).start;
958                 end = (*i).end;
959                 cnt = end - start + 1;
960
961                 rect = get_selection_rect ((*i).id);
962
963                 x1 = _editor.sample_to_pixel (start);
964                 x2 = _editor.sample_to_pixel (start + cnt - 1);
965                 y2 = current_height() - 1;
966
967                 rect->rect->set (ArdourCanvas::Rect (x1, 0, x2, y2));
968
969                 // trim boxes are at the top for selections
970
971                 if (x2 > x1) {
972                         rect->start_trim->set (ArdourCanvas::Rect (x1, 0, x1 + trim_handle_size, y2));
973                         rect->end_trim->set (ArdourCanvas::Rect (x2 - trim_handle_size, 1, x2, y2));
974
975                         rect->start_trim->show();
976                         rect->end_trim->show();
977                 } else {
978                         rect->start_trim->hide();
979                         rect->end_trim->hide();
980                 }
981
982                 rect->rect->show ();
983                 used_selection_rects.push_back (rect);
984         }
985 }
986
987 void
988 TimeAxisView::reshow_selection (TimeSelection& ts)
989 {
990         show_selection (ts);
991
992         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
993                 (*i)->show_selection (ts);
994         }
995 }
996
997 void
998 TimeAxisView::hide_selection ()
999 {
1000         if (selection_group->visible ()) {
1001                 while (!used_selection_rects.empty()) {
1002                         free_selection_rects.push_front (used_selection_rects.front());
1003                         used_selection_rects.pop_front();
1004                         free_selection_rects.front()->rect->hide();
1005                         free_selection_rects.front()->start_trim->hide();
1006                         free_selection_rects.front()->end_trim->hide();
1007                 }
1008                 selection_group->hide();
1009         }
1010
1011         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1012                 (*i)->hide_selection ();
1013         }
1014 }
1015
1016 void
1017 TimeAxisView::order_selection_trims (ArdourCanvas::Item *item, bool put_start_on_top)
1018 {
1019         /* find the selection rect this is for. we have the item corresponding to one
1020            of the trim handles.
1021          */
1022
1023         for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
1024                 if ((*i)->start_trim == item || (*i)->end_trim == item) {
1025
1026                         /* make one trim handle be "above" the other so that if they overlap,
1027                            the top one is the one last used.
1028                         */
1029
1030                         (*i)->rect->raise_to_top ();
1031                         (put_start_on_top ? (*i)->start_trim : (*i)->end_trim)->raise_to_top ();
1032                         (put_start_on_top ? (*i)->end_trim : (*i)->start_trim)->raise_to_top ();
1033
1034                         break;
1035                 }
1036         }
1037 }
1038
1039 SelectionRect *
1040 TimeAxisView::get_selection_rect (uint32_t id)
1041 {
1042         SelectionRect *rect;
1043
1044         /* check to see if we already have a visible rect for this particular selection ID */
1045
1046         for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
1047                 if ((*i)->id == id) {
1048                         return (*i);
1049                 }
1050         }
1051
1052         /* ditto for the free rect list */
1053
1054         for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
1055                 if ((*i)->id == id) {
1056                         SelectionRect* ret = (*i);
1057                         free_selection_rects.erase (i);
1058                         return ret;
1059                 }
1060         }
1061
1062         /* no existing matching rect, so go get a new one from the free list, or create one if there are none */
1063
1064         if (free_selection_rects.empty()) {
1065
1066                 rect = new SelectionRect;
1067
1068                 rect->rect = new ArdourCanvas::Rectangle (selection_group);
1069                 CANVAS_DEBUG_NAME (rect->rect, "selection rect");
1070                 rect->rect->set_outline (false);
1071                 rect->rect->set_fill_color (UIConfiguration::instance().color_mod ("selection rect", "selection rect"));
1072
1073                 rect->start_trim = new ArdourCanvas::Rectangle (selection_group);
1074                 CANVAS_DEBUG_NAME (rect->start_trim, "selection rect start trim");
1075                 rect->start_trim->set_outline (false);
1076                 rect->start_trim->set_fill (false);
1077
1078                 rect->end_trim = new ArdourCanvas::Rectangle (selection_group);
1079                 CANVAS_DEBUG_NAME (rect->end_trim, "selection rect end trim");
1080                 rect->end_trim->set_outline (false);
1081                 rect->end_trim->set_fill (false);
1082
1083                 free_selection_rects.push_front (rect);
1084
1085                 rect->rect->Event.connect (sigc::bind (sigc::mem_fun (_editor, &PublicEditor::canvas_selection_rect_event), rect->rect, rect));
1086                 rect->start_trim->Event.connect (sigc::bind (sigc::mem_fun (_editor, &PublicEditor::canvas_selection_start_trim_event), rect->rect, rect));
1087                 rect->end_trim->Event.connect (sigc::bind (sigc::mem_fun (_editor, &PublicEditor::canvas_selection_end_trim_event), rect->rect, rect));
1088         }
1089
1090         rect = free_selection_rects.front();
1091         rect->id = id;
1092         free_selection_rects.pop_front();
1093         return rect;
1094 }
1095
1096 struct null_deleter { void operator()(void const *) const {} };
1097
1098 bool
1099 TimeAxisView::is_child (TimeAxisView* tav)
1100 {
1101         return find (children.begin(), children.end(), boost::shared_ptr<TimeAxisView>(tav, null_deleter())) != children.end();
1102 }
1103
1104 void
1105 TimeAxisView::add_child (boost::shared_ptr<TimeAxisView> child)
1106 {
1107         children.push_back (child);
1108 }
1109
1110 void
1111 TimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> child)
1112 {
1113         Children::iterator i;
1114
1115         if ((i = find (children.begin(), children.end(), child)) != children.end()) {
1116                 children.erase (i);
1117         }
1118 }
1119
1120 /** Get selectable things within a given range.
1121  *  @param start Start time in session frames.
1122  *  @param end End time in session frames.
1123  *  @param top Top y range, in trackview coordinates (ie 0 is the top of the track view)
1124  *  @param bot Bottom y range, in trackview coordinates (ie 0 is the top of the track view)
1125  *  @param result Filled in with selectable things.
1126  */
1127 void
1128 TimeAxisView::get_selectables (framepos_t /*start*/, framepos_t /*end*/, double /*top*/, double /*bot*/, list<Selectable*>& /*result*/, bool /*within*/)
1129 {
1130         return;
1131 }
1132
1133 void
1134 TimeAxisView::get_inverted_selectables (Selection& /*sel*/, list<Selectable*>& /*result*/)
1135 {
1136         return;
1137 }
1138
1139 void
1140 TimeAxisView::add_ghost (RegionView* rv)
1141 {
1142         GhostRegion* gr = rv->add_ghost (*this);
1143
1144         if (gr) {
1145                 ghosts.push_back(gr);
1146         }
1147 }
1148
1149 void
1150 TimeAxisView::remove_ghost (RegionView* rv)
1151 {
1152         rv->remove_ghost_in (*this);
1153 }
1154
1155 void
1156 TimeAxisView::erase_ghost (GhostRegion* gr)
1157 {
1158         if (in_destructor) {
1159                 return;
1160         }
1161
1162         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1163                 if ((*i) == gr) {
1164                         ghosts.erase (i);
1165                         break;
1166                 }
1167         }
1168 }
1169
1170 bool
1171 TimeAxisView::touched (double top, double bot)
1172 {
1173         /* remember: this is X Window - coordinate space starts in upper left and moves down.
1174           y_position is the "origin" or "top" of the track.
1175         */
1176
1177         double mybot = _y_position + current_height();
1178
1179         return ((_y_position <= bot && _y_position >= top) ||
1180                 ((mybot <= bot) && (top < mybot)) ||
1181                 (mybot >= bot && _y_position < top));
1182 }
1183
1184 void
1185 TimeAxisView::set_parent (TimeAxisView& p)
1186 {
1187         parent = &p;
1188 }
1189
1190 void
1191 TimeAxisView::reset_height ()
1192 {
1193         set_height (height);
1194
1195         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1196                 (*i)->set_height ((*i)->height);
1197         }
1198 }
1199
1200 void
1201 TimeAxisView::compute_heights ()
1202 {
1203         // TODO this function should be re-evaluated when font-scaling changes (!)
1204         Gtk::Window window (Gtk::WINDOW_TOPLEVEL);
1205         Gtk::Table one_row_table (1, 1);
1206         ArdourButton* test_button = manage (new ArdourButton);
1207         const int border_width = 2;
1208         const int frame_height = 2;
1209         extra_height = (2 * border_width) + frame_height;
1210
1211         window.add (one_row_table);
1212         test_button->set_name ("mute button");
1213         test_button->set_text (S_("Mute|M"));
1214         test_button->set_tweaks (ArdourButton::TrackHeader);
1215
1216         one_row_table.set_border_width (border_width);
1217         one_row_table.set_row_spacings (2);
1218         one_row_table.set_col_spacings (2);
1219
1220         one_row_table.attach (*test_button, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
1221         one_row_table.show_all ();
1222
1223         Gtk::Requisition req(one_row_table.size_request ());
1224         button_height = req.height;
1225 }
1226
1227 void
1228 TimeAxisView::color_handler ()
1229 {
1230         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); i++) {
1231                 (*i)->set_colors();
1232         }
1233
1234         for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
1235
1236                 (*i)->rect->set_fill_color (UIConfiguration::instance().color_mod ("selection rect", "selection rect"));
1237                 (*i)->rect->set_outline_color (UIConfiguration::instance().color ("selection"));
1238
1239                 (*i)->start_trim->set_fill_color (UIConfiguration::instance().color ("selection"));
1240                 (*i)->start_trim->set_outline_color (UIConfiguration::instance().color ("selection"));
1241
1242                 (*i)->end_trim->set_fill_color (UIConfiguration::instance().color ("selection"));
1243                 (*i)->end_trim->set_outline_color (UIConfiguration::instance().color ("selection"));
1244         }
1245
1246         for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
1247
1248                 (*i)->rect->set_fill_color (UIConfiguration::instance().color_mod ("selection rect", "selection rect"));
1249                 (*i)->rect->set_outline_color (UIConfiguration::instance().color ("selection"));
1250
1251                 (*i)->start_trim->set_fill_color (UIConfiguration::instance().color ("selection"));
1252                 (*i)->start_trim->set_outline_color (UIConfiguration::instance().color ("selection"));
1253
1254                 (*i)->end_trim->set_fill_color (UIConfiguration::instance().color ("selection"));
1255                 (*i)->end_trim->set_outline_color (UIConfiguration::instance().color ("selection"));
1256         }
1257 }
1258
1259 /** @return Pair: TimeAxisView, layer index.
1260  * TimeAxisView is non-0 if this object covers @param y, or one of its children
1261  * does. @param y is an offset from the top of the trackview area.
1262  *
1263  * If the covering object is a child axis, then the child is returned.
1264  * TimeAxisView is 0 otherwise.
1265  *
1266  * Layer index is the layer number (possibly fractional) if the TimeAxisView is valid
1267  * and is in stacked or expanded * region display mode, otherwise 0.
1268  */
1269 std::pair<TimeAxisView*, double>
1270 TimeAxisView::covers_y_position (double y) const
1271 {
1272         if (hidden()) {
1273                 return std::make_pair ((TimeAxisView *) 0, 0);
1274         }
1275
1276         if (_y_position <= y && y < (_y_position + height)) {
1277
1278                 /* work out the layer index if appropriate */
1279                 double l = 0;
1280                 switch (layer_display ()) {
1281                 case Overlaid:
1282                         break;
1283                 case Stacked:
1284                         if (view ()) {
1285                                 /* compute layer */
1286                                 l = layer_t ((_y_position + height - y) / (view()->child_height ()));
1287                                 /* clamp to max layers to be on the safe side; sometimes the above calculation
1288                                    returns a too-high value */
1289                                 if (l >= view()->layers ()) {
1290                                         l = view()->layers() - 1;
1291                                 }
1292                         }
1293                         break;
1294                 case Expanded:
1295                         if (view ()) {
1296                                 int const n = floor ((_y_position + height - y) / (view()->child_height ()));
1297                                 l = n * 0.5 - 0.5;
1298                                 if (l >= (view()->layers() - 0.5)) {
1299                                         l = view()->layers() - 0.5;
1300                                 }
1301                         }
1302                         break;
1303                 }
1304
1305                 return std::make_pair (const_cast<TimeAxisView*>(this), l);
1306         }
1307
1308         for (Children::const_iterator i = children.begin(); i != children.end(); ++i) {
1309
1310                 std::pair<TimeAxisView*, int> const r = (*i)->covers_y_position (y);
1311                 if (r.first) {
1312                         return r;
1313                 }
1314         }
1315
1316         return std::make_pair ((TimeAxisView *) 0, 0);
1317 }
1318
1319 bool
1320 TimeAxisView::covered_by_y_range (double y0, double y1) const
1321 {
1322         if (hidden()) {
1323                 return false;
1324         }
1325
1326         /* if either the top or bottom of the axisview is in the vertical
1327          * range, we cover it.
1328          */
1329
1330         if ((y0 < _y_position && y1 < _y_position) ||
1331             (y0 >= _y_position + height && y1 >= _y_position + height)) {
1332                 return false;
1333         }
1334
1335         for (Children::const_iterator i = children.begin(); i != children.end(); ++i) {
1336                 if ((*i)->covered_by_y_range (y0, y1)) {
1337                         return true;
1338                 }
1339         }
1340
1341         return true;
1342 }
1343
1344 uint32_t
1345 TimeAxisView::preset_height (Height h)
1346 {
1347         switch (h) {
1348         case HeightLargest:
1349                 return (button_height * 2) + extra_height + 260;
1350         case HeightLarger:
1351                 return (button_height * 2) + extra_height + 160;
1352         case HeightLarge:
1353                 return (button_height * 2) + extra_height + 60;
1354         case HeightNormal:
1355                 return (button_height * 2) + extra_height + 10;
1356         case HeightSmall:
1357                 return button_height + extra_height;
1358         }
1359
1360         abort(); /* NOTREACHED */
1361         return 0;
1362 }
1363
1364 /** @return Child time axis views that are not hidden */
1365 TimeAxisView::Children
1366 TimeAxisView::get_child_list ()
1367 {
1368         Children c;
1369
1370         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1371                 if (!(*i)->hidden()) {
1372                         c.push_back(*i);
1373                 }
1374         }
1375
1376         return c;
1377 }
1378
1379 void
1380 TimeAxisView::build_size_menu ()
1381 {
1382         if (_size_menu && _size_menu->gobj ()) {
1383                 return;
1384         }
1385
1386         delete _size_menu;
1387
1388         using namespace Menu_Helpers;
1389
1390         _size_menu = new Menu;
1391         _size_menu->set_name ("ArdourContextMenu");
1392         MenuList& items = _size_menu->items();
1393
1394         items.push_back (MenuElem (_("Largest"), sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightLargest, true)));
1395         items.push_back (MenuElem (_("Larger"),  sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightLarger, true)));
1396         items.push_back (MenuElem (_("Large"),   sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightLarge, true)));
1397         items.push_back (MenuElem (_("Normal"),  sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightNormal, true)));
1398         items.push_back (MenuElem (_("Small"),   sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightSmall, true)));
1399 }
1400
1401 void
1402 TimeAxisView::reset_visual_state ()
1403 {
1404         /* this method is not required to trigger a global redraw */
1405
1406         string str = gui_property ("height");
1407
1408         if (!str.empty()) {
1409                 set_height (atoi (str));
1410         } else {
1411                 set_height (preset_height (HeightNormal));
1412         }
1413 }
1414
1415 TrackViewList
1416 TrackViewList::filter_to_unique_playlists ()
1417 {
1418         std::set<boost::shared_ptr<ARDOUR::Playlist> > playlists;
1419         TrackViewList ts;
1420
1421         for (iterator i = begin(); i != end(); ++i) {
1422                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
1423                 if (!rtav) {
1424                         /* not a route: include it anyway */
1425                         ts.push_back (*i);
1426                 } else {
1427                         boost::shared_ptr<ARDOUR::Track> t = rtav->track();
1428                         if (t) {
1429                                 if (playlists.insert (t->playlist()).second) {
1430                                         /* playlist not seen yet */
1431                                         ts.push_back (*i);
1432                                 }
1433                         } else {
1434                                 /* not a track: include it anyway */
1435                                 ts.push_back (*i);
1436                         }
1437                 }
1438         }
1439         return ts;
1440 }