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