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