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