6b780a7fc7e899b9ed4fecace543687b568a3134
[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 (3, 3)
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, 2,  Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK, 0, 0);
175         } else {
176                 controls_table.attach (name_hbox, 1, 2, 0, 2,  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                 selection_click (ev);
514                 break;
515
516         case 3:
517                 popup_display_menu (ev->time);
518                 break;
519         }
520
521         return true;
522 }
523
524 void
525 TimeAxisView::selection_click (GdkEventButton* ev)
526 {
527         Selection::Operation op = ArdourKeyboard::selection_type (ev->state);
528         _editor.set_selected_track (*this, op, false);
529 }
530
531
532 /** Steps through the defined heights for this TrackView.
533  *  @param coarser true if stepping should decrease in size, otherwise false.
534  */
535 void
536 TimeAxisView::step_height (bool coarser)
537 {
538         static const uint32_t step = 25;
539
540         if (coarser) {
541
542                 if (height <= preset_height (HeightSmall)) {
543                         return;
544                 } else if (height <= preset_height (HeightNormal) && height > preset_height (HeightSmall)) {
545                         set_height_enum (HeightSmall);
546                 } else {
547                         set_height (height - step);
548                 }
549
550         } else {
551
552                 if (height <= preset_height(HeightSmall)) {
553                         set_height_enum (HeightNormal);
554                 } else {
555                         set_height (height + step);
556                 }
557
558         }
559 }
560
561 void
562 TimeAxisView::set_height_enum (Height h, bool apply_to_selection)
563 {
564         if (apply_to_selection) {
565                 _editor.get_selection().tracks.foreach_time_axis (boost::bind (&TimeAxisView::set_height_enum, _1, h, false));
566         } else {
567                 set_height (preset_height (h));
568         }
569 }
570
571 void
572 TimeAxisView::set_height (uint32_t h, TrackHeightMode m)
573 {
574         uint32_t lanes = 0;
575         if (m == TotalHeight) {
576                 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
577                         if ( !(*i)->hidden()) ++lanes;
578                 }
579         }
580         h /= (lanes + 1);
581
582         if (h < preset_height (HeightSmall)) {
583                 h = preset_height (HeightSmall);
584         }
585
586         TOP_LEVEL_WIDGET.property_height_request () = h;
587         height = h;
588
589         char buf[32];
590         snprintf (buf, sizeof (buf), "%u", height);
591         set_gui_property ("height", buf);
592
593         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
594                 (*i)->set_height ();
595         }
596
597         if (selection_group->visible ()) {
598                 /* resize the selection rect */
599                 show_selection (_editor.get_selection().time);
600         }
601
602         if (m != OnlySelf) {
603                 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
604                         (*i)->set_height(h, OnlySelf);
605                 }
606         }
607
608         _editor.override_visible_track_count ();
609 }
610
611 bool
612 TimeAxisView::name_entry_key_press (GdkEventKey* ev)
613 {
614         /* steal escape, tabs from GTK */
615
616         switch (ev->keyval) {
617         case GDK_Escape:
618         case GDK_ISO_Left_Tab:
619         case GDK_Tab:
620                 return true;
621         }
622         return false;
623 }
624
625 bool
626 TimeAxisView::name_entry_key_release (GdkEventKey* ev)
627 {
628         TrackViewList::iterator i;
629
630         switch (ev->keyval) {
631         case GDK_Escape:
632                 end_name_edit (RESPONSE_CANCEL);
633                 return true;
634
635         /* Shift+Tab Keys Pressed. Note that for Shift+Tab, GDK actually
636          * generates a different ev->keyval, rather than setting
637          * ev->state.
638          */
639         case GDK_ISO_Left_Tab:
640                 end_name_edit (RESPONSE_APPLY);
641                 return true;
642
643         case GDK_Tab:
644                 end_name_edit (RESPONSE_ACCEPT);
645                 return true;
646         default:
647                 break;
648         }
649
650         return false;
651 }
652
653 bool
654 TimeAxisView::name_entry_focus_out (GdkEventFocus*)
655 {
656         if (by_popup_menu) {
657                 by_popup_menu = false;
658                 return false;
659         }
660         end_name_edit (RESPONSE_OK);
661         return false;
662 }
663
664 void
665 TimeAxisView::name_entry_populate_popup (Gtk::Menu *)
666 {
667         by_popup_menu = true;
668 }
669
670 void
671 TimeAxisView::begin_name_edit ()
672 {
673         if (name_entry) {
674                 return;
675         }
676
677         if (can_edit_name()) {
678
679                 name_entry = manage (new Gtkmm2ext::FocusEntry);
680
681                 name_entry->set_width_chars(8); // min width, entry expands
682
683                 name_entry->set_name ("EditorTrackNameDisplay");
684                 name_entry->signal_key_press_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_key_press), false);
685                 name_entry->signal_key_release_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_key_release), false);
686                 name_entry->signal_focus_out_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_focus_out));
687                 name_entry->set_text (name_label.get_text());
688                 name_entry->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &TimeAxisView::end_name_edit), RESPONSE_OK));
689                 name_entry->signal_populate_popup().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_populate_popup));
690
691                 if (name_label.is_ancestor (name_hbox)) {
692                         name_hbox.remove (name_label);
693                 }
694
695                 name_hbox.pack_end (*name_entry, true, true);
696                 name_entry->show ();
697
698                 name_entry->select_region (0, -1);
699                 name_entry->set_state (STATE_SELECTED);
700                 name_entry->grab_focus ();
701                 name_entry->start_editing (0);
702         }
703 }
704
705 void
706 TimeAxisView::end_name_edit (int response)
707 {
708         if (!name_entry) {
709                 return;
710         }
711
712         if (ending_name_edit) {
713                 /* already doing this, and focus out or other event has caused
714                    us to re-enter this code.
715                 */
716                 return;
717         }
718
719         PBD::Unwinder<bool> uw (ending_name_edit, true);
720
721         bool edit_next = false;
722         bool edit_prev = false;
723
724         switch (response) {
725         case RESPONSE_CANCEL:
726                 break;
727         case RESPONSE_OK:
728                 name_entry_changed ();
729                 break;
730         case RESPONSE_ACCEPT:
731                 name_entry_changed ();
732                 edit_next = true;
733         case RESPONSE_APPLY:
734                 name_entry_changed ();
735                 edit_prev = true;
736         }
737
738         /* this will delete the name_entry. but it will also drop focus, which
739          * will cause another callback to this function, so set name_entry = 0
740          * first to ensure we don't double-remove etc. etc.
741          */
742
743         Gtk::Entry* tmp = name_entry;
744         name_entry = 0;
745         name_hbox.remove (*tmp);
746
747         /* put the name label back */
748
749         name_hbox.pack_end (name_label);
750         name_label.show ();
751
752         if (edit_next) {
753
754                 TrackViewList const & allviews = _editor.get_track_views ();
755                 TrackViewList::const_iterator i = find (allviews.begin(), allviews.end(), this);
756
757                 if (i != allviews.end()) {
758
759                         do {
760                                 if (++i == allviews.end()) {
761                                         return;
762                                 }
763
764                                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*>(*i);
765
766                                 if (rtav && rtav->route()->record_enabled()) {
767                                         continue;
768                                 }
769
770                                 if (!(*i)->hidden()) {
771                                         break;
772                                 }
773
774                         } while (true);
775                 }
776
777                 if ((i != allviews.end()) && (*i != this) && !(*i)->hidden()) {
778                         _editor.ensure_time_axis_view_is_visible (**i, false);
779                         (*i)->begin_name_edit ();
780                 }
781
782         } else if (edit_prev) {
783
784                 TrackViewList const & allviews = _editor.get_track_views ();
785                 TrackViewList::const_iterator i = find (allviews.begin(), allviews.end(), this);
786
787                 if (i != allviews.begin()) {
788                         do {
789                                 if (i == allviews.begin()) {
790                                         return;
791                                 }
792
793                                 --i;
794
795                                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*>(*i);
796
797                                 if (rtav && rtav->route()->record_enabled()) {
798                                         continue;
799                                 }
800
801                                 if (!(*i)->hidden()) {
802                                         break;
803                                 }
804
805                         } while (true);
806                 }
807
808                 if ((i != allviews.end()) && (*i != this) && !(*i)->hidden()) {
809                         _editor.ensure_time_axis_view_is_visible (**i, false);
810                         (*i)->begin_name_edit ();
811                 }
812         }
813 }
814
815 void
816 TimeAxisView::name_entry_changed ()
817 {
818 }
819
820 bool
821 TimeAxisView::can_edit_name () const
822 {
823         return true;
824 }
825
826 void
827 TimeAxisView::conditionally_add_to_selection ()
828 {
829         Selection& s (_editor.get_selection ());
830
831         if (!s.selected (this)) {
832                 _editor.set_selected_track (*this, Selection::Set);
833         }
834 }
835
836 void
837 TimeAxisView::popup_display_menu (guint32 when)
838 {
839         conditionally_add_to_selection ();
840
841         build_display_menu ();
842         display_menu->popup (1, when);
843 }
844
845 void
846 TimeAxisView::set_selected (bool yn)
847 {
848         if (can_edit_name() && name_entry && name_entry->get_visible()) {
849                 end_name_edit (RESPONSE_CANCEL);
850         }
851
852         if (yn == _selected) {
853                 return;
854         }
855
856         Selectable::set_selected (yn);
857
858         if (_selected) {
859                 time_axis_frame.set_shadow_type (Gtk::SHADOW_IN);
860                 time_axis_frame.set_name ("MixerStripSelectedFrame");
861                 controls_ebox.set_name (controls_base_selected_name);
862                 controls_vbox.set_name (controls_base_selected_name);
863                 time_axis_vbox.set_name (controls_base_selected_name);
864         } else {
865                 time_axis_frame.set_shadow_type (Gtk::SHADOW_NONE);
866                 time_axis_frame.set_name (controls_base_unselected_name);
867                 controls_ebox.set_name (controls_base_unselected_name);
868                 controls_vbox.set_name (controls_base_unselected_name);
869                 time_axis_vbox.set_name (controls_base_unselected_name);
870
871                 hide_selection ();
872
873                 /* children will be set for the yn=true case. but when deselecting
874                    the editor only has a list of top-level trackviews, so we
875                    have to do this here.
876                 */
877
878                 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
879                         (*i)->set_selected (false);
880                 }
881         }
882
883         time_axis_frame.show();
884
885 }
886
887 void
888 TimeAxisView::build_display_menu ()
889 {
890         using namespace Menu_Helpers;
891
892         delete display_menu;
893
894         display_menu = new Menu;
895         display_menu->set_name ("ArdourContextMenu");
896
897         // Just let implementing classes define what goes into the manu
898 }
899
900 void
901 TimeAxisView::set_samples_per_pixel (double fpp)
902 {
903         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
904                 (*i)->set_samples_per_pixel (fpp);
905         }
906 }
907
908 void
909 TimeAxisView::show_timestretch (framepos_t start, framepos_t end, int layers, int layer)
910 {
911         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
912                 (*i)->show_timestretch (start, end, layers, layer);
913         }
914 }
915
916 void
917 TimeAxisView::hide_timestretch ()
918 {
919         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
920                 (*i)->hide_timestretch ();
921         }
922 }
923
924 void
925 TimeAxisView::show_selection (TimeSelection& ts)
926 {
927         double x1;
928         double x2;
929         double y2;
930         SelectionRect *rect;    time_axis_frame.show();
931
932
933         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
934                 (*i)->show_selection (ts);
935         }
936
937         if (selection_group->visible ()) {
938                 while (!used_selection_rects.empty()) {
939                         free_selection_rects.push_front (used_selection_rects.front());
940                         used_selection_rects.pop_front();
941                         free_selection_rects.front()->rect->hide();
942                         free_selection_rects.front()->start_trim->hide();
943                         free_selection_rects.front()->end_trim->hide();
944                 }
945                 selection_group->hide();
946         }
947
948         selection_group->show();
949         selection_group->raise_to_top();
950
951         for (list<AudioRange>::iterator i = ts.begin(); i != ts.end(); ++i) {
952                 framepos_t start, end;
953                 framecnt_t cnt;
954
955                 start = (*i).start;
956                 end = (*i).end;
957                 cnt = end - start + 1;
958
959                 rect = get_selection_rect ((*i).id);
960
961                 x1 = _editor.sample_to_pixel (start);
962                 x2 = _editor.sample_to_pixel (start + cnt - 1);
963                 y2 = current_height() - 1;
964
965                 rect->rect->set (ArdourCanvas::Rect (x1, 0, x2, y2));
966
967                 // trim boxes are at the top for selections
968
969                 if (x2 > x1) {
970                         rect->start_trim->set (ArdourCanvas::Rect (x1, 0, x1 + trim_handle_size, y2));
971                         rect->end_trim->set (ArdourCanvas::Rect (x2 - trim_handle_size, 1, x2, y2));
972
973                         rect->start_trim->show();
974                         rect->end_trim->show();
975                 } else {
976                         rect->start_trim->hide();
977                         rect->end_trim->hide();
978                 }
979
980                 rect->rect->show ();
981                 used_selection_rects.push_back (rect);
982         }
983 }
984
985 void
986 TimeAxisView::reshow_selection (TimeSelection& ts)
987 {
988         show_selection (ts);
989
990         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
991                 (*i)->show_selection (ts);
992         }
993 }
994
995 void
996 TimeAxisView::hide_selection ()
997 {
998         if (selection_group->visible ()) {
999                 while (!used_selection_rects.empty()) {
1000                         free_selection_rects.push_front (used_selection_rects.front());
1001                         used_selection_rects.pop_front();
1002                         free_selection_rects.front()->rect->hide();
1003                         free_selection_rects.front()->start_trim->hide();
1004                         free_selection_rects.front()->end_trim->hide();
1005                 }
1006                 selection_group->hide();
1007         }
1008
1009         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1010                 (*i)->hide_selection ();
1011         }
1012 }
1013
1014 void
1015 TimeAxisView::order_selection_trims (ArdourCanvas::Item *item, bool put_start_on_top)
1016 {
1017         /* find the selection rect this is for. we have the item corresponding to one
1018            of the trim handles.
1019          */
1020
1021         for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
1022                 if ((*i)->start_trim == item || (*i)->end_trim == item) {
1023
1024                         /* make one trim handle be "above" the other so that if they overlap,
1025                            the top one is the one last used.
1026                         */
1027
1028                         (*i)->rect->raise_to_top ();
1029                         (put_start_on_top ? (*i)->start_trim : (*i)->end_trim)->raise_to_top ();
1030                         (put_start_on_top ? (*i)->end_trim : (*i)->start_trim)->raise_to_top ();
1031
1032                         break;
1033                 }
1034         }
1035 }
1036
1037 SelectionRect *
1038 TimeAxisView::get_selection_rect (uint32_t id)
1039 {
1040         SelectionRect *rect;
1041
1042         /* check to see if we already have a visible rect for this particular selection ID */
1043
1044         for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
1045                 if ((*i)->id == id) {
1046                         return (*i);
1047                 }
1048         }
1049
1050         /* ditto for the free rect list */
1051
1052         for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
1053                 if ((*i)->id == id) {
1054                         SelectionRect* ret = (*i);
1055                         free_selection_rects.erase (i);
1056                         return ret;
1057                 }
1058         }
1059
1060         /* no existing matching rect, so go get a new one from the free list, or create one if there are none */
1061
1062         if (free_selection_rects.empty()) {
1063
1064                 rect = new SelectionRect;
1065
1066                 rect->rect = new ArdourCanvas::Rectangle (selection_group);
1067                 CANVAS_DEBUG_NAME (rect->rect, "selection rect");
1068                 rect->rect->set_outline (false);
1069                 rect->rect->set_fill_color (UIConfiguration::instance().color_mod ("selection rect", "selection rect"));
1070
1071                 rect->start_trim = new ArdourCanvas::Rectangle (selection_group);
1072                 CANVAS_DEBUG_NAME (rect->start_trim, "selection rect start trim");
1073                 rect->start_trim->set_outline (false);
1074                 rect->start_trim->set_fill (false);
1075
1076                 rect->end_trim = new ArdourCanvas::Rectangle (selection_group);
1077                 CANVAS_DEBUG_NAME (rect->end_trim, "selection rect end trim");
1078                 rect->end_trim->set_outline (false);
1079                 rect->end_trim->set_fill (false);
1080
1081                 free_selection_rects.push_front (rect);
1082
1083                 rect->rect->Event.connect (sigc::bind (sigc::mem_fun (_editor, &PublicEditor::canvas_selection_rect_event), rect->rect, rect));
1084                 rect->start_trim->Event.connect (sigc::bind (sigc::mem_fun (_editor, &PublicEditor::canvas_selection_start_trim_event), rect->rect, rect));
1085                 rect->end_trim->Event.connect (sigc::bind (sigc::mem_fun (_editor, &PublicEditor::canvas_selection_end_trim_event), rect->rect, rect));
1086         }
1087
1088         rect = free_selection_rects.front();
1089         rect->id = id;
1090         free_selection_rects.pop_front();
1091         return rect;
1092 }
1093
1094 struct null_deleter { void operator()(void const *) const {} };
1095
1096 bool
1097 TimeAxisView::is_child (TimeAxisView* tav)
1098 {
1099         return find (children.begin(), children.end(), boost::shared_ptr<TimeAxisView>(tav, null_deleter())) != children.end();
1100 }
1101
1102 void
1103 TimeAxisView::add_child (boost::shared_ptr<TimeAxisView> child)
1104 {
1105         children.push_back (child);
1106 }
1107
1108 void
1109 TimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> child)
1110 {
1111         Children::iterator i;
1112
1113         if ((i = find (children.begin(), children.end(), child)) != children.end()) {
1114                 children.erase (i);
1115         }
1116 }
1117
1118 /** Get selectable things within a given range.
1119  *  @param start Start time in session frames.
1120  *  @param end End time in session frames.
1121  *  @param top Top y range, in trackview coordinates (ie 0 is the top of the track view)
1122  *  @param bot Bottom y range, in trackview coordinates (ie 0 is the top of the track view)
1123  *  @param result Filled in with selectable things.
1124  */
1125 void
1126 TimeAxisView::get_selectables (framepos_t /*start*/, framepos_t /*end*/, double /*top*/, double /*bot*/, list<Selectable*>& /*result*/, bool /*within*/)
1127 {
1128         return;
1129 }
1130
1131 void
1132 TimeAxisView::get_inverted_selectables (Selection& /*sel*/, list<Selectable*>& /*result*/)
1133 {
1134         return;
1135 }
1136
1137 void
1138 TimeAxisView::add_ghost (RegionView* rv)
1139 {
1140         GhostRegion* gr = rv->add_ghost (*this);
1141
1142         if (gr) {
1143                 ghosts.push_back(gr);
1144         }
1145 }
1146
1147 void
1148 TimeAxisView::remove_ghost (RegionView* rv)
1149 {
1150         rv->remove_ghost_in (*this);
1151 }
1152
1153 void
1154 TimeAxisView::erase_ghost (GhostRegion* gr)
1155 {
1156         if (in_destructor) {
1157                 return;
1158         }
1159
1160         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1161                 if ((*i) == gr) {
1162                         ghosts.erase (i);
1163                         break;
1164                 }
1165         }
1166 }
1167
1168 bool
1169 TimeAxisView::touched (double top, double bot)
1170 {
1171         /* remember: this is X Window - coordinate space starts in upper left and moves down.
1172           y_position is the "origin" or "top" of the track.
1173         */
1174
1175         double mybot = _y_position + current_height();
1176
1177         return ((_y_position <= bot && _y_position >= top) ||
1178                 ((mybot <= bot) && (top < mybot)) ||
1179                 (mybot >= bot && _y_position < top));
1180 }
1181
1182 void
1183 TimeAxisView::set_parent (TimeAxisView& p)
1184 {
1185         parent = &p;
1186 }
1187
1188 void
1189 TimeAxisView::reset_height ()
1190 {
1191         set_height (height);
1192
1193         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1194                 (*i)->set_height ((*i)->height);
1195         }
1196 }
1197
1198 void
1199 TimeAxisView::compute_heights ()
1200 {
1201         // TODO this function should be re-evaluated when font-scaling changes (!)
1202         Gtk::Window window (Gtk::WINDOW_TOPLEVEL);
1203         Gtk::Table one_row_table (1, 1);
1204         ArdourButton* test_button = manage (new ArdourButton);
1205         const int border_width = 2;
1206         const int frame_height = 2;
1207         extra_height = (2 * border_width) + frame_height;
1208
1209         window.add (one_row_table);
1210         test_button->set_name ("mute button");
1211         test_button->set_text (S_("Mute|M"));
1212         test_button->set_tweaks (ArdourButton::TrackHeader);
1213
1214         one_row_table.set_border_width (border_width);
1215         one_row_table.set_row_spacings (2);
1216         one_row_table.set_col_spacings (2);
1217
1218         one_row_table.attach (*test_button, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
1219         one_row_table.show_all ();
1220
1221         Gtk::Requisition req(one_row_table.size_request ());
1222         button_height = req.height;
1223 }
1224
1225 void
1226 TimeAxisView::color_handler ()
1227 {
1228         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); i++) {
1229                 (*i)->set_colors();
1230         }
1231
1232         for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
1233
1234                 (*i)->rect->set_fill_color (UIConfiguration::instance().color_mod ("selection rect", "selection rect"));
1235                 (*i)->rect->set_outline_color (UIConfiguration::instance().color ("selection"));
1236
1237                 (*i)->start_trim->set_fill_color (UIConfiguration::instance().color ("selection"));
1238                 (*i)->start_trim->set_outline_color (UIConfiguration::instance().color ("selection"));
1239
1240                 (*i)->end_trim->set_fill_color (UIConfiguration::instance().color ("selection"));
1241                 (*i)->end_trim->set_outline_color (UIConfiguration::instance().color ("selection"));
1242         }
1243
1244         for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
1245
1246                 (*i)->rect->set_fill_color (UIConfiguration::instance().color_mod ("selection rect", "selection rect"));
1247                 (*i)->rect->set_outline_color (UIConfiguration::instance().color ("selection"));
1248
1249                 (*i)->start_trim->set_fill_color (UIConfiguration::instance().color ("selection"));
1250                 (*i)->start_trim->set_outline_color (UIConfiguration::instance().color ("selection"));
1251
1252                 (*i)->end_trim->set_fill_color (UIConfiguration::instance().color ("selection"));
1253                 (*i)->end_trim->set_outline_color (UIConfiguration::instance().color ("selection"));
1254         }
1255 }
1256
1257 /** @return Pair: TimeAxisView, layer index.
1258  * TimeAxisView is non-0 if this object covers @param y, or one of its children
1259  * does. @param y is an offset from the top of the trackview area.
1260  *
1261  * If the covering object is a child axis, then the child is returned.
1262  * TimeAxisView is 0 otherwise.
1263  *
1264  * Layer index is the layer number (possibly fractional) if the TimeAxisView is valid
1265  * and is in stacked or expanded * region display mode, otherwise 0.
1266  */
1267 std::pair<TimeAxisView*, double>
1268 TimeAxisView::covers_y_position (double y) const
1269 {
1270         if (hidden()) {
1271                 return std::make_pair ((TimeAxisView *) 0, 0);
1272         }
1273
1274         if (_y_position <= y && y < (_y_position + height)) {
1275
1276                 /* work out the layer index if appropriate */
1277                 double l = 0;
1278                 switch (layer_display ()) {
1279                 case Overlaid:
1280                         break;
1281                 case Stacked:
1282                         if (view ()) {
1283                                 /* compute layer */
1284                                 l = layer_t ((_y_position + height - y) / (view()->child_height ()));
1285                                 /* clamp to max layers to be on the safe side; sometimes the above calculation
1286                                    returns a too-high value */
1287                                 if (l >= view()->layers ()) {
1288                                         l = view()->layers() - 1;
1289                                 }
1290                         }
1291                         break;
1292                 case Expanded:
1293                         if (view ()) {
1294                                 int const n = floor ((_y_position + height - y) / (view()->child_height ()));
1295                                 l = n * 0.5 - 0.5;
1296                                 if (l >= (view()->layers() - 0.5)) {
1297                                         l = view()->layers() - 0.5;
1298                                 }
1299                         }
1300                         break;
1301                 }
1302
1303                 return std::make_pair (const_cast<TimeAxisView*>(this), l);
1304         }
1305
1306         for (Children::const_iterator i = children.begin(); i != children.end(); ++i) {
1307
1308                 std::pair<TimeAxisView*, int> const r = (*i)->covers_y_position (y);
1309                 if (r.first) {
1310                         return r;
1311                 }
1312         }
1313
1314         return std::make_pair ((TimeAxisView *) 0, 0);
1315 }
1316
1317 bool
1318 TimeAxisView::covered_by_y_range (double y0, double y1) const
1319 {
1320         if (hidden()) {
1321                 return false;
1322         }
1323
1324         /* if either the top or bottom of the axisview is in the vertical
1325          * range, we cover it.
1326          */
1327
1328         if ((y0 < _y_position && y1 < _y_position) ||
1329             (y0 >= _y_position + height && y1 >= _y_position + height)) {
1330                 return false;
1331         }
1332
1333         for (Children::const_iterator i = children.begin(); i != children.end(); ++i) {
1334                 if ((*i)->covered_by_y_range (y0, y1)) {
1335                         return true;
1336                 }
1337         }
1338
1339         return true;
1340 }
1341
1342 uint32_t
1343 TimeAxisView::preset_height (Height h)
1344 {
1345         switch (h) {
1346         case HeightLargest:
1347                 return (button_height * 2) + extra_height + 260;
1348         case HeightLarger:
1349                 return (button_height * 2) + extra_height + 160;
1350         case HeightLarge:
1351                 return (button_height * 2) + extra_height + 60;
1352         case HeightNormal:
1353                 return (button_height * 2) + extra_height + 10;
1354         case HeightSmall:
1355                 return button_height + extra_height;
1356         }
1357
1358         abort(); /* NOTREACHED */
1359         return 0;
1360 }
1361
1362 /** @return Child time axis views that are not hidden */
1363 TimeAxisView::Children
1364 TimeAxisView::get_child_list ()
1365 {
1366         Children c;
1367
1368         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1369                 if (!(*i)->hidden()) {
1370                         c.push_back(*i);
1371                 }
1372         }
1373
1374         return c;
1375 }
1376
1377 void
1378 TimeAxisView::build_size_menu ()
1379 {
1380         if (_size_menu && _size_menu->gobj ()) {
1381                 return;
1382         }
1383
1384         delete _size_menu;
1385
1386         using namespace Menu_Helpers;
1387
1388         _size_menu = new Menu;
1389         _size_menu->set_name ("ArdourContextMenu");
1390         MenuList& items = _size_menu->items();
1391
1392         items.push_back (MenuElem (_("Largest"), sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightLargest, true)));
1393         items.push_back (MenuElem (_("Larger"),  sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightLarger, true)));
1394         items.push_back (MenuElem (_("Large"),   sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightLarge, true)));
1395         items.push_back (MenuElem (_("Normal"),  sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightNormal, true)));
1396         items.push_back (MenuElem (_("Small"),   sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightSmall, true)));
1397 }
1398
1399 void
1400 TimeAxisView::reset_visual_state ()
1401 {
1402         /* this method is not required to trigger a global redraw */
1403
1404         string str = gui_property ("height");
1405
1406         if (!str.empty()) {
1407                 set_height (atoi (str));
1408         } else {
1409                 set_height (preset_height (HeightNormal));
1410         }
1411 }
1412
1413 TrackViewList
1414 TrackViewList::filter_to_unique_playlists ()
1415 {
1416         std::set<boost::shared_ptr<ARDOUR::Playlist> > playlists;
1417         TrackViewList ts;
1418
1419         for (iterator i = begin(); i != end(); ++i) {
1420                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
1421                 if (!rtav) {
1422                         /* not a route: include it anyway */
1423                         ts.push_back (*i);
1424                 } else {
1425                         boost::shared_ptr<ARDOUR::Track> t = rtav->track();
1426                         if (t) {
1427                                 if (playlists.insert (t->playlist()).second) {
1428                                         /* playlist not seen yet */
1429                                         ts.push_back (*i);
1430                                 }
1431                         } else {
1432                                 /* not a track: include it anyway */
1433                                 ts.push_back (*i);
1434                         }
1435                 }
1436         }
1437         return ts;
1438 }