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