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