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