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