Unify gain and draw tools.
[ardour.git] / gtk2_ardour / editor.cc
1 /*
2     Copyright (C) 2000-2009 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 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <stdint.h>
23 #include <unistd.h>
24 #include <cstdlib>
25 #include <cmath>
26 #include <string>
27 #include <algorithm>
28 #include <map>
29
30 #include "ardour_ui.h"
31 /*
32  * ardour_ui.h include was moved to the top of the list
33  * due to a conflicting definition of 'Style' between
34  * Apple's MacTypes.h and BarController.
35  */
36
37 #include <boost/none.hpp>
38
39 #include <sigc++/bind.h>
40
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
49
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
55
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
58
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
67
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
77
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
80
81 #include "control_protocol/control_protocol.h"
82
83 #include "actions.h"
84 #include "actions.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
93 #include "debug.h"
94 #include "editing.h"
95 #include "editor.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
109 #include "marker.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
120 #include "sfdb_ui.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
123 #include "utils.h"
124 #include "verbose_cursor.h"
125
126 #include "i18n.h"
127
128 using namespace std;
129 using namespace ARDOUR;
130 using namespace ARDOUR_UI_UTILS;
131 using namespace PBD;
132 using namespace Gtk;
133 using namespace Glib;
134 using namespace Gtkmm2ext;
135 using namespace Editing;
136
137 using PBD::internationalize;
138 using PBD::atoi;
139 using Gtkmm2ext::Keyboard;
140
141 const double Editor::timebar_height = 15.0;
142
143 static const gchar *_snap_type_strings[] = {
144         N_("CD Frames"),
145         N_("TC Frames"),
146         N_("TC Seconds"),
147         N_("TC Minutes"),
148         N_("Seconds"),
149         N_("Minutes"),
150         N_("Beats/128"),
151         N_("Beats/64"),
152         N_("Beats/32"),
153         N_("Beats/28"),
154         N_("Beats/24"),
155         N_("Beats/20"),
156         N_("Beats/16"),
157         N_("Beats/14"),
158         N_("Beats/12"),
159         N_("Beats/10"),
160         N_("Beats/8"),
161         N_("Beats/7"),
162         N_("Beats/6"),
163         N_("Beats/5"),
164         N_("Beats/4"),
165         N_("Beats/3"),
166         N_("Beats/2"),
167         N_("Beats"),
168         N_("Bars"),
169         N_("Marks"),
170         N_("Region starts"),
171         N_("Region ends"),
172         N_("Region syncs"),
173         N_("Region bounds"),
174         0
175 };
176
177 static const gchar *_snap_mode_strings[] = {
178         N_("No Grid"),
179         N_("Grid"),
180         N_("Magnetic"),
181         0
182 };
183
184 static const gchar *_edit_point_strings[] = {
185         N_("Playhead"),
186         N_("Marker"),
187         N_("Mouse"),
188         0
189 };
190
191 static const gchar *_edit_mode_strings[] = {
192         N_("Slide"),
193         N_("Splice"),
194         N_("Ripple"),
195         N_("Lock"),
196         0
197 };
198
199 static const gchar *_zoom_focus_strings[] = {
200         N_("Left"),
201         N_("Right"),
202         N_("Center"),
203         N_("Playhead"),
204         N_("Mouse"),
205         N_("Edit point"),
206         0
207 };
208
209 #ifdef USE_RUBBERBAND
210 static const gchar *_rb_opt_strings[] = {
211         N_("Mushy"),
212         N_("Smooth"),
213         N_("Balanced multitimbral mixture"),
214         N_("Unpitched percussion with stable notes"),
215         N_("Crisp monophonic instrumental"),
216         N_("Unpitched solo percussion"),
217         N_("Resample without preserving pitch"),
218         0
219 };
220 #endif
221
222 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
223
224 static void
225 pane_size_watcher (Paned* pane)
226 {
227         /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
228            it is:
229
230               X: hard to access
231               Quartz: impossible to access
232               
233            so stop that by preventing it from ever getting too narrow. 35
234            pixels is basically a rough guess at the tab width.
235
236            ugh.
237         */
238
239         int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
240
241         gint pos = pane->get_position ();
242
243         if (pos > max_width_of_lhs) {
244                 pane->set_position (max_width_of_lhs);
245         }
246 }
247
248 Editor::Editor ()
249         : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
250
251           /* time display buttons */
252         , minsec_label (_("Mins:Secs"))
253         , bbt_label (_("Bars:Beats"))
254         , timecode_label (_("Timecode"))
255         , samples_label (_("Samples"))
256         , tempo_label (_("Tempo"))
257         , meter_label (_("Meter"))
258         , mark_label (_("Location Markers"))
259         , range_mark_label (_("Range Markers"))
260         , transport_mark_label (_("Loop/Punch Ranges"))
261         , cd_mark_label (_("CD Markers"))
262         , videotl_label (_("Video Timeline"))
263         , edit_packer (4, 4, true)
264
265           /* the values here don't matter: layout widgets
266              reset them as needed.
267           */
268
269         , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
270         , horizontal_adjustment (0.0, 0.0, 1e16)
271         , unused_adjustment (0.0, 0.0, 10.0, 400.0)
272
273         , controls_layout (unused_adjustment, vertical_adjustment)
274
275           /* tool bar related */
276
277         , toolbar_selection_clock_table (2,3)
278         , _mouse_mode_tearoff (0)
279         , automation_mode_button (_("mode"))
280         , _zoom_tearoff (0)
281         , _tools_tearoff (0)
282
283         , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
284
285           /* nudge */
286
287         , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
288         , meters_running(false)
289         , _pending_locate_request (false)
290         , _pending_initial_locate (false)
291         , _last_cut_copy_source_track (0)
292
293         , _region_selection_change_updates_region_list (true)
294         , _following_mixer_selection (false)
295         , _control_point_toggled_on_press (false)
296         , _stepping_axis_view (0)
297 {
298         constructed = false;
299
300         /* we are a singleton */
301
302         PublicEditor::_instance = this;
303
304         _have_idled = false;
305         
306         selection = new Selection (this);
307         cut_buffer = new Selection (this);
308
309         clicked_regionview = 0;
310         clicked_axisview = 0;
311         clicked_routeview = 0;
312         clicked_control_point = 0;
313         last_update_frame = 0;
314         pre_press_cursor = 0;
315         last_paste_pos = 0;
316         paste_count = 0;
317         _drags = new DragManager (this);
318         lock_dialog = 0;
319         ruler_dialog = 0;
320         current_mixer_strip = 0;
321         tempo_lines = 0;
322
323         snap_type_strings =  I18N (_snap_type_strings);
324         snap_mode_strings =  I18N (_snap_mode_strings);
325         zoom_focus_strings = I18N (_zoom_focus_strings);
326         edit_mode_strings = I18N (_edit_mode_strings);
327         edit_point_strings = I18N (_edit_point_strings);
328 #ifdef USE_RUBBERBAND
329         rb_opt_strings = I18N (_rb_opt_strings);
330         rb_current_opt = 4;
331 #endif
332
333         build_edit_mode_menu();
334         build_zoom_focus_menu();
335         build_track_count_menu();
336         build_snap_mode_menu();
337         build_snap_type_menu();
338         build_edit_point_menu();
339
340         snap_threshold = 5.0;
341         bbt_beat_subdivision = 4;
342         _visible_canvas_width = 0;
343         _visible_canvas_height = 0;
344         autoscroll_horizontal_allowed = false;
345         autoscroll_vertical_allowed = false;
346         logo_item = 0;
347
348         analysis_window = 0;
349
350         current_interthread_info = 0;
351         _show_measures = true;
352         _maximised = false;
353         show_gain_after_trim = false;
354
355         have_pending_keyboard_selection = false;
356         _follow_playhead = true;
357         _stationary_playhead = false;
358         editor_ruler_menu = 0;
359         no_ruler_shown_update = false;
360         marker_menu = 0;
361         range_marker_menu = 0;
362         marker_menu_item = 0;
363         tempo_or_meter_marker_menu = 0;
364         transport_marker_menu = 0;
365         new_transport_marker_menu = 0;
366         editor_mixer_strip_width = Wide;
367         show_editor_mixer_when_tracks_arrive = false;
368         region_edit_menu_split_multichannel_item = 0;
369         region_edit_menu_split_item = 0;
370         temp_location = 0;
371         leftmost_frame = 0;
372         current_stepping_trackview = 0;
373         entered_track = 0;
374         entered_regionview = 0;
375         entered_marker = 0;
376         clear_entered_track = false;
377         current_timefx = 0;
378         playhead_cursor = 0;
379         button_release_can_deselect = true;
380         _dragging_playhead = false;
381         _dragging_edit_point = false;
382         select_new_marker = false;
383         rhythm_ferret = 0;
384         layering_order_editor = 0;
385         no_save_visual = false;
386         resize_idle_id = -1;
387         within_track_canvas = false;
388
389         scrubbing_direction = 0;
390
391         sfbrowser = 0;
392
393         location_marker_color = ARDOUR_UI::config()->get_LocationMarker();
394         location_range_color = ARDOUR_UI::config()->get_LocationRange();
395         location_cd_marker_color = ARDOUR_UI::config()->get_LocationCDMarker();
396         location_loop_color = ARDOUR_UI::config()->get_LocationLoop();
397         location_punch_color = ARDOUR_UI::config()->get_LocationPunch();
398
399         zoom_focus = ZoomFocusLeft;
400         _edit_point = EditAtMouse;
401         _internal_editing = false;
402         current_canvas_cursor = 0;
403         _visible_track_count = -1;
404
405         samples_per_pixel = 2048; /* too early to use reset_zoom () */
406
407         _scroll_callbacks = 0;
408
409         bbt_label.set_name ("EditorRulerLabel");
410         bbt_label.set_size_request (-1, (int)timebar_height);
411         bbt_label.set_alignment (1.0, 0.5);
412         bbt_label.set_padding (5,0);
413         bbt_label.hide ();
414         bbt_label.set_no_show_all();
415         minsec_label.set_name ("EditorRulerLabel");
416         minsec_label.set_size_request (-1, (int)timebar_height);
417         minsec_label.set_alignment (1.0, 0.5);
418         minsec_label.set_padding (5,0);
419         minsec_label.hide ();
420         minsec_label.set_no_show_all();
421         timecode_label.set_name ("EditorRulerLabel");
422         timecode_label.set_size_request (-1, (int)timebar_height);
423         timecode_label.set_alignment (1.0, 0.5);
424         timecode_label.set_padding (5,0);
425         timecode_label.hide ();
426         timecode_label.set_no_show_all();
427         samples_label.set_name ("EditorRulerLabel");
428         samples_label.set_size_request (-1, (int)timebar_height);
429         samples_label.set_alignment (1.0, 0.5);
430         samples_label.set_padding (5,0);
431         samples_label.hide ();
432         samples_label.set_no_show_all();
433
434         tempo_label.set_name ("EditorRulerLabel");
435         tempo_label.set_size_request (-1, (int)timebar_height);
436         tempo_label.set_alignment (1.0, 0.5);
437         tempo_label.set_padding (5,0);
438         tempo_label.hide();
439         tempo_label.set_no_show_all();
440
441         meter_label.set_name ("EditorRulerLabel");
442         meter_label.set_size_request (-1, (int)timebar_height);
443         meter_label.set_alignment (1.0, 0.5);
444         meter_label.set_padding (5,0);
445         meter_label.hide();
446         meter_label.set_no_show_all();
447
448         if (Profile->get_trx()) {
449                 mark_label.set_text (_("Markers"));
450         }
451         mark_label.set_name ("EditorRulerLabel");
452         mark_label.set_size_request (-1, (int)timebar_height);
453         mark_label.set_alignment (1.0, 0.5);
454         mark_label.set_padding (5,0);
455         mark_label.hide();
456         mark_label.set_no_show_all();
457
458         cd_mark_label.set_name ("EditorRulerLabel");
459         cd_mark_label.set_size_request (-1, (int)timebar_height);
460         cd_mark_label.set_alignment (1.0, 0.5);
461         cd_mark_label.set_padding (5,0);
462         cd_mark_label.hide();
463         cd_mark_label.set_no_show_all();
464
465         videotl_bar_height = 4;
466         videotl_label.set_name ("EditorRulerLabel");
467         videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
468         videotl_label.set_alignment (1.0, 0.5);
469         videotl_label.set_padding (5,0);
470         videotl_label.hide();
471         videotl_label.set_no_show_all();
472
473         range_mark_label.set_name ("EditorRulerLabel");
474         range_mark_label.set_size_request (-1, (int)timebar_height);
475         range_mark_label.set_alignment (1.0, 0.5);
476         range_mark_label.set_padding (5,0);
477         range_mark_label.hide();
478         range_mark_label.set_no_show_all();
479
480         transport_mark_label.set_name ("EditorRulerLabel");
481         transport_mark_label.set_size_request (-1, (int)timebar_height);
482         transport_mark_label.set_alignment (1.0, 0.5);
483         transport_mark_label.set_padding (5,0);
484         transport_mark_label.hide();
485         transport_mark_label.set_no_show_all();
486
487         initialize_canvas ();
488
489         CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
490
491         _summary = new EditorSummary (this);
492
493         selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
494         selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
495
496         editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
497
498         selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
499         selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
500
501         edit_controls_vbox.set_spacing (0);
502         vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
503         _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
504
505         HBox* h = manage (new HBox);
506         _group_tabs = new EditorGroupTabs (this);
507         if (!ARDOUR::Profile->get_trx()) {
508                 h->pack_start (*_group_tabs, PACK_SHRINK);
509         }
510         h->pack_start (edit_controls_vbox);
511         controls_layout.add (*h);
512
513         controls_layout.set_name ("EditControlsBase");
514         controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
515         controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
516         controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
517
518         _cursors = new MouseCursors;
519         _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
520         cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
521
522         ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
523
524         ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
525         pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
526         pad_line_1->set_outline_color (0xFF0000FF);
527         pad_line_1->show();
528
529         // CAIROCANVAS
530         time_pad->show();
531
532         edit_packer.set_col_spacings (0);
533         edit_packer.set_row_spacings (0);
534         edit_packer.set_homogeneous (false);
535         edit_packer.set_border_width (0);
536         edit_packer.set_name ("EditorWindow");
537
538         time_bars_event_box.add (time_bars_vbox);
539         time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
540         time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
541
542         /* labels for the time bars */
543         edit_packer.attach (time_bars_event_box,     0, 1, 0, 1,    FILL,        SHRINK, 0, 0);
544         /* track controls */
545         edit_packer.attach (controls_layout,         0, 1, 1, 2,    FILL,        FILL|EXPAND, 0, 0);
546         /* canvas */
547         edit_packer.attach (*_track_canvas_viewport,  1, 2, 0, 2,    FILL|EXPAND, FILL|EXPAND, 0, 0);
548
549         bottom_hbox.set_border_width (2);
550         bottom_hbox.set_spacing (3);
551
552         _route_groups = new EditorRouteGroups (this);
553         _routes = new EditorRoutes (this);
554         _regions = new EditorRegions (this);
555         _snapshots = new EditorSnapshots (this);
556         _locations = new EditorLocations (this);
557
558         /* these are static location signals */
559
560         Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
561         Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
562         Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
563
564         add_notebook_page (_("Regions"), _regions->widget ());
565         add_notebook_page (_("Tracks & Busses"), _routes->widget ());
566         add_notebook_page (_("Snapshots"), _snapshots->widget ());
567         add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
568         add_notebook_page (_("Ranges & Marks"), _locations->widget ());
569
570         _the_notebook.set_show_tabs (true);
571         _the_notebook.set_scrollable (true);
572         _the_notebook.popup_disable ();
573         _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
574         _the_notebook.show_all ();
575
576         _notebook_shrunk = false;
577
578         editor_summary_pane.pack1(edit_packer);
579
580         Button* summary_arrows_left_left = manage (new Button);
581         summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
582         summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
583         summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
584
585         Button* summary_arrows_left_right = manage (new Button);
586         summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
587         summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
588         summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
589
590         VBox* summary_arrows_left = manage (new VBox);
591         summary_arrows_left->pack_start (*summary_arrows_left_left);
592         summary_arrows_left->pack_start (*summary_arrows_left_right);
593
594         Button* summary_arrows_right_up = manage (new Button);
595         summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
596         summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
597         summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
598
599         Button* summary_arrows_right_down = manage (new Button);
600         summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
601         summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
602         summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
603
604         VBox* summary_arrows_right = manage (new VBox);
605         summary_arrows_right->pack_start (*summary_arrows_right_up);
606         summary_arrows_right->pack_start (*summary_arrows_right_down);
607
608         Frame* summary_frame = manage (new Frame);
609         summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
610
611         summary_frame->add (*_summary);
612         summary_frame->show ();
613
614         _summary_hbox.pack_start (*summary_arrows_left, false, false);
615         _summary_hbox.pack_start (*summary_frame, true, true);
616         _summary_hbox.pack_start (*summary_arrows_right, false, false);
617
618         if (!ARDOUR::Profile->get_trx()) {
619                 editor_summary_pane.pack2 (_summary_hbox);
620         }
621
622         edit_pane.pack1 (editor_summary_pane, true, true);
623         if (!ARDOUR::Profile->get_trx()) {
624                 edit_pane.pack2 (_the_notebook, false, true);
625         }
626
627         editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
628
629         /* XXX: editor_summary_pane might need similar to the edit_pane */
630
631         edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
632
633         Glib::PropertyProxy<int> proxy = edit_pane.property_position();
634         proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
635
636         top_hbox.pack_start (toolbar_frame);
637
638         HBox *hbox = manage (new HBox);
639         hbox->pack_start (edit_pane, true, true);
640
641         global_vpacker.pack_start (top_hbox, false, false);
642         global_vpacker.pack_start (*hbox, true, true);
643
644         global_hpacker.pack_start (global_vpacker, true, true);
645
646         set_name ("EditorWindow");
647         add_accel_group (ActionManager::ui_manager->get_accel_group());
648
649         status_bar_hpacker.show ();
650
651         vpacker.pack_end (status_bar_hpacker, false, false);
652         vpacker.pack_end (global_hpacker, true, true);
653
654         /* register actions now so that set_state() can find them and set toggles/checks etc */
655
656         register_actions ();
657         /* when we start using our own keybinding system for the editor, this
658          * will be uncommented
659          */
660         // load_bindings ();
661
662         setup_toolbar ();
663
664         set_zoom_focus (zoom_focus);
665         set_visible_track_count (_visible_track_count);
666         _snap_type = SnapToBeat;
667         set_snap_to (_snap_type);
668         _snap_mode = SnapOff;
669         set_snap_mode (_snap_mode);
670         set_mouse_mode (MouseObject, true);
671         pre_internal_mouse_mode = MouseObject;
672         pre_internal_snap_type = _snap_type;
673         pre_internal_snap_mode = _snap_mode;
674         internal_snap_type = _snap_type;
675         internal_snap_mode = _snap_mode;
676         set_edit_point_preference (EditAtMouse, true);
677
678         _playlist_selector = new PlaylistSelector();
679         _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
680
681         RegionView::RegionViewGoingAway.connect (*this, invalidator (*this),  boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
682
683         /* nudge stuff */
684
685         nudge_forward_button.set_name ("nudge button");
686         nudge_forward_button.set_image(::get_icon("nudge_right"));
687
688         nudge_backward_button.set_name ("nudge button");
689         nudge_backward_button.set_image(::get_icon("nudge_left"));
690
691         fade_context_menu.set_name ("ArdourContextMenu");
692
693         /* icons, titles, WM stuff */
694
695         list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
696         Glib::RefPtr<Gdk::Pixbuf> icon;
697
698         if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
699                 window_icons.push_back (icon);
700         }
701         if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
702                 window_icons.push_back (icon);
703         }
704         if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
705                 window_icons.push_back (icon);
706         }
707         if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
708                 window_icons.push_back (icon);
709         }
710         if (!window_icons.empty()) {
711                 // set_icon_list (window_icons);
712                 set_default_icon_list (window_icons);
713         }
714
715         WindowTitle title(Glib::get_application_name());
716         title += _("Editor");
717         set_title (title.get_string());
718         set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
719
720         add (vpacker);
721         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
722
723         signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
724         signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
725
726         Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
727         
728         /* allow external control surfaces/protocols to do various things */
729
730         ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
731         ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
732         ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
733         ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
734         ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
735         ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
736         ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
737         ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
738         ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
739         ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
740         ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
741         ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
742         ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
743         ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
744
745         ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
746         ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
747         ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
748         ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
749         ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
750
751         BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
752
753         /* problematic: has to return a value and thus cannot be x-thread */
754
755         Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
756
757         Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
758         ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
759
760         TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
761
762         _ignore_region_action = false;
763         _last_region_menu_was_main = false;
764         _popup_region_menu_item = 0;
765
766         _ignore_follow_edits = false;
767
768         _show_marker_lines = false;
769
770         /* Button bindings */
771
772         button_bindings = new Bindings;
773
774         XMLNode* node = button_settings();
775         if (node) {
776                 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
777                         button_bindings->load (**i);
778                 }
779         }
780
781         constructed = true;
782
783         /* grab current parameter state */
784         boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
785         ARDOUR_UI::config()->map_parameters (pc);
786
787         setup_fade_images ();
788
789         instant_save ();
790 }
791
792 Editor::~Editor()
793 {
794         delete button_bindings;
795         delete _routes;
796         delete _route_groups;
797         delete _track_canvas_viewport;
798         delete _drags;
799         delete nudge_clock;
800 }
801
802 XMLNode*
803 Editor::button_settings () const
804 {
805         XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
806         XMLNode* node = find_named_node (*settings, X_("Buttons"));
807
808         if (!node) {
809                 node = new XMLNode (X_("Buttons"));
810         }
811
812         return node;
813 }
814
815 void
816 Editor::add_toplevel_menu (Container& cont)
817 {
818         vpacker.pack_start (cont, false, false);
819         cont.show_all ();
820 }
821
822 void
823 Editor::add_transport_frame (Container& cont)
824 {
825         if(ARDOUR::Profile->get_mixbus()) {
826                 global_vpacker.pack_start (cont, false, false);
827                 global_vpacker.reorder_child (cont, 0);
828                 cont.show_all ();
829         } else {
830                 vpacker.pack_start (cont, false, false);
831         }
832 }
833
834 bool
835 Editor::get_smart_mode () const
836 {
837         return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
838 }
839
840 void
841 Editor::catch_vanishing_regionview (RegionView *rv)
842 {
843         /* note: the selection will take care of the vanishing
844            audioregionview by itself.
845         */
846
847         if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
848                 _drags->abort ();
849         }
850
851         if (clicked_regionview == rv) {
852                 clicked_regionview = 0;
853         }
854
855         if (entered_regionview == rv) {
856                 set_entered_regionview (0);
857         }
858
859         if (!_all_region_actions_sensitized) {
860                 sensitize_all_region_actions (true);
861         }
862 }
863
864 void
865 Editor::set_entered_regionview (RegionView* rv)
866 {
867         if (rv == entered_regionview) {
868                 return;
869         }
870
871         if (entered_regionview) {
872                 entered_regionview->exited ();
873         }
874
875         entered_regionview = rv;
876
877         if (entered_regionview  != 0) {
878                 entered_regionview->entered (internal_editing ());
879         }
880
881         if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
882                 /* This RegionView entry might have changed what region actions
883                    are allowed, so sensitize them all in case a key is pressed.
884                 */
885                 sensitize_all_region_actions (true);
886         }
887 }
888
889 void
890 Editor::set_entered_track (TimeAxisView* tav)
891 {
892         if (entered_track) {
893                 entered_track->exited ();
894         }
895
896         entered_track = tav;
897
898         if (entered_track) {
899                 entered_track->entered ();
900         }
901 }
902
903 void
904 Editor::show_window ()
905 {
906         if (!is_visible ()) {
907                 DisplaySuspender ds;
908                 show_all ();
909
910                 /* XXX: this is a bit unfortunate; it would probably
911                    be nicer if we could just call show () above rather
912                    than needing the show_all ()
913                 */
914
915                 /* re-hide stuff if necessary */
916                 editor_list_button_toggled ();
917                 parameter_changed ("show-summary");
918                 parameter_changed ("show-group-tabs");
919                 parameter_changed ("show-zoom-tools");
920
921                 /* now reset all audio_time_axis heights, because widgets might need
922                    to be re-hidden
923                 */
924
925                 TimeAxisView *tv;
926
927                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
928                         tv = (static_cast<TimeAxisView*>(*i));
929                         tv->reset_height ();
930                 }
931
932                 if (current_mixer_strip) {
933                         current_mixer_strip->hide_things ();
934                         current_mixer_strip->parameter_changed ("mixer-element-visibility");
935                 }
936         }
937
938         present ();
939 }
940
941 void
942 Editor::instant_save ()
943 {
944         if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
945                 return;
946         }
947
948         if (_session) {
949                 _session->add_instant_xml(get_state());
950         } else {
951                 Config->add_instant_xml(get_state());
952         }
953 }
954
955 void
956 Editor::control_vertical_zoom_in_all ()
957 {
958         tav_zoom_smooth (false, true);
959 }
960
961 void
962 Editor::control_vertical_zoom_out_all ()
963 {
964         tav_zoom_smooth (true, true);
965 }
966
967 void
968 Editor::control_vertical_zoom_in_selected ()
969 {
970         tav_zoom_smooth (false, false);
971 }
972
973 void
974 Editor::control_vertical_zoom_out_selected ()
975 {
976         tav_zoom_smooth (true, false);
977 }
978
979 void
980 Editor::control_view (uint32_t view)
981 {
982         goto_visual_state (view);
983 }
984
985 void
986 Editor::control_unselect ()
987 {
988         selection->clear_tracks ();
989 }
990
991 void
992 Editor::control_select (uint32_t rid, Selection::Operation op) 
993 {
994         /* handles the (static) signal from the ControlProtocol class that
995          * requests setting the selected track to a given RID
996          */
997          
998         if (!_session) {
999                 return;
1000         }
1001
1002         boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1003
1004         if (!r) {
1005                 return;
1006         }
1007
1008         TimeAxisView* tav = axis_view_from_route (r);
1009
1010         if (tav) {
1011                 switch (op) {
1012                 case Selection::Add:
1013                         selection->add (tav);
1014                         break;
1015                 case Selection::Toggle:
1016                         selection->toggle (tav);
1017                         break;
1018                 case Selection::Extend:
1019                         break;
1020                 case Selection::Set:
1021                         selection->set (tav);
1022                         break;
1023                 }
1024         } else {
1025                 selection->clear_tracks ();
1026         }
1027 }
1028
1029 void
1030 Editor::control_step_tracks_up ()
1031 {
1032         scroll_tracks_up_line ();
1033 }
1034
1035 void
1036 Editor::control_step_tracks_down ()
1037 {
1038         scroll_tracks_down_line ();
1039 }
1040
1041 void
1042 Editor::control_scroll (float fraction)
1043 {
1044         ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1045
1046         if (!_session) {
1047                 return;
1048         }
1049
1050         double step = fraction * current_page_samples();
1051
1052         /*
1053                 _control_scroll_target is an optional<T>
1054
1055                 it acts like a pointer to an framepos_t, with
1056                 a operator conversion to boolean to check
1057                 that it has a value could possibly use
1058                 playhead_cursor->current_frame to store the
1059                 value and a boolean in the class to know
1060                 when it's out of date
1061         */
1062
1063         if (!_control_scroll_target) {
1064                 _control_scroll_target = _session->transport_frame();
1065                 _dragging_playhead = true;
1066         }
1067
1068         if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1069                 *_control_scroll_target = 0;
1070         } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1071                 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1072         } else {
1073                 *_control_scroll_target += (framepos_t) trunc (step);
1074         }
1075
1076         /* move visuals, we'll catch up with it later */
1077
1078         playhead_cursor->set_position (*_control_scroll_target);
1079         UpdateAllTransportClocks (*_control_scroll_target);
1080
1081         if (*_control_scroll_target > (current_page_samples() / 2)) {
1082                 /* try to center PH in window */
1083                 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1084         } else {
1085                 reset_x_origin (0);
1086         }
1087
1088         /*
1089                 Now we do a timeout to actually bring the session to the right place
1090                 according to the playhead. This is to avoid reading disk buffers on every
1091                 call to control_scroll, which is driven by ScrollTimeline and therefore
1092                 probably by a control surface wheel which can generate lots of events.
1093         */
1094         /* cancel the existing timeout */
1095
1096         control_scroll_connection.disconnect ();
1097
1098         /* add the next timeout */
1099
1100         control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1101 }
1102
1103 bool
1104 Editor::deferred_control_scroll (framepos_t /*target*/)
1105 {
1106         _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1107         // reset for next stream
1108         _control_scroll_target = boost::none;
1109         _dragging_playhead = false;
1110         return false;
1111 }
1112
1113 void
1114 Editor::access_action (std::string action_group, std::string action_item)
1115 {
1116         if (!_session) {
1117                 return;
1118         }
1119
1120         ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1121
1122         RefPtr<Action> act;
1123         act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1124
1125         if (act) {
1126                 act->activate();
1127         }
1128 }
1129
1130 void
1131 Editor::on_realize ()
1132 {
1133         Window::on_realize ();
1134         Realized ();
1135
1136         if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1137                 start_lock_event_timing ();
1138         }
1139
1140         signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1141 }
1142
1143 void
1144 Editor::start_lock_event_timing ()
1145 {
1146         /* check if we should lock the GUI every 30 seconds */
1147
1148         Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1149 }
1150
1151 bool
1152 Editor::generic_event_handler (GdkEvent* ev)
1153 {
1154         switch (ev->type) {
1155         case GDK_BUTTON_PRESS:
1156         case GDK_BUTTON_RELEASE:
1157         case GDK_MOTION_NOTIFY:
1158         case GDK_KEY_PRESS:
1159         case GDK_KEY_RELEASE:
1160                 gettimeofday (&last_event_time, 0);
1161                 break;
1162
1163         case GDK_LEAVE_NOTIFY:
1164                 switch (ev->crossing.detail) {
1165                 case GDK_NOTIFY_UNKNOWN:
1166                 case GDK_NOTIFY_INFERIOR:
1167                 case GDK_NOTIFY_ANCESTOR:
1168                         break; 
1169                 case GDK_NOTIFY_VIRTUAL:
1170                 case GDK_NOTIFY_NONLINEAR:
1171                 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1172                         /* leaving window, so reset focus, thus ending any and
1173                            all text entry operations.
1174                         */
1175                         reset_focus();
1176                         break;
1177                 }
1178                 break;
1179
1180         default:
1181                 break;
1182         }
1183
1184         return false;
1185 }
1186
1187 bool
1188 Editor::lock_timeout_callback ()
1189 {
1190         struct timeval now, delta;
1191
1192         gettimeofday (&now, 0);
1193
1194         timersub (&now, &last_event_time, &delta);
1195
1196         if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1197                 lock ();
1198                 /* don't call again. Returning false will effectively
1199                    disconnect us from the timer callback.
1200
1201                    unlock() will call start_lock_event_timing() to get things
1202                    started again.
1203                 */
1204                 return false;
1205         }
1206
1207         return true;
1208 }
1209
1210 void
1211 Editor::map_position_change (framepos_t frame)
1212 {
1213         ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1214
1215         if (_session == 0) {
1216                 return;
1217         }
1218
1219         if (_follow_playhead) {
1220                 center_screen (frame);
1221         }
1222
1223         playhead_cursor->set_position (frame);
1224 }
1225
1226 void
1227 Editor::center_screen (framepos_t frame)
1228 {
1229         framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1230
1231         /* if we're off the page, then scroll.
1232          */
1233
1234         if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1235                 center_screen_internal (frame, page);
1236         }
1237 }
1238
1239 void
1240 Editor::center_screen_internal (framepos_t frame, float page)
1241 {
1242         page /= 2;
1243
1244         if (frame > page) {
1245                 frame -= (framepos_t) page;
1246         } else {
1247                 frame = 0;
1248         }
1249
1250         reset_x_origin (frame);
1251 }
1252
1253
1254 void
1255 Editor::update_title ()
1256 {
1257         ENSURE_GUI_THREAD (*this, &Editor::update_title)
1258
1259         if (_session) {
1260                 bool dirty = _session->dirty();
1261
1262                 string session_name;
1263
1264                 if (_session->snap_name() != _session->name()) {
1265                         session_name = _session->snap_name();
1266                 } else {
1267                         session_name = _session->name();
1268                 }
1269
1270                 if (dirty) {
1271                         session_name = "*" + session_name;
1272                 }
1273
1274                 WindowTitle title(session_name);
1275                 title += Glib::get_application_name();
1276                 set_title (title.get_string());
1277         } else {
1278                 /* ::session_going_away() will have taken care of it */
1279         }
1280 }
1281
1282 void
1283 Editor::set_session (Session *t)
1284 {
1285         SessionHandlePtr::set_session (t);
1286
1287         if (!_session) {
1288                 return;
1289         }
1290
1291         _playlist_selector->set_session (_session);
1292         nudge_clock->set_session (_session);
1293         _summary->set_session (_session);
1294         _group_tabs->set_session (_session);
1295         _route_groups->set_session (_session);
1296         _regions->set_session (_session);
1297         _snapshots->set_session (_session);
1298         _routes->set_session (_session);
1299         _locations->set_session (_session);
1300
1301         if (rhythm_ferret) {
1302                 rhythm_ferret->set_session (_session);
1303         }
1304
1305         if (analysis_window) {
1306                 analysis_window->set_session (_session);
1307         }
1308
1309         if (sfbrowser) {
1310                 sfbrowser->set_session (_session);
1311         }
1312
1313         compute_fixed_ruler_scale ();
1314
1315         /* Make sure we have auto loop and auto punch ranges */
1316
1317         Location* loc = _session->locations()->auto_loop_location();
1318         if (loc != 0) {
1319                 loc->set_name (_("Loop"));
1320         }
1321
1322         loc = _session->locations()->auto_punch_location();
1323         if (loc != 0) {
1324                 // force name
1325                 loc->set_name (_("Punch"));
1326         }
1327
1328         refresh_location_display ();
1329
1330         /* This must happen after refresh_location_display(), as (amongst other things) we restore
1331            the selected Marker; this needs the LocationMarker list to be available.
1332         */
1333         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1334         set_state (*node, Stateful::loading_state_version);
1335
1336         /* catch up with the playhead */
1337
1338         _session->request_locate (playhead_cursor->current_frame ());
1339         _pending_initial_locate = true;
1340
1341         update_title ();
1342
1343         /* These signals can all be emitted by a non-GUI thread. Therefore the
1344            handlers for them must not attempt to directly interact with the GUI,
1345            but use PBD::Signal<T>::connect() which accepts an event loop
1346            ("context") where the handler will be asked to run.
1347         */
1348
1349         _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1350         _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1351         _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1352         _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1353         _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1354         _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1355         _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1356         _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1357         _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1358         _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1359         _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1360         _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1361         _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1362
1363         playhead_cursor->show ();
1364
1365         boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1366         Config->map_parameters (pc);
1367         _session->config.map_parameters (pc);
1368
1369         restore_ruler_visibility ();
1370         //tempo_map_changed (PropertyChange (0));
1371         _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1372
1373         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1374                 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1375         }
1376
1377         super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1378                 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1379                 );
1380
1381         switch (_snap_type) {
1382         case SnapToRegionStart:
1383         case SnapToRegionEnd:
1384         case SnapToRegionSync:
1385         case SnapToRegionBoundary:
1386                 build_region_boundary_cache ();
1387                 break;
1388
1389         default:
1390                 break;
1391         }
1392
1393         /* register for undo history */
1394         _session->register_with_memento_command_factory(id(), this);
1395
1396         ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1397
1398         start_updating_meters ();
1399 }
1400
1401 void
1402 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1403 {
1404         if (a->get_name() == "RegionMenu") {
1405                 /* When the main menu's region menu is opened, we setup the actions so that they look right
1406                    in the menu.  I can't find a way of getting a signal when this menu is subsequently closed,
1407                    so we resensitize all region actions when the entered regionview or the region selection
1408                    changes.  HOWEVER we can't always resensitize on entered_regionview change because that
1409                    happens after the region context menu is opened.  So we set a flag here, too.
1410
1411                    What a carry on :(
1412                 */
1413                 sensitize_the_right_region_actions ();
1414                 _last_region_menu_was_main = true;
1415         }
1416 }
1417
1418 void
1419 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1420 {
1421         using namespace Menu_Helpers;
1422
1423         void (Editor::*emf)(FadeShape);
1424         std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1425
1426         if (start) {
1427                 images = &_xfade_in_images;
1428                 emf = &Editor::set_fade_in_shape;
1429         } else {
1430                 images = &_xfade_out_images;
1431                 emf = &Editor::set_fade_out_shape;
1432         }
1433
1434         items.push_back (
1435                 ImageMenuElem (
1436                         _("Linear (for highly correlated material)"),
1437                         *(*images)[FadeLinear],
1438                         sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1439                         )
1440                 );
1441         
1442         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1443         
1444         items.push_back (
1445                 ImageMenuElem (
1446                         _("Constant power"),
1447                         *(*images)[FadeConstantPower],
1448                         sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1449                         ));
1450         
1451         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1452         
1453         items.push_back (
1454                 ImageMenuElem (
1455                         _("Symmetric"),
1456                         *(*images)[FadeSymmetric],
1457                         sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1458                         )
1459                 );
1460         
1461         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1462         
1463         items.push_back (
1464                 ImageMenuElem (
1465                         _("Slow"),
1466                         *(*images)[FadeSlow],
1467                         sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1468                         ));
1469         
1470         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1471         
1472         items.push_back (
1473                 ImageMenuElem (
1474                         _("Fast"),
1475                         *(*images)[FadeFast],
1476                         sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1477                         ));
1478         
1479         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1480 }
1481
1482 /** Pop up a context menu for when the user clicks on a start crossfade */
1483 void
1484 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1485 {
1486         using namespace Menu_Helpers;
1487         AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1488         assert(arv);
1489
1490         MenuList& items (xfade_in_context_menu.items());
1491         items.clear ();
1492
1493         if (arv->audio_region()->fade_in_active()) {
1494                 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1495         } else {
1496                 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1497         }
1498
1499         items.push_back (SeparatorElem());
1500         fill_xfade_menu (items, true);
1501
1502         xfade_in_context_menu.popup (button, time);
1503 }
1504
1505 /** Pop up a context menu for when the user clicks on an end crossfade */
1506 void
1507 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1508 {
1509         using namespace Menu_Helpers;
1510         AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1511         assert(arv);
1512
1513         MenuList& items (xfade_out_context_menu.items());
1514         items.clear ();
1515
1516         if (arv->audio_region()->fade_out_active()) {
1517                 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1518         } else {
1519                 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1520         }
1521
1522         items.push_back (SeparatorElem());
1523         fill_xfade_menu (items, false);
1524
1525         xfade_out_context_menu.popup (button, time);
1526 }
1527
1528 void
1529 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1530 {
1531         using namespace Menu_Helpers;
1532         Menu* (Editor::*build_menu_function)();
1533         Menu *menu;
1534
1535         switch (item_type) {
1536         case RegionItem:
1537         case RegionViewName:
1538         case RegionViewNameHighlight:
1539         case LeftFrameHandle:
1540         case RightFrameHandle:
1541                 if (with_selection) {
1542                         build_menu_function = &Editor::build_track_selection_context_menu;
1543                 } else {
1544                         build_menu_function = &Editor::build_track_region_context_menu;
1545                 }
1546                 break;
1547
1548         case SelectionItem:
1549                 if (with_selection) {
1550                         build_menu_function = &Editor::build_track_selection_context_menu;
1551                 } else {
1552                         build_menu_function = &Editor::build_track_context_menu;
1553                 }
1554                 break;
1555
1556         case StreamItem:
1557                 if (clicked_routeview->track()) {
1558                         build_menu_function = &Editor::build_track_context_menu;
1559                 } else {
1560                         build_menu_function = &Editor::build_track_bus_context_menu;
1561                 }
1562                 break;
1563
1564         default:
1565                 /* probably shouldn't happen but if it does, we don't care */
1566                 return;
1567         }
1568
1569         menu = (this->*build_menu_function)();
1570         menu->set_name ("ArdourContextMenu");
1571
1572         /* now handle specific situations */
1573
1574         switch (item_type) {
1575         case RegionItem:
1576         case RegionViewName:
1577         case RegionViewNameHighlight:
1578         case LeftFrameHandle:
1579         case RightFrameHandle:
1580                 if (!with_selection) {
1581                         if (region_edit_menu_split_item) {
1582                                 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1583                                         ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1584                                 } else {
1585                                         ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1586                                 }
1587                         }
1588                         if (region_edit_menu_split_multichannel_item) {
1589                                 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1590                                         region_edit_menu_split_multichannel_item->set_sensitive (true);
1591                                 } else {
1592                                         region_edit_menu_split_multichannel_item->set_sensitive (false);
1593                                 }
1594                         }
1595                 }
1596                 break;
1597
1598         case SelectionItem:
1599                 break;
1600
1601         case StreamItem:
1602                 break;
1603
1604         default:
1605                 /* probably shouldn't happen but if it does, we don't care */
1606                 return;
1607         }
1608
1609         if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1610
1611                 /* Bounce to disk */
1612
1613                 using namespace Menu_Helpers;
1614                 MenuList& edit_items  = menu->items();
1615
1616                 edit_items.push_back (SeparatorElem());
1617
1618                 switch (clicked_routeview->audio_track()->freeze_state()) {
1619                 case AudioTrack::NoFreeze:
1620                         edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1621                         break;
1622
1623                 case AudioTrack::Frozen:
1624                         edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1625                         break;
1626
1627                 case AudioTrack::UnFrozen:
1628                         edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1629                         break;
1630                 }
1631
1632         }
1633
1634         if (item_type == StreamItem && clicked_routeview) {
1635                 clicked_routeview->build_underlay_menu(menu);
1636         }
1637
1638         /* When the region menu is opened, we setup the actions so that they look right
1639            in the menu.
1640         */
1641         sensitize_the_right_region_actions ();
1642         _last_region_menu_was_main = false;
1643
1644         menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1645         menu->popup (button, time);
1646 }
1647
1648 Menu*
1649 Editor::build_track_context_menu ()
1650 {
1651         using namespace Menu_Helpers;
1652
1653         MenuList& edit_items = track_context_menu.items();
1654         edit_items.clear();
1655
1656         add_dstream_context_items (edit_items);
1657         return &track_context_menu;
1658 }
1659
1660 Menu*
1661 Editor::build_track_bus_context_menu ()
1662 {
1663         using namespace Menu_Helpers;
1664
1665         MenuList& edit_items = track_context_menu.items();
1666         edit_items.clear();
1667
1668         add_bus_context_items (edit_items);
1669         return &track_context_menu;
1670 }
1671
1672 Menu*
1673 Editor::build_track_region_context_menu ()
1674 {
1675         using namespace Menu_Helpers;
1676         MenuList& edit_items  = track_region_context_menu.items();
1677         edit_items.clear();
1678
1679         /* we've just cleared the track region context menu, so the menu that these
1680            two items were on will have disappeared; stop them dangling.
1681         */
1682         region_edit_menu_split_item = 0;
1683         region_edit_menu_split_multichannel_item = 0;
1684
1685         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1686
1687         if (rtv) {
1688                 boost::shared_ptr<Track> tr;
1689                 boost::shared_ptr<Playlist> pl;
1690
1691                 if ((tr = rtv->track())) {
1692                         add_region_context_items (edit_items, tr);
1693                 }
1694         }
1695
1696         add_dstream_context_items (edit_items);
1697
1698         return &track_region_context_menu;
1699 }
1700
1701 void
1702 Editor::analyze_region_selection ()
1703 {
1704         if (analysis_window == 0) {
1705                 analysis_window = new AnalysisWindow();
1706
1707                 if (_session != 0)
1708                         analysis_window->set_session(_session);
1709
1710                 analysis_window->show_all();
1711         }
1712
1713         analysis_window->set_regionmode();
1714         analysis_window->analyze();
1715
1716         analysis_window->present();
1717 }
1718
1719 void
1720 Editor::analyze_range_selection()
1721 {
1722         if (analysis_window == 0) {
1723                 analysis_window = new AnalysisWindow();
1724
1725                 if (_session != 0)
1726                         analysis_window->set_session(_session);
1727
1728                 analysis_window->show_all();
1729         }
1730
1731         analysis_window->set_rangemode();
1732         analysis_window->analyze();
1733
1734         analysis_window->present();
1735 }
1736
1737 Menu*
1738 Editor::build_track_selection_context_menu ()
1739 {
1740         using namespace Menu_Helpers;
1741         MenuList& edit_items  = track_selection_context_menu.items();
1742         edit_items.clear ();
1743
1744         add_selection_context_items (edit_items);
1745         // edit_items.push_back (SeparatorElem());
1746         // add_dstream_context_items (edit_items);
1747
1748         return &track_selection_context_menu;
1749 }
1750
1751 void
1752 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1753 {
1754         using namespace Menu_Helpers;
1755
1756         /* OK, stick the region submenu at the top of the list, and then add
1757            the standard items.
1758         */
1759
1760         RegionSelection rs = get_regions_from_selection_and_entered ();
1761
1762         string::size_type pos = 0;
1763         string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1764
1765         /* we have to hack up the region name because "_" has a special
1766            meaning for menu titles.
1767         */
1768
1769         while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1770                 menu_item_name.replace (pos, 1, "__");
1771                 pos += 2;
1772         }
1773
1774         if (_popup_region_menu_item == 0) {
1775                 _popup_region_menu_item = new MenuItem (menu_item_name);
1776                 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1777                 _popup_region_menu_item->show ();
1778         } else {
1779                 _popup_region_menu_item->set_label (menu_item_name);
1780         }
1781
1782         const framepos_t position = get_preferred_edit_position (false, true);
1783
1784         edit_items.push_back (*_popup_region_menu_item);
1785         if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1786                 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1787         }
1788         edit_items.push_back (SeparatorElem());
1789 }
1790
1791 /** Add context menu items relevant to selection ranges.
1792  * @param edit_items List to add the items to.
1793  */
1794 void
1795 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1796 {
1797         using namespace Menu_Helpers;
1798
1799         edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1800         edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1801
1802         edit_items.push_back (SeparatorElem());
1803         edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1804
1805         edit_items.push_back (SeparatorElem());
1806         edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1807
1808         edit_items.push_back (SeparatorElem());
1809
1810         edit_items.push_back (
1811                 MenuElem (
1812                         _("Move Range Start to Previous Region Boundary"),
1813                         sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1814                         )
1815                 );
1816
1817         edit_items.push_back (
1818                 MenuElem (
1819                         _("Move Range Start to Next Region Boundary"),
1820                         sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1821                         )
1822                 );
1823
1824         edit_items.push_back (
1825                 MenuElem (
1826                         _("Move Range End to Previous Region Boundary"),
1827                         sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1828                         )
1829                 );
1830
1831         edit_items.push_back (
1832                 MenuElem (
1833                         _("Move Range End to Next Region Boundary"),
1834                         sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1835                         )
1836                 );
1837
1838         edit_items.push_back (SeparatorElem());
1839         edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1840         edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1841
1842         edit_items.push_back (SeparatorElem());
1843         edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1844
1845         edit_items.push_back (SeparatorElem());
1846         edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1847         edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1848
1849         edit_items.push_back (SeparatorElem());
1850         edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1851
1852         edit_items.push_back (SeparatorElem());
1853         edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1854         edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1855         edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1856
1857         edit_items.push_back (SeparatorElem());
1858         edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1859         edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1860         edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1861         edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1862         edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1863         if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1864                 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1865         }
1866 }
1867
1868
1869 void
1870 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1871 {
1872         using namespace Menu_Helpers;
1873
1874         /* Playback */
1875
1876         Menu *play_menu = manage (new Menu);
1877         MenuList& play_items = play_menu->items();
1878         play_menu->set_name ("ArdourContextMenu");
1879
1880         play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1881         play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1882         play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1883         play_items.push_back (SeparatorElem());
1884         play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1885
1886         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1887
1888         /* Selection */
1889
1890         Menu *select_menu = manage (new Menu);
1891         MenuList& select_items = select_menu->items();
1892         select_menu->set_name ("ArdourContextMenu");
1893
1894         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1895         select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1896         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1897         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1898         select_items.push_back (SeparatorElem());
1899         select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1900         select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1901         select_items.push_back (SeparatorElem());
1902         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1903         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1904         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1905         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1906         select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1907         select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1908         select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1909
1910         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1911
1912         /* Cut-n-Paste */
1913
1914         Menu *cutnpaste_menu = manage (new Menu);
1915         MenuList& cutnpaste_items = cutnpaste_menu->items();
1916         cutnpaste_menu->set_name ("ArdourContextMenu");
1917
1918         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1919         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1920         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1921
1922         cutnpaste_items.push_back (SeparatorElem());
1923
1924         cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1925         cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1926
1927         edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1928
1929         /* Adding new material */
1930
1931         edit_items.push_back (SeparatorElem());
1932         edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1933         edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1934
1935         /* Nudge track */
1936
1937         Menu *nudge_menu = manage (new Menu());
1938         MenuList& nudge_items = nudge_menu->items();
1939         nudge_menu->set_name ("ArdourContextMenu");
1940
1941         edit_items.push_back (SeparatorElem());
1942         nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1943         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1944         nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1945         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1946
1947         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1948 }
1949
1950 void
1951 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1952 {
1953         using namespace Menu_Helpers;
1954
1955         /* Playback */
1956
1957         Menu *play_menu = manage (new Menu);
1958         MenuList& play_items = play_menu->items();
1959         play_menu->set_name ("ArdourContextMenu");
1960
1961         play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1962         play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1963         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1964
1965         /* Selection */
1966
1967         Menu *select_menu = manage (new Menu);
1968         MenuList& select_items = select_menu->items();
1969         select_menu->set_name ("ArdourContextMenu");
1970
1971         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1972         select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1973         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1974         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1975         select_items.push_back (SeparatorElem());
1976         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1977         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1978         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1979         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1980
1981         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1982
1983         /* Cut-n-Paste */
1984
1985         Menu *cutnpaste_menu = manage (new Menu);
1986         MenuList& cutnpaste_items = cutnpaste_menu->items();
1987         cutnpaste_menu->set_name ("ArdourContextMenu");
1988
1989         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1990         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1991         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1992
1993         Menu *nudge_menu = manage (new Menu());
1994         MenuList& nudge_items = nudge_menu->items();
1995         nudge_menu->set_name ("ArdourContextMenu");
1996
1997         edit_items.push_back (SeparatorElem());
1998         nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1999         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2000         nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2001         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2002
2003         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2004 }
2005
2006 SnapType
2007 Editor::snap_type() const
2008 {
2009         return _snap_type;
2010 }
2011
2012 SnapMode
2013 Editor::snap_mode() const
2014 {
2015         return _snap_mode;
2016 }
2017
2018 void
2019 Editor::set_snap_to (SnapType st)
2020 {
2021         unsigned int snap_ind = (unsigned int)st;
2022
2023         _snap_type = st;
2024
2025         if (snap_ind > snap_type_strings.size() - 1) {
2026                 snap_ind = 0;
2027                 _snap_type = (SnapType)snap_ind;
2028         }
2029
2030         string str = snap_type_strings[snap_ind];
2031
2032         if (str != snap_type_selector.get_text()) {
2033                 snap_type_selector.set_text (str);
2034         }
2035
2036         instant_save ();
2037
2038         switch (_snap_type) {
2039         case SnapToBeatDiv128:
2040         case SnapToBeatDiv64:
2041         case SnapToBeatDiv32:
2042         case SnapToBeatDiv28:
2043         case SnapToBeatDiv24:
2044         case SnapToBeatDiv20:
2045         case SnapToBeatDiv16:
2046         case SnapToBeatDiv14:
2047         case SnapToBeatDiv12:
2048         case SnapToBeatDiv10:
2049         case SnapToBeatDiv8:
2050         case SnapToBeatDiv7:
2051         case SnapToBeatDiv6:
2052         case SnapToBeatDiv5:
2053         case SnapToBeatDiv4:
2054         case SnapToBeatDiv3:
2055         case SnapToBeatDiv2: {
2056                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2057                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2058                 
2059                 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2060                                             current_bbt_points_begin, current_bbt_points_end);
2061                 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2062                                          current_bbt_points_begin, current_bbt_points_end);
2063                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2064                 break;
2065         }
2066
2067         case SnapToRegionStart:
2068         case SnapToRegionEnd:
2069         case SnapToRegionSync:
2070         case SnapToRegionBoundary:
2071                 build_region_boundary_cache ();
2072                 break;
2073
2074         default:
2075                 /* relax */
2076                 break;
2077         }
2078
2079         SnapChanged (); /* EMIT SIGNAL */
2080 }
2081
2082 void
2083 Editor::set_snap_mode (SnapMode mode)
2084 {
2085         string str = snap_mode_strings[(int)mode];
2086
2087         if (_internal_editing) {
2088                 internal_snap_mode = mode;
2089         } else {
2090                 pre_internal_snap_mode = mode;
2091         }
2092
2093         _snap_mode = mode;
2094
2095         if (str != snap_mode_selector.get_text ()) {
2096                 snap_mode_selector.set_text (str);
2097         }
2098
2099         instant_save ();
2100 }
2101 void
2102 Editor::set_edit_point_preference (EditPoint ep, bool force)
2103 {
2104         bool changed = (_edit_point != ep);
2105
2106         _edit_point = ep;
2107         if (Profile->get_mixbus())
2108                 if (ep == EditAtSelectedMarker)
2109                         ep = EditAtPlayhead;
2110
2111         string str = edit_point_strings[(int)ep];
2112         if (str != edit_point_selector.get_text ()) {
2113                 edit_point_selector.set_text (str);
2114         }
2115
2116         reset_canvas_cursor ();
2117
2118         if (!force && !changed) {
2119                 return;
2120         }
2121
2122         const char* action=NULL;
2123
2124         switch (_edit_point) {
2125         case EditAtPlayhead:
2126                 action = "edit-at-playhead";
2127                 break;
2128         case EditAtSelectedMarker:
2129                 action = "edit-at-marker";
2130                 break;
2131         case EditAtMouse:
2132                 action = "edit-at-mouse";
2133                 break;
2134         }
2135
2136         Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2137         if (act) {
2138                 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2139         }
2140
2141         framepos_t foo;
2142         bool in_track_canvas;
2143
2144         if (!mouse_frame (foo, in_track_canvas)) {
2145                 in_track_canvas = false;
2146         }
2147
2148         reset_canvas_action_sensitivity (in_track_canvas);
2149
2150         instant_save ();
2151 }
2152
2153 int
2154 Editor::set_state (const XMLNode& node, int /*version*/)
2155 {
2156         const XMLProperty* prop;
2157         XMLNode* geometry;
2158         int x, y;
2159         Gdk::Geometry g;
2160
2161         set_id (node);
2162
2163         g.base_width = default_width;
2164         g.base_height = default_height;
2165         x = 1;
2166         y = 1;
2167
2168         if ((geometry = find_named_node (node, "geometry")) != 0) {
2169
2170                 XMLProperty* prop;
2171
2172                 if ((prop = geometry->property("x_size")) == 0) {
2173                         prop = geometry->property ("x-size");
2174                 }
2175                 if (prop) {
2176                         g.base_width = atoi(prop->value());
2177                 }
2178                 if ((prop = geometry->property("y_size")) == 0) {
2179                         prop = geometry->property ("y-size");
2180                 }
2181                 if (prop) {
2182                         g.base_height = atoi(prop->value());
2183                 }
2184
2185                 if ((prop = geometry->property ("x_pos")) == 0) {
2186                         prop = geometry->property ("x-pos");
2187                 }
2188                 if (prop) {
2189                         x = atoi (prop->value());
2190
2191                 }
2192                 if ((prop = geometry->property ("y_pos")) == 0) {
2193                         prop = geometry->property ("y-pos");
2194                 }
2195                 if (prop) {
2196                         y = atoi (prop->value());
2197                 }
2198         }
2199
2200         set_default_size (g.base_width, g.base_height);
2201         move (x, y);
2202
2203         if (_session && (prop = node.property ("playhead"))) {
2204                 framepos_t pos;
2205                 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2206                 if (pos >= 0) {
2207                         playhead_cursor->set_position (pos);
2208                 } else {
2209                         warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2210                         playhead_cursor->set_position (0);
2211                 }
2212         } else {
2213                 playhead_cursor->set_position (0);
2214         }
2215
2216         if ((prop = node.property ("mixer-width"))) {
2217                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2218         }
2219
2220         if ((prop = node.property ("zoom-focus"))) {
2221                 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2222         }
2223
2224         if ((prop = node.property ("zoom"))) {
2225                 /* older versions of ardour used floating point samples_per_pixel */
2226                 double f = PBD::atof (prop->value());
2227                 reset_zoom (llrintf (f));
2228         } else {
2229                 reset_zoom (samples_per_pixel);
2230         }
2231
2232         if ((prop = node.property ("visible-track-count"))) {
2233                 set_visible_track_count (PBD::atoi (prop->value()));
2234         }
2235
2236         if ((prop = node.property ("snap-to"))) {
2237                 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2238         }
2239
2240         if ((prop = node.property ("snap-mode"))) {
2241                 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2242         }
2243
2244         if ((prop = node.property ("internal-snap-to"))) {
2245                 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2246         }
2247
2248         if ((prop = node.property ("internal-snap-mode"))) {
2249                 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2250         }
2251
2252         if ((prop = node.property ("pre-internal-snap-to"))) {
2253                 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2254         }
2255
2256
2257         if ((prop = node.property ("pre-internal-snap-mode"))) {
2258                 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2259         }
2260
2261         if ((prop = node.property ("mouse-mode"))) {
2262                 MouseMode m = str2mousemode(prop->value());
2263                 set_mouse_mode (m, true);
2264         } else {
2265                 set_mouse_mode (MouseObject, true);
2266         }
2267
2268         if ((prop = node.property ("left-frame")) != 0) {
2269                 framepos_t pos;
2270                 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2271                         if (pos < 0) {
2272                                 pos = 0;
2273                         }
2274                         reset_x_origin (pos);
2275                 }
2276         }
2277
2278         if ((prop = node.property ("y-origin")) != 0) {
2279                 reset_y_origin (atof (prop->value ()));
2280         }
2281
2282         if ((prop = node.property ("internal-edit"))) {
2283                 bool yn = string_is_affirmative (prop->value());
2284                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2285                 if (act) {
2286                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2287                         tact->set_active (!yn);
2288                         tact->set_active (yn);
2289                 }
2290         }
2291
2292         if ((prop = node.property ("join-object-range"))) {
2293                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2294                 bool yn = string_is_affirmative (prop->value());
2295                 if (act) {
2296                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2297                         tact->set_active (!yn);
2298                         tact->set_active (yn);
2299                 }
2300                 set_mouse_mode(mouse_mode, true);
2301         }
2302
2303         if ((prop = node.property ("edit-point"))) {
2304                 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2305         }
2306
2307         if ((prop = node.property ("show-measures"))) {
2308                 bool yn = string_is_affirmative (prop->value());
2309                 _show_measures = yn;
2310                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2311                 if (act) {
2312                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2313                         /* do it twice to force the change */
2314                         tact->set_active (!yn);
2315                         tact->set_active (yn);
2316                 }
2317         }
2318
2319         if ((prop = node.property ("follow-playhead"))) {
2320                 bool yn = string_is_affirmative (prop->value());
2321                 set_follow_playhead (yn);
2322                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2323                 if (act) {
2324                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2325                         if (tact->get_active() != yn) {
2326                                 tact->set_active (yn);
2327                         }
2328                 }
2329         }
2330
2331         if ((prop = node.property ("stationary-playhead"))) {
2332                 bool yn = string_is_affirmative (prop->value());
2333                 set_stationary_playhead (yn);
2334                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2335                 if (act) {
2336                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2337                         if (tact->get_active() != yn) {
2338                                 tact->set_active (yn);
2339                         }
2340                 }
2341         }
2342
2343         if ((prop = node.property ("region-list-sort-type"))) {
2344                 RegionListSortType st;
2345                 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2346         }
2347
2348         if ((prop = node.property ("show-editor-mixer"))) {
2349
2350                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2351                 assert (act);
2352
2353                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2354                 bool yn = string_is_affirmative (prop->value());
2355
2356                 /* do it twice to force the change */
2357
2358                 tact->set_active (!yn);
2359                 tact->set_active (yn);
2360         }
2361
2362         if ((prop = node.property ("show-editor-list"))) {
2363
2364                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2365                 assert (act);
2366
2367                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2368                 bool yn = string_is_affirmative (prop->value());
2369
2370                 /* do it twice to force the change */
2371
2372                 tact->set_active (!yn);
2373                 tact->set_active (yn);
2374         }
2375
2376         if ((prop = node.property (X_("editor-list-page")))) {
2377                 _the_notebook.set_current_page (atoi (prop->value ()));
2378         }
2379
2380         if ((prop = node.property (X_("show-marker-lines")))) {
2381                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2382                 assert (act);
2383                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2384                 bool yn = string_is_affirmative (prop->value ());
2385
2386                 tact->set_active (!yn);
2387                 tact->set_active (yn);
2388         }
2389
2390         XMLNodeList children = node.children ();
2391         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2392                 selection->set_state (**i, Stateful::current_state_version);
2393                 _regions->set_state (**i);
2394         }
2395
2396         if ((prop = node.property ("maximised"))) {
2397                 bool yn = string_is_affirmative (prop->value());
2398                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2399                 assert (act);
2400                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2401                 bool fs = tact && tact->get_active();
2402                 if (yn ^ fs) {
2403                         ActionManager::do_action ("Common", "ToggleMaximalEditor");
2404                 }
2405         }
2406
2407         if ((prop = node.property ("nudge-clock-value"))) {
2408                 framepos_t f;
2409                 sscanf (prop->value().c_str(), "%" PRId64, &f);
2410                 nudge_clock->set (f);
2411         } else {
2412                 nudge_clock->set_mode (AudioClock::Timecode);
2413                 nudge_clock->set (_session->frame_rate() * 5, true);
2414         }
2415
2416         return 0;
2417 }
2418
2419 XMLNode&
2420 Editor::get_state ()
2421 {
2422         XMLNode* node = new XMLNode ("Editor");
2423         char buf[32];
2424
2425         id().print (buf, sizeof (buf));
2426         node->add_property ("id", buf);
2427
2428         if (is_realized()) {
2429                 Glib::RefPtr<Gdk::Window> win = get_window();
2430
2431                 int x, y, width, height;
2432                 win->get_root_origin(x, y);
2433                 win->get_size(width, height);
2434
2435                 XMLNode* geometry = new XMLNode ("geometry");
2436
2437                 snprintf(buf, sizeof(buf), "%d", width);
2438                 geometry->add_property("x-size", string(buf));
2439                 snprintf(buf, sizeof(buf), "%d", height);
2440                 geometry->add_property("y-size", string(buf));
2441                 snprintf(buf, sizeof(buf), "%d", x);
2442                 geometry->add_property("x-pos", string(buf));
2443                 snprintf(buf, sizeof(buf), "%d", y);
2444                 geometry->add_property("y-pos", string(buf));
2445                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2446                 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2447                 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2448                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2449                 geometry->add_property("edit-vertical-pane-pos", string(buf));
2450
2451                 node->add_child_nocopy (*geometry);
2452         }
2453
2454         maybe_add_mixer_strip_width (*node);
2455
2456         node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2457
2458         snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2459         node->add_property ("zoom", buf);
2460         node->add_property ("snap-to", enum_2_string (_snap_type));
2461         node->add_property ("snap-mode", enum_2_string (_snap_mode));
2462         node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2463         node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2464         node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2465         node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2466         node->add_property ("edit-point", enum_2_string (_edit_point));
2467         snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2468         node->add_property ("visible-track-count", buf);
2469
2470         snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2471         node->add_property ("playhead", buf);
2472         snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2473         node->add_property ("left-frame", buf);
2474         snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2475         node->add_property ("y-origin", buf);
2476
2477         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2478         node->add_property ("maximised", _maximised ? "yes" : "no");
2479         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2480         node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2481         node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2482         node->add_property ("mouse-mode", enum2str(mouse_mode));
2483         node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2484         node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2485
2486         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2487         if (act) {
2488                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2489                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2490         }
2491
2492         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2493         if (act) {
2494                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2495                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2496         }
2497
2498         snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2499         node->add_property (X_("editor-list-page"), buf);
2500
2501         if (button_bindings) {
2502                 XMLNode* bb = new XMLNode (X_("Buttons"));
2503                 button_bindings->save (*bb);
2504                 node->add_child_nocopy (*bb);
2505         }
2506
2507         node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2508
2509         node->add_child_nocopy (selection->get_state ());
2510         node->add_child_nocopy (_regions->get_state ());
2511
2512         snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2513         node->add_property ("nudge-clock-value", buf);
2514
2515         return *node;
2516 }
2517
2518 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2519  *  if @param trackview_relative_offset is false, @param y y is a global canvas *  coordinate, in pixel units
2520  *
2521  *  @return pair: TimeAxisView that y is over, layer index.
2522  *
2523  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2524  *  in stacked or expanded region display mode, otherwise 0.
2525  */
2526 std::pair<TimeAxisView *, double>
2527 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2528 {
2529         if (!trackview_relative_offset) {
2530                 y -= _trackview_group->canvas_origin().y;
2531         }
2532
2533         if (y < 0) {
2534                 return std::make_pair ( (TimeAxisView *) 0, 0);
2535         }
2536
2537         for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2538                         
2539                 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2540                         
2541                 if (r.first) {
2542                         return r;
2543                 }
2544         }
2545
2546         return std::make_pair ( (TimeAxisView *) 0, 0);
2547 }
2548
2549 /** Snap a position to the grid, if appropriate, taking into account current
2550  *  grid settings and also the state of any snap modifier keys that may be pressed.
2551  *  @param start Position to snap.
2552  *  @param event Event to get current key modifier information from, or 0.
2553  */
2554 void
2555 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2556 {
2557         if (!_session || !event) {
2558                 return;
2559         }
2560
2561         if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2562                 if (_snap_mode == SnapOff) {
2563                         snap_to_internal (start, direction, for_mark);
2564                 }
2565         } else {
2566                 if (_snap_mode != SnapOff) {
2567                         snap_to_internal (start, direction, for_mark);
2568                 }
2569         }
2570 }
2571
2572 void
2573 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2574 {
2575         if (!_session || _snap_mode == SnapOff) {
2576                 return;
2577         }
2578
2579         snap_to_internal (start, direction, for_mark);
2580 }
2581
2582 void
2583 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2584 {
2585         const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2586         framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2587
2588         switch (_snap_type) {
2589         case SnapToTimecodeFrame:
2590                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2591                     fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2592                         /* start is already on a whole timecode frame, do nothing */
2593                 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2594                         start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2595                 } else {
2596                         start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) *  _session->frames_per_timecode_frame());
2597                 }
2598                 break;
2599
2600         case SnapToTimecodeSeconds:
2601                 if (_session->config.get_timecode_offset_negative()) {
2602                         start += _session->config.get_timecode_offset ();
2603                 } else {
2604                         start -= _session->config.get_timecode_offset ();
2605                 }
2606                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2607                     (start % one_timecode_second == 0)) {
2608                         /* start is already on a whole second, do nothing */
2609                 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2610                         start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2611                 } else {
2612                         start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2613                 }
2614
2615                 if (_session->config.get_timecode_offset_negative()) {
2616                         start -= _session->config.get_timecode_offset ();
2617                 } else {
2618                         start += _session->config.get_timecode_offset ();
2619                 }
2620                 break;
2621
2622         case SnapToTimecodeMinutes:
2623                 if (_session->config.get_timecode_offset_negative()) {
2624                         start += _session->config.get_timecode_offset ();
2625                 } else {
2626                         start -= _session->config.get_timecode_offset ();
2627                 }
2628                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2629                     (start % one_timecode_minute == 0)) {
2630                         /* start is already on a whole minute, do nothing */
2631                 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2632                         start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2633                 } else {
2634                         start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2635                 }
2636                 if (_session->config.get_timecode_offset_negative()) {
2637                         start -= _session->config.get_timecode_offset ();
2638                 } else {
2639                         start += _session->config.get_timecode_offset ();
2640                 }
2641                 break;
2642         default:
2643                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2644                 abort(); /*NOTREACHED*/
2645         }
2646 }
2647
2648 void
2649 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2650 {
2651         const framepos_t one_second = _session->frame_rate();
2652         const framepos_t one_minute = _session->frame_rate() * 60;
2653         framepos_t presnap = start;
2654         framepos_t before;
2655         framepos_t after;
2656
2657         switch (_snap_type) {
2658         case SnapToTimecodeFrame:
2659         case SnapToTimecodeSeconds:
2660         case SnapToTimecodeMinutes:
2661                 return timecode_snap_to_internal (start, direction, for_mark);
2662
2663         case SnapToCDFrame:
2664                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2665                     start % (one_second/75) == 0) {
2666                         /* start is already on a whole CD frame, do nothing */
2667                 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2668                         start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2669                 } else {
2670                         start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2671                 }
2672                 break;
2673
2674         case SnapToSeconds:
2675                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2676                     start % one_second == 0) {
2677                         /* start is already on a whole second, do nothing */
2678                 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2679                         start = (framepos_t) ceil ((double) start / one_second) * one_second;
2680                 } else {
2681                         start = (framepos_t) floor ((double) start / one_second) * one_second;
2682                 }
2683                 break;
2684
2685         case SnapToMinutes:
2686                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2687                     start % one_minute == 0) {
2688                         /* start is already on a whole minute, do nothing */
2689                 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2690                         start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2691                 } else {
2692                         start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2693                 }
2694                 break;
2695
2696         case SnapToBar:
2697                 start = _session->tempo_map().round_to_bar (start, direction);
2698                 break;
2699
2700         case SnapToBeat:
2701                 start = _session->tempo_map().round_to_beat (start, direction);
2702                 break;
2703
2704         case SnapToBeatDiv128:
2705                 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2706                 break;
2707         case SnapToBeatDiv64:
2708                 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2709                 break;
2710         case SnapToBeatDiv32:
2711                 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2712                 break;
2713         case SnapToBeatDiv28:
2714                 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2715                 break;
2716         case SnapToBeatDiv24:
2717                 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2718                 break;
2719         case SnapToBeatDiv20:
2720                 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2721                 break;
2722         case SnapToBeatDiv16:
2723                 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2724                 break;
2725         case SnapToBeatDiv14:
2726                 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2727                 break;
2728         case SnapToBeatDiv12:
2729                 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2730                 break;
2731         case SnapToBeatDiv10:
2732                 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2733                 break;
2734         case SnapToBeatDiv8:
2735                 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2736                 break;
2737         case SnapToBeatDiv7:
2738                 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2739                 break;
2740         case SnapToBeatDiv6:
2741                 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2742                 break;
2743         case SnapToBeatDiv5:
2744                 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2745                 break;
2746         case SnapToBeatDiv4:
2747                 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2748                 break;
2749         case SnapToBeatDiv3:
2750                 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2751                 break;
2752         case SnapToBeatDiv2:
2753                 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2754                 break;
2755
2756         case SnapToMark:
2757                 if (for_mark) {
2758                         return;
2759                 }
2760
2761                 _session->locations()->marks_either_side (start, before, after);
2762
2763                 if (before == max_framepos && after == max_framepos) {
2764                         /* No marks to snap to, so just don't snap */
2765                         return;
2766                 } else if (before == max_framepos) {
2767                         start = after;
2768                 } else if (after == max_framepos) {
2769                         start = before;
2770                 } else if (before != max_framepos && after != max_framepos) {
2771                         /* have before and after */
2772                         if ((start - before) < (after - start)) {
2773                                 start = before;
2774                         } else {
2775                                 start = after;
2776                         }
2777                 }
2778
2779                 break;
2780
2781         case SnapToRegionStart:
2782         case SnapToRegionEnd:
2783         case SnapToRegionSync:
2784         case SnapToRegionBoundary:
2785                 if (!region_boundary_cache.empty()) {
2786
2787                         vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2788                         vector<framepos_t>::iterator next = region_boundary_cache.end ();
2789
2790                         if (direction > 0) {
2791                                 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2792                         } else {
2793                                 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2794                         }
2795
2796                         if (next != region_boundary_cache.begin ()) {
2797                                 prev = next;
2798                                 prev--;
2799                         }
2800
2801                         framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2802                         framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2803
2804                         if (start > (p + n) / 2) {
2805                                 start = n;
2806                         } else {
2807                                 start = p;
2808                         }
2809                 }
2810                 break;
2811         }
2812
2813         switch (_snap_mode) {
2814         case SnapNormal:
2815                 return;
2816
2817         case SnapMagnetic:
2818
2819                 if (presnap > start) {
2820                         if (presnap > (start + pixel_to_sample(snap_threshold))) {
2821                                 start = presnap;
2822                         }
2823
2824                 } else if (presnap < start) {
2825                         if (presnap < (start - pixel_to_sample(snap_threshold))) {
2826                                 start = presnap;
2827                         }
2828                 }
2829
2830         default:
2831                 /* handled at entry */
2832                 return;
2833
2834         }
2835 }
2836
2837
2838 void
2839 Editor::setup_toolbar ()
2840 {
2841         HBox* mode_box = manage(new HBox);
2842         mode_box->set_border_width (2);
2843         mode_box->set_spacing(2);
2844
2845         HBox* mouse_mode_box = manage (new HBox);
2846         HBox* mouse_mode_hbox = manage (new HBox);
2847         VBox* mouse_mode_vbox = manage (new VBox);
2848         Alignment* mouse_mode_align = manage (new Alignment);
2849
2850         Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2851         mouse_mode_size_group->add_widget (smart_mode_button);
2852         mouse_mode_size_group->add_widget (mouse_move_button);
2853         mouse_mode_size_group->add_widget (mouse_cut_button);
2854         mouse_mode_size_group->add_widget (mouse_select_button);
2855         mouse_mode_size_group->add_widget (mouse_timefx_button);
2856         mouse_mode_size_group->add_widget (mouse_audition_button);
2857         mouse_mode_size_group->add_widget (mouse_draw_button);
2858         mouse_mode_size_group->add_widget (internal_edit_button);
2859
2860         mouse_mode_size_group->add_widget (zoom_in_button);
2861         mouse_mode_size_group->add_widget (zoom_out_button);
2862         mouse_mode_size_group->add_widget (zoom_preset_selector);
2863         mouse_mode_size_group->add_widget (zoom_out_full_button);
2864         mouse_mode_size_group->add_widget (zoom_focus_selector);
2865
2866         mouse_mode_size_group->add_widget (tav_shrink_button);
2867         mouse_mode_size_group->add_widget (tav_expand_button);
2868         mouse_mode_size_group->add_widget (visible_tracks_selector);
2869
2870         mouse_mode_size_group->add_widget (snap_type_selector);
2871         mouse_mode_size_group->add_widget (snap_mode_selector);
2872
2873         mouse_mode_size_group->add_widget (edit_point_selector);
2874         mouse_mode_size_group->add_widget (edit_mode_selector);
2875
2876         mouse_mode_size_group->add_widget (*nudge_clock);
2877         mouse_mode_size_group->add_widget (nudge_forward_button);
2878         mouse_mode_size_group->add_widget (nudge_backward_button);
2879
2880         mouse_mode_hbox->set_spacing (2);
2881
2882         if (!ARDOUR::Profile->get_trx()) {
2883                 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2884         }
2885
2886         mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2887         mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2888
2889         if (!ARDOUR::Profile->get_mixbus()) {
2890                 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2891         }
2892         
2893         if (!ARDOUR::Profile->get_trx()) {
2894                 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2895                 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2896                 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2897                 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2898         }
2899
2900         mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2901
2902         mouse_mode_align->add (*mouse_mode_vbox);
2903         mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2904
2905         mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2906
2907         edit_mode_selector.set_name ("mouse mode button");
2908
2909         if (!ARDOUR::Profile->get_trx()) {
2910                 mode_box->pack_start (edit_mode_selector, false, false);
2911         }
2912         mode_box->pack_start (*mouse_mode_box, false, false);
2913
2914         _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2915         _mouse_mode_tearoff->set_name ("MouseModeBase");
2916         _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2917
2918         if (Profile->get_sae() || Profile->get_mixbus() ) {
2919                 _mouse_mode_tearoff->set_can_be_torn_off (false);
2920         }
2921
2922         _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2923                                                          &_mouse_mode_tearoff->tearoff_window()));
2924         _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2925                                                          &_mouse_mode_tearoff->tearoff_window(), 1));
2926         _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2927                                                          &_mouse_mode_tearoff->tearoff_window()));
2928         _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2929                                                           &_mouse_mode_tearoff->tearoff_window(), 1));
2930
2931         /* Zoom */
2932
2933         _zoom_box.set_spacing (2);
2934         _zoom_box.set_border_width (2);
2935
2936         RefPtr<Action> act;
2937
2938         zoom_preset_selector.set_name ("zoom button");
2939         zoom_preset_selector.set_image(::get_icon ("time_exp"));
2940         zoom_preset_selector.set_size_request (42, -1);
2941
2942         zoom_in_button.set_name ("zoom button");
2943         zoom_in_button.set_image(::get_icon ("zoom_in"));
2944         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2945         zoom_in_button.set_related_action (act);
2946
2947         zoom_out_button.set_name ("zoom button");
2948         zoom_out_button.set_image(::get_icon ("zoom_out"));
2949         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2950         zoom_out_button.set_related_action (act);
2951
2952         zoom_out_full_button.set_name ("zoom button");
2953         zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2954         act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2955         zoom_out_full_button.set_related_action (act);
2956
2957         zoom_focus_selector.set_name ("zoom button");
2958
2959         if (ARDOUR::Profile->get_mixbus()) {
2960                 _zoom_box.pack_start (zoom_preset_selector, false, false);
2961         } else if (ARDOUR::Profile->get_trx()) {
2962                 mode_box->pack_start (zoom_out_button, false, false);
2963                 mode_box->pack_start (zoom_in_button, false, false);
2964         } else {
2965                 _zoom_box.pack_start (zoom_out_button, false, false);
2966                 _zoom_box.pack_start (zoom_in_button, false, false);
2967                 _zoom_box.pack_start (zoom_out_full_button, false, false);
2968                 _zoom_box.pack_start (zoom_focus_selector, false, false);
2969         }
2970
2971         /* Track zoom buttons */
2972         visible_tracks_selector.set_name ("zoom button");
2973         if (Profile->get_mixbus()) {
2974                 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2975                 visible_tracks_selector.set_size_request (42, -1);
2976         } else {
2977                 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2978         }
2979
2980         tav_expand_button.set_name ("zoom button");
2981         tav_expand_button.set_image(::get_icon ("tav_exp"));
2982         act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2983         tav_expand_button.set_related_action (act);
2984
2985         tav_shrink_button.set_name ("zoom button");
2986         tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2987         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2988         tav_shrink_button.set_related_action (act);
2989
2990         if (ARDOUR::Profile->get_mixbus()) {
2991                 _zoom_box.pack_start (visible_tracks_selector);
2992         } else if (ARDOUR::Profile->get_trx()) {
2993                 _zoom_box.pack_start (tav_shrink_button);
2994                 _zoom_box.pack_start (tav_expand_button);
2995         } else {
2996                 _zoom_box.pack_start (visible_tracks_selector);
2997                 _zoom_box.pack_start (tav_shrink_button);
2998                 _zoom_box.pack_start (tav_expand_button);
2999         }
3000
3001         if (!ARDOUR::Profile->get_trx()) {
3002                 _zoom_tearoff = manage (new TearOff (_zoom_box));
3003                 
3004                 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3005                                                            &_zoom_tearoff->tearoff_window()));
3006                 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3007                                                            &_zoom_tearoff->tearoff_window(), 0));
3008                 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3009                                                            &_zoom_tearoff->tearoff_window()));
3010                 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3011                                                             &_zoom_tearoff->tearoff_window(), 0));
3012         } 
3013
3014         if (Profile->get_sae() || Profile->get_mixbus() ) {
3015                 _zoom_tearoff->set_can_be_torn_off (false);
3016         }
3017
3018         snap_box.set_spacing (2);
3019         snap_box.set_border_width (2);
3020
3021         snap_type_selector.set_name ("mouse mode button");
3022
3023         snap_mode_selector.set_name ("mouse mode button");
3024
3025         edit_point_selector.set_name ("mouse mode button");
3026
3027         snap_box.pack_start (snap_mode_selector, false, false);
3028         snap_box.pack_start (snap_type_selector, false, false);
3029         snap_box.pack_start (edit_point_selector, false, false);
3030
3031         /* Nudge */
3032
3033         HBox *nudge_box = manage (new HBox);
3034         nudge_box->set_spacing (2);
3035         nudge_box->set_border_width (2);
3036
3037         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3038         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3039
3040         nudge_box->pack_start (nudge_backward_button, false, false);
3041         nudge_box->pack_start (nudge_forward_button, false, false);
3042         nudge_box->pack_start (*nudge_clock, false, false);
3043
3044
3045         /* Pack everything in... */
3046
3047         HBox* hbox = manage (new HBox);
3048         hbox->set_spacing(2);
3049
3050         _tools_tearoff = manage (new TearOff (*hbox));
3051         _tools_tearoff->set_name ("MouseModeBase");
3052         _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3053
3054         if (Profile->get_sae() || Profile->get_mixbus()) {
3055                 _tools_tearoff->set_can_be_torn_off (false);
3056         }
3057
3058         _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3059                                                     &_tools_tearoff->tearoff_window()));
3060         _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3061                                                     &_tools_tearoff->tearoff_window(), 0));
3062         _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3063                                                     &_tools_tearoff->tearoff_window()));
3064         _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3065                                                      &_tools_tearoff->tearoff_window(), 0));
3066
3067         toolbar_hbox.set_spacing (2);
3068         toolbar_hbox.set_border_width (1);
3069
3070         toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3071         if (!ARDOUR::Profile->get_trx()) {
3072                 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3073                 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3074         }
3075
3076         if (!ARDOUR::Profile->get_trx()) {
3077                 hbox->pack_start (snap_box, false, false);
3078                 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3079                         hbox->pack_start (*nudge_box, false, false);
3080                 } else {
3081                         ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3082                 }
3083         }
3084         hbox->pack_start (panic_box, false, false);
3085
3086         hbox->show_all ();
3087
3088         toolbar_base.set_name ("ToolBarBase");
3089         toolbar_base.add (toolbar_hbox);
3090
3091         _toolbar_viewport.add (toolbar_base);
3092         /* stick to the required height but allow width to vary if there's not enough room */
3093         _toolbar_viewport.set_size_request (1, -1);
3094
3095         toolbar_frame.set_shadow_type (SHADOW_OUT);
3096         toolbar_frame.set_name ("BaseFrame");
3097         toolbar_frame.add (_toolbar_viewport);
3098 }
3099
3100 void
3101 Editor::build_edit_point_menu ()
3102 {
3103         using namespace Menu_Helpers;
3104
3105         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3106         if(!Profile->get_mixbus())
3107                 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3108         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3109
3110         set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3111 }
3112
3113 void
3114 Editor::build_edit_mode_menu ()
3115 {
3116         using namespace Menu_Helpers;
3117         
3118         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3119 //      edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3120         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3121         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
3122
3123         set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3124 }
3125
3126 void
3127 Editor::build_snap_mode_menu ()
3128 {
3129         using namespace Menu_Helpers;
3130
3131         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3132         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3133         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3134
3135         set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3136 }
3137
3138 void
3139 Editor::build_snap_type_menu ()
3140 {
3141         using namespace Menu_Helpers;
3142
3143         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3144         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3145         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3146         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3147         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3148         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3149         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3150         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3151         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3152         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3153         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3154         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3155         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3156         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3157         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3158         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3159         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3160         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3161         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3162         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3163         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3164         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3165         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3166         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3167         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3168         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3169         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3170         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3171         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3172         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3173
3174         set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3175
3176 }
3177
3178 void
3179 Editor::setup_tooltips ()
3180 {
3181         ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3182         ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3183         ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3184         ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3185         ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3186         ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3187         ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3188         ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3189         ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3190         ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3191         ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3192         ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3193         ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3194         ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3195         ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3196         ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3197         ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3198         ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3199         ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3200         ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3201         ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3202         ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3203         ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3204         ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3205 }
3206
3207 int
3208 Editor::convert_drop_to_paths (
3209                 vector<string>&                paths,
3210                 const RefPtr<Gdk::DragContext>& /*context*/,
3211                 gint                            /*x*/,
3212                 gint                            /*y*/,
3213                 const SelectionData&            data,
3214                 guint                           /*info*/,
3215                 guint                           /*time*/)
3216 {
3217         if (_session == 0) {
3218                 return -1;
3219         }
3220
3221         vector<string> uris = data.get_uris();
3222
3223         if (uris.empty()) {
3224
3225                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3226                    are actually URI lists. So do it by hand.
3227                 */
3228
3229                 if (data.get_target() != "text/plain") {
3230                         return -1;
3231                 }
3232
3233                 /* Parse the "uri-list" format that Nautilus provides,
3234                    where each pathname is delimited by \r\n.
3235
3236                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3237                 */
3238
3239                 string txt = data.get_text();
3240                 char* p;
3241                 const char* q;
3242
3243                 p = (char *) malloc (txt.length() + 1);
3244                 txt.copy (p, txt.length(), 0);
3245                 p[txt.length()] = '\0';
3246
3247                 while (p)
3248                 {
3249                         if (*p != '#')
3250                         {
3251                                 while (g_ascii_isspace (*p))
3252                                         p++;
3253
3254                                 q = p;
3255                                 while (*q && (*q != '\n') && (*q != '\r')) {
3256                                         q++;
3257                                 }
3258
3259                                 if (q > p)
3260                                 {
3261                                         q--;
3262                                         while (q > p && g_ascii_isspace (*q))
3263                                                 q--;
3264
3265                                         if (q > p)
3266                                         {
3267                                                 uris.push_back (string (p, q - p + 1));
3268                                         }
3269                                 }
3270                         }
3271                         p = strchr (p, '\n');
3272                         if (p)
3273                                 p++;
3274                 }
3275
3276                 free ((void*)p);
3277
3278                 if (uris.empty()) {
3279                         return -1;
3280                 }
3281         }
3282
3283         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3284                 if ((*i).substr (0,7) == "file://") {
3285                         paths.push_back (Glib::filename_from_uri (*i));
3286                 }
3287         }
3288
3289         return 0;
3290 }
3291
3292 void
3293 Editor::new_tempo_section ()
3294 {
3295 }
3296
3297 void
3298 Editor::map_transport_state ()
3299 {
3300         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3301
3302         if (_session && _session->transport_stopped()) {
3303                 have_pending_keyboard_selection = false;
3304         }
3305
3306         update_loop_range_view ();
3307 }
3308
3309 /* UNDO/REDO */
3310
3311 void
3312 Editor::begin_reversible_command (string name)
3313 {
3314         if (_session) {
3315                 _session->begin_reversible_command (name);
3316         }
3317 }
3318
3319 void
3320 Editor::begin_reversible_command (GQuark q)
3321 {
3322         if (_session) {
3323                 _session->begin_reversible_command (q);
3324         }
3325 }
3326
3327 void
3328 Editor::commit_reversible_command ()
3329 {
3330         if (_session) {
3331                 _session->commit_reversible_command ();
3332         }
3333 }
3334
3335 void
3336 Editor::history_changed ()
3337 {
3338         string label;
3339
3340         if (undo_action && _session) {
3341                 if (_session->undo_depth() == 0) {
3342                         label = S_("Command|Undo");
3343                 } else {
3344                         label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3345                 }
3346                 undo_action->property_label() = label;
3347         }
3348
3349         if (redo_action && _session) {
3350                 if (_session->redo_depth() == 0) {
3351                         label = _("Redo");
3352                 } else {
3353                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3354                 }
3355                 redo_action->property_label() = label;
3356         }
3357 }
3358
3359 void
3360 Editor::duplicate_range (bool with_dialog)
3361 {
3362         float times = 1.0f;
3363
3364         RegionSelection rs = get_regions_from_selection_and_entered ();
3365
3366         if ( selection->time.length() == 0 && rs.empty()) {
3367                 return;
3368         }
3369
3370         if (with_dialog) {
3371
3372                 ArdourDialog win (_("Duplicate"));
3373                 Label label (_("Number of duplications:"));
3374                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3375                 SpinButton spinner (adjustment, 0.0, 1);
3376                 HBox hbox;
3377
3378                 win.get_vbox()->set_spacing (12);
3379                 win.get_vbox()->pack_start (hbox);
3380                 hbox.set_border_width (6);
3381                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3382
3383                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3384                    place, visually. so do this by hand.
3385                 */
3386
3387                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3388                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3389                 spinner.grab_focus();
3390
3391                 hbox.show ();
3392                 label.show ();
3393                 spinner.show ();
3394
3395                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3396                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3397                 win.set_default_response (RESPONSE_ACCEPT);
3398
3399                 spinner.grab_focus ();
3400
3401                 switch (win.run ()) {
3402                 case RESPONSE_ACCEPT:
3403                         break;
3404                 default:
3405                         return;
3406                 }
3407
3408                 times = adjustment.get_value();
3409         }
3410
3411         if ((current_mouse_mode() == Editing::MouseRange)) {
3412                 if (selection->time.length()) {
3413                         duplicate_selection (times);
3414                 }
3415         } else if (get_smart_mode()) {
3416                 if (selection->time.length()) {
3417                         duplicate_selection (times);
3418                 } else 
3419                         duplicate_some_regions (rs, times);
3420         } else {
3421                 duplicate_some_regions (rs, times);
3422         }
3423 }
3424
3425 void
3426 Editor::set_edit_mode (EditMode m)
3427 {
3428         Config->set_edit_mode (m);
3429 }
3430
3431 void
3432 Editor::cycle_edit_mode ()
3433 {
3434         switch (Config->get_edit_mode()) {
3435         case Slide:
3436                 if (Profile->get_sae()) {
3437                         Config->set_edit_mode (Lock);
3438                 } else {
3439                         Config->set_edit_mode (Ripple);
3440                 }
3441                 break;
3442         case Splice:
3443         case Ripple:
3444                 Config->set_edit_mode (Lock);
3445                 break;
3446         case Lock:
3447                 Config->set_edit_mode (Slide);
3448                 break;
3449         }
3450 }
3451
3452 void
3453 Editor::edit_mode_selection_done ( EditMode m )
3454 {
3455         Config->set_edit_mode ( m );
3456 }
3457
3458 void
3459 Editor::snap_type_selection_done (SnapType snaptype)
3460 {
3461         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3462         if (ract) {
3463                 ract->set_active ();
3464         }
3465 }
3466
3467 void
3468 Editor::snap_mode_selection_done (SnapMode mode)
3469 {
3470         RefPtr<RadioAction> ract = snap_mode_action (mode);
3471
3472         if (ract) {
3473                 ract->set_active (true);
3474         }
3475 }
3476
3477 void
3478 Editor::cycle_edit_point (bool with_marker)
3479 {
3480         if(Profile->get_mixbus())
3481                 with_marker = false;
3482
3483         switch (_edit_point) {
3484         case EditAtMouse:
3485                 set_edit_point_preference (EditAtPlayhead);
3486                 break;
3487         case EditAtPlayhead:
3488                 if (with_marker) {
3489                         set_edit_point_preference (EditAtSelectedMarker);
3490                 } else {
3491                         set_edit_point_preference (EditAtMouse);
3492                 }
3493                 break;
3494         case EditAtSelectedMarker:
3495                 set_edit_point_preference (EditAtMouse);
3496                 break;
3497         }
3498 }
3499
3500 void
3501 Editor::edit_point_selection_done (EditPoint ep)
3502 {
3503         set_edit_point_preference ( ep );
3504 }
3505
3506 void
3507 Editor::build_zoom_focus_menu ()
3508 {
3509         using namespace Menu_Helpers;
3510
3511         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3512         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3513         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3514         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3515         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3516         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3517
3518         set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3519 }
3520
3521 void
3522 Editor::zoom_focus_selection_done ( ZoomFocus f )
3523 {
3524         RefPtr<RadioAction> ract = zoom_focus_action (f);
3525         if (ract) {
3526                 ract->set_active ();
3527         }
3528 }
3529
3530 void
3531 Editor::build_track_count_menu ()
3532 {
3533         using namespace Menu_Helpers;
3534
3535         if (!Profile->get_mixbus()) {
3536                 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3537                 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3538                 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3539                 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3540                 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3541                 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3542                 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3543                 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3544                 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3545                 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3546                 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3547                 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3548                 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3549         } else {
3550                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3551                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3552                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3553                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3554                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3555                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3556                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3557                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3558                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3559                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3560
3561                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3562                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3563                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3564                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3565                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3566                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3567                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3568                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3569                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3570                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3571                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3572         }
3573 }
3574
3575 void
3576 Editor::set_zoom_preset (int64_t ms)
3577 {
3578         if ( ms <= 0 ) {
3579                 temporal_zoom_session();
3580                 return;
3581         }
3582         
3583         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3584         temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3585 }
3586
3587 void
3588 Editor::set_visible_track_count (int32_t n)
3589 {
3590         _visible_track_count = n;
3591
3592         /* if the canvas hasn't really been allocated any size yet, just
3593            record the desired number of visible tracks and return. when canvas
3594            allocation happens, we will get called again and then we can do the
3595            real work.
3596         */
3597         
3598         if (_visible_canvas_height <= 1) {
3599                 return;
3600         }
3601
3602         int h;
3603         string str;
3604         
3605         if (_visible_track_count > 0) {
3606                 h = trackviews_height() / _visible_track_count;
3607                 std::ostringstream s;
3608                 s << _visible_track_count;
3609                 str = s.str();
3610         } else if (_visible_track_count == 0) {
3611                 uint32_t n = 0;
3612                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3613                         if ((*i)->marked_for_display()) {
3614                                 ++n;
3615                         }
3616                 }
3617                 h = trackviews_height() / n;
3618                 str = _("All");
3619         } else {
3620                 /* negative value means that the visible track count has 
3621                    been overridden by explicit track height changes.
3622                 */
3623                 visible_tracks_selector.set_text (X_("*"));
3624                 return;
3625         }
3626
3627         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3628                 (*i)->set_height (h);
3629         }
3630         
3631         if (str != visible_tracks_selector.get_text()) {
3632                 visible_tracks_selector.set_text (str);
3633         }
3634 }
3635
3636 void
3637 Editor::override_visible_track_count ()
3638 {
3639         _visible_track_count = -1;
3640         visible_tracks_selector.set_text ( _("*") );
3641 }
3642
3643 bool
3644 Editor::edit_controls_button_release (GdkEventButton* ev)
3645 {
3646         if (Keyboard::is_context_menu_event (ev)) {
3647                 ARDOUR_UI::instance()->add_route (this);
3648         } else if (ev->button == 1) {
3649                 selection->clear_tracks ();
3650         }
3651
3652         return true;
3653 }
3654
3655 bool
3656 Editor::mouse_select_button_release (GdkEventButton* ev)
3657 {
3658         /* this handles just right-clicks */
3659
3660         if (ev->button != 3) {
3661                 return false;
3662         }
3663
3664         return true;
3665 }
3666
3667 void
3668 Editor::set_zoom_focus (ZoomFocus f)
3669 {
3670         string str = zoom_focus_strings[(int)f];
3671
3672         if (str != zoom_focus_selector.get_text()) {
3673                 zoom_focus_selector.set_text (str);
3674         }
3675
3676         if (zoom_focus != f) {
3677                 zoom_focus = f;
3678                 instant_save ();
3679         }
3680 }
3681
3682 void
3683 Editor::cycle_zoom_focus ()
3684 {
3685         switch (zoom_focus) {
3686         case ZoomFocusLeft:
3687                 set_zoom_focus (ZoomFocusRight);
3688                 break;
3689         case ZoomFocusRight:
3690                 set_zoom_focus (ZoomFocusCenter);
3691                 break;
3692         case ZoomFocusCenter:
3693                 set_zoom_focus (ZoomFocusPlayhead);
3694                 break;
3695         case ZoomFocusPlayhead:
3696                 set_zoom_focus (ZoomFocusMouse);
3697                 break;
3698         case ZoomFocusMouse:
3699                 set_zoom_focus (ZoomFocusEdit);
3700                 break;
3701         case ZoomFocusEdit:
3702                 set_zoom_focus (ZoomFocusLeft);
3703                 break;
3704         }
3705 }
3706
3707 void
3708 Editor::ensure_float (Window& win)
3709 {
3710         win.set_transient_for (*this);
3711 }
3712
3713 void
3714 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3715 {
3716         /* recover or initialize pane positions. do this here rather than earlier because
3717            we don't want the positions to change the child allocations, which they seem to do.
3718          */
3719
3720         int pos;
3721         XMLProperty* prop;
3722         char buf[32];
3723         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3724
3725         enum Pane {
3726                 Horizontal = 0x1,
3727                 Vertical = 0x2
3728         };
3729
3730         static Pane done;
3731
3732         XMLNode* geometry = find_named_node (*node, "geometry");
3733
3734         if (which == static_cast<Paned*> (&edit_pane)) {
3735
3736                 if (done & Horizontal) {
3737                         return;
3738                 }
3739
3740                 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3741                         _notebook_shrunk = string_is_affirmative (prop->value ());
3742                 }
3743
3744                 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3745                         /* initial allocation is 90% to canvas, 10% to notebook */
3746                         pos = (int) floor (alloc.get_width() * 0.90f);
3747                         snprintf (buf, sizeof(buf), "%d", pos);
3748                 } else {
3749                         pos = atoi (prop->value());
3750                 }
3751
3752                 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3753                         edit_pane.set_position (pos);
3754                 }
3755
3756                 done = (Pane) (done | Horizontal);
3757
3758         } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3759
3760                 if (done & Vertical) {
3761                         return;
3762                 }
3763
3764                 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3765                         /* initial allocation is 90% to canvas, 10% to summary */
3766                         pos = (int) floor (alloc.get_height() * 0.90f);
3767                         snprintf (buf, sizeof(buf), "%d", pos);
3768                 } else {
3769
3770                         pos = atoi (prop->value());
3771                 }
3772
3773                 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3774                         editor_summary_pane.set_position (pos);
3775                 }
3776
3777                 done = (Pane) (done | Vertical);
3778         }
3779 }
3780
3781 void
3782 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3783 {
3784         if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) && 
3785             (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) && 
3786             (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3787                 top_hbox.remove (toolbar_frame);
3788         }
3789 }
3790
3791 void
3792 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3793 {
3794         if (toolbar_frame.get_parent() == 0) {
3795                 top_hbox.pack_end (toolbar_frame);
3796         }
3797 }
3798
3799 void
3800 Editor::set_show_measures (bool yn)
3801 {
3802         if (_show_measures != yn) {
3803                 hide_measures ();
3804
3805                 if ((_show_measures = yn) == true) {
3806                         if (tempo_lines) {
3807                                 tempo_lines->show();
3808                         }
3809
3810                         ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3811                         ARDOUR::TempoMap::BBTPointList::const_iterator end;
3812                         
3813                         compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3814                         draw_measures (begin, end);
3815                 } 
3816
3817                 instant_save ();
3818         }
3819 }
3820
3821 void
3822 Editor::toggle_follow_playhead ()
3823 {
3824         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3825         if (act) {
3826                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3827                 set_follow_playhead (tact->get_active());
3828         }
3829 }
3830
3831 /** @param yn true to follow playhead, otherwise false.
3832  *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3833  */
3834 void
3835 Editor::set_follow_playhead (bool yn, bool catch_up)
3836 {
3837         if (_follow_playhead != yn) {
3838                 if ((_follow_playhead = yn) == true && catch_up) {
3839                         /* catch up */
3840                         reset_x_origin_to_follow_playhead ();
3841                 }
3842                 instant_save ();
3843         }
3844 }
3845
3846 void
3847 Editor::toggle_stationary_playhead ()
3848 {
3849         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3850         if (act) {
3851                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3852                 set_stationary_playhead (tact->get_active());
3853         }
3854 }
3855
3856 void
3857 Editor::set_stationary_playhead (bool yn)
3858 {
3859         if (_stationary_playhead != yn) {
3860                 if ((_stationary_playhead = yn) == true) {
3861                         /* catch up */
3862                         // FIXME need a 3.0 equivalent of this 2.X call
3863                         // update_current_screen ();
3864                 }
3865                 instant_save ();
3866         }
3867 }
3868
3869 PlaylistSelector&
3870 Editor::playlist_selector () const
3871 {
3872         return *_playlist_selector;
3873 }
3874
3875 framecnt_t
3876 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3877 {
3878         if (paste_count == 0) {
3879                 /* don't bother calculating an offset that will be zero anyway */
3880                 return 0;
3881         }
3882
3883         /* calculate basic unsnapped multi-paste offset */
3884         framecnt_t offset = paste_count * duration;
3885
3886         /* snap offset so pos + offset is aligned to the grid */
3887         framepos_t offset_pos = pos + offset;
3888         snap_to(offset_pos, RoundUpMaybe);
3889         offset = offset_pos - pos;
3890
3891         return offset;
3892 }
3893
3894 Evoral::MusicalTime
3895 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3896 {
3897         success = true;
3898
3899         switch (_snap_type) {
3900         case SnapToBeat:
3901                 return Evoral::MusicalTime(1.0);
3902                 break;
3903
3904         case SnapToBeatDiv128:
3905                 return Evoral::MusicalTime(1.0/128.0);
3906                 break;
3907         case SnapToBeatDiv64:
3908                 return Evoral::MusicalTime(1.0/64.0);
3909                 break;
3910         case SnapToBeatDiv32:
3911                 return Evoral::MusicalTime(1.0/32.0);
3912                 break;
3913         case SnapToBeatDiv28:
3914                 return Evoral::MusicalTime(1.0/28.0);
3915                 break;
3916         case SnapToBeatDiv24:
3917                 return Evoral::MusicalTime(1.0/24.0);
3918                 break;
3919         case SnapToBeatDiv20:
3920                 return Evoral::MusicalTime(1.0/20.0);
3921                 break;
3922         case SnapToBeatDiv16:
3923                 return Evoral::MusicalTime(1.0/16.0);
3924                 break;
3925         case SnapToBeatDiv14:
3926                 return Evoral::MusicalTime(1.0/14.0);
3927                 break;
3928         case SnapToBeatDiv12:
3929                 return Evoral::MusicalTime(1.0/12.0);
3930                 break;
3931         case SnapToBeatDiv10:
3932                 return Evoral::MusicalTime(1.0/10.0);
3933                 break;
3934         case SnapToBeatDiv8:
3935                 return Evoral::MusicalTime(1.0/8.0);
3936                 break;
3937         case SnapToBeatDiv7:
3938                 return Evoral::MusicalTime(1.0/7.0);
3939                 break;
3940         case SnapToBeatDiv6:
3941                 return Evoral::MusicalTime(1.0/6.0);
3942                 break;
3943         case SnapToBeatDiv5:
3944                 return Evoral::MusicalTime(1.0/5.0);
3945                 break;
3946         case SnapToBeatDiv4:
3947                 return Evoral::MusicalTime(1.0/4.0);
3948                 break;
3949         case SnapToBeatDiv3:
3950                 return Evoral::MusicalTime(1.0/3.0);
3951                 break;
3952         case SnapToBeatDiv2:
3953                 return Evoral::MusicalTime(1.0/2.0);
3954                 break;
3955
3956         case SnapToBar:
3957                 if (_session) {
3958                         return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
3959                 }
3960                 break;
3961
3962         case SnapToCDFrame:
3963         case SnapToTimecodeFrame:
3964         case SnapToTimecodeSeconds:
3965         case SnapToTimecodeMinutes:
3966         case SnapToSeconds:
3967         case SnapToMinutes:
3968         case SnapToRegionStart:
3969         case SnapToRegionEnd:
3970         case SnapToRegionSync:
3971         case SnapToRegionBoundary:
3972         default:
3973                 success = false;
3974                 break;
3975         }
3976
3977         return Evoral::MusicalTime();
3978 }
3979
3980 framecnt_t
3981 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3982 {
3983         framecnt_t ret;
3984
3985         ret = nudge_clock->current_duration (pos);
3986         next = ret + 1; /* XXXX fix me */
3987
3988         return ret;
3989 }
3990
3991 int
3992 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3993 {
3994         ArdourDialog dialog (_("Playlist Deletion"));
3995         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
3996                                         "If it is kept, its audio files will not be cleaned.\n"
3997                                         "If it is deleted, audio files used by it alone will be cleaned."),
3998                                       pl->name()));
3999
4000         dialog.set_position (WIN_POS_CENTER);
4001         dialog.get_vbox()->pack_start (label);
4002
4003         label.show ();
4004
4005         dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4006         dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4007         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4008
4009         switch (dialog.run ()) {
4010         case RESPONSE_ACCEPT:
4011                 /* delete the playlist */
4012                 return 0;
4013                 break;
4014
4015         case RESPONSE_REJECT:
4016                 /* keep the playlist */
4017                 return 1;
4018                 break;
4019
4020         default:
4021                 break;
4022         }
4023
4024         return -1;
4025 }
4026
4027 bool
4028 Editor::audio_region_selection_covers (framepos_t where)
4029 {
4030         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4031                 if ((*a)->region()->covers (where)) {
4032                         return true;
4033                 }
4034         }
4035
4036         return false;
4037 }
4038
4039 void
4040 Editor::prepare_for_cleanup ()
4041 {
4042         cut_buffer->clear_regions ();
4043         cut_buffer->clear_playlists ();
4044
4045         selection->clear_regions ();
4046         selection->clear_playlists ();
4047
4048         _regions->suspend_redisplay ();
4049 }
4050
4051 void
4052 Editor::finish_cleanup ()
4053 {
4054         _regions->resume_redisplay ();
4055 }
4056
4057 Location*
4058 Editor::transport_loop_location()
4059 {
4060         if (_session) {
4061                 return _session->locations()->auto_loop_location();
4062         } else {
4063                 return 0;
4064         }
4065 }
4066
4067 Location*
4068 Editor::transport_punch_location()
4069 {
4070         if (_session) {
4071                 return _session->locations()->auto_punch_location();
4072         } else {
4073                 return 0;
4074         }
4075 }
4076
4077 bool
4078 Editor::control_layout_scroll (GdkEventScroll* ev)
4079 {
4080         /* Just forward to the normal canvas scroll method. The coordinate
4081            systems are different but since the canvas is always larger than the
4082            track headers, and aligned with the trackview area, this will work.
4083
4084            In the not too distant future this layout is going away anyway and
4085            headers will be on the canvas.
4086         */
4087         return canvas_scroll_event (ev, false);
4088 }
4089
4090 void
4091 Editor::session_state_saved (string)
4092 {
4093         update_title ();
4094         _snapshots->redisplay ();
4095 }
4096
4097 void
4098 Editor::update_tearoff_visibility()
4099 {
4100         bool visible = Config->get_keep_tearoffs();
4101         _mouse_mode_tearoff->set_visible (visible);
4102         _tools_tearoff->set_visible (visible);
4103         if (_zoom_tearoff) {
4104                 _zoom_tearoff->set_visible (visible);
4105         }
4106 }
4107
4108 void
4109 Editor::reattach_all_tearoffs ()
4110 {
4111         if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4112         if (_tools_tearoff) _tools_tearoff->put_it_back ();
4113         if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4114 }
4115
4116 void
4117 Editor::maximise_editing_space ()
4118 {
4119         if (_maximised) {
4120                 return;
4121         }
4122
4123         fullscreen ();
4124
4125         _maximised = true;
4126 }
4127
4128 void
4129 Editor::restore_editing_space ()
4130 {
4131         if (!_maximised) {
4132                 return;
4133         }
4134
4135         unfullscreen();
4136
4137         _maximised = false;
4138 }
4139
4140 /**
4141  *  Make new playlists for a given track and also any others that belong
4142  *  to the same active route group with the `select' property.
4143  *  @param v Track.
4144  */
4145
4146 void
4147 Editor::new_playlists (TimeAxisView* v)
4148 {
4149         begin_reversible_command (_("new playlists"));
4150         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4151         _session->playlists->get (playlists);
4152         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4153         commit_reversible_command ();
4154 }
4155
4156 /**
4157  *  Use a copy of the current playlist for a given track and also any others that belong
4158  *  to the same active route group with the `select' property.
4159  *  @param v Track.
4160  */
4161
4162 void
4163 Editor::copy_playlists (TimeAxisView* v)
4164 {
4165         begin_reversible_command (_("copy playlists"));
4166         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4167         _session->playlists->get (playlists);
4168         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4169         commit_reversible_command ();
4170 }
4171
4172 /** Clear the current playlist for a given track and also any others that belong
4173  *  to the same active route group with the `select' property.
4174  *  @param v Track.
4175  */
4176
4177 void
4178 Editor::clear_playlists (TimeAxisView* v)
4179 {
4180         begin_reversible_command (_("clear playlists"));
4181         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4182         _session->playlists->get (playlists);
4183         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4184         commit_reversible_command ();
4185 }
4186
4187 void
4188 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4189 {
4190         atv.use_new_playlist (sz > 1 ? false : true, playlists);
4191 }
4192
4193 void
4194 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4195 {
4196         atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4197 }
4198
4199 void
4200 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4201 {
4202         atv.clear_playlist ();
4203 }
4204
4205 bool
4206 Editor::on_key_press_event (GdkEventKey* ev)
4207 {
4208         return key_press_focus_accelerator_handler (*this, ev);
4209 }
4210
4211 bool
4212 Editor::on_key_release_event (GdkEventKey* ev)
4213 {
4214         return Gtk::Window::on_key_release_event (ev);
4215         // return key_press_focus_accelerator_handler (*this, ev);
4216 }
4217
4218 /** Queue up a change to the viewport x origin.
4219  *  @param frame New x origin.
4220  */
4221 void
4222 Editor::reset_x_origin (framepos_t frame)
4223 {
4224         pending_visual_change.add (VisualChange::TimeOrigin);
4225         pending_visual_change.time_origin = frame;
4226         ensure_visual_change_idle_handler ();
4227 }
4228
4229 void
4230 Editor::reset_y_origin (double y)
4231 {
4232         pending_visual_change.add (VisualChange::YOrigin);
4233         pending_visual_change.y_origin = y;
4234         ensure_visual_change_idle_handler ();
4235 }
4236
4237 void
4238 Editor::reset_zoom (framecnt_t spp)
4239 {
4240         if (spp == samples_per_pixel) {
4241                 return;
4242         }
4243
4244         pending_visual_change.add (VisualChange::ZoomLevel);
4245         pending_visual_change.samples_per_pixel = spp;
4246         ensure_visual_change_idle_handler ();
4247 }
4248
4249 void
4250 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4251 {
4252         reset_x_origin (frame);
4253         reset_zoom (fpu);
4254
4255         if (!no_save_visual) {
4256                 undo_visual_stack.push_back (current_visual_state(false));
4257         }
4258 }
4259
4260 Editor::VisualState::VisualState (bool with_tracks)
4261         : gui_state (with_tracks ? new GUIObjectState : 0)
4262 {
4263 }
4264
4265 Editor::VisualState::~VisualState ()
4266 {
4267         delete gui_state;
4268 }
4269
4270 Editor::VisualState*
4271 Editor::current_visual_state (bool with_tracks)
4272 {
4273         VisualState* vs = new VisualState (with_tracks);
4274         vs->y_position = vertical_adjustment.get_value();
4275         vs->samples_per_pixel = samples_per_pixel;
4276         vs->leftmost_frame = leftmost_frame;
4277         vs->zoom_focus = zoom_focus;
4278
4279         if (with_tracks) {      
4280                 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4281         }
4282
4283         return vs;
4284 }
4285
4286 void
4287 Editor::undo_visual_state ()
4288 {
4289         if (undo_visual_stack.empty()) {
4290                 return;
4291         }
4292
4293         VisualState* vs = undo_visual_stack.back();
4294         undo_visual_stack.pop_back();
4295
4296
4297         redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4298
4299         if (vs) {
4300                 use_visual_state (*vs);
4301         }
4302 }
4303
4304 void
4305 Editor::redo_visual_state ()
4306 {
4307         if (redo_visual_stack.empty()) {
4308                 return;
4309         }
4310
4311         VisualState* vs = redo_visual_stack.back();
4312         redo_visual_stack.pop_back();
4313
4314         // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4315         // why do we check here?
4316         undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4317
4318         if (vs) {
4319                 use_visual_state (*vs);
4320         }
4321 }
4322
4323 void
4324 Editor::swap_visual_state ()
4325 {
4326         if (undo_visual_stack.empty()) {
4327                 redo_visual_state ();
4328         } else {
4329                 undo_visual_state ();
4330         }
4331 }
4332
4333 void
4334 Editor::use_visual_state (VisualState& vs)
4335 {
4336         PBD::Unwinder<bool> nsv (no_save_visual, true);
4337         DisplaySuspender ds;
4338
4339         vertical_adjustment.set_value (vs.y_position);
4340
4341         set_zoom_focus (vs.zoom_focus);
4342         reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4343         
4344         if (vs.gui_state) {
4345                 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4346                 
4347                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {    
4348                         (*i)->reset_visual_state ();
4349                 }
4350         }
4351
4352         _routes->update_visibility ();
4353 }
4354
4355 /** This is the core function that controls the zoom level of the canvas. It is called
4356  *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
4357  *  @param spp new number of samples per pixel
4358  */
4359 void
4360 Editor::set_samples_per_pixel (framecnt_t spp)
4361 {
4362         if (spp < 1) {
4363                 return;
4364         }
4365
4366         const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4367         const framecnt_t lots_of_pixels = 4000;
4368
4369         /* if the zoom level is greater than what you'd get trying to display 3
4370          * days of audio on a really big screen, then it's too big.
4371          */
4372
4373         if (spp * lots_of_pixels > three_days) {
4374                 return;
4375         }
4376
4377         samples_per_pixel = spp;
4378
4379         if (tempo_lines) {
4380                 tempo_lines->tempo_map_changed();
4381         }
4382
4383         bool const showing_time_selection = selection->time.length() > 0;
4384
4385         if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4386                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4387                         (*i)->reshow_selection (selection->time);
4388                 }
4389         }
4390
4391         ZoomChanged (); /* EMIT_SIGNAL */
4392
4393         ArdourCanvas::GtkCanvasViewport* c;
4394
4395         c = get_track_canvas();
4396         if (c) {
4397                 c->canvas()->zoomed ();
4398         }
4399
4400         if (playhead_cursor) {
4401                 playhead_cursor->set_position (playhead_cursor->current_frame ());
4402         }
4403
4404         refresh_location_display();
4405         _summary->set_overlays_dirty ();
4406
4407         update_marker_labels ();
4408
4409         instant_save ();
4410 }
4411
4412 void
4413 Editor::queue_visual_videotimeline_update ()
4414 {
4415         /* TODO:
4416          * pending_visual_change.add (VisualChange::VideoTimeline);
4417          * or maybe even more specific: which videotimeline-image
4418          * currently it calls update_video_timeline() to update
4419          * _all outdated_ images on the video-timeline.
4420          * see 'exposeimg()' in video_image_frame.cc
4421          */
4422         ensure_visual_change_idle_handler ();
4423 }
4424
4425 void
4426 Editor::ensure_visual_change_idle_handler ()
4427 {
4428         if (pending_visual_change.idle_handler_id < 0) {
4429                 // see comment in add_to_idle_resize above.
4430                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4431                 pending_visual_change.being_handled = false;
4432         }
4433 }
4434
4435 int
4436 Editor::_idle_visual_changer (void* arg)
4437 {
4438         return static_cast<Editor*>(arg)->idle_visual_changer ();
4439 }
4440
4441 int
4442 Editor::idle_visual_changer ()
4443 {
4444         /* set_horizontal_position() below (and maybe other calls) call
4445            gtk_main_iteration(), so it's possible that a signal will be handled
4446            half-way through this method.  If this signal wants an
4447            idle_visual_changer we must schedule another one after this one, so
4448            mark the idle_handler_id as -1 here to allow that.  Also make a note
4449            that we are doing the visual change, so that changes in response to
4450            super-rapid-screen-update can be dropped if we are still processing
4451            the last one.
4452         */
4453
4454         pending_visual_change.idle_handler_id = -1;
4455         pending_visual_change.being_handled = true;
4456         
4457         VisualChange vc = pending_visual_change;
4458
4459         pending_visual_change.pending = (VisualChange::Type) 0;
4460
4461         visual_changer (vc);
4462
4463         pending_visual_change.being_handled = false;
4464
4465         return 0; /* this is always a one-shot call */
4466 }
4467
4468 void
4469 Editor::visual_changer (const VisualChange& vc)
4470 {
4471         double const last_time_origin = horizontal_position ();
4472
4473         if (vc.pending & VisualChange::ZoomLevel) {
4474                 set_samples_per_pixel (vc.samples_per_pixel);
4475
4476                 compute_fixed_ruler_scale ();
4477
4478                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4479                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4480                 
4481                 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4482                                             current_bbt_points_begin, current_bbt_points_end);
4483                 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4484                                          current_bbt_points_begin, current_bbt_points_end);
4485                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4486
4487                 update_video_timeline();
4488         }
4489
4490         if (vc.pending & VisualChange::TimeOrigin) {
4491                 set_horizontal_position (vc.time_origin / samples_per_pixel);
4492         }
4493
4494         if (vc.pending & VisualChange::YOrigin) {
4495                 vertical_adjustment.set_value (vc.y_origin);
4496         }
4497
4498         if (last_time_origin == horizontal_position ()) {
4499                 /* changed signal not emitted */
4500                 update_fixed_rulers ();
4501                 redisplay_tempo (true);
4502         }
4503
4504         if (!(vc.pending & VisualChange::ZoomLevel)) {
4505                 update_video_timeline();
4506         }
4507
4508         _summary->set_overlays_dirty ();
4509 }
4510
4511 struct EditorOrderTimeAxisSorter {
4512     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4513             return a->order () < b->order ();
4514     }
4515 };
4516
4517 void
4518 Editor::sort_track_selection (TrackViewList& sel)
4519 {
4520         EditorOrderTimeAxisSorter cmp;
4521         sel.sort (cmp);
4522 }
4523
4524 framepos_t
4525 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4526 {
4527         bool ignored;
4528         framepos_t where = 0;
4529         EditPoint ep = _edit_point;
4530
4531         if(Profile->get_mixbus())
4532                 if (ep == EditAtSelectedMarker)
4533                         ep=EditAtPlayhead;
4534                 
4535         if (from_context_menu && (ep == EditAtMouse)) {
4536                 return  canvas_event_sample (&context_click_event, 0, 0);
4537         }
4538
4539         if (entered_marker) {
4540                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4541                 return entered_marker->position();
4542         }
4543
4544         if (ignore_playhead && ep == EditAtPlayhead) {
4545                 ep = EditAtSelectedMarker;
4546         }
4547
4548         switch (ep) {
4549         case EditAtPlayhead:
4550                 where = _session->audible_frame();
4551                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4552                 break;
4553
4554         case EditAtSelectedMarker:
4555                 if (!selection->markers.empty()) {
4556                         bool is_start;
4557                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4558                         if (loc) {
4559                                 if (is_start) {
4560                                         where =  loc->start();
4561                                 } else {
4562                                         where = loc->end();
4563                                 }
4564                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4565                                 break;
4566                         }
4567                 }
4568                 /* fallthru */
4569
4570         default:
4571         case EditAtMouse:
4572                 if (!mouse_frame (where, ignored)) {
4573                         /* XXX not right but what can we do ? */
4574                         return 0;
4575                 }
4576                 snap_to (where);
4577                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4578                 break;
4579         }
4580
4581         return where;
4582 }
4583
4584 void
4585 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4586 {
4587         if (!_session) return;
4588
4589         begin_reversible_command (cmd);
4590
4591         Location* tll;
4592
4593         if ((tll = transport_loop_location()) == 0) {
4594                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4595                 XMLNode &before = _session->locations()->get_state();
4596                 _session->locations()->add (loc, true);
4597                 _session->set_auto_loop_location (loc);
4598                 XMLNode &after = _session->locations()->get_state();
4599                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4600         } else {
4601                 XMLNode &before = tll->get_state();
4602                 tll->set_hidden (false, this);
4603                 tll->set (start, end);
4604                 XMLNode &after = tll->get_state();
4605                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4606         }
4607
4608         commit_reversible_command ();
4609 }
4610
4611 void
4612 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4613 {
4614         if (!_session) return;
4615
4616         begin_reversible_command (cmd);
4617
4618         Location* tpl;
4619
4620         if ((tpl = transport_punch_location()) == 0) {
4621                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
4622                 XMLNode &before = _session->locations()->get_state();
4623                 _session->locations()->add (loc, true);
4624                 _session->set_auto_punch_location (loc);
4625                 XMLNode &after = _session->locations()->get_state();
4626                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4627         }
4628         else {
4629                 XMLNode &before = tpl->get_state();
4630                 tpl->set_hidden (false, this);
4631                 tpl->set (start, end);
4632                 XMLNode &after = tpl->get_state();
4633                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4634         }
4635
4636         commit_reversible_command ();
4637 }
4638
4639 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4640  *  @param rs List to which found regions are added.
4641  *  @param where Time to look at.
4642  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4643  */
4644 void
4645 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4646 {
4647         const TrackViewList* tracks;
4648
4649         if (ts.empty()) {
4650                 tracks = &track_views;
4651         } else {
4652                 tracks = &ts;
4653         }
4654
4655         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4656
4657                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4658
4659                 if (rtv) {
4660                         boost::shared_ptr<Track> tr;
4661                         boost::shared_ptr<Playlist> pl;
4662
4663                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4664
4665                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4666                                                 (framepos_t) floor ( (double) where * tr->speed()));
4667
4668                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4669                                         RegionView* rv = rtv->view()->find_view (*i);
4670                                         if (rv) {
4671                                                 rs.add (rv);
4672                                         }
4673                                 }
4674                         }
4675                 }
4676         }
4677 }
4678
4679 void
4680 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4681 {
4682         const TrackViewList* tracks;
4683
4684         if (ts.empty()) {
4685                 tracks = &track_views;
4686         } else {
4687                 tracks = &ts;
4688         }
4689
4690         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4691                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4692                 if (rtv) {
4693                         boost::shared_ptr<Track> tr;
4694                         boost::shared_ptr<Playlist> pl;
4695
4696                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4697
4698                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4699                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4700
4701                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4702
4703                                         RegionView* rv = rtv->view()->find_view (*i);
4704
4705                                         if (rv) {
4706                                                 rs.add (rv);
4707                                         }
4708                                 }
4709                         }
4710                 }
4711         }
4712 }
4713
4714 /** Get regions using the following method:
4715  *
4716  *  Make a region list using:
4717  *   (a) any selected regions
4718  *   (b) the intersection of any selected tracks and the edit point(*)
4719  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4720  *
4721  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4722  *
4723  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4724  */
4725
4726 RegionSelection
4727 Editor::get_regions_from_selection_and_edit_point ()
4728 {
4729         RegionSelection regions;
4730
4731         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4732                 regions.add (entered_regionview);
4733         } else {
4734                 regions = selection->regions;
4735         }
4736
4737         if ( regions.empty() ) {
4738                 TrackViewList tracks = selection->tracks;
4739
4740                 if (!tracks.empty()) {
4741                         /* no region selected or entered, but some selected tracks:
4742                          * act on all regions on the selected tracks at the edit point
4743                          */ 
4744                         framepos_t const where = get_preferred_edit_position ();
4745                         get_regions_at(regions, where, tracks);
4746                 }
4747         }
4748
4749         return regions;
4750 }
4751
4752 /** Get regions using the following method:
4753  *
4754  *  Make a region list using:
4755  *   (a) any selected regions
4756  *   (b) the intersection of any selected tracks and the edit point(*)
4757  *   (c) if neither exists, then whatever region is under the mouse
4758  *
4759  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4760  *
4761  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4762  */
4763 RegionSelection
4764 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4765 {
4766         RegionSelection regions;
4767
4768         if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4769                 regions.add (entered_regionview);
4770         } else {
4771                 regions = selection->regions;
4772         }
4773
4774         if ( regions.empty() ) {
4775                 TrackViewList tracks = selection->tracks;
4776
4777                 if (!tracks.empty()) {
4778                         /* no region selected or entered, but some selected tracks:
4779                          * act on all regions on the selected tracks at the edit point
4780                          */ 
4781                         get_regions_at(regions, pos, tracks);
4782                 }
4783         }
4784
4785         return regions;
4786 }
4787
4788 /** Start with regions that are selected, or the entered regionview if none are selected.
4789  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4790  *  of the regions that we started with.
4791  */
4792
4793 RegionSelection
4794 Editor::get_regions_from_selection_and_entered ()
4795 {
4796         RegionSelection regions = selection->regions;
4797
4798         if (regions.empty() && entered_regionview) {
4799                 regions.add (entered_regionview);
4800         }
4801
4802         return regions;
4803 }
4804
4805 void
4806 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4807 {
4808         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4809
4810                 RouteTimeAxisView* tatv;
4811
4812                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4813
4814                         boost::shared_ptr<Playlist> pl;
4815                         vector<boost::shared_ptr<Region> > results;
4816                         RegionView* marv;
4817                         boost::shared_ptr<Track> tr;
4818
4819                         if ((tr = tatv->track()) == 0) {
4820                                 /* bus */
4821                                 continue;
4822                         }
4823
4824                         if ((pl = (tr->playlist())) != 0) {
4825                                 if (src_comparison) {
4826                                         pl->get_source_equivalent_regions (region, results);
4827                                 } else {
4828                                         pl->get_region_list_equivalent_regions (region, results);
4829                                 }
4830                         }
4831
4832                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4833                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4834                                         regions.push_back (marv);
4835                                 }
4836                         }
4837
4838                 }
4839         }
4840 }
4841
4842 void
4843 Editor::show_rhythm_ferret ()
4844 {
4845         if (rhythm_ferret == 0) {
4846                 rhythm_ferret = new RhythmFerret(*this);
4847         }
4848
4849         rhythm_ferret->set_session (_session);
4850         rhythm_ferret->show ();
4851         rhythm_ferret->present ();
4852 }
4853
4854 void
4855 Editor::first_idle ()
4856 {
4857         MessageDialog* dialog = 0;
4858         
4859         if (track_views.size() > 1) {
4860                 dialog = new MessageDialog (
4861                         *this,
4862                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4863                         true
4864                         );
4865                 dialog->present ();
4866                 ARDOUR_UI::instance()->flush_pending ();
4867         }
4868
4869         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4870                 (*t)->first_idle();
4871         }
4872
4873         // first idle adds route children (automation tracks), so we need to redisplay here
4874         _routes->redisplay ();
4875
4876         delete dialog;
4877         _have_idled = true;
4878 }
4879
4880 gboolean
4881 Editor::_idle_resize (gpointer arg)
4882 {
4883         return ((Editor*)arg)->idle_resize ();
4884 }
4885
4886 void
4887 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4888 {
4889         if (resize_idle_id < 0) {
4890                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4891                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4892                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4893                  */
4894                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4895                 _pending_resize_amount = 0;
4896         }
4897
4898         /* make a note of the smallest resulting height, so that we can clamp the
4899            lower limit at TimeAxisView::hSmall */
4900
4901         int32_t min_resulting = INT32_MAX;
4902
4903         _pending_resize_amount += h;
4904         _pending_resize_view = view;
4905
4906         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4907
4908         if (selection->tracks.contains (_pending_resize_view)) {
4909                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4910                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4911                 }
4912         }
4913
4914         if (min_resulting < 0) {
4915                 min_resulting = 0;
4916         }
4917
4918         /* clamp */
4919         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4920                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4921         }
4922 }
4923
4924 /** Handle pending resizing of tracks */
4925 bool
4926 Editor::idle_resize ()
4927 {
4928         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4929
4930         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4931             selection->tracks.contains (_pending_resize_view)) {
4932
4933                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4934                         if (*i != _pending_resize_view) {
4935                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4936                         }
4937                 }
4938         }
4939
4940         _pending_resize_amount = 0;
4941         _group_tabs->set_dirty ();
4942         resize_idle_id = -1;
4943
4944         return false;
4945 }
4946
4947 void
4948 Editor::located ()
4949 {
4950         ENSURE_GUI_THREAD (*this, &Editor::located);
4951
4952         if (_session) {
4953                 playhead_cursor->set_position (_session->audible_frame ());
4954                 if (_follow_playhead && !_pending_initial_locate) {
4955                         reset_x_origin_to_follow_playhead ();
4956                 }
4957         }
4958
4959         _pending_locate_request = false;
4960         _pending_initial_locate = false;
4961 }
4962
4963 void
4964 Editor::region_view_added (RegionView *)
4965 {
4966         _summary->set_background_dirty ();
4967 }
4968
4969 void
4970 Editor::region_view_removed ()
4971 {
4972         _summary->set_background_dirty ();
4973 }
4974
4975 RouteTimeAxisView*
4976 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4977 {
4978         TrackViewList::const_iterator j = track_views.begin ();
4979         while (j != track_views.end()) {
4980                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4981                 if (rtv && rtv->route() == r) {
4982                         return rtv;
4983                 }
4984                 ++j;
4985         }
4986
4987         return 0;
4988 }
4989
4990
4991 TrackViewList
4992 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4993 {
4994         TrackViewList t;
4995
4996         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4997                 TimeAxisView* tv = axis_view_from_route (*i);
4998                 if (tv) {
4999                         t.push_back (tv);
5000                 }
5001         }
5002
5003         return t;
5004 }
5005
5006 void
5007 Editor::suspend_route_redisplay ()
5008 {
5009         if (_routes) {
5010                 _routes->suspend_redisplay();
5011         }
5012 }
5013
5014 void
5015 Editor::resume_route_redisplay ()
5016 {
5017         if (_routes) {
5018                 _routes->resume_redisplay();
5019         }
5020 }
5021
5022 void
5023 Editor::add_routes (RouteList& routes)
5024 {
5025         ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5026
5027         RouteTimeAxisView *rtv;
5028         list<RouteTimeAxisView*> new_views;
5029
5030         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5031                 boost::shared_ptr<Route> route = (*x);
5032
5033                 if (route->is_auditioner() || route->is_monitor()) {
5034                         continue;
5035                 }
5036
5037                 DataType dt = route->input()->default_type();
5038
5039                 if (dt == ARDOUR::DataType::AUDIO) {
5040                         rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5041                         rtv->set_route (route);
5042                 } else if (dt == ARDOUR::DataType::MIDI) {
5043                         rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5044                         rtv->set_route (route);
5045                 } else {
5046                         throw unknown_type();
5047                 }
5048
5049                 new_views.push_back (rtv);
5050                 track_views.push_back (rtv);
5051
5052                 rtv->effective_gain_display ();
5053
5054                 if (internal_editing()) {
5055                         rtv->enter_internal_edit_mode ();
5056                 } else {
5057                         rtv->leave_internal_edit_mode ();
5058                 }
5059
5060                 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5061                 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5062         }
5063
5064         if (new_views.size() > 0) {
5065                 _routes->routes_added (new_views);
5066                 _summary->routes_added (new_views);
5067         }
5068
5069         if (show_editor_mixer_when_tracks_arrive) {
5070                 show_editor_mixer (true);
5071         }
5072
5073         editor_list_button.set_sensitive (true);
5074 }
5075
5076 void
5077 Editor::timeaxisview_deleted (TimeAxisView *tv)
5078 {
5079         if (tv == entered_track) {
5080                 entered_track = 0;
5081         }
5082
5083         if (_session && _session->deletion_in_progress()) {
5084                 /* the situation is under control */
5085                 return;
5086         }
5087
5088         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5089
5090         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5091
5092         _routes->route_removed (tv);
5093
5094         TimeAxisView::Children c = tv->get_child_list ();
5095         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5096                 if (entered_track == i->get()) {
5097                         entered_track = 0;
5098                 }
5099         }
5100
5101         /* remove it from the list of track views */
5102
5103         TrackViewList::iterator i;
5104
5105         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5106                 i = track_views.erase (i);
5107         }
5108
5109         /* update whatever the current mixer strip is displaying, if revelant */
5110
5111         boost::shared_ptr<Route> route;
5112
5113         if (rtav) {
5114                 route = rtav->route ();
5115         }
5116
5117         if (current_mixer_strip && current_mixer_strip->route() == route) {
5118
5119                 TimeAxisView* next_tv;
5120
5121                 if (track_views.empty()) {
5122                         next_tv = 0;
5123                 } else if (i == track_views.end()) {
5124                         next_tv = track_views.front();
5125                 } else {
5126                         next_tv = (*i);
5127                 }
5128
5129
5130                 if (next_tv) {
5131                         set_selected_mixer_strip (*next_tv);
5132                 } else {
5133                         /* make the editor mixer strip go away setting the
5134                          * button to inactive (which also unticks the menu option)
5135                          */
5136
5137                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5138                 }
5139         }
5140 }
5141
5142 void
5143 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5144 {
5145         if (apply_to_selection) {
5146                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5147
5148                         TrackSelection::iterator j = i;
5149                         ++j;
5150
5151                         hide_track_in_display (*i, false);
5152
5153                         i = j;
5154                 }
5155         } else {
5156                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5157
5158                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5159                         // this will hide the mixer strip
5160                         set_selected_mixer_strip (*tv);
5161                 }
5162
5163                 _routes->hide_track_in_display (*tv);
5164         }
5165 }
5166
5167 bool
5168 Editor::sync_track_view_list_and_routes ()
5169 {
5170         track_views = TrackViewList (_routes->views ());
5171
5172         _summary->set_dirty ();
5173         _group_tabs->set_dirty ();
5174
5175         return false; // do not call again (until needed)
5176 }
5177
5178 void
5179 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5180 {
5181         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5182                 theslot (**i);
5183         }
5184 }
5185
5186 /** Find a RouteTimeAxisView by the ID of its route */
5187 RouteTimeAxisView*
5188 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5189 {
5190         RouteTimeAxisView* v;
5191
5192         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5193                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5194                         if(v->route()->id() == id) {
5195                                 return v;
5196                         }
5197                 }
5198         }
5199
5200         return 0;
5201 }
5202
5203 void
5204 Editor::fit_route_group (RouteGroup *g)
5205 {
5206         TrackViewList ts = axis_views_from_routes (g->route_list ());
5207         fit_tracks (ts);
5208 }
5209
5210 void
5211 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5212 {
5213         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5214
5215         if (r == 0) {
5216                 _session->cancel_audition ();
5217                 return;
5218         }
5219
5220         if (_session->is_auditioning()) {
5221                 _session->cancel_audition ();
5222                 if (r == last_audition_region) {
5223                         return;
5224                 }
5225         }
5226
5227         _session->audition_region (r);
5228         last_audition_region = r;
5229 }
5230
5231
5232 void
5233 Editor::hide_a_region (boost::shared_ptr<Region> r)
5234 {
5235         r->set_hidden (true);
5236 }
5237
5238 void
5239 Editor::show_a_region (boost::shared_ptr<Region> r)
5240 {
5241         r->set_hidden (false);
5242 }
5243
5244 void
5245 Editor::audition_region_from_region_list ()
5246 {
5247         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5248 }
5249
5250 void
5251 Editor::hide_region_from_region_list ()
5252 {
5253         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5254 }
5255
5256 void
5257 Editor::show_region_in_region_list ()
5258 {
5259         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5260 }
5261
5262 void
5263 Editor::step_edit_status_change (bool yn)
5264 {
5265         if (yn) {
5266                 start_step_editing ();
5267         } else {
5268                 stop_step_editing ();
5269         }
5270 }
5271
5272 void
5273 Editor::start_step_editing ()
5274 {
5275         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5276 }
5277
5278 void
5279 Editor::stop_step_editing ()
5280 {
5281         step_edit_connection.disconnect ();
5282 }
5283
5284 bool
5285 Editor::check_step_edit ()
5286 {
5287         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5288                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5289                 if (mtv) {
5290                         mtv->check_step_edit ();
5291                 }
5292         }
5293
5294         return true; // do it again, till we stop
5295 }
5296
5297 bool
5298 Editor::scroll_press (Direction dir)
5299 {
5300         ++_scroll_callbacks;
5301
5302         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5303                 /* delay the first auto-repeat */
5304                 return true;
5305         }
5306
5307         switch (dir) {
5308         case LEFT:
5309                 scroll_backward (1);
5310                 break;
5311
5312         case RIGHT:
5313                 scroll_forward (1);
5314                 break;
5315
5316         case UP:
5317                 scroll_up_one_track ();
5318                 break;
5319
5320         case DOWN:
5321                 scroll_down_one_track ();
5322                 break;
5323         }
5324
5325         /* do hacky auto-repeat */
5326         if (!_scroll_connection.connected ()) {
5327
5328                 _scroll_connection = Glib::signal_timeout().connect (
5329                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5330                         );
5331
5332                 _scroll_callbacks = 0;
5333         }
5334
5335         return true;
5336 }
5337
5338 void
5339 Editor::scroll_release ()
5340 {
5341         _scroll_connection.disconnect ();
5342 }
5343
5344 /** Queue a change for the Editor viewport x origin to follow the playhead */
5345 void
5346 Editor::reset_x_origin_to_follow_playhead ()
5347 {
5348         framepos_t const frame = playhead_cursor->current_frame ();
5349
5350         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5351
5352                 if (_session->transport_speed() < 0) {
5353
5354                         if (frame > (current_page_samples() / 2)) {
5355                                 center_screen (frame-(current_page_samples()/2));
5356                         } else {
5357                                 center_screen (current_page_samples()/2);
5358                         }
5359
5360                 } else {
5361
5362                         framepos_t l = 0;
5363                         
5364                         if (frame < leftmost_frame) {
5365                                 /* moving left */
5366                                 if (_session->transport_rolling()) {
5367                                         /* rolling; end up with the playhead at the right of the page */
5368                                         l = frame - current_page_samples ();
5369                                 } else {
5370                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5371                                         l = frame - current_page_samples() / 4;
5372                                 }
5373                         } else {
5374                                 /* moving right */
5375                                 if (_session->transport_rolling()) {
5376                                         /* rolling: end up with the playhead on the left of the page */
5377                                         l = frame;
5378                                 } else {
5379                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5380                                         l = frame - 3 * current_page_samples() / 4;
5381                                 }
5382                         }
5383
5384                         if (l < 0) {
5385                                 l = 0;
5386                         }
5387                         
5388                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5389                 }
5390         }
5391 }
5392
5393 void
5394 Editor::super_rapid_screen_update ()
5395 {
5396         if (!_session || !_session->engine().running()) {
5397                 return;
5398         }
5399
5400         /* METERING / MIXER STRIPS */
5401
5402         /* update track meters, if required */
5403         if (is_mapped() && meters_running) {
5404                 RouteTimeAxisView* rtv;
5405                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5406                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5407                                 rtv->fast_update ();
5408                         }
5409                 }
5410         }
5411
5412         /* and any current mixer strip */
5413         if (current_mixer_strip) {
5414                 current_mixer_strip->fast_update ();
5415         }
5416
5417         /* PLAYHEAD AND VIEWPORT */
5418
5419         framepos_t const frame = _session->audible_frame();
5420
5421         /* There are a few reasons why we might not update the playhead / viewport stuff:
5422          *
5423          * 1.  we don't update things when there's a pending locate request, otherwise
5424          *     when the editor requests a locate there is a chance that this method
5425          *     will move the playhead before the locate request is processed, causing
5426          *     a visual glitch.
5427          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5428          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5429          */
5430
5431         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5432
5433                 last_update_frame = frame;
5434
5435                 if (!_dragging_playhead) {
5436                         playhead_cursor->set_position (frame);
5437                 }
5438
5439                 if (!_stationary_playhead) {
5440
5441                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5442                                 /* We only do this if we aren't already
5443                                    handling a visual change (ie if
5444                                    pending_visual_change.being_handled is
5445                                    false) so that these requests don't stack
5446                                    up there are too many of them to handle in
5447                                    time.
5448                                 */
5449                                 reset_x_origin_to_follow_playhead ();
5450                         }
5451
5452                 } else {
5453
5454                         /* don't do continuous scroll till the new position is in the rightmost quarter of the
5455                            editor canvas
5456                         */
5457 #if 0
5458                         // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5459                         double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5460                         if (target <= 0.0) {
5461                                 target = 0.0;
5462                         }
5463                         if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5464                                 target = (target * 0.15) + (current * 0.85);
5465                         } else {
5466                                 /* relax */
5467                         }
5468
5469                         current = target;
5470                         set_horizontal_position (current);
5471 #endif
5472                 }
5473
5474         }
5475 }
5476
5477
5478 void
5479 Editor::session_going_away ()
5480 {
5481         _have_idled = false;
5482
5483         _session_connections.drop_connections ();
5484
5485         super_rapid_screen_update_connection.disconnect ();
5486
5487         selection->clear ();
5488         cut_buffer->clear ();
5489
5490         clicked_regionview = 0;
5491         clicked_axisview = 0;
5492         clicked_routeview = 0;
5493         entered_regionview = 0;
5494         entered_track = 0;
5495         last_update_frame = 0;
5496         _drags->abort ();
5497
5498         playhead_cursor->hide ();
5499
5500         /* rip everything out of the list displays */
5501
5502         _regions->clear ();
5503         _routes->clear ();
5504         _route_groups->clear ();
5505
5506         /* do this first so that deleting a track doesn't reset cms to null
5507            and thus cause a leak.
5508         */
5509
5510         if (current_mixer_strip) {
5511                 if (current_mixer_strip->get_parent() != 0) {
5512                         global_hpacker.remove (*current_mixer_strip);
5513                 }
5514                 delete current_mixer_strip;
5515                 current_mixer_strip = 0;
5516         }
5517
5518         /* delete all trackviews */
5519
5520         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5521                 delete *i;
5522         }
5523         track_views.clear ();
5524
5525         nudge_clock->set_session (0);
5526
5527         editor_list_button.set_active(false);
5528         editor_list_button.set_sensitive(false);
5529
5530         /* clear tempo/meter rulers */
5531         remove_metric_marks ();
5532         hide_measures ();
5533         clear_marker_display ();
5534
5535         stop_step_editing ();
5536         
5537         /* get rid of any existing editor mixer strip */
5538
5539         WindowTitle title(Glib::get_application_name());
5540         title += _("Editor");
5541
5542         set_title (title.get_string());
5543
5544         SessionHandlePtr::session_going_away ();
5545 }
5546
5547
5548 void
5549 Editor::show_editor_list (bool yn)
5550 {
5551         if (yn) {
5552                 _the_notebook.show ();
5553         } else {
5554                 _the_notebook.hide ();
5555         }
5556 }
5557
5558 void
5559 Editor::change_region_layering_order (bool from_context_menu)
5560 {
5561         const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5562
5563         if (!clicked_routeview) {
5564                 if (layering_order_editor) {
5565                         layering_order_editor->hide ();
5566                 }
5567                 return;
5568         }
5569
5570         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5571
5572         if (!track) {
5573                 return;
5574         }
5575
5576         boost::shared_ptr<Playlist> pl = track->playlist();
5577
5578         if (!pl) {
5579                 return;
5580         }
5581
5582         if (layering_order_editor == 0) {
5583                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5584         }
5585
5586         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5587         layering_order_editor->maybe_present ();
5588 }
5589
5590 void
5591 Editor::update_region_layering_order_editor ()
5592 {
5593         if (layering_order_editor && layering_order_editor->is_visible ()) {
5594                 change_region_layering_order (true);
5595         }
5596 }
5597
5598 void
5599 Editor::setup_fade_images ()
5600 {
5601         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5602         _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5603         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5604         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5605         _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5606
5607         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5608         _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5609         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5610         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5611         _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5612         
5613         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5614         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5615         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5616         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5617         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5618
5619         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5620         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5621         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5622         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5623         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5624
5625 }
5626
5627 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5628 Gtk::MenuItem&
5629 Editor::action_menu_item (std::string const & name)
5630 {
5631         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5632         assert (a);
5633
5634         return *manage (a->create_menu_item ());
5635 }
5636
5637 void
5638 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5639 {
5640         EventBox* b = manage (new EventBox);
5641         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5642         Label* l = manage (new Label (name));
5643         l->set_angle (-90);
5644         b->add (*l);
5645         b->show_all ();
5646         _the_notebook.append_page (widget, *b);
5647 }
5648
5649 bool
5650 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5651 {
5652         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5653                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5654         }
5655
5656         if (ev->type == GDK_2BUTTON_PRESS) {
5657
5658                 /* double-click on a notebook tab shrinks or expands the notebook */
5659
5660                 if (_notebook_shrunk) {
5661                         if (pre_notebook_shrink_pane_width) {
5662                                 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5663                         }
5664                         _notebook_shrunk = false;
5665                 } else {
5666                         pre_notebook_shrink_pane_width = edit_pane.get_position();
5667
5668                         /* this expands the LHS of the edit pane to cover the notebook
5669                            PAGE but leaves the tabs visible.
5670                          */
5671                         edit_pane.set_position (edit_pane.get_position() + page->get_width());
5672                         _notebook_shrunk = true;
5673                 }
5674         }
5675
5676         return true;
5677 }
5678
5679 void
5680 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5681 {
5682         using namespace Menu_Helpers;
5683         
5684         MenuList& items = _control_point_context_menu.items ();
5685         items.clear ();
5686         
5687         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5688         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5689         if (!can_remove_control_point (item)) {
5690                 items.back().set_sensitive (false);
5691         }
5692
5693         _control_point_context_menu.popup (event->button.button, event->button.time);
5694 }
5695
5696 void
5697 Editor::zoom_vertical_modifier_released()
5698 {
5699         _stepping_axis_view = 0;
5700 }
5701
5702 void
5703 Editor::ui_parameter_changed (string parameter)
5704 {
5705         if (parameter == "icon-set") {
5706                 while (!_cursor_stack.empty()) {
5707                         _cursor_stack.pop();
5708                 }
5709                 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5710         } else if (parameter == "draggable-playhead") {
5711                 if (_verbose_cursor) {
5712                         playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());
5713                 }
5714         }
5715 }