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