Add automation track control points to undo history (and selection_op history).
[ardour.git] / gtk2_ardour / editor.cc
1 /*
2     Copyright (C) 2000-2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <stdint.h>
23 #include <unistd.h>
24 #include <cstdlib>
25 #include <cmath>
26 #include <string>
27 #include <algorithm>
28 #include <map>
29
30 #include "ardour_ui.h"
31 /*
32  * ardour_ui.h include was moved to the top of the list
33  * due to a conflicting definition of 'Style' between
34  * Apple's MacTypes.h and BarController.
35  */
36
37 #include <boost/none.hpp>
38
39 #include <sigc++/bind.h>
40
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
49
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
55
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
58
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
67
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
77
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
80
81 #include "control_protocol/control_protocol.h"
82
83 #include "actions.h"
84 #include "actions.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
93 #include "debug.h"
94 #include "editing.h"
95 #include "editor.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
109 #include "marker.h"
110 #include "midi_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           /* time display buttons */
255         , minsec_label (_("Mins:Secs"))
256         , bbt_label (_("Bars:Beats"))
257         , timecode_label (_("Timecode"))
258         , samples_label (_("Samples"))
259         , tempo_label (_("Tempo"))
260         , meter_label (_("Meter"))
261         , mark_label (_("Location Markers"))
262         , range_mark_label (_("Range Markers"))
263         , transport_mark_label (_("Loop/Punch Ranges"))
264         , cd_mark_label (_("CD Markers"))
265         , videotl_label (_("Video Timeline"))
266         , edit_packer (4, 4, true)
267
268           /* the values here don't matter: layout widgets
269              reset them as needed.
270           */
271
272         , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
273         , horizontal_adjustment (0.0, 0.0, 1e16)
274         , unused_adjustment (0.0, 0.0, 10.0, 400.0)
275
276         , controls_layout (unused_adjustment, vertical_adjustment)
277
278           /* tool bar related */
279
280         , toolbar_selection_clock_table (2,3)
281         , _mouse_mode_tearoff (0)
282         , automation_mode_button (_("mode"))
283         , _zoom_tearoff (0)
284         , _tools_tearoff (0)
285
286         , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
287         , selection_op_cmd_depth (0)
288         , selection_op_history_it (0)
289
290           /* nudge */
291
292         , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
293         , meters_running(false)
294         , _pending_locate_request (false)
295         , _pending_initial_locate (false)
296         , _last_cut_copy_source_track (0)
297
298         , _region_selection_change_updates_region_list (true)
299         , _following_mixer_selection (false)
300         , _control_point_toggled_on_press (false)
301         , _stepping_axis_view (0)
302 {
303         constructed = false;
304
305         /* we are a singleton */
306
307         PublicEditor::_instance = this;
308
309         _have_idled = false;
310         
311         selection = new Selection (this);
312         cut_buffer = new Selection (this);
313         _selection_memento = new SelectionMemento ();
314         selection_op_history.clear();
315         before.clear();
316
317         clicked_regionview = 0;
318         clicked_axisview = 0;
319         clicked_routeview = 0;
320         clicked_control_point = 0;
321         last_update_frame = 0;
322         last_paste_pos = 0;
323         paste_count = 0;
324         _drags = new DragManager (this);
325         lock_dialog = 0;
326         ruler_dialog = 0;
327         current_mixer_strip = 0;
328         tempo_lines = 0;
329
330         snap_type_strings =  I18N (_snap_type_strings);
331         snap_mode_strings =  I18N (_snap_mode_strings);
332         zoom_focus_strings = I18N (_zoom_focus_strings);
333         edit_mode_strings = I18N (_edit_mode_strings);
334         edit_point_strings = I18N (_edit_point_strings);
335 #ifdef USE_RUBBERBAND
336         rb_opt_strings = I18N (_rb_opt_strings);
337         rb_current_opt = 4;
338 #endif
339
340         build_edit_mode_menu();
341         build_zoom_focus_menu();
342         build_track_count_menu();
343         build_snap_mode_menu();
344         build_snap_type_menu();
345         build_edit_point_menu();
346
347         snap_threshold = 5.0;
348         bbt_beat_subdivision = 4;
349         _visible_canvas_width = 0;
350         _visible_canvas_height = 0;
351         autoscroll_horizontal_allowed = false;
352         autoscroll_vertical_allowed = false;
353         logo_item = 0;
354
355         analysis_window = 0;
356
357         current_interthread_info = 0;
358         _show_measures = true;
359         _maximised = false;
360         show_gain_after_trim = false;
361
362         have_pending_keyboard_selection = false;
363         _follow_playhead = true;
364         _stationary_playhead = false;
365         editor_ruler_menu = 0;
366         no_ruler_shown_update = false;
367         marker_menu = 0;
368         range_marker_menu = 0;
369         marker_menu_item = 0;
370         tempo_or_meter_marker_menu = 0;
371         transport_marker_menu = 0;
372         new_transport_marker_menu = 0;
373         editor_mixer_strip_width = Wide;
374         show_editor_mixer_when_tracks_arrive = false;
375         region_edit_menu_split_multichannel_item = 0;
376         region_edit_menu_split_item = 0;
377         temp_location = 0;
378         leftmost_frame = 0;
379         current_stepping_trackview = 0;
380         entered_track = 0;
381         entered_regionview = 0;
382         entered_marker = 0;
383         clear_entered_track = false;
384         current_timefx = 0;
385         playhead_cursor = 0;
386         button_release_can_deselect = true;
387         _dragging_playhead = false;
388         _dragging_edit_point = false;
389         select_new_marker = false;
390         rhythm_ferret = 0;
391         layering_order_editor = 0;
392         no_save_visual = false;
393         resize_idle_id = -1;
394         within_track_canvas = false;
395
396         scrubbing_direction = 0;
397
398         sfbrowser = 0;
399
400         location_marker_color = ARDOUR_UI::config()->color ("location marker");
401         location_range_color = ARDOUR_UI::config()->color ("location range");
402         location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
403         location_loop_color = ARDOUR_UI::config()->color ("location loop");
404         location_punch_color = ARDOUR_UI::config()->color ("location punch");
405
406         zoom_focus = ZoomFocusLeft;
407         _edit_point = EditAtMouse;
408         _visible_track_count = -1;
409
410         samples_per_pixel = 2048; /* too early to use reset_zoom () */
411
412         timebar_height = std::max(12., ceil (15. * ARDOUR_UI::config()->get_font_scale() / 102400.));
413         TimeAxisView::setup_sizes ();
414         Marker::setup_sizes (timebar_height);
415
416         _scroll_callbacks = 0;
417
418         bbt_label.set_name ("EditorRulerLabel");
419         bbt_label.set_size_request (-1, (int)timebar_height);
420         bbt_label.set_alignment (1.0, 0.5);
421         bbt_label.set_padding (5,0);
422         bbt_label.hide ();
423         bbt_label.set_no_show_all();
424         minsec_label.set_name ("EditorRulerLabel");
425         minsec_label.set_size_request (-1, (int)timebar_height);
426         minsec_label.set_alignment (1.0, 0.5);
427         minsec_label.set_padding (5,0);
428         minsec_label.hide ();
429         minsec_label.set_no_show_all();
430         timecode_label.set_name ("EditorRulerLabel");
431         timecode_label.set_size_request (-1, (int)timebar_height);
432         timecode_label.set_alignment (1.0, 0.5);
433         timecode_label.set_padding (5,0);
434         timecode_label.hide ();
435         timecode_label.set_no_show_all();
436         samples_label.set_name ("EditorRulerLabel");
437         samples_label.set_size_request (-1, (int)timebar_height);
438         samples_label.set_alignment (1.0, 0.5);
439         samples_label.set_padding (5,0);
440         samples_label.hide ();
441         samples_label.set_no_show_all();
442
443         tempo_label.set_name ("EditorRulerLabel");
444         tempo_label.set_size_request (-1, (int)timebar_height);
445         tempo_label.set_alignment (1.0, 0.5);
446         tempo_label.set_padding (5,0);
447         tempo_label.hide();
448         tempo_label.set_no_show_all();
449
450         meter_label.set_name ("EditorRulerLabel");
451         meter_label.set_size_request (-1, (int)timebar_height);
452         meter_label.set_alignment (1.0, 0.5);
453         meter_label.set_padding (5,0);
454         meter_label.hide();
455         meter_label.set_no_show_all();
456
457         if (Profile->get_trx()) {
458                 mark_label.set_text (_("Markers"));
459         }
460         mark_label.set_name ("EditorRulerLabel");
461         mark_label.set_size_request (-1, (int)timebar_height);
462         mark_label.set_alignment (1.0, 0.5);
463         mark_label.set_padding (5,0);
464         mark_label.hide();
465         mark_label.set_no_show_all();
466
467         cd_mark_label.set_name ("EditorRulerLabel");
468         cd_mark_label.set_size_request (-1, (int)timebar_height);
469         cd_mark_label.set_alignment (1.0, 0.5);
470         cd_mark_label.set_padding (5,0);
471         cd_mark_label.hide();
472         cd_mark_label.set_no_show_all();
473
474         videotl_bar_height = 4;
475         videotl_label.set_name ("EditorRulerLabel");
476         videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
477         videotl_label.set_alignment (1.0, 0.5);
478         videotl_label.set_padding (5,0);
479         videotl_label.hide();
480         videotl_label.set_no_show_all();
481
482         range_mark_label.set_name ("EditorRulerLabel");
483         range_mark_label.set_size_request (-1, (int)timebar_height);
484         range_mark_label.set_alignment (1.0, 0.5);
485         range_mark_label.set_padding (5,0);
486         range_mark_label.hide();
487         range_mark_label.set_no_show_all();
488
489         transport_mark_label.set_name ("EditorRulerLabel");
490         transport_mark_label.set_size_request (-1, (int)timebar_height);
491         transport_mark_label.set_alignment (1.0, 0.5);
492         transport_mark_label.set_padding (5,0);
493         transport_mark_label.hide();
494         transport_mark_label.set_no_show_all();
495
496         initialize_canvas ();
497
498         CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
499
500         _summary = new EditorSummary (this);
501
502         selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
503         selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
504
505         editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
506
507         selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
508         selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
509
510         edit_controls_vbox.set_spacing (0);
511         vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
512         _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
513
514         HBox* h = manage (new HBox);
515         _group_tabs = new EditorGroupTabs (this);
516         if (!ARDOUR::Profile->get_trx()) {
517                 h->pack_start (*_group_tabs, PACK_SHRINK);
518         }
519         h->pack_start (edit_controls_vbox);
520         controls_layout.add (*h);
521
522         controls_layout.set_name ("EditControlsBase");
523         controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
524         controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
525         controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
526
527         _cursors = new MouseCursors;
528         _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
529         cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
530
531         /* Push default cursor to ever-present bottom of cursor stack. */
532         push_canvas_cursor(_cursors->grabber);
533
534         ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
535
536         ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
537         pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
538         pad_line_1->set_outline_color (0xFF0000FF);
539         pad_line_1->show();
540
541         // CAIROCANVAS
542         time_pad->show();
543
544         edit_packer.set_col_spacings (0);
545         edit_packer.set_row_spacings (0);
546         edit_packer.set_homogeneous (false);
547         edit_packer.set_border_width (0);
548         edit_packer.set_name ("EditorWindow");
549
550         time_bars_event_box.add (time_bars_vbox);
551         time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
552         time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
553
554         /* labels for the time bars */
555         edit_packer.attach (time_bars_event_box,     0, 1, 0, 1,    FILL,        SHRINK, 0, 0);
556         /* track controls */
557         edit_packer.attach (controls_layout,         0, 1, 1, 2,    FILL,        FILL|EXPAND, 0, 0);
558         /* canvas */
559         edit_packer.attach (*_track_canvas_viewport,  1, 2, 0, 2,    FILL|EXPAND, FILL|EXPAND, 0, 0);
560
561         bottom_hbox.set_border_width (2);
562         bottom_hbox.set_spacing (3);
563
564         _route_groups = new EditorRouteGroups (this);
565         _routes = new EditorRoutes (this);
566         _regions = new EditorRegions (this);
567         _snapshots = new EditorSnapshots (this);
568         _locations = new EditorLocations (this);
569
570         /* these are static location signals */
571
572         Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
573         Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
574         Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
575
576         add_notebook_page (_("Regions"), _regions->widget ());
577         add_notebook_page (_("Tracks & Busses"), _routes->widget ());
578         add_notebook_page (_("Snapshots"), _snapshots->widget ());
579         add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
580         add_notebook_page (_("Ranges & Marks"), _locations->widget ());
581
582         _the_notebook.set_show_tabs (true);
583         _the_notebook.set_scrollable (true);
584         _the_notebook.popup_disable ();
585         _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
586         _the_notebook.show_all ();
587
588         _notebook_shrunk = false;
589
590         editor_summary_pane.pack1(edit_packer);
591
592         Button* summary_arrows_left_left = manage (new Button);
593         summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
594         summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
595         summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
596
597         Button* summary_arrows_left_right = manage (new Button);
598         summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
599         summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
600         summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
601
602         VBox* summary_arrows_left = manage (new VBox);
603         summary_arrows_left->pack_start (*summary_arrows_left_left);
604         summary_arrows_left->pack_start (*summary_arrows_left_right);
605
606         Button* summary_arrows_right_up = manage (new Button);
607         summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
608         summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
609         summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
610
611         Button* summary_arrows_right_down = manage (new Button);
612         summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
613         summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
614         summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
615
616         VBox* summary_arrows_right = manage (new VBox);
617         summary_arrows_right->pack_start (*summary_arrows_right_up);
618         summary_arrows_right->pack_start (*summary_arrows_right_down);
619
620         Frame* summary_frame = manage (new Frame);
621         summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
622
623         summary_frame->add (*_summary);
624         summary_frame->show ();
625
626         _summary_hbox.pack_start (*summary_arrows_left, false, false);
627         _summary_hbox.pack_start (*summary_frame, true, true);
628         _summary_hbox.pack_start (*summary_arrows_right, false, false);
629
630         if (!ARDOUR::Profile->get_trx()) {
631                 editor_summary_pane.pack2 (_summary_hbox);
632         }
633
634         edit_pane.pack1 (editor_summary_pane, true, true);
635         if (!ARDOUR::Profile->get_trx()) {
636                 edit_pane.pack2 (_the_notebook, false, true);
637         }
638
639         editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
640
641         /* XXX: editor_summary_pane might need similar to the edit_pane */
642
643         edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
644
645         Glib::PropertyProxy<int> proxy = edit_pane.property_position();
646         proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
647
648         top_hbox.pack_start (toolbar_frame);
649
650         HBox *hbox = manage (new HBox);
651         hbox->pack_start (edit_pane, true, true);
652
653         global_vpacker.pack_start (top_hbox, false, false);
654         global_vpacker.pack_start (*hbox, true, true);
655
656         global_hpacker.pack_start (global_vpacker, true, true);
657
658         set_name ("EditorWindow");
659         add_accel_group (ActionManager::ui_manager->get_accel_group());
660
661         status_bar_hpacker.show ();
662
663         vpacker.pack_end (status_bar_hpacker, false, false);
664         vpacker.pack_end (global_hpacker, true, true);
665
666         /* register actions now so that set_state() can find them and set toggles/checks etc */
667
668         register_actions ();
669         /* when we start using our own keybinding system for the editor, this
670          * will be uncommented
671          */
672         // load_bindings ();
673
674         setup_toolbar ();
675
676         set_zoom_focus (zoom_focus);
677         set_visible_track_count (_visible_track_count);
678         _snap_type = SnapToBeat;
679         set_snap_to (_snap_type);
680         _snap_mode = SnapOff;
681         set_snap_mode (_snap_mode);
682         set_mouse_mode (MouseObject, true);
683         pre_internal_mouse_mode = MouseObject;
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 (false, 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 Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1864         edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1865         edit_items.push_back (MenuElem (_("Set Session Start/End from Range"), 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(*this, &Editor::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         _snap_type = st;
2042
2043         if (snap_ind > snap_type_strings.size() - 1) {
2044                 snap_ind = 0;
2045                 _snap_type = (SnapType)snap_ind;
2046         }
2047
2048         string str = snap_type_strings[snap_ind];
2049
2050         if (str != snap_type_selector.get_text()) {
2051                 snap_type_selector.set_text (str);
2052         }
2053
2054         instant_save ();
2055
2056         switch (_snap_type) {
2057         case SnapToBeatDiv128:
2058         case SnapToBeatDiv64:
2059         case SnapToBeatDiv32:
2060         case SnapToBeatDiv28:
2061         case SnapToBeatDiv24:
2062         case SnapToBeatDiv20:
2063         case SnapToBeatDiv16:
2064         case SnapToBeatDiv14:
2065         case SnapToBeatDiv12:
2066         case SnapToBeatDiv10:
2067         case SnapToBeatDiv8:
2068         case SnapToBeatDiv7:
2069         case SnapToBeatDiv6:
2070         case SnapToBeatDiv5:
2071         case SnapToBeatDiv4:
2072         case SnapToBeatDiv3:
2073         case SnapToBeatDiv2: {
2074                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2075                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2076                 
2077                 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2078                                             current_bbt_points_begin, current_bbt_points_end);
2079                 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2080                                          current_bbt_points_begin, current_bbt_points_end);
2081                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2082                 break;
2083         }
2084
2085         case SnapToRegionStart:
2086         case SnapToRegionEnd:
2087         case SnapToRegionSync:
2088         case SnapToRegionBoundary:
2089                 build_region_boundary_cache ();
2090                 break;
2091
2092         default:
2093                 /* relax */
2094                 break;
2095         }
2096
2097         SnapChanged (); /* EMIT SIGNAL */
2098 }
2099
2100 void
2101 Editor::set_snap_mode (SnapMode mode)
2102 {
2103         string str = snap_mode_strings[(int)mode];
2104
2105         if (internal_editing()) {
2106                 internal_snap_mode = mode;
2107         } else {
2108                 pre_internal_snap_mode = mode;
2109         }
2110
2111         _snap_mode = mode;
2112
2113         if (str != snap_mode_selector.get_text ()) {
2114                 snap_mode_selector.set_text (str);
2115         }
2116
2117         instant_save ();
2118 }
2119 void
2120 Editor::set_edit_point_preference (EditPoint ep, bool force)
2121 {
2122         bool changed = (_edit_point != ep);
2123
2124         _edit_point = ep;
2125         if (Profile->get_mixbus())
2126                 if (ep == EditAtSelectedMarker)
2127                         ep = EditAtPlayhead;
2128
2129         string str = edit_point_strings[(int)ep];
2130         if (str != edit_point_selector.get_text ()) {
2131                 edit_point_selector.set_text (str);
2132         }
2133
2134         update_all_enter_cursors();
2135
2136         if (!force && !changed) {
2137                 return;
2138         }
2139
2140         const char* action=NULL;
2141
2142         switch (_edit_point) {
2143         case EditAtPlayhead:
2144                 action = "edit-at-playhead";
2145                 break;
2146         case EditAtSelectedMarker:
2147                 action = "edit-at-marker";
2148                 break;
2149         case EditAtMouse:
2150                 action = "edit-at-mouse";
2151                 break;
2152         }
2153
2154         Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2155         if (act) {
2156                 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2157         }
2158
2159         framepos_t foo;
2160         bool in_track_canvas;
2161
2162         if (!mouse_frame (foo, in_track_canvas)) {
2163                 in_track_canvas = false;
2164         }
2165
2166         reset_canvas_action_sensitivity (in_track_canvas);
2167
2168         instant_save ();
2169 }
2170
2171 int
2172 Editor::set_state (const XMLNode& node, int /*version*/)
2173 {
2174         const XMLProperty* prop;
2175         XMLNode* geometry;
2176         int x, y;
2177         Gdk::Geometry g;
2178
2179         set_id (node);
2180
2181         g.base_width = default_width;
2182         g.base_height = default_height;
2183         x = 1;
2184         y = 1;
2185
2186         if ((geometry = find_named_node (node, "geometry")) != 0) {
2187
2188                 XMLProperty* prop;
2189
2190                 if ((prop = geometry->property("x_size")) == 0) {
2191                         prop = geometry->property ("x-size");
2192                 }
2193                 if (prop) {
2194                         g.base_width = atoi(prop->value());
2195                 }
2196                 if ((prop = geometry->property("y_size")) == 0) {
2197                         prop = geometry->property ("y-size");
2198                 }
2199                 if (prop) {
2200                         g.base_height = atoi(prop->value());
2201                 }
2202
2203                 if ((prop = geometry->property ("x_pos")) == 0) {
2204                         prop = geometry->property ("x-pos");
2205                 }
2206                 if (prop) {
2207                         x = atoi (prop->value());
2208
2209                 }
2210                 if ((prop = geometry->property ("y_pos")) == 0) {
2211                         prop = geometry->property ("y-pos");
2212                 }
2213                 if (prop) {
2214                         y = atoi (prop->value());
2215                 }
2216         }
2217
2218         set_default_size (g.base_width, g.base_height);
2219         move (x, y);
2220
2221         if (_session && (prop = node.property ("playhead"))) {
2222                 framepos_t pos;
2223                 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2224                 if (pos >= 0) {
2225                         playhead_cursor->set_position (pos);
2226                 } else {
2227                         warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2228                         playhead_cursor->set_position (0);
2229                 }
2230         } else {
2231                 playhead_cursor->set_position (0);
2232         }
2233
2234         if ((prop = node.property ("mixer-width"))) {
2235                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2236         }
2237
2238         if ((prop = node.property ("zoom-focus"))) {
2239                 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2240         }
2241
2242         if ((prop = node.property ("zoom"))) {
2243                 /* older versions of ardour used floating point samples_per_pixel */
2244                 double f = PBD::atof (prop->value());
2245                 reset_zoom (llrintf (f));
2246         } else {
2247                 reset_zoom (samples_per_pixel);
2248         }
2249
2250         if ((prop = node.property ("visible-track-count"))) {
2251                 set_visible_track_count (PBD::atoi (prop->value()));
2252         }
2253
2254         if ((prop = node.property ("snap-to"))) {
2255                 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2256         }
2257
2258         if ((prop = node.property ("snap-mode"))) {
2259                 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2260         }
2261
2262         if ((prop = node.property ("internal-snap-to"))) {
2263                 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2264         }
2265
2266         if ((prop = node.property ("internal-snap-mode"))) {
2267                 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2268         }
2269
2270         if ((prop = node.property ("pre-internal-snap-to"))) {
2271                 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2272         }
2273
2274         if ((prop = node.property ("pre-internal-snap-mode"))) {
2275                 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2276         }
2277
2278         if ((prop = node.property ("mouse-mode"))) {
2279                 MouseMode m = str2mousemode(prop->value());
2280                 set_mouse_mode (m, true);
2281         } else {
2282                 set_mouse_mode (MouseObject, true);
2283         }
2284
2285         if ((prop = node.property ("left-frame")) != 0) {
2286                 framepos_t pos;
2287                 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2288                         if (pos < 0) {
2289                                 pos = 0;
2290                         }
2291                         reset_x_origin (pos);
2292                 }
2293         }
2294
2295         if ((prop = node.property ("y-origin")) != 0) {
2296                 reset_y_origin (atof (prop->value ()));
2297         }
2298
2299         if ((prop = node.property ("join-object-range"))) {
2300                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2301                 bool yn = string_is_affirmative (prop->value());
2302                 if (act) {
2303                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2304                         tact->set_active (!yn);
2305                         tact->set_active (yn);
2306                 }
2307                 set_mouse_mode(mouse_mode, true);
2308         }
2309
2310         if ((prop = node.property ("edit-point"))) {
2311                 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2312         }
2313
2314         if ((prop = node.property ("show-measures"))) {
2315                 bool yn = string_is_affirmative (prop->value());
2316                 _show_measures = yn;
2317                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2318                 if (act) {
2319                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2320                         /* do it twice to force the change */
2321                         tact->set_active (!yn);
2322                         tact->set_active (yn);
2323                 }
2324         }
2325
2326         if ((prop = node.property ("follow-playhead"))) {
2327                 bool yn = string_is_affirmative (prop->value());
2328                 set_follow_playhead (yn);
2329                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2330                 if (act) {
2331                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2332                         if (tact->get_active() != yn) {
2333                                 tact->set_active (yn);
2334                         }
2335                 }
2336         }
2337
2338         if ((prop = node.property ("stationary-playhead"))) {
2339                 bool yn = string_is_affirmative (prop->value());
2340                 set_stationary_playhead (yn);
2341                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2342                 if (act) {
2343                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2344                         if (tact->get_active() != yn) {
2345                                 tact->set_active (yn);
2346                         }
2347                 }
2348         }
2349
2350         if ((prop = node.property ("region-list-sort-type"))) {
2351                 RegionListSortType st;
2352                 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2353         }
2354
2355         if ((prop = node.property ("show-editor-mixer"))) {
2356
2357                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2358                 assert (act);
2359
2360                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2361                 bool yn = string_is_affirmative (prop->value());
2362
2363                 /* do it twice to force the change */
2364
2365                 tact->set_active (!yn);
2366                 tact->set_active (yn);
2367         }
2368
2369         if ((prop = node.property ("show-editor-list"))) {
2370
2371                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2372                 assert (act);
2373
2374                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2375                 bool yn = string_is_affirmative (prop->value());
2376
2377                 /* do it twice to force the change */
2378
2379                 tact->set_active (!yn);
2380                 tact->set_active (yn);
2381         }
2382
2383         if ((prop = node.property (X_("editor-list-page")))) {
2384                 _the_notebook.set_current_page (atoi (prop->value ()));
2385         }
2386
2387         if ((prop = node.property (X_("show-marker-lines")))) {
2388                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2389                 assert (act);
2390                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2391                 bool yn = string_is_affirmative (prop->value ());
2392
2393                 tact->set_active (!yn);
2394                 tact->set_active (yn);
2395         }
2396
2397         XMLNodeList children = node.children ();
2398         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2399                 selection->set_state (**i, Stateful::current_state_version);
2400                 _regions->set_state (**i);
2401         }
2402
2403         if ((prop = node.property ("maximised"))) {
2404                 bool yn = string_is_affirmative (prop->value());
2405                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2406                 assert (act);
2407                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2408                 bool fs = tact && tact->get_active();
2409                 if (yn ^ fs) {
2410                         ActionManager::do_action ("Common", "ToggleMaximalEditor");
2411                 }
2412         }
2413
2414         if ((prop = node.property ("nudge-clock-value"))) {
2415                 framepos_t f;
2416                 sscanf (prop->value().c_str(), "%" PRId64, &f);
2417                 nudge_clock->set (f);
2418         } else {
2419                 nudge_clock->set_mode (AudioClock::Timecode);
2420                 nudge_clock->set (_session->frame_rate() * 5, true);
2421         }
2422
2423         return 0;
2424 }
2425
2426 XMLNode&
2427 Editor::get_state ()
2428 {
2429         XMLNode* node = new XMLNode ("Editor");
2430         char buf[32];
2431
2432         id().print (buf, sizeof (buf));
2433         node->add_property ("id", buf);
2434
2435         if (is_realized()) {
2436                 Glib::RefPtr<Gdk::Window> win = get_window();
2437
2438                 int x, y, width, height;
2439                 win->get_root_origin(x, y);
2440                 win->get_size(width, height);
2441
2442                 XMLNode* geometry = new XMLNode ("geometry");
2443
2444                 snprintf(buf, sizeof(buf), "%d", width);
2445                 geometry->add_property("x-size", string(buf));
2446                 snprintf(buf, sizeof(buf), "%d", height);
2447                 geometry->add_property("y-size", string(buf));
2448                 snprintf(buf, sizeof(buf), "%d", x);
2449                 geometry->add_property("x-pos", string(buf));
2450                 snprintf(buf, sizeof(buf), "%d", y);
2451                 geometry->add_property("y-pos", string(buf));
2452                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2453                 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2454                 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2455                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2456                 geometry->add_property("edit-vertical-pane-pos", string(buf));
2457
2458                 node->add_child_nocopy (*geometry);
2459         }
2460
2461         maybe_add_mixer_strip_width (*node);
2462
2463         node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2464
2465         snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2466         node->add_property ("zoom", buf);
2467         node->add_property ("snap-to", enum_2_string (_snap_type));
2468         node->add_property ("snap-mode", enum_2_string (_snap_mode));
2469         node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2470         node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2471         node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2472         node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2473         node->add_property ("edit-point", enum_2_string (_edit_point));
2474         snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2475         node->add_property ("visible-track-count", buf);
2476
2477         snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2478         node->add_property ("playhead", buf);
2479         snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2480         node->add_property ("left-frame", buf);
2481         snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2482         node->add_property ("y-origin", buf);
2483
2484         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2485         node->add_property ("maximised", _maximised ? "yes" : "no");
2486         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2487         node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2488         node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2489         node->add_property ("mouse-mode", enum2str(mouse_mode));
2490         node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2491
2492         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2493         if (act) {
2494                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2495                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2496         }
2497
2498         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2499         if (act) {
2500                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2501                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2502         }
2503
2504         snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2505         node->add_property (X_("editor-list-page"), buf);
2506
2507         if (button_bindings) {
2508                 XMLNode* bb = new XMLNode (X_("Buttons"));
2509                 button_bindings->save (*bb);
2510                 node->add_child_nocopy (*bb);
2511         }
2512
2513         node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2514
2515         node->add_child_nocopy (selection->get_state ());
2516         node->add_child_nocopy (_regions->get_state ());
2517
2518         snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2519         node->add_property ("nudge-clock-value", buf);
2520
2521         return *node;
2522 }
2523
2524 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2525  *  if @param trackview_relative_offset is false, @param y y is a global canvas *  coordinate, in pixel units
2526  *
2527  *  @return pair: TimeAxisView that y is over, layer index.
2528  *
2529  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2530  *  in stacked or expanded region display mode, otherwise 0.
2531  */
2532 std::pair<TimeAxisView *, double>
2533 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2534 {
2535         if (!trackview_relative_offset) {
2536                 y -= _trackview_group->canvas_origin().y;
2537         }
2538
2539         if (y < 0) {
2540                 return std::make_pair ( (TimeAxisView *) 0, 0);
2541         }
2542
2543         for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2544                         
2545                 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2546                         
2547                 if (r.first) {
2548                         return r;
2549                 }
2550         }
2551
2552         return std::make_pair ( (TimeAxisView *) 0, 0);
2553 }
2554
2555 /** Snap a position to the grid, if appropriate, taking into account current
2556  *  grid settings and also the state of any snap modifier keys that may be pressed.
2557  *  @param start Position to snap.
2558  *  @param event Event to get current key modifier information from, or 0.
2559  */
2560 void
2561 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2562 {
2563         if (!_session || !event) {
2564                 return;
2565         }
2566
2567         if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2568                 if (_snap_mode == SnapOff) {
2569                         snap_to_internal (start, direction, for_mark);
2570                 }
2571         } else {
2572                 if (_snap_mode != SnapOff) {
2573                         snap_to_internal (start, direction, for_mark);
2574                 }
2575         }
2576 }
2577
2578 void
2579 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2580 {
2581         if (!_session || _snap_mode == SnapOff) {
2582                 return;
2583         }
2584
2585         snap_to_internal (start, direction, for_mark);
2586 }
2587
2588 void
2589 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2590 {
2591         const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2592         framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2593
2594         switch (_snap_type) {
2595         case SnapToTimecodeFrame:
2596                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2597                     fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2598                         /* start is already on a whole timecode frame, do nothing */
2599                 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2600                         start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2601                 } else {
2602                         start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) *  _session->frames_per_timecode_frame());
2603                 }
2604                 break;
2605
2606         case SnapToTimecodeSeconds:
2607                 if (_session->config.get_timecode_offset_negative()) {
2608                         start += _session->config.get_timecode_offset ();
2609                 } else {
2610                         start -= _session->config.get_timecode_offset ();
2611                 }
2612                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2613                     (start % one_timecode_second == 0)) {
2614                         /* start is already on a whole second, do nothing */
2615                 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2616                         start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2617                 } else {
2618                         start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2619                 }
2620
2621                 if (_session->config.get_timecode_offset_negative()) {
2622                         start -= _session->config.get_timecode_offset ();
2623                 } else {
2624                         start += _session->config.get_timecode_offset ();
2625                 }
2626                 break;
2627
2628         case SnapToTimecodeMinutes:
2629                 if (_session->config.get_timecode_offset_negative()) {
2630                         start += _session->config.get_timecode_offset ();
2631                 } else {
2632                         start -= _session->config.get_timecode_offset ();
2633                 }
2634                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2635                     (start % one_timecode_minute == 0)) {
2636                         /* start is already on a whole minute, do nothing */
2637                 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2638                         start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2639                 } else {
2640                         start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2641                 }
2642                 if (_session->config.get_timecode_offset_negative()) {
2643                         start -= _session->config.get_timecode_offset ();
2644                 } else {
2645                         start += _session->config.get_timecode_offset ();
2646                 }
2647                 break;
2648         default:
2649                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2650                 abort(); /*NOTREACHED*/
2651         }
2652 }
2653
2654 void
2655 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2656 {
2657         const framepos_t one_second = _session->frame_rate();
2658         const framepos_t one_minute = _session->frame_rate() * 60;
2659         framepos_t presnap = start;
2660         framepos_t before;
2661         framepos_t after;
2662
2663         switch (_snap_type) {
2664         case SnapToTimecodeFrame:
2665         case SnapToTimecodeSeconds:
2666         case SnapToTimecodeMinutes:
2667                 return timecode_snap_to_internal (start, direction, for_mark);
2668
2669         case SnapToCDFrame:
2670                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2671                     start % (one_second/75) == 0) {
2672                         /* start is already on a whole CD frame, do nothing */
2673                 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2674                         start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2675                 } else {
2676                         start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2677                 }
2678                 break;
2679
2680         case SnapToSeconds:
2681                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2682                     start % one_second == 0) {
2683                         /* start is already on a whole second, do nothing */
2684                 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2685                         start = (framepos_t) ceil ((double) start / one_second) * one_second;
2686                 } else {
2687                         start = (framepos_t) floor ((double) start / one_second) * one_second;
2688                 }
2689                 break;
2690
2691         case SnapToMinutes:
2692                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2693                     start % one_minute == 0) {
2694                         /* start is already on a whole minute, do nothing */
2695                 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2696                         start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2697                 } else {
2698                         start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2699                 }
2700                 break;
2701
2702         case SnapToBar:
2703                 start = _session->tempo_map().round_to_bar (start, direction);
2704                 break;
2705
2706         case SnapToBeat:
2707                 start = _session->tempo_map().round_to_beat (start, direction);
2708                 break;
2709
2710         case SnapToBeatDiv128:
2711                 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2712                 break;
2713         case SnapToBeatDiv64:
2714                 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2715                 break;
2716         case SnapToBeatDiv32:
2717                 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2718                 break;
2719         case SnapToBeatDiv28:
2720                 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2721                 break;
2722         case SnapToBeatDiv24:
2723                 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2724                 break;
2725         case SnapToBeatDiv20:
2726                 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2727                 break;
2728         case SnapToBeatDiv16:
2729                 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2730                 break;
2731         case SnapToBeatDiv14:
2732                 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2733                 break;
2734         case SnapToBeatDiv12:
2735                 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2736                 break;
2737         case SnapToBeatDiv10:
2738                 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2739                 break;
2740         case SnapToBeatDiv8:
2741                 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2742                 break;
2743         case SnapToBeatDiv7:
2744                 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2745                 break;
2746         case SnapToBeatDiv6:
2747                 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2748                 break;
2749         case SnapToBeatDiv5:
2750                 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2751                 break;
2752         case SnapToBeatDiv4:
2753                 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2754                 break;
2755         case SnapToBeatDiv3:
2756                 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2757                 break;
2758         case SnapToBeatDiv2:
2759                 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2760                 break;
2761
2762         case SnapToMark:
2763                 if (for_mark) {
2764                         return;
2765                 }
2766
2767                 _session->locations()->marks_either_side (start, before, after);
2768
2769                 if (before == max_framepos && after == max_framepos) {
2770                         /* No marks to snap to, so just don't snap */
2771                         return;
2772                 } else if (before == max_framepos) {
2773                         start = after;
2774                 } else if (after == max_framepos) {
2775                         start = before;
2776                 } else if (before != max_framepos && after != max_framepos) {
2777                         /* have before and after */
2778                         if ((start - before) < (after - start)) {
2779                                 start = before;
2780                         } else {
2781                                 start = after;
2782                         }
2783                 }
2784
2785                 break;
2786
2787         case SnapToRegionStart:
2788         case SnapToRegionEnd:
2789         case SnapToRegionSync:
2790         case SnapToRegionBoundary:
2791                 if (!region_boundary_cache.empty()) {
2792
2793                         vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2794                         vector<framepos_t>::iterator next = region_boundary_cache.end ();
2795
2796                         if (direction > 0) {
2797                                 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2798                         } else {
2799                                 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2800                         }
2801
2802                         if (next != region_boundary_cache.begin ()) {
2803                                 prev = next;
2804                                 prev--;
2805                         }
2806
2807                         framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2808                         framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2809
2810                         if (start > (p + n) / 2) {
2811                                 start = n;
2812                         } else {
2813                                 start = p;
2814                         }
2815                 }
2816                 break;
2817         }
2818
2819         switch (_snap_mode) {
2820         case SnapNormal:
2821                 return;
2822
2823         case SnapMagnetic:
2824
2825                 if (presnap > start) {
2826                         if (presnap > (start + pixel_to_sample(snap_threshold))) {
2827                                 start = presnap;
2828                         }
2829
2830                 } else if (presnap < start) {
2831                         if (presnap < (start - pixel_to_sample(snap_threshold))) {
2832                                 start = presnap;
2833                         }
2834                 }
2835
2836         default:
2837                 /* handled at entry */
2838                 return;
2839
2840         }
2841 }
2842
2843
2844 void
2845 Editor::setup_toolbar ()
2846 {
2847         HBox* mode_box = manage(new HBox);
2848         mode_box->set_border_width (2);
2849         mode_box->set_spacing(2);
2850
2851         HBox* mouse_mode_box = manage (new HBox);
2852         HBox* mouse_mode_hbox = manage (new HBox);
2853         VBox* mouse_mode_vbox = manage (new VBox);
2854         Alignment* mouse_mode_align = manage (new Alignment);
2855
2856         Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2857         mouse_mode_size_group->add_widget (smart_mode_button);
2858         mouse_mode_size_group->add_widget (mouse_move_button);
2859         mouse_mode_size_group->add_widget (mouse_cut_button);
2860         mouse_mode_size_group->add_widget (mouse_select_button);
2861         mouse_mode_size_group->add_widget (mouse_timefx_button);
2862         mouse_mode_size_group->add_widget (mouse_audition_button);
2863         mouse_mode_size_group->add_widget (mouse_draw_button);
2864         mouse_mode_size_group->add_widget (mouse_content_button);
2865
2866         mouse_mode_size_group->add_widget (zoom_in_button);
2867         mouse_mode_size_group->add_widget (zoom_out_button);
2868         mouse_mode_size_group->add_widget (zoom_preset_selector);
2869         mouse_mode_size_group->add_widget (zoom_out_full_button);
2870         mouse_mode_size_group->add_widget (zoom_focus_selector);
2871
2872         mouse_mode_size_group->add_widget (tav_shrink_button);
2873         mouse_mode_size_group->add_widget (tav_expand_button);
2874         mouse_mode_size_group->add_widget (visible_tracks_selector);
2875
2876         mouse_mode_size_group->add_widget (snap_type_selector);
2877         mouse_mode_size_group->add_widget (snap_mode_selector);
2878
2879         mouse_mode_size_group->add_widget (edit_point_selector);
2880         mouse_mode_size_group->add_widget (edit_mode_selector);
2881
2882         mouse_mode_size_group->add_widget (*nudge_clock);
2883         mouse_mode_size_group->add_widget (nudge_forward_button);
2884         mouse_mode_size_group->add_widget (nudge_backward_button);
2885
2886         mouse_mode_hbox->set_spacing (2);
2887
2888         if (!ARDOUR::Profile->get_trx()) {
2889                 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2890         }
2891
2892         mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2893         mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2894
2895         if (!ARDOUR::Profile->get_mixbus()) {
2896                 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2897         }
2898         
2899         if (!ARDOUR::Profile->get_trx()) {
2900                 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2901                 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2902                 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2903                 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2904         }
2905
2906         mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2907
2908         mouse_mode_align->add (*mouse_mode_vbox);
2909         mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2910
2911         mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2912
2913         edit_mode_selector.set_name ("mouse mode button");
2914
2915         if (!ARDOUR::Profile->get_trx()) {
2916                 mode_box->pack_start (edit_mode_selector, false, false);
2917         }
2918         mode_box->pack_start (*mouse_mode_box, false, false);
2919
2920         _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2921         _mouse_mode_tearoff->set_name ("MouseModeBase");
2922         _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2923
2924         if (Profile->get_sae() || Profile->get_mixbus() ) {
2925                 _mouse_mode_tearoff->set_can_be_torn_off (false);
2926         }
2927
2928         _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2929                                                          &_mouse_mode_tearoff->tearoff_window()));
2930         _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2931                                                          &_mouse_mode_tearoff->tearoff_window(), 1));
2932         _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2933                                                          &_mouse_mode_tearoff->tearoff_window()));
2934         _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2935                                                           &_mouse_mode_tearoff->tearoff_window(), 1));
2936
2937         /* Zoom */
2938
2939         _zoom_box.set_spacing (2);
2940         _zoom_box.set_border_width (2);
2941
2942         RefPtr<Action> act;
2943
2944         zoom_preset_selector.set_name ("zoom button");
2945         zoom_preset_selector.set_image(::get_icon ("time_exp"));
2946         zoom_preset_selector.set_size_request (42, -1);
2947
2948         zoom_in_button.set_name ("zoom button");
2949         zoom_in_button.set_image(::get_icon ("zoom_in"));
2950         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2951         zoom_in_button.set_related_action (act);
2952
2953         zoom_out_button.set_name ("zoom button");
2954         zoom_out_button.set_image(::get_icon ("zoom_out"));
2955         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2956         zoom_out_button.set_related_action (act);
2957
2958         zoom_out_full_button.set_name ("zoom button");
2959         zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2960         act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2961         zoom_out_full_button.set_related_action (act);
2962
2963         zoom_focus_selector.set_name ("zoom button");
2964
2965         if (ARDOUR::Profile->get_mixbus()) {
2966                 _zoom_box.pack_start (zoom_preset_selector, false, false);
2967         } else if (ARDOUR::Profile->get_trx()) {
2968                 mode_box->pack_start (zoom_out_button, false, false);
2969                 mode_box->pack_start (zoom_in_button, false, false);
2970         } else {
2971                 _zoom_box.pack_start (zoom_out_button, false, false);
2972                 _zoom_box.pack_start (zoom_in_button, false, false);
2973                 _zoom_box.pack_start (zoom_out_full_button, false, false);
2974                 _zoom_box.pack_start (zoom_focus_selector, false, false);
2975         }
2976
2977         /* Track zoom buttons */
2978         visible_tracks_selector.set_name ("zoom button");
2979         if (Profile->get_mixbus()) {
2980                 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2981                 visible_tracks_selector.set_size_request (42, -1);
2982         } else {
2983                 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2984         }
2985
2986         tav_expand_button.set_name ("zoom button");
2987         tav_expand_button.set_image(::get_icon ("tav_exp"));
2988         act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2989         tav_expand_button.set_related_action (act);
2990
2991         tav_shrink_button.set_name ("zoom button");
2992         tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2993         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2994         tav_shrink_button.set_related_action (act);
2995
2996         if (ARDOUR::Profile->get_mixbus()) {
2997                 _zoom_box.pack_start (visible_tracks_selector);
2998         } else if (ARDOUR::Profile->get_trx()) {
2999                 _zoom_box.pack_start (tav_shrink_button);
3000                 _zoom_box.pack_start (tav_expand_button);
3001         } else {
3002                 _zoom_box.pack_start (visible_tracks_selector);
3003                 _zoom_box.pack_start (tav_shrink_button);
3004                 _zoom_box.pack_start (tav_expand_button);
3005         }
3006
3007         if (!ARDOUR::Profile->get_trx()) {
3008                 _zoom_tearoff = manage (new TearOff (_zoom_box));
3009                 
3010                 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3011                                                            &_zoom_tearoff->tearoff_window()));
3012                 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3013                                                            &_zoom_tearoff->tearoff_window(), 0));
3014                 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3015                                                            &_zoom_tearoff->tearoff_window()));
3016                 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3017                                                             &_zoom_tearoff->tearoff_window(), 0));
3018         } 
3019
3020         if (Profile->get_sae() || Profile->get_mixbus() ) {
3021                 _zoom_tearoff->set_can_be_torn_off (false);
3022         }
3023
3024         snap_box.set_spacing (2);
3025         snap_box.set_border_width (2);
3026
3027         snap_type_selector.set_name ("mouse mode button");
3028
3029         snap_mode_selector.set_name ("mouse mode button");
3030
3031         edit_point_selector.set_name ("mouse mode button");
3032
3033         snap_box.pack_start (snap_mode_selector, false, false);
3034         snap_box.pack_start (snap_type_selector, false, false);
3035         snap_box.pack_start (edit_point_selector, false, false);
3036
3037         /* Nudge */
3038
3039         HBox *nudge_box = manage (new HBox);
3040         nudge_box->set_spacing (2);
3041         nudge_box->set_border_width (2);
3042
3043         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3044         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3045
3046         nudge_box->pack_start (nudge_backward_button, false, false);
3047         nudge_box->pack_start (nudge_forward_button, false, false);
3048         nudge_box->pack_start (*nudge_clock, false, false);
3049
3050
3051         /* Pack everything in... */
3052
3053         HBox* hbox = manage (new HBox);
3054         hbox->set_spacing(2);
3055
3056         _tools_tearoff = manage (new TearOff (*hbox));
3057         _tools_tearoff->set_name ("MouseModeBase");
3058         _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3059
3060         if (Profile->get_sae() || Profile->get_mixbus()) {
3061                 _tools_tearoff->set_can_be_torn_off (false);
3062         }
3063
3064         _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3065                                                     &_tools_tearoff->tearoff_window()));
3066         _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3067                                                     &_tools_tearoff->tearoff_window(), 0));
3068         _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3069                                                     &_tools_tearoff->tearoff_window()));
3070         _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3071                                                      &_tools_tearoff->tearoff_window(), 0));
3072
3073         toolbar_hbox.set_spacing (2);
3074         toolbar_hbox.set_border_width (1);
3075
3076         toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3077         if (!ARDOUR::Profile->get_trx()) {
3078                 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3079                 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3080         }
3081
3082         if (!ARDOUR::Profile->get_trx()) {
3083                 hbox->pack_start (snap_box, false, false);
3084                 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3085                         hbox->pack_start (*nudge_box, false, false);
3086                 } else {
3087                         ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3088                 }
3089         }
3090         hbox->pack_start (panic_box, false, false);
3091
3092         hbox->show_all ();
3093
3094         toolbar_base.set_name ("ToolBarBase");
3095         toolbar_base.add (toolbar_hbox);
3096
3097         _toolbar_viewport.add (toolbar_base);
3098         /* stick to the required height but allow width to vary if there's not enough room */
3099         _toolbar_viewport.set_size_request (1, -1);
3100
3101         toolbar_frame.set_shadow_type (SHADOW_OUT);
3102         toolbar_frame.set_name ("BaseFrame");
3103         toolbar_frame.add (_toolbar_viewport);
3104 }
3105
3106 void
3107 Editor::build_edit_point_menu ()
3108 {
3109         using namespace Menu_Helpers;
3110
3111         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3112         if(!Profile->get_mixbus())
3113                 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3114         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3115
3116         set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3117 }
3118
3119 void
3120 Editor::build_edit_mode_menu ()
3121 {
3122         using namespace Menu_Helpers;
3123         
3124         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3125 //      edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3126         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3127         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
3128
3129         set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3130 }
3131
3132 void
3133 Editor::build_snap_mode_menu ()
3134 {
3135         using namespace Menu_Helpers;
3136
3137         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3138         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3139         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3140
3141         set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3142 }
3143
3144 void
3145 Editor::build_snap_type_menu ()
3146 {
3147         using namespace Menu_Helpers;
3148
3149         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3150         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3151         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3152         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3153         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3154         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3155         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3156         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3157         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3158         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3159         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3160         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3161         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3162         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3163         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3164         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3165         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3166         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3167         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3168         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3169         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3170         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3171         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3172         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3173         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3174         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3175         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3176         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3177         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3178         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3179
3180         set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3181
3182 }
3183
3184 void
3185 Editor::setup_tooltips ()
3186 {
3187         ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3188         ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3189         ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3190         ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Grab/Select Objects"));
3191         ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3192         ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3193         ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3194         ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Edit Contents (notes and automation)"));
3195         ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3196         ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3197         ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3198         ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3199         ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3200         ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3201         ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3202         ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3203         ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3204         ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3205         ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3206         ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3207         ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3208         ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3209         ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3210         ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3211 }
3212
3213 int
3214 Editor::convert_drop_to_paths (
3215                 vector<string>&                paths,
3216                 const RefPtr<Gdk::DragContext>& /*context*/,
3217                 gint                            /*x*/,
3218                 gint                            /*y*/,
3219                 const SelectionData&            data,
3220                 guint                           /*info*/,
3221                 guint                           /*time*/)
3222 {
3223         if (_session == 0) {
3224                 return -1;
3225         }
3226
3227         vector<string> uris = data.get_uris();
3228
3229         if (uris.empty()) {
3230
3231                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3232                    are actually URI lists. So do it by hand.
3233                 */
3234
3235                 if (data.get_target() != "text/plain") {
3236                         return -1;
3237                 }
3238
3239                 /* Parse the "uri-list" format that Nautilus provides,
3240                    where each pathname is delimited by \r\n.
3241
3242                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3243                 */
3244
3245                 string txt = data.get_text();
3246                 char* p;
3247                 const char* q;
3248
3249                 p = (char *) malloc (txt.length() + 1);
3250                 txt.copy (p, txt.length(), 0);
3251                 p[txt.length()] = '\0';
3252
3253                 while (p)
3254                 {
3255                         if (*p != '#')
3256                         {
3257                                 while (g_ascii_isspace (*p))
3258                                         p++;
3259
3260                                 q = p;
3261                                 while (*q && (*q != '\n') && (*q != '\r')) {
3262                                         q++;
3263                                 }
3264
3265                                 if (q > p)
3266                                 {
3267                                         q--;
3268                                         while (q > p && g_ascii_isspace (*q))
3269                                                 q--;
3270
3271                                         if (q > p)
3272                                         {
3273                                                 uris.push_back (string (p, q - p + 1));
3274                                         }
3275                                 }
3276                         }
3277                         p = strchr (p, '\n');
3278                         if (p)
3279                                 p++;
3280                 }
3281
3282                 free ((void*)p);
3283
3284                 if (uris.empty()) {
3285                         return -1;
3286                 }
3287         }
3288
3289         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3290                 if ((*i).substr (0,7) == "file://") {
3291                         paths.push_back (Glib::filename_from_uri (*i));
3292                 }
3293         }
3294
3295         return 0;
3296 }
3297
3298 void
3299 Editor::new_tempo_section ()
3300 {
3301 }
3302
3303 void
3304 Editor::map_transport_state ()
3305 {
3306         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3307
3308         if (_session && _session->transport_stopped()) {
3309                 have_pending_keyboard_selection = false;
3310         }
3311
3312         update_loop_range_view ();
3313 }
3314
3315 /* UNDO/REDO */
3316
3317 void
3318 Editor::begin_selection_op_history ()
3319 {
3320         selection_op_cmd_depth = 0;
3321         selection_op_history_it = 0;
3322         selection_op_history.clear();
3323         selection_undo_action->set_sensitive (false);
3324         selection_redo_action->set_sensitive (false);
3325         selection_op_history.push_front (&_selection_memento->get_state ());
3326 }
3327
3328 void
3329 Editor::begin_reversible_selection_op (string name)
3330 {
3331         if (_session) {
3332                 //cerr << name << endl;
3333                 /* begin/commit pairs can be nested */
3334                 selection_op_cmd_depth++;
3335         }
3336 }
3337
3338 void
3339 Editor::commit_reversible_selection_op ()
3340 {
3341         if (_session) {
3342                 if (selection_op_cmd_depth == 1) {
3343
3344                         if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3345                                 list<XMLNode *>::iterator it = selection_op_history.begin();
3346                                 advance (it, selection_op_history_it);
3347                                 selection_op_history.erase (selection_op_history.begin(), it);
3348                         }
3349                         selection_op_history.push_front (&_selection_memento->get_state ());
3350                         selection_op_history_it = 0;
3351                 }
3352
3353                 if (selection_op_cmd_depth > 0) {
3354                         selection_op_cmd_depth--;
3355                 }
3356
3357                 selection_undo_action->set_sensitive (true);
3358                 selection_redo_action->set_sensitive (false);
3359         }
3360 }
3361
3362 void
3363 Editor::undo_selection_op ()
3364 {
3365         if (_session) {
3366                 selection_op_history_it++;
3367                 uint32_t n = 0;
3368                 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3369                         if (n == selection_op_history_it) {
3370                                 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3371                                 selection_redo_action->set_sensitive (true);
3372                         }
3373                         ++n;
3374
3375                 }
3376                 /* is there an earlier entry? */
3377                 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3378                         selection_undo_action->set_sensitive (false);
3379                 }
3380         }
3381 }
3382
3383 void
3384 Editor::redo_selection_op ()
3385 {
3386         if (_session) {
3387                 if (selection_op_history_it > 0) {
3388                         selection_op_history_it--;
3389                 }
3390                 uint32_t n = 0;
3391                 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3392                         if (n == selection_op_history_it) {
3393                                 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3394                                 selection_undo_action->set_sensitive (true);
3395                         }
3396                         ++n;
3397
3398                 }
3399
3400                 if (selection_op_history_it == 0) {
3401                         selection_redo_action->set_sensitive (false);
3402                 }
3403         }
3404 }
3405
3406 void
3407 Editor::begin_reversible_command (string name)
3408 {
3409         if (_session) {
3410                 before.push_back (&_selection_memento->get_state ());
3411                 _session->begin_reversible_command (name);
3412         }
3413 }
3414
3415 void
3416 Editor::begin_reversible_command (GQuark q)
3417 {
3418         if (_session) {
3419                 before.push_back (&_selection_memento->get_state ());
3420                 _session->begin_reversible_command (q);
3421         }
3422 }
3423
3424 void
3425 Editor::commit_reversible_command ()
3426 {
3427         if (_session) {
3428                 if (before.size() == 1) {
3429                         _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3430                         undo_action->set_sensitive(true);
3431                         begin_selection_op_history ();
3432                 }
3433
3434                 if (before.empty()) {
3435                         cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3436                 } else {
3437                         before.pop_back();
3438                 }
3439
3440                 _session->commit_reversible_command ();
3441         }
3442 }
3443
3444 void
3445 Editor::history_changed ()
3446 {
3447         string label;
3448
3449         if (undo_action && _session) {
3450                 if (_session->undo_depth() == 0) {
3451                         label = S_("Command|Undo");
3452                 } else {
3453                         label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3454                 }
3455                 undo_action->property_label() = label;
3456         }
3457
3458         if (redo_action && _session) {
3459                 if (_session->redo_depth() == 0) {
3460                         label = _("Redo");
3461                 } else {
3462                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3463                 }
3464                 redo_action->property_label() = label;
3465         }
3466 }
3467
3468 void
3469 Editor::duplicate_range (bool with_dialog)
3470 {
3471         float times = 1.0f;
3472
3473         RegionSelection rs = get_regions_from_selection_and_entered ();
3474
3475         if ( selection->time.length() == 0 && rs.empty()) {
3476                 return;
3477         }
3478
3479         if (with_dialog) {
3480
3481                 ArdourDialog win (_("Duplicate"));
3482                 Label label (_("Number of duplications:"));
3483                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3484                 SpinButton spinner (adjustment, 0.0, 1);
3485                 HBox hbox;
3486
3487                 win.get_vbox()->set_spacing (12);
3488                 win.get_vbox()->pack_start (hbox);
3489                 hbox.set_border_width (6);
3490                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3491
3492                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3493                    place, visually. so do this by hand.
3494                 */
3495
3496                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3497                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3498                 spinner.grab_focus();
3499
3500                 hbox.show ();
3501                 label.show ();
3502                 spinner.show ();
3503
3504                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3505                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3506                 win.set_default_response (RESPONSE_ACCEPT);
3507
3508                 spinner.grab_focus ();
3509
3510                 switch (win.run ()) {
3511                 case RESPONSE_ACCEPT:
3512                         break;
3513                 default:
3514                         return;
3515                 }
3516
3517                 times = adjustment.get_value();
3518         }
3519
3520         if ((current_mouse_mode() == Editing::MouseRange)) {
3521                 if (selection->time.length()) {
3522                         duplicate_selection (times);
3523                 }
3524         } else if (get_smart_mode()) {
3525                 if (selection->time.length()) {
3526                         duplicate_selection (times);
3527                 } else 
3528                         duplicate_some_regions (rs, times);
3529         } else {
3530                 duplicate_some_regions (rs, times);
3531         }
3532 }
3533
3534 void
3535 Editor::set_edit_mode (EditMode m)
3536 {
3537         Config->set_edit_mode (m);
3538 }
3539
3540 void
3541 Editor::cycle_edit_mode ()
3542 {
3543         switch (Config->get_edit_mode()) {
3544         case Slide:
3545                 if (Profile->get_sae()) {
3546                         Config->set_edit_mode (Lock);
3547                 } else {
3548                         Config->set_edit_mode (Ripple);
3549                 }
3550                 break;
3551         case Splice:
3552         case Ripple:
3553                 Config->set_edit_mode (Lock);
3554                 break;
3555         case Lock:
3556                 Config->set_edit_mode (Slide);
3557                 break;
3558         }
3559 }
3560
3561 void
3562 Editor::edit_mode_selection_done ( EditMode m )
3563 {
3564         Config->set_edit_mode ( m );
3565 }
3566
3567 void
3568 Editor::snap_type_selection_done (SnapType snaptype)
3569 {
3570         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3571         if (ract) {
3572                 ract->set_active ();
3573         }
3574 }
3575
3576 void
3577 Editor::snap_mode_selection_done (SnapMode mode)
3578 {
3579         RefPtr<RadioAction> ract = snap_mode_action (mode);
3580
3581         if (ract) {
3582                 ract->set_active (true);
3583         }
3584 }
3585
3586 void
3587 Editor::cycle_edit_point (bool with_marker)
3588 {
3589         if(Profile->get_mixbus())
3590                 with_marker = false;
3591
3592         switch (_edit_point) {
3593         case EditAtMouse:
3594                 set_edit_point_preference (EditAtPlayhead);
3595                 break;
3596         case EditAtPlayhead:
3597                 if (with_marker) {
3598                         set_edit_point_preference (EditAtSelectedMarker);
3599                 } else {
3600                         set_edit_point_preference (EditAtMouse);
3601                 }
3602                 break;
3603         case EditAtSelectedMarker:
3604                 set_edit_point_preference (EditAtMouse);
3605                 break;
3606         }
3607 }
3608
3609 void
3610 Editor::edit_point_selection_done (EditPoint ep)
3611 {
3612         set_edit_point_preference ( ep );
3613 }
3614
3615 void
3616 Editor::build_zoom_focus_menu ()
3617 {
3618         using namespace Menu_Helpers;
3619
3620         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3621         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3622         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3623         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3624         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3625         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3626
3627         set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3628 }
3629
3630 void
3631 Editor::zoom_focus_selection_done ( ZoomFocus f )
3632 {
3633         RefPtr<RadioAction> ract = zoom_focus_action (f);
3634         if (ract) {
3635                 ract->set_active ();
3636         }
3637 }
3638
3639 void
3640 Editor::build_track_count_menu ()
3641 {
3642         using namespace Menu_Helpers;
3643
3644         if (!Profile->get_mixbus()) {
3645                 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3646                 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3647                 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3648                 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3649                 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3650                 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3651                 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3652                 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3653                 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3654                 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3655                 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3656                 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3657                 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3658         } else {
3659                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3660                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3661                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3662                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3663                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3664                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3665                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3666                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3667                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3668                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3669
3670                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3671                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3672                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3673                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3674                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3675                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3676                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3677                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3678                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3679                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3680                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3681         }
3682 }
3683
3684 void
3685 Editor::set_zoom_preset (int64_t ms)
3686 {
3687         if ( ms <= 0 ) {
3688                 temporal_zoom_session();
3689                 return;
3690         }
3691         
3692         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3693         temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3694 }
3695
3696 void
3697 Editor::set_visible_track_count (int32_t n)
3698 {
3699         _visible_track_count = n;
3700
3701         /* if the canvas hasn't really been allocated any size yet, just
3702            record the desired number of visible tracks and return. when canvas
3703            allocation happens, we will get called again and then we can do the
3704            real work.
3705         */
3706         
3707         if (_visible_canvas_height <= 1) {
3708                 return;
3709         }
3710
3711         int h;
3712         string str;
3713         DisplaySuspender ds;
3714         
3715         if (_visible_track_count > 0) {
3716                 h = trackviews_height() / _visible_track_count;
3717                 std::ostringstream s;
3718                 s << _visible_track_count;
3719                 str = s.str();
3720         } else if (_visible_track_count == 0) {
3721                 uint32_t n = 0;
3722                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3723                         if ((*i)->marked_for_display()) {
3724                                 ++n;
3725                         }
3726                 }
3727                 h = trackviews_height() / n;
3728                 str = _("All");
3729         } else {
3730                 /* negative value means that the visible track count has 
3731                    been overridden by explicit track height changes.
3732                 */
3733                 visible_tracks_selector.set_text (X_("*"));
3734                 return;
3735         }
3736
3737         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3738                 (*i)->set_height (h);
3739         }
3740         
3741         if (str != visible_tracks_selector.get_text()) {
3742                 visible_tracks_selector.set_text (str);
3743         }
3744 }
3745
3746 void
3747 Editor::override_visible_track_count ()
3748 {
3749         _visible_track_count = -1;
3750         visible_tracks_selector.set_text ( _("*") );
3751 }
3752
3753 bool
3754 Editor::edit_controls_button_release (GdkEventButton* ev)
3755 {
3756         if (Keyboard::is_context_menu_event (ev)) {
3757                 ARDOUR_UI::instance()->add_route (this);
3758         } else if (ev->button == 1) {
3759                 selection->clear_tracks ();
3760         }
3761
3762         return true;
3763 }
3764
3765 bool
3766 Editor::mouse_select_button_release (GdkEventButton* ev)
3767 {
3768         /* this handles just right-clicks */
3769
3770         if (ev->button != 3) {
3771                 return false;
3772         }
3773
3774         return true;
3775 }
3776
3777 void
3778 Editor::set_zoom_focus (ZoomFocus f)
3779 {
3780         string str = zoom_focus_strings[(int)f];
3781
3782         if (str != zoom_focus_selector.get_text()) {
3783                 zoom_focus_selector.set_text (str);
3784         }
3785
3786         if (zoom_focus != f) {
3787                 zoom_focus = f;
3788                 instant_save ();
3789         }
3790 }
3791
3792 void
3793 Editor::cycle_zoom_focus ()
3794 {
3795         switch (zoom_focus) {
3796         case ZoomFocusLeft:
3797                 set_zoom_focus (ZoomFocusRight);
3798                 break;
3799         case ZoomFocusRight:
3800                 set_zoom_focus (ZoomFocusCenter);
3801                 break;
3802         case ZoomFocusCenter:
3803                 set_zoom_focus (ZoomFocusPlayhead);
3804                 break;
3805         case ZoomFocusPlayhead:
3806                 set_zoom_focus (ZoomFocusMouse);
3807                 break;
3808         case ZoomFocusMouse:
3809                 set_zoom_focus (ZoomFocusEdit);
3810                 break;
3811         case ZoomFocusEdit:
3812                 set_zoom_focus (ZoomFocusLeft);
3813                 break;
3814         }
3815 }
3816
3817 void
3818 Editor::ensure_float (Window& win)
3819 {
3820         win.set_transient_for (*this);
3821 }
3822
3823 void
3824 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3825 {
3826         /* recover or initialize pane positions. do this here rather than earlier because
3827            we don't want the positions to change the child allocations, which they seem to do.
3828          */
3829
3830         int pos;
3831         XMLProperty* prop;
3832         char buf[32];
3833         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3834
3835         enum Pane {
3836                 Horizontal = 0x1,
3837                 Vertical = 0x2
3838         };
3839
3840         static Pane done;
3841
3842         XMLNode* geometry = find_named_node (*node, "geometry");
3843
3844         if (which == static_cast<Paned*> (&edit_pane)) {
3845
3846                 if (done & Horizontal) {
3847                         return;
3848                 }
3849
3850                 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3851                         _notebook_shrunk = string_is_affirmative (prop->value ());
3852                 }
3853
3854                 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3855                         /* initial allocation is 90% to canvas, 10% to notebook */
3856                         pos = (int) floor (alloc.get_width() * 0.90f);
3857                         snprintf (buf, sizeof(buf), "%d", pos);
3858                 } else {
3859                         pos = atoi (prop->value());
3860                 }
3861
3862                 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3863                         edit_pane.set_position (pos);
3864                 }
3865
3866                 done = (Pane) (done | Horizontal);
3867
3868         } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3869
3870                 if (done & Vertical) {
3871                         return;
3872                 }
3873
3874                 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3875                         /* initial allocation is 90% to canvas, 10% to summary */
3876                         pos = (int) floor (alloc.get_height() * 0.90f);
3877                         snprintf (buf, sizeof(buf), "%d", pos);
3878                 } else {
3879
3880                         pos = atoi (prop->value());
3881                 }
3882
3883                 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3884                         editor_summary_pane.set_position (pos);
3885                 }
3886
3887                 done = (Pane) (done | Vertical);
3888         }
3889 }
3890
3891 void
3892 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3893 {
3894         if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) && 
3895             (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) && 
3896             (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3897                 top_hbox.remove (toolbar_frame);
3898         }
3899 }
3900
3901 void
3902 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3903 {
3904         if (toolbar_frame.get_parent() == 0) {
3905                 top_hbox.pack_end (toolbar_frame);
3906         }
3907 }
3908
3909 void
3910 Editor::set_show_measures (bool yn)
3911 {
3912         if (_show_measures != yn) {
3913                 hide_measures ();
3914
3915                 if ((_show_measures = yn) == true) {
3916                         if (tempo_lines) {
3917                                 tempo_lines->show();
3918                         }
3919
3920                         ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3921                         ARDOUR::TempoMap::BBTPointList::const_iterator end;
3922                         
3923                         compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3924                         draw_measures (begin, end);
3925                 } 
3926
3927                 instant_save ();
3928         }
3929 }
3930
3931 void
3932 Editor::toggle_follow_playhead ()
3933 {
3934         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3935         if (act) {
3936                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3937                 set_follow_playhead (tact->get_active());
3938         }
3939 }
3940
3941 /** @param yn true to follow playhead, otherwise false.
3942  *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3943  */
3944 void
3945 Editor::set_follow_playhead (bool yn, bool catch_up)
3946 {
3947         if (_follow_playhead != yn) {
3948                 if ((_follow_playhead = yn) == true && catch_up) {
3949                         /* catch up */
3950                         reset_x_origin_to_follow_playhead ();
3951                 }
3952                 instant_save ();
3953         }
3954 }
3955
3956 void
3957 Editor::toggle_stationary_playhead ()
3958 {
3959         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3960         if (act) {
3961                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3962                 set_stationary_playhead (tact->get_active());
3963         }
3964 }
3965
3966 void
3967 Editor::set_stationary_playhead (bool yn)
3968 {
3969         if (_stationary_playhead != yn) {
3970                 if ((_stationary_playhead = yn) == true) {
3971                         /* catch up */
3972                         // FIXME need a 3.0 equivalent of this 2.X call
3973                         // update_current_screen ();
3974                 }
3975                 instant_save ();
3976         }
3977 }
3978
3979 PlaylistSelector&
3980 Editor::playlist_selector () const
3981 {
3982         return *_playlist_selector;
3983 }
3984
3985 framecnt_t
3986 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3987 {
3988         if (paste_count == 0) {
3989                 /* don't bother calculating an offset that will be zero anyway */
3990                 return 0;
3991         }
3992
3993         /* calculate basic unsnapped multi-paste offset */
3994         framecnt_t offset = paste_count * duration;
3995
3996         /* snap offset so pos + offset is aligned to the grid */
3997         framepos_t offset_pos = pos + offset;
3998         snap_to(offset_pos, RoundUpMaybe);
3999         offset = offset_pos - pos;
4000
4001         return offset;
4002 }
4003
4004 Evoral::MusicalTime
4005 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4006 {
4007         success = true;
4008
4009         switch (_snap_type) {
4010         case SnapToBeat:
4011                 return Evoral::MusicalTime(1.0);
4012                 break;
4013
4014         case SnapToBeatDiv128:
4015                 return Evoral::MusicalTime(1.0/128.0);
4016                 break;
4017         case SnapToBeatDiv64:
4018                 return Evoral::MusicalTime(1.0/64.0);
4019                 break;
4020         case SnapToBeatDiv32:
4021                 return Evoral::MusicalTime(1.0/32.0);
4022                 break;
4023         case SnapToBeatDiv28:
4024                 return Evoral::MusicalTime(1.0/28.0);
4025                 break;
4026         case SnapToBeatDiv24:
4027                 return Evoral::MusicalTime(1.0/24.0);
4028                 break;
4029         case SnapToBeatDiv20:
4030                 return Evoral::MusicalTime(1.0/20.0);
4031                 break;
4032         case SnapToBeatDiv16:
4033                 return Evoral::MusicalTime(1.0/16.0);
4034                 break;
4035         case SnapToBeatDiv14:
4036                 return Evoral::MusicalTime(1.0/14.0);
4037                 break;
4038         case SnapToBeatDiv12:
4039                 return Evoral::MusicalTime(1.0/12.0);
4040                 break;
4041         case SnapToBeatDiv10:
4042                 return Evoral::MusicalTime(1.0/10.0);
4043                 break;
4044         case SnapToBeatDiv8:
4045                 return Evoral::MusicalTime(1.0/8.0);
4046                 break;
4047         case SnapToBeatDiv7:
4048                 return Evoral::MusicalTime(1.0/7.0);
4049                 break;
4050         case SnapToBeatDiv6:
4051                 return Evoral::MusicalTime(1.0/6.0);
4052                 break;
4053         case SnapToBeatDiv5:
4054                 return Evoral::MusicalTime(1.0/5.0);
4055                 break;
4056         case SnapToBeatDiv4:
4057                 return Evoral::MusicalTime(1.0/4.0);
4058                 break;
4059         case SnapToBeatDiv3:
4060                 return Evoral::MusicalTime(1.0/3.0);
4061                 break;
4062         case SnapToBeatDiv2:
4063                 return Evoral::MusicalTime(1.0/2.0);
4064                 break;
4065
4066         case SnapToBar:
4067                 if (_session) {
4068                         return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
4069                 }
4070                 break;
4071
4072         case SnapToCDFrame:
4073         case SnapToTimecodeFrame:
4074         case SnapToTimecodeSeconds:
4075         case SnapToTimecodeMinutes:
4076         case SnapToSeconds:
4077         case SnapToMinutes:
4078         case SnapToRegionStart:
4079         case SnapToRegionEnd:
4080         case SnapToRegionSync:
4081         case SnapToRegionBoundary:
4082         default:
4083                 success = false;
4084                 break;
4085         }
4086
4087         return Evoral::MusicalTime();
4088 }
4089
4090 framecnt_t
4091 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4092 {
4093         framecnt_t ret;
4094
4095         ret = nudge_clock->current_duration (pos);
4096         next = ret + 1; /* XXXX fix me */
4097
4098         return ret;
4099 }
4100
4101 int
4102 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4103 {
4104         ArdourDialog dialog (_("Playlist Deletion"));
4105         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
4106                                         "If it is kept, its audio files will not be cleaned.\n"
4107                                         "If it is deleted, audio files used by it alone will be cleaned."),
4108                                       pl->name()));
4109
4110         dialog.set_position (WIN_POS_CENTER);
4111         dialog.get_vbox()->pack_start (label);
4112
4113         label.show ();
4114
4115         dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4116         dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4117         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4118
4119         switch (dialog.run ()) {
4120         case RESPONSE_ACCEPT:
4121                 /* delete the playlist */
4122                 return 0;
4123                 break;
4124
4125         case RESPONSE_REJECT:
4126                 /* keep the playlist */
4127                 return 1;
4128                 break;
4129
4130         default:
4131                 break;
4132         }
4133
4134         return -1;
4135 }
4136
4137 bool
4138 Editor::audio_region_selection_covers (framepos_t where)
4139 {
4140         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4141                 if ((*a)->region()->covers (where)) {
4142                         return true;
4143                 }
4144         }
4145
4146         return false;
4147 }
4148
4149 void
4150 Editor::prepare_for_cleanup ()
4151 {
4152         cut_buffer->clear_regions ();
4153         cut_buffer->clear_playlists ();
4154
4155         selection->clear_regions ();
4156         selection->clear_playlists ();
4157
4158         _regions->suspend_redisplay ();
4159 }
4160
4161 void
4162 Editor::finish_cleanup ()
4163 {
4164         _regions->resume_redisplay ();
4165 }
4166
4167 Location*
4168 Editor::transport_loop_location()
4169 {
4170         if (_session) {
4171                 return _session->locations()->auto_loop_location();
4172         } else {
4173                 return 0;
4174         }
4175 }
4176
4177 Location*
4178 Editor::transport_punch_location()
4179 {
4180         if (_session) {
4181                 return _session->locations()->auto_punch_location();
4182         } else {
4183                 return 0;
4184         }
4185 }
4186
4187 bool
4188 Editor::control_layout_scroll (GdkEventScroll* ev)
4189 {
4190         /* Just forward to the normal canvas scroll method. The coordinate
4191            systems are different but since the canvas is always larger than the
4192            track headers, and aligned with the trackview area, this will work.
4193
4194            In the not too distant future this layout is going away anyway and
4195            headers will be on the canvas.
4196         */
4197         return canvas_scroll_event (ev, false);
4198 }
4199
4200 void
4201 Editor::session_state_saved (string)
4202 {
4203         update_title ();
4204         _snapshots->redisplay ();
4205 }
4206
4207 void
4208 Editor::update_tearoff_visibility()
4209 {
4210         bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4211         _mouse_mode_tearoff->set_visible (visible);
4212         _tools_tearoff->set_visible (visible);
4213         if (_zoom_tearoff) {
4214                 _zoom_tearoff->set_visible (visible);
4215         }
4216 }
4217
4218 void
4219 Editor::reattach_all_tearoffs ()
4220 {
4221         if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4222         if (_tools_tearoff) _tools_tearoff->put_it_back ();
4223         if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4224 }
4225
4226 void
4227 Editor::maximise_editing_space ()
4228 {
4229         if (_maximised) {
4230                 return;
4231         }
4232
4233         fullscreen ();
4234
4235         _maximised = true;
4236 }
4237
4238 void
4239 Editor::restore_editing_space ()
4240 {
4241         if (!_maximised) {
4242                 return;
4243         }
4244
4245         unfullscreen();
4246
4247         _maximised = false;
4248 }
4249
4250 /**
4251  *  Make new playlists for a given track and also any others that belong
4252  *  to the same active route group with the `select' property.
4253  *  @param v Track.
4254  */
4255
4256 void
4257 Editor::new_playlists (TimeAxisView* v)
4258 {
4259         begin_reversible_command (_("new playlists"));
4260         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4261         _session->playlists->get (playlists);
4262         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4263         commit_reversible_command ();
4264 }
4265
4266 /**
4267  *  Use a copy of the current playlist 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::copy_playlists (TimeAxisView* v)
4274 {
4275         begin_reversible_command (_("copy 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_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4279         commit_reversible_command ();
4280 }
4281
4282 /** Clear the current playlist for a given track and also any others that belong
4283  *  to the same active route group with the `select' property.
4284  *  @param v Track.
4285  */
4286
4287 void
4288 Editor::clear_playlists (TimeAxisView* v)
4289 {
4290         begin_reversible_command (_("clear playlists"));        
4291         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4292         _session->playlists->get (playlists);
4293         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4294         commit_reversible_command ();
4295 }
4296
4297 void
4298 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4299 {
4300         atv.use_new_playlist (sz > 1 ? false : true, playlists);
4301 }
4302
4303 void
4304 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4305 {
4306         atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4307 }
4308
4309 void
4310 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4311 {
4312         atv.clear_playlist ();
4313 }
4314
4315 bool
4316 Editor::on_key_press_event (GdkEventKey* ev)
4317 {
4318         return key_press_focus_accelerator_handler (*this, ev);
4319 }
4320
4321 bool
4322 Editor::on_key_release_event (GdkEventKey* ev)
4323 {
4324         return Gtk::Window::on_key_release_event (ev);
4325         // return key_press_focus_accelerator_handler (*this, ev);
4326 }
4327
4328 double
4329 Editor::get_y_origin () const
4330 {
4331         return vertical_adjustment.get_value ();
4332 }
4333
4334 /** Queue up a change to the viewport x origin.
4335  *  @param frame New x origin.
4336  */
4337 void
4338 Editor::reset_x_origin (framepos_t frame)
4339 {
4340         pending_visual_change.add (VisualChange::TimeOrigin);
4341         pending_visual_change.time_origin = frame;
4342         ensure_visual_change_idle_handler ();
4343 }
4344
4345 void
4346 Editor::reset_y_origin (double y)
4347 {
4348         pending_visual_change.add (VisualChange::YOrigin);
4349         pending_visual_change.y_origin = y;
4350         ensure_visual_change_idle_handler ();
4351 }
4352
4353 void
4354 Editor::reset_zoom (framecnt_t spp)
4355 {
4356         if (spp == samples_per_pixel) {
4357                 return;
4358         }
4359
4360         pending_visual_change.add (VisualChange::ZoomLevel);
4361         pending_visual_change.samples_per_pixel = spp;
4362         ensure_visual_change_idle_handler ();
4363 }
4364
4365 void
4366 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4367 {
4368         reset_x_origin (frame);
4369         reset_zoom (fpu);
4370
4371         if (!no_save_visual) {
4372                 undo_visual_stack.push_back (current_visual_state(false));
4373         }
4374 }
4375
4376 Editor::VisualState::VisualState (bool with_tracks)
4377         : gui_state (with_tracks ? new GUIObjectState : 0)
4378 {
4379 }
4380
4381 Editor::VisualState::~VisualState ()
4382 {
4383         delete gui_state;
4384 }
4385
4386 Editor::VisualState*
4387 Editor::current_visual_state (bool with_tracks)
4388 {
4389         VisualState* vs = new VisualState (with_tracks);
4390         vs->y_position = vertical_adjustment.get_value();
4391         vs->samples_per_pixel = samples_per_pixel;
4392         vs->leftmost_frame = leftmost_frame;
4393         vs->zoom_focus = zoom_focus;
4394
4395         if (with_tracks) {      
4396                 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4397         }
4398
4399         return vs;
4400 }
4401
4402 void
4403 Editor::undo_visual_state ()
4404 {
4405         if (undo_visual_stack.empty()) {
4406                 return;
4407         }
4408
4409         VisualState* vs = undo_visual_stack.back();
4410         undo_visual_stack.pop_back();
4411
4412
4413         redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4414
4415         if (vs) {
4416                 use_visual_state (*vs);
4417         }
4418 }
4419
4420 void
4421 Editor::redo_visual_state ()
4422 {
4423         if (redo_visual_stack.empty()) {
4424                 return;
4425         }
4426
4427         VisualState* vs = redo_visual_stack.back();
4428         redo_visual_stack.pop_back();
4429
4430         // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4431         // why do we check here?
4432         undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4433
4434         if (vs) {
4435                 use_visual_state (*vs);
4436         }
4437 }
4438
4439 void
4440 Editor::swap_visual_state ()
4441 {
4442         if (undo_visual_stack.empty()) {
4443                 redo_visual_state ();
4444         } else {
4445                 undo_visual_state ();
4446         }
4447 }
4448
4449 void
4450 Editor::use_visual_state (VisualState& vs)
4451 {
4452         PBD::Unwinder<bool> nsv (no_save_visual, true);
4453         DisplaySuspender ds;
4454
4455         vertical_adjustment.set_value (vs.y_position);
4456
4457         set_zoom_focus (vs.zoom_focus);
4458         reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4459         
4460         if (vs.gui_state) {
4461                 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4462                 
4463                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {    
4464                         (*i)->reset_visual_state ();
4465                 }
4466         }
4467
4468         _routes->update_visibility ();
4469 }
4470
4471 /** This is the core function that controls the zoom level of the canvas. It is called
4472  *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
4473  *  @param spp new number of samples per pixel
4474  */
4475 void
4476 Editor::set_samples_per_pixel (framecnt_t spp)
4477 {
4478         if (spp < 1) {
4479                 return;
4480         }
4481
4482         const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4483         const framecnt_t lots_of_pixels = 4000;
4484
4485         /* if the zoom level is greater than what you'd get trying to display 3
4486          * days of audio on a really big screen, then it's too big.
4487          */
4488
4489         if (spp * lots_of_pixels > three_days) {
4490                 return;
4491         }
4492
4493         samples_per_pixel = spp;
4494
4495         if (tempo_lines) {
4496                 tempo_lines->tempo_map_changed();
4497         }
4498
4499         bool const showing_time_selection = selection->time.length() > 0;
4500
4501         if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4502                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4503                         (*i)->reshow_selection (selection->time);
4504                 }
4505         }
4506
4507         ZoomChanged (); /* EMIT_SIGNAL */
4508
4509         ArdourCanvas::GtkCanvasViewport* c;
4510
4511         c = get_track_canvas();
4512         if (c) {
4513                 c->canvas()->zoomed ();
4514         }
4515
4516         if (playhead_cursor) {
4517                 playhead_cursor->set_position (playhead_cursor->current_frame ());
4518         }
4519
4520         refresh_location_display();
4521         _summary->set_overlays_dirty ();
4522
4523         update_marker_labels ();
4524
4525         instant_save ();
4526 }
4527
4528 void
4529 Editor::queue_visual_videotimeline_update ()
4530 {
4531         /* TODO:
4532          * pending_visual_change.add (VisualChange::VideoTimeline);
4533          * or maybe even more specific: which videotimeline-image
4534          * currently it calls update_video_timeline() to update
4535          * _all outdated_ images on the video-timeline.
4536          * see 'exposeimg()' in video_image_frame.cc
4537          */
4538         ensure_visual_change_idle_handler ();
4539 }
4540
4541 void
4542 Editor::ensure_visual_change_idle_handler ()
4543 {
4544         if (pending_visual_change.idle_handler_id < 0) {
4545                 // see comment in add_to_idle_resize above.
4546                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4547                 pending_visual_change.being_handled = false;
4548         }
4549 }
4550
4551 int
4552 Editor::_idle_visual_changer (void* arg)
4553 {
4554         return static_cast<Editor*>(arg)->idle_visual_changer ();
4555 }
4556
4557 int
4558 Editor::idle_visual_changer ()
4559 {
4560         /* set_horizontal_position() below (and maybe other calls) call
4561            gtk_main_iteration(), so it's possible that a signal will be handled
4562            half-way through this method.  If this signal wants an
4563            idle_visual_changer we must schedule another one after this one, so
4564            mark the idle_handler_id as -1 here to allow that.  Also make a note
4565            that we are doing the visual change, so that changes in response to
4566            super-rapid-screen-update can be dropped if we are still processing
4567            the last one.
4568         */
4569
4570         pending_visual_change.idle_handler_id = -1;
4571         pending_visual_change.being_handled = true;
4572         
4573         VisualChange vc = pending_visual_change;
4574
4575         pending_visual_change.pending = (VisualChange::Type) 0;
4576
4577         visual_changer (vc);
4578
4579         pending_visual_change.being_handled = false;
4580
4581         return 0; /* this is always a one-shot call */
4582 }
4583
4584 void
4585 Editor::visual_changer (const VisualChange& vc)
4586 {
4587         double const last_time_origin = horizontal_position ();
4588
4589         if (vc.pending & VisualChange::ZoomLevel) {
4590                 set_samples_per_pixel (vc.samples_per_pixel);
4591
4592                 compute_fixed_ruler_scale ();
4593
4594                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4595                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4596                 
4597                 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4598                                             current_bbt_points_begin, current_bbt_points_end);
4599                 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4600                                          current_bbt_points_begin, current_bbt_points_end);
4601                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4602
4603                 update_video_timeline();
4604         }
4605
4606         if (vc.pending & VisualChange::TimeOrigin) {
4607                 set_horizontal_position (vc.time_origin / samples_per_pixel);
4608         }
4609
4610         if (vc.pending & VisualChange::YOrigin) {
4611                 vertical_adjustment.set_value (vc.y_origin);
4612         }
4613
4614         if (last_time_origin == horizontal_position ()) {
4615                 /* changed signal not emitted */
4616                 update_fixed_rulers ();
4617                 redisplay_tempo (true);
4618         }
4619
4620         if (!(vc.pending & VisualChange::ZoomLevel)) {
4621                 update_video_timeline();
4622         }
4623
4624         _summary->set_overlays_dirty ();
4625 }
4626
4627 struct EditorOrderTimeAxisSorter {
4628     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4629             return a->order () < b->order ();
4630     }
4631 };
4632
4633 void
4634 Editor::sort_track_selection (TrackViewList& sel)
4635 {
4636         EditorOrderTimeAxisSorter cmp;
4637         sel.sort (cmp);
4638 }
4639
4640 framepos_t
4641 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4642 {
4643         bool ignored;
4644         framepos_t where = 0;
4645         EditPoint ep = _edit_point;
4646
4647         if(Profile->get_mixbus())
4648                 if (ep == EditAtSelectedMarker)
4649                         ep=EditAtPlayhead;
4650                 
4651         if (from_context_menu && (ep == EditAtMouse)) {
4652                 return  canvas_event_sample (&context_click_event, 0, 0);
4653         }
4654
4655         if (entered_marker) {
4656                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4657                 return entered_marker->position();
4658         }
4659
4660         if (ignore_playhead && ep == EditAtPlayhead) {
4661                 ep = EditAtSelectedMarker;
4662         }
4663
4664         switch (ep) {
4665         case EditAtPlayhead:
4666                 where = _session->audible_frame();
4667                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4668                 break;
4669
4670         case EditAtSelectedMarker:
4671                 if (!selection->markers.empty()) {
4672                         bool is_start;
4673                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4674                         if (loc) {
4675                                 if (is_start) {
4676                                         where =  loc->start();
4677                                 } else {
4678                                         where = loc->end();
4679                                 }
4680                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4681                                 break;
4682                         }
4683                 }
4684                 /* fallthru */
4685
4686         default:
4687         case EditAtMouse:
4688                 if (!mouse_frame (where, ignored)) {
4689                         /* XXX not right but what can we do ? */
4690                         return 0;
4691                 }
4692                 snap_to (where);
4693                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4694                 break;
4695         }
4696
4697         return where;
4698 }
4699
4700 void
4701 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4702 {
4703         if (!_session) return;
4704
4705         begin_reversible_command (cmd);
4706
4707         Location* tll;
4708
4709         if ((tll = transport_loop_location()) == 0) {
4710                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4711                 XMLNode &before = _session->locations()->get_state();
4712                 _session->locations()->add (loc, true);
4713                 _session->set_auto_loop_location (loc);
4714                 XMLNode &after = _session->locations()->get_state();
4715                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4716         } else {
4717                 XMLNode &before = tll->get_state();
4718                 tll->set_hidden (false, this);
4719                 tll->set (start, end);
4720                 XMLNode &after = tll->get_state();
4721                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4722         }
4723
4724         commit_reversible_command ();
4725 }
4726
4727 void
4728 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4729 {
4730         if (!_session) return;
4731
4732         begin_reversible_command (cmd);
4733
4734         Location* tpl;
4735
4736         if ((tpl = transport_punch_location()) == 0) {
4737                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
4738                 XMLNode &before = _session->locations()->get_state();
4739                 _session->locations()->add (loc, true);
4740                 _session->set_auto_punch_location (loc);
4741                 XMLNode &after = _session->locations()->get_state();
4742                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4743         } else {
4744                 XMLNode &before = tpl->get_state();
4745                 tpl->set_hidden (false, this);
4746                 tpl->set (start, end);
4747                 XMLNode &after = tpl->get_state();
4748                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4749         }
4750
4751         commit_reversible_command ();
4752 }
4753
4754 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4755  *  @param rs List to which found regions are added.
4756  *  @param where Time to look at.
4757  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4758  */
4759 void
4760 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4761 {
4762         const TrackViewList* tracks;
4763
4764         if (ts.empty()) {
4765                 tracks = &track_views;
4766         } else {
4767                 tracks = &ts;
4768         }
4769
4770         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4771
4772                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4773
4774                 if (rtv) {
4775                         boost::shared_ptr<Track> tr;
4776                         boost::shared_ptr<Playlist> pl;
4777
4778                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4779
4780                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4781                                                 (framepos_t) floor ( (double) where * tr->speed()));
4782
4783                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4784                                         RegionView* rv = rtv->view()->find_view (*i);
4785                                         if (rv) {
4786                                                 rs.add (rv);
4787                                         }
4788                                 }
4789                         }
4790                 }
4791         }
4792 }
4793
4794 void
4795 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4796 {
4797         const TrackViewList* tracks;
4798
4799         if (ts.empty()) {
4800                 tracks = &track_views;
4801         } else {
4802                 tracks = &ts;
4803         }
4804
4805         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4806                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4807                 if (rtv) {
4808                         boost::shared_ptr<Track> tr;
4809                         boost::shared_ptr<Playlist> pl;
4810
4811                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4812
4813                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4814                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4815
4816                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4817
4818                                         RegionView* rv = rtv->view()->find_view (*i);
4819
4820                                         if (rv) {
4821                                                 rs.add (rv);
4822                                         }
4823                                 }
4824                         }
4825                 }
4826         }
4827 }
4828
4829 /** Get regions using the following method:
4830  *
4831  *  Make a region list using:
4832  *   (a) any selected regions
4833  *   (b) the intersection of any selected tracks and the edit point(*)
4834  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4835  *
4836  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4837  *
4838  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4839  */
4840
4841 RegionSelection
4842 Editor::get_regions_from_selection_and_edit_point ()
4843 {
4844         RegionSelection regions;
4845
4846         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4847                 regions.add (entered_regionview);
4848         } else {
4849                 regions = selection->regions;
4850         }
4851
4852         if ( regions.empty() ) {
4853                 TrackViewList tracks = selection->tracks;
4854
4855                 if (!tracks.empty()) {
4856                         /* no region selected or entered, but some selected tracks:
4857                          * act on all regions on the selected tracks at the edit point
4858                          */ 
4859                         framepos_t const where = get_preferred_edit_position ();
4860                         get_regions_at(regions, where, tracks);
4861                 }
4862         }
4863
4864         return regions;
4865 }
4866
4867 /** Get regions using the following method:
4868  *
4869  *  Make a region list using:
4870  *   (a) any selected regions
4871  *   (b) the intersection of any selected tracks and the edit point(*)
4872  *   (c) if neither exists, then whatever region is under the mouse
4873  *
4874  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4875  *
4876  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4877  */
4878 RegionSelection
4879 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4880 {
4881         RegionSelection regions;
4882
4883         if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4884                 regions.add (entered_regionview);
4885         } else {
4886                 regions = selection->regions;
4887         }
4888
4889         if ( regions.empty() ) {
4890                 TrackViewList tracks = selection->tracks;
4891
4892                 if (!tracks.empty()) {
4893                         /* no region selected or entered, but some selected tracks:
4894                          * act on all regions on the selected tracks at the edit point
4895                          */ 
4896                         get_regions_at(regions, pos, tracks);
4897                 }
4898         }
4899
4900         return regions;
4901 }
4902
4903 /** Start with regions that are selected, or the entered regionview if none are selected.
4904  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4905  *  of the regions that we started with.
4906  */
4907
4908 RegionSelection
4909 Editor::get_regions_from_selection_and_entered ()
4910 {
4911         RegionSelection regions = selection->regions;
4912
4913         if (regions.empty() && entered_regionview) {
4914                 regions.add (entered_regionview);
4915         }
4916
4917         return regions;
4918 }
4919
4920 void
4921 Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
4922 {
4923         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4924                 RouteTimeAxisView* tatv;
4925                 
4926                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4927                         boost::shared_ptr<Playlist> pl;
4928                         std::vector<boost::shared_ptr<Region> > results;
4929                         boost::shared_ptr<Track> tr;
4930                         
4931                         if ((tr = tatv->track()) == 0) {
4932                                 /* bus */
4933                                 continue;
4934                         }
4935                         
4936                         if ((pl = (tr->playlist())) != 0) {
4937                                 boost::shared_ptr<Region> r = pl->region_by_id (id);
4938                                 if (r) {
4939                                         RegionView* marv = tatv->view()->find_view (r);
4940                                         if (marv) {
4941                                                 regions.push_back (marv);
4942                                         }
4943                                 }
4944                         }
4945                 }
4946         }
4947 }
4948
4949 void
4950 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4951 {
4952         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4953
4954                 RouteTimeAxisView* tatv;
4955
4956                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4957
4958                         boost::shared_ptr<Playlist> pl;
4959                         vector<boost::shared_ptr<Region> > results;
4960                         RegionView* marv;
4961                         boost::shared_ptr<Track> tr;
4962
4963                         if ((tr = tatv->track()) == 0) {
4964                                 /* bus */
4965                                 continue;
4966                         }
4967
4968                         if ((pl = (tr->playlist())) != 0) {
4969                                 if (src_comparison) {
4970                                         pl->get_source_equivalent_regions (region, results);
4971                                 } else {
4972                                         pl->get_region_list_equivalent_regions (region, results);
4973                                 }
4974                         }
4975
4976                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4977                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4978                                         regions.push_back (marv);
4979                                 }
4980                         }
4981
4982                 }
4983         }
4984 }
4985
4986 void
4987 Editor::show_rhythm_ferret ()
4988 {
4989         if (rhythm_ferret == 0) {
4990                 rhythm_ferret = new RhythmFerret(*this);
4991         }
4992
4993         rhythm_ferret->set_session (_session);
4994         rhythm_ferret->show ();
4995         rhythm_ferret->present ();
4996 }
4997
4998 void
4999 Editor::first_idle ()
5000 {
5001         MessageDialog* dialog = 0;
5002         
5003         if (track_views.size() > 1) {
5004                 dialog = new MessageDialog (
5005                         *this,
5006                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5007                         true
5008                         );
5009                 dialog->present ();
5010                 ARDOUR_UI::instance()->flush_pending ();
5011         }
5012
5013         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5014                 (*t)->first_idle();
5015         }
5016
5017         // first idle adds route children (automation tracks), so we need to redisplay here
5018         _routes->redisplay ();
5019
5020         delete dialog;
5021
5022         if (_session->undo_depth() == 0) {
5023                 undo_action->set_sensitive(false);
5024         }
5025         redo_action->set_sensitive(false);
5026         begin_selection_op_history ();
5027
5028         _have_idled = true;
5029 }
5030
5031 gboolean
5032 Editor::_idle_resize (gpointer arg)
5033 {
5034         return ((Editor*)arg)->idle_resize ();
5035 }
5036
5037 void
5038 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5039 {
5040         if (resize_idle_id < 0) {
5041                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5042                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5043                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5044                  */
5045                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5046                 _pending_resize_amount = 0;
5047         }
5048
5049         /* make a note of the smallest resulting height, so that we can clamp the
5050            lower limit at TimeAxisView::hSmall */
5051
5052         int32_t min_resulting = INT32_MAX;
5053
5054         _pending_resize_amount += h;
5055         _pending_resize_view = view;
5056
5057         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5058
5059         if (selection->tracks.contains (_pending_resize_view)) {
5060                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5061                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5062                 }
5063         }
5064
5065         if (min_resulting < 0) {
5066                 min_resulting = 0;
5067         }
5068
5069         /* clamp */
5070         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5071                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5072         }
5073 }
5074
5075 /** Handle pending resizing of tracks */
5076 bool
5077 Editor::idle_resize ()
5078 {
5079         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5080
5081         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5082             selection->tracks.contains (_pending_resize_view)) {
5083
5084                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5085                         if (*i != _pending_resize_view) {
5086                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5087                         }
5088                 }
5089         }
5090
5091         _pending_resize_amount = 0;
5092         _group_tabs->set_dirty ();
5093         resize_idle_id = -1;
5094
5095         return false;
5096 }
5097
5098 void
5099 Editor::located ()
5100 {
5101         ENSURE_GUI_THREAD (*this, &Editor::located);
5102
5103         if (_session) {
5104                 playhead_cursor->set_position (_session->audible_frame ());
5105                 if (_follow_playhead && !_pending_initial_locate) {
5106                         reset_x_origin_to_follow_playhead ();
5107                 }
5108         }
5109
5110         _pending_locate_request = false;
5111         _pending_initial_locate = false;
5112 }
5113
5114 void
5115 Editor::region_view_added (RegionView * rv)
5116 {
5117         for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5118                 if (rv->region ()->id () == (*pr)) {
5119                         selection->add (rv);
5120                         selection->regions.pending.erase (pr);
5121                         break;
5122                 }
5123         }
5124         _summary->set_background_dirty ();
5125 }
5126
5127 void
5128 Editor::region_view_removed ()
5129 {
5130         _summary->set_background_dirty ();
5131 }
5132
5133 RouteTimeAxisView*
5134 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5135 {
5136         TrackViewList::const_iterator j = track_views.begin ();
5137         while (j != track_views.end()) {
5138                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5139                 if (rtv && rtv->route() == r) {
5140                         return rtv;
5141                 }
5142                 ++j;
5143         }
5144
5145         return 0;
5146 }
5147
5148
5149 TrackViewList
5150 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5151 {
5152         TrackViewList t;
5153
5154         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5155                 TimeAxisView* tv = axis_view_from_route (*i);
5156                 if (tv) {
5157                         t.push_back (tv);
5158                 }
5159         }
5160
5161         return t;
5162 }
5163
5164 void
5165 Editor::suspend_route_redisplay ()
5166 {
5167         if (_routes) {
5168                 _routes->suspend_redisplay();
5169         }
5170 }
5171
5172 void
5173 Editor::resume_route_redisplay ()
5174 {
5175         if (_routes) {
5176                 _routes->resume_redisplay();
5177         }
5178 }
5179
5180 void
5181 Editor::add_routes (RouteList& routes)
5182 {
5183         ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5184
5185         RouteTimeAxisView *rtv;
5186         list<RouteTimeAxisView*> new_views;
5187
5188         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5189                 boost::shared_ptr<Route> route = (*x);
5190
5191                 if (route->is_auditioner() || route->is_monitor()) {
5192                         continue;
5193                 }
5194
5195                 DataType dt = route->input()->default_type();
5196
5197                 if (dt == ARDOUR::DataType::AUDIO) {
5198                         rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5199                         rtv->set_route (route);
5200                 } else if (dt == ARDOUR::DataType::MIDI) {
5201                         rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5202                         rtv->set_route (route);
5203                 } else {
5204                         throw unknown_type();
5205                 }
5206
5207                 new_views.push_back (rtv);
5208                 track_views.push_back (rtv);
5209
5210                 rtv->effective_gain_display ();
5211
5212                 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5213                 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5214         }
5215
5216         if (new_views.size() > 0) {
5217                 _routes->routes_added (new_views);
5218                 _summary->routes_added (new_views);
5219         }
5220
5221         if (show_editor_mixer_when_tracks_arrive) {
5222                 show_editor_mixer (true);
5223         }
5224
5225         editor_list_button.set_sensitive (true);
5226 }
5227
5228 void
5229 Editor::timeaxisview_deleted (TimeAxisView *tv)
5230 {
5231         if (tv == entered_track) {
5232                 entered_track = 0;
5233         }
5234
5235         if (_session && _session->deletion_in_progress()) {
5236                 /* the situation is under control */
5237                 return;
5238         }
5239
5240         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5241
5242         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5243
5244         _routes->route_removed (tv);
5245
5246         TimeAxisView::Children c = tv->get_child_list ();
5247         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5248                 if (entered_track == i->get()) {
5249                         entered_track = 0;
5250                 }
5251         }
5252
5253         /* remove it from the list of track views */
5254
5255         TrackViewList::iterator i;
5256
5257         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5258                 i = track_views.erase (i);
5259         }
5260
5261         /* update whatever the current mixer strip is displaying, if revelant */
5262
5263         boost::shared_ptr<Route> route;
5264
5265         if (rtav) {
5266                 route = rtav->route ();
5267         }
5268
5269         if (current_mixer_strip && current_mixer_strip->route() == route) {
5270
5271                 TimeAxisView* next_tv;
5272
5273                 if (track_views.empty()) {
5274                         next_tv = 0;
5275                 } else if (i == track_views.end()) {
5276                         next_tv = track_views.front();
5277                 } else {
5278                         next_tv = (*i);
5279                 }
5280
5281
5282                 if (next_tv) {
5283                         set_selected_mixer_strip (*next_tv);
5284                 } else {
5285                         /* make the editor mixer strip go away setting the
5286                          * button to inactive (which also unticks the menu option)
5287                          */
5288
5289                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5290                 }
5291         }
5292 }
5293
5294 void
5295 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5296 {
5297         if (apply_to_selection) {
5298                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5299
5300                         TrackSelection::iterator j = i;
5301                         ++j;
5302
5303                         hide_track_in_display (*i, false);
5304
5305                         i = j;
5306                 }
5307         } else {
5308                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5309
5310                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5311                         // this will hide the mixer strip
5312                         set_selected_mixer_strip (*tv);
5313                 }
5314
5315                 _routes->hide_track_in_display (*tv);
5316         }
5317 }
5318
5319 bool
5320 Editor::sync_track_view_list_and_routes ()
5321 {
5322         track_views = TrackViewList (_routes->views ());
5323
5324         _summary->set_dirty ();
5325         _group_tabs->set_dirty ();
5326
5327         return false; // do not call again (until needed)
5328 }
5329
5330 void
5331 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5332 {
5333         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5334                 theslot (**i);
5335         }
5336 }
5337
5338 /** Find a RouteTimeAxisView by the ID of its route */
5339 RouteTimeAxisView*
5340 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5341 {
5342         RouteTimeAxisView* v;
5343
5344         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5345                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5346                         if(v->route()->id() == id) {
5347                                 return v;
5348                         }
5349                 }
5350         }
5351
5352         return 0;
5353 }
5354
5355 void
5356 Editor::fit_route_group (RouteGroup *g)
5357 {
5358         TrackViewList ts = axis_views_from_routes (g->route_list ());
5359         fit_tracks (ts);
5360 }
5361
5362 void
5363 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5364 {
5365         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5366
5367         if (r == 0) {
5368                 _session->cancel_audition ();
5369                 return;
5370         }
5371
5372         if (_session->is_auditioning()) {
5373                 _session->cancel_audition ();
5374                 if (r == last_audition_region) {
5375                         return;
5376                 }
5377         }
5378
5379         _session->audition_region (r);
5380         last_audition_region = r;
5381 }
5382
5383
5384 void
5385 Editor::hide_a_region (boost::shared_ptr<Region> r)
5386 {
5387         r->set_hidden (true);
5388 }
5389
5390 void
5391 Editor::show_a_region (boost::shared_ptr<Region> r)
5392 {
5393         r->set_hidden (false);
5394 }
5395
5396 void
5397 Editor::audition_region_from_region_list ()
5398 {
5399         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5400 }
5401
5402 void
5403 Editor::hide_region_from_region_list ()
5404 {
5405         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5406 }
5407
5408 void
5409 Editor::show_region_in_region_list ()
5410 {
5411         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5412 }
5413
5414 void
5415 Editor::step_edit_status_change (bool yn)
5416 {
5417         if (yn) {
5418                 start_step_editing ();
5419         } else {
5420                 stop_step_editing ();
5421         }
5422 }
5423
5424 void
5425 Editor::start_step_editing ()
5426 {
5427         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5428 }
5429
5430 void
5431 Editor::stop_step_editing ()
5432 {
5433         step_edit_connection.disconnect ();
5434 }
5435
5436 bool
5437 Editor::check_step_edit ()
5438 {
5439         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5440                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5441                 if (mtv) {
5442                         mtv->check_step_edit ();
5443                 }
5444         }
5445
5446         return true; // do it again, till we stop
5447 }
5448
5449 bool
5450 Editor::scroll_press (Direction dir)
5451 {
5452         ++_scroll_callbacks;
5453
5454         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5455                 /* delay the first auto-repeat */
5456                 return true;
5457         }
5458
5459         switch (dir) {
5460         case LEFT:
5461                 scroll_backward (1);
5462                 break;
5463
5464         case RIGHT:
5465                 scroll_forward (1);
5466                 break;
5467
5468         case UP:
5469                 scroll_up_one_track ();
5470                 break;
5471
5472         case DOWN:
5473                 scroll_down_one_track ();
5474                 break;
5475         }
5476
5477         /* do hacky auto-repeat */
5478         if (!_scroll_connection.connected ()) {
5479
5480                 _scroll_connection = Glib::signal_timeout().connect (
5481                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5482                         );
5483
5484                 _scroll_callbacks = 0;
5485         }
5486
5487         return true;
5488 }
5489
5490 void
5491 Editor::scroll_release ()
5492 {
5493         _scroll_connection.disconnect ();
5494 }
5495
5496 /** Queue a change for the Editor viewport x origin to follow the playhead */
5497 void
5498 Editor::reset_x_origin_to_follow_playhead ()
5499 {
5500         framepos_t const frame = playhead_cursor->current_frame ();
5501
5502         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5503
5504                 if (_session->transport_speed() < 0) {
5505
5506                         if (frame > (current_page_samples() / 2)) {
5507                                 center_screen (frame-(current_page_samples()/2));
5508                         } else {
5509                                 center_screen (current_page_samples()/2);
5510                         }
5511
5512                 } else {
5513
5514                         framepos_t l = 0;
5515                         
5516                         if (frame < leftmost_frame) {
5517                                 /* moving left */
5518                                 if (_session->transport_rolling()) {
5519                                         /* rolling; end up with the playhead at the right of the page */
5520                                         l = frame - current_page_samples ();
5521                                 } else {
5522                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5523                                         l = frame - current_page_samples() / 4;
5524                                 }
5525                         } else {
5526                                 /* moving right */
5527                                 if (_session->transport_rolling()) {
5528                                         /* rolling: end up with the playhead on the left of the page */
5529                                         l = frame;
5530                                 } else {
5531                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5532                                         l = frame - 3 * current_page_samples() / 4;
5533                                 }
5534                         }
5535
5536                         if (l < 0) {
5537                                 l = 0;
5538                         }
5539                         
5540                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5541                 }
5542         }
5543 }
5544
5545 void
5546 Editor::super_rapid_screen_update ()
5547 {
5548         if (!_session || !_session->engine().running()) {
5549                 return;
5550         }
5551
5552         /* METERING / MIXER STRIPS */
5553
5554         /* update track meters, if required */
5555         if (is_mapped() && meters_running) {
5556                 RouteTimeAxisView* rtv;
5557                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5558                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5559                                 rtv->fast_update ();
5560                         }
5561                 }
5562         }
5563
5564         /* and any current mixer strip */
5565         if (current_mixer_strip) {
5566                 current_mixer_strip->fast_update ();
5567         }
5568
5569         /* PLAYHEAD AND VIEWPORT */
5570
5571         framepos_t const frame = _session->audible_frame();
5572
5573         /* There are a few reasons why we might not update the playhead / viewport stuff:
5574          *
5575          * 1.  we don't update things when there's a pending locate request, otherwise
5576          *     when the editor requests a locate there is a chance that this method
5577          *     will move the playhead before the locate request is processed, causing
5578          *     a visual glitch.
5579          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5580          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5581          */
5582
5583         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5584
5585                 last_update_frame = frame;
5586
5587                 if (!_dragging_playhead) {
5588                         playhead_cursor->set_position (frame);
5589                 }
5590
5591                 if (!_stationary_playhead) {
5592
5593                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5594                                 /* We only do this if we aren't already
5595                                    handling a visual change (ie if
5596                                    pending_visual_change.being_handled is
5597                                    false) so that these requests don't stack
5598                                    up there are too many of them to handle in
5599                                    time.
5600                                 */
5601                                 reset_x_origin_to_follow_playhead ();
5602                         }
5603
5604                 } else {
5605
5606                         /* don't do continuous scroll till the new position is in the rightmost quarter of the
5607                            editor canvas
5608                         */
5609 #if 0
5610                         // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5611                         double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5612                         if (target <= 0.0) {
5613                                 target = 0.0;
5614                         }
5615                         if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5616                                 target = (target * 0.15) + (current * 0.85);
5617                         } else {
5618                                 /* relax */
5619                         }
5620
5621                         current = target;
5622                         set_horizontal_position (current);
5623 #endif
5624                 }
5625
5626         }
5627 }
5628
5629
5630 void
5631 Editor::session_going_away ()
5632 {
5633         _have_idled = false;
5634
5635         _session_connections.drop_connections ();
5636
5637         super_rapid_screen_update_connection.disconnect ();
5638
5639         selection->clear ();
5640         cut_buffer->clear ();
5641
5642         clicked_regionview = 0;
5643         clicked_axisview = 0;
5644         clicked_routeview = 0;
5645         entered_regionview = 0;
5646         entered_track = 0;
5647         last_update_frame = 0;
5648         _drags->abort ();
5649
5650         playhead_cursor->hide ();
5651
5652         /* rip everything out of the list displays */
5653
5654         _regions->clear ();
5655         _routes->clear ();
5656         _route_groups->clear ();
5657
5658         /* do this first so that deleting a track doesn't reset cms to null
5659            and thus cause a leak.
5660         */
5661
5662         if (current_mixer_strip) {
5663                 if (current_mixer_strip->get_parent() != 0) {
5664                         global_hpacker.remove (*current_mixer_strip);
5665                 }
5666                 delete current_mixer_strip;
5667                 current_mixer_strip = 0;
5668         }
5669
5670         /* delete all trackviews */
5671
5672         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5673                 delete *i;
5674         }
5675         track_views.clear ();
5676
5677         nudge_clock->set_session (0);
5678
5679         editor_list_button.set_active(false);
5680         editor_list_button.set_sensitive(false);
5681
5682         /* clear tempo/meter rulers */
5683         remove_metric_marks ();
5684         hide_measures ();
5685         clear_marker_display ();
5686
5687         stop_step_editing ();
5688         
5689         /* get rid of any existing editor mixer strip */
5690
5691         WindowTitle title(Glib::get_application_name());
5692         title += _("Editor");
5693
5694         set_title (title.get_string());
5695
5696         SessionHandlePtr::session_going_away ();
5697 }
5698
5699
5700 void
5701 Editor::show_editor_list (bool yn)
5702 {
5703         if (yn) {
5704                 _the_notebook.show ();
5705         } else {
5706                 _the_notebook.hide ();
5707         }
5708 }
5709
5710 void
5711 Editor::change_region_layering_order (bool from_context_menu)
5712 {
5713         const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5714
5715         if (!clicked_routeview) {
5716                 if (layering_order_editor) {
5717                         layering_order_editor->hide ();
5718                 }
5719                 return;
5720         }
5721
5722         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5723
5724         if (!track) {
5725                 return;
5726         }
5727
5728         boost::shared_ptr<Playlist> pl = track->playlist();
5729
5730         if (!pl) {
5731                 return;
5732         }
5733
5734         if (layering_order_editor == 0) {
5735                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5736         }
5737
5738         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5739         layering_order_editor->maybe_present ();
5740 }
5741
5742 void
5743 Editor::update_region_layering_order_editor ()
5744 {
5745         if (layering_order_editor && layering_order_editor->is_visible ()) {
5746                 change_region_layering_order (true);
5747         }
5748 }
5749
5750 void
5751 Editor::setup_fade_images ()
5752 {
5753         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5754         _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5755         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5756         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5757         _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5758
5759         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5760         _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5761         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5762         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5763         _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5764         
5765         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5766         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5767         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5768         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5769         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5770
5771         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5772         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5773         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5774         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5775         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5776
5777 }
5778
5779 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5780 Gtk::MenuItem&
5781 Editor::action_menu_item (std::string const & name)
5782 {
5783         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5784         assert (a);
5785
5786         return *manage (a->create_menu_item ());
5787 }
5788
5789 void
5790 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5791 {
5792         EventBox* b = manage (new EventBox);
5793         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5794         Label* l = manage (new Label (name));
5795         l->set_angle (-90);
5796         b->add (*l);
5797         b->show_all ();
5798         _the_notebook.append_page (widget, *b);
5799 }
5800
5801 bool
5802 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5803 {
5804         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5805                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5806         }
5807
5808         if (ev->type == GDK_2BUTTON_PRESS) {
5809
5810                 /* double-click on a notebook tab shrinks or expands the notebook */
5811
5812                 if (_notebook_shrunk) {
5813                         if (pre_notebook_shrink_pane_width) {
5814                                 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5815                         }
5816                         _notebook_shrunk = false;
5817                 } else {
5818                         pre_notebook_shrink_pane_width = edit_pane.get_position();
5819
5820                         /* this expands the LHS of the edit pane to cover the notebook
5821                            PAGE but leaves the tabs visible.
5822                          */
5823                         edit_pane.set_position (edit_pane.get_position() + page->get_width());
5824                         _notebook_shrunk = true;
5825                 }
5826         }
5827
5828         return true;
5829 }
5830
5831 void
5832 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5833 {
5834         using namespace Menu_Helpers;
5835         
5836         MenuList& items = _control_point_context_menu.items ();
5837         items.clear ();
5838         
5839         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5840         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5841         if (!can_remove_control_point (item)) {
5842                 items.back().set_sensitive (false);
5843         }
5844
5845         _control_point_context_menu.popup (event->button.button, event->button.time);
5846 }
5847
5848 void
5849 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5850 {
5851         using namespace Menu_Helpers;
5852
5853         NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5854         if (!note) {
5855                 return;
5856         }
5857
5858         /* We need to get the selection here and pass it to the operations, since
5859            popping up the menu will cause a region leave event which clears
5860            entered_regionview. */
5861
5862         MidiRegionView&       mrv = note->region_view();
5863         const RegionSelection rs  = get_regions_from_selection_and_entered ();
5864
5865         MenuList& items = _note_context_menu.items();
5866         items.clear();
5867
5868         items.push_back(MenuElem(_("Delete"),
5869                                  sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5870         items.push_back(MenuElem(_("Edit..."),
5871                                  sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5872         items.push_back(MenuElem(_("Legatize"),
5873                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5874         items.push_back(MenuElem(_("Quantize..."),
5875                                  sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5876         items.push_back(MenuElem(_("Remove Overlap"),
5877                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5878         items.push_back(MenuElem(_("Transform..."),
5879                                  sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5880
5881         _note_context_menu.popup (event->button.button, event->button.time);
5882 }
5883
5884 void
5885 Editor::zoom_vertical_modifier_released()
5886 {
5887         _stepping_axis_view = 0;
5888 }
5889
5890 void
5891 Editor::ui_parameter_changed (string parameter)
5892 {
5893         if (parameter == "icon-set") {
5894                 while (!_cursor_stack.empty()) {
5895                         _cursor_stack.pop_back();
5896                 }
5897                 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5898                 _cursor_stack.push_back(_cursors->grabber);
5899         } else if (parameter == "draggable-playhead") {
5900                 if (_verbose_cursor) {
5901                         playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());
5902                 }
5903         }
5904 }