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