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