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