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