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