round control-scroll offsets towards zero
[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         string str = edit_point_strings[(int)ep];
2108
2109         if (Profile->get_mixbus())
2110                 if (ep == EditAtSelectedMarker)
2111                         ep = EditAtPlayhead;
2112         
2113         if (str != edit_point_selector.get_text ()) {
2114                 edit_point_selector.set_text (str);
2115         }
2116
2117         reset_canvas_cursor ();
2118
2119         if (!force && !changed) {
2120                 return;
2121         }
2122
2123         const char* action=NULL;
2124
2125         switch (_edit_point) {
2126         case EditAtPlayhead:
2127                 action = "edit-at-playhead";
2128                 break;
2129         case EditAtSelectedMarker:
2130                 action = "edit-at-marker";
2131                 break;
2132         case EditAtMouse:
2133                 action = "edit-at-mouse";
2134                 break;
2135         }
2136
2137         Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2138         if (act) {
2139                 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2140         }
2141
2142         framepos_t foo;
2143         bool in_track_canvas;
2144
2145         if (!mouse_frame (foo, in_track_canvas)) {
2146                 in_track_canvas = false;
2147         }
2148
2149         reset_canvas_action_sensitivity (in_track_canvas);
2150
2151         instant_save ();
2152 }
2153
2154 int
2155 Editor::set_state (const XMLNode& node, int /*version*/)
2156 {
2157         const XMLProperty* prop;
2158         XMLNode* geometry;
2159         int x, y;
2160         Gdk::Geometry g;
2161
2162         set_id (node);
2163
2164         g.base_width = default_width;
2165         g.base_height = default_height;
2166         x = 1;
2167         y = 1;
2168
2169         if ((geometry = find_named_node (node, "geometry")) != 0) {
2170
2171                 XMLProperty* prop;
2172
2173                 if ((prop = geometry->property("x_size")) == 0) {
2174                         prop = geometry->property ("x-size");
2175                 }
2176                 if (prop) {
2177                         g.base_width = atoi(prop->value());
2178                 }
2179                 if ((prop = geometry->property("y_size")) == 0) {
2180                         prop = geometry->property ("y-size");
2181                 }
2182                 if (prop) {
2183                         g.base_height = atoi(prop->value());
2184                 }
2185
2186                 if ((prop = geometry->property ("x_pos")) == 0) {
2187                         prop = geometry->property ("x-pos");
2188                 }
2189                 if (prop) {
2190                         x = atoi (prop->value());
2191
2192                 }
2193                 if ((prop = geometry->property ("y_pos")) == 0) {
2194                         prop = geometry->property ("y-pos");
2195                 }
2196                 if (prop) {
2197                         y = atoi (prop->value());
2198                 }
2199         }
2200
2201         set_default_size (g.base_width, g.base_height);
2202         move (x, y);
2203
2204         if (_session && (prop = node.property ("playhead"))) {
2205                 framepos_t pos;
2206                 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2207                 if (pos >= 0) {
2208                         playhead_cursor->set_position (pos);
2209                 } else {
2210                         warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2211                         playhead_cursor->set_position (0);
2212                 }
2213         } else {
2214                 playhead_cursor->set_position (0);
2215         }
2216
2217         if ((prop = node.property ("mixer-width"))) {
2218                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2219         }
2220
2221         if ((prop = node.property ("zoom-focus"))) {
2222                 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2223         }
2224
2225         if ((prop = node.property ("zoom"))) {
2226                 /* older versions of ardour used floating point samples_per_pixel */
2227                 double f = PBD::atof (prop->value());
2228                 reset_zoom (llrintf (f));
2229         } else {
2230                 reset_zoom (samples_per_pixel);
2231         }
2232
2233         if ((prop = node.property ("visible-track-count"))) {
2234                 set_visible_track_count (PBD::atoi (prop->value()));
2235         }
2236
2237         if ((prop = node.property ("snap-to"))) {
2238                 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2239         }
2240
2241         if ((prop = node.property ("snap-mode"))) {
2242                 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2243         }
2244
2245         if ((prop = node.property ("internal-snap-to"))) {
2246                 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2247         }
2248
2249         if ((prop = node.property ("internal-snap-mode"))) {
2250                 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2251         }
2252
2253         if ((prop = node.property ("pre-internal-snap-to"))) {
2254                 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2255         }
2256
2257
2258         if ((prop = node.property ("pre-internal-snap-mode"))) {
2259                 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2260         }
2261
2262         if ((prop = node.property ("mouse-mode"))) {
2263                 MouseMode m = str2mousemode(prop->value());
2264                 set_mouse_mode (m, true);
2265         } else {
2266                 set_mouse_mode (MouseObject, true);
2267         }
2268
2269         if ((prop = node.property ("left-frame")) != 0) {
2270                 framepos_t pos;
2271                 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2272                         if (pos < 0) {
2273                                 pos = 0;
2274                         }
2275                         reset_x_origin (pos);
2276                 }
2277         }
2278
2279         if ((prop = node.property ("y-origin")) != 0) {
2280                 reset_y_origin (atof (prop->value ()));
2281         }
2282
2283         if ((prop = node.property ("internal-edit"))) {
2284                 bool yn = string_is_affirmative (prop->value());
2285                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2286                 if (act) {
2287                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2288                         tact->set_active (!yn);
2289                         tact->set_active (yn);
2290                 }
2291         }
2292
2293         if ((prop = node.property ("join-object-range"))) {
2294                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2295                 bool yn = string_is_affirmative (prop->value());
2296                 if (act) {
2297                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2298                         tact->set_active (!yn);
2299                         tact->set_active (yn);
2300                 }
2301                 set_mouse_mode(mouse_mode, true);
2302         }
2303
2304         if ((prop = node.property ("edit-point"))) {
2305                 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2306         }
2307
2308         if ((prop = node.property ("show-measures"))) {
2309                 bool yn = string_is_affirmative (prop->value());
2310                 _show_measures = yn;
2311                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2312                 if (act) {
2313                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2314                         /* do it twice to force the change */
2315                         tact->set_active (!yn);
2316                         tact->set_active (yn);
2317                 }
2318         }
2319
2320         if ((prop = node.property ("follow-playhead"))) {
2321                 bool yn = string_is_affirmative (prop->value());
2322                 set_follow_playhead (yn);
2323                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2324                 if (act) {
2325                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2326                         if (tact->get_active() != yn) {
2327                                 tact->set_active (yn);
2328                         }
2329                 }
2330         }
2331
2332         if ((prop = node.property ("stationary-playhead"))) {
2333                 bool yn = string_is_affirmative (prop->value());
2334                 set_stationary_playhead (yn);
2335                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2336                 if (act) {
2337                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2338                         if (tact->get_active() != yn) {
2339                                 tact->set_active (yn);
2340                         }
2341                 }
2342         }
2343
2344         if ((prop = node.property ("region-list-sort-type"))) {
2345                 RegionListSortType st;
2346                 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2347         }
2348
2349         if ((prop = node.property ("show-editor-mixer"))) {
2350
2351                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2352                 assert (act);
2353
2354                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2355                 bool yn = string_is_affirmative (prop->value());
2356
2357                 /* do it twice to force the change */
2358
2359                 tact->set_active (!yn);
2360                 tact->set_active (yn);
2361         }
2362
2363         if ((prop = node.property ("show-editor-list"))) {
2364
2365                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2366                 assert (act);
2367
2368                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2369                 bool yn = string_is_affirmative (prop->value());
2370
2371                 /* do it twice to force the change */
2372
2373                 tact->set_active (!yn);
2374                 tact->set_active (yn);
2375         }
2376
2377         if ((prop = node.property (X_("editor-list-page")))) {
2378                 _the_notebook.set_current_page (atoi (prop->value ()));
2379         }
2380
2381         if ((prop = node.property (X_("show-marker-lines")))) {
2382                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2383                 assert (act);
2384                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2385                 bool yn = string_is_affirmative (prop->value ());
2386
2387                 tact->set_active (!yn);
2388                 tact->set_active (yn);
2389         }
2390
2391         XMLNodeList children = node.children ();
2392         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2393                 selection->set_state (**i, Stateful::current_state_version);
2394                 _regions->set_state (**i);
2395         }
2396
2397         if ((prop = node.property ("maximised"))) {
2398                 bool yn = string_is_affirmative (prop->value());
2399                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2400                 assert (act);
2401                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2402                 bool fs = tact && tact->get_active();
2403                 if (yn ^ fs) {
2404                         ActionManager::do_action ("Common", "ToggleMaximalEditor");
2405                 }
2406         }
2407
2408         if ((prop = node.property ("nudge-clock-value"))) {
2409                 framepos_t f;
2410                 sscanf (prop->value().c_str(), "%" PRId64, &f);
2411                 nudge_clock->set (f);
2412         } else {
2413                 nudge_clock->set_mode (AudioClock::Timecode);
2414                 nudge_clock->set (_session->frame_rate() * 5, true);
2415         }
2416
2417         return 0;
2418 }
2419
2420 XMLNode&
2421 Editor::get_state ()
2422 {
2423         XMLNode* node = new XMLNode ("Editor");
2424         char buf[32];
2425
2426         id().print (buf, sizeof (buf));
2427         node->add_property ("id", buf);
2428
2429         if (is_realized()) {
2430                 Glib::RefPtr<Gdk::Window> win = get_window();
2431
2432                 int x, y, width, height;
2433                 win->get_root_origin(x, y);
2434                 win->get_size(width, height);
2435
2436                 XMLNode* geometry = new XMLNode ("geometry");
2437
2438                 snprintf(buf, sizeof(buf), "%d", width);
2439                 geometry->add_property("x-size", string(buf));
2440                 snprintf(buf, sizeof(buf), "%d", height);
2441                 geometry->add_property("y-size", string(buf));
2442                 snprintf(buf, sizeof(buf), "%d", x);
2443                 geometry->add_property("x-pos", string(buf));
2444                 snprintf(buf, sizeof(buf), "%d", y);
2445                 geometry->add_property("y-pos", string(buf));
2446                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2447                 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2448                 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2449                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2450                 geometry->add_property("edit-vertical-pane-pos", string(buf));
2451
2452                 node->add_child_nocopy (*geometry);
2453         }
2454
2455         maybe_add_mixer_strip_width (*node);
2456
2457         node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2458
2459         snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2460         node->add_property ("zoom", buf);
2461         node->add_property ("snap-to", enum_2_string (_snap_type));
2462         node->add_property ("snap-mode", enum_2_string (_snap_mode));
2463         node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2464         node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2465         node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2466         node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2467         node->add_property ("edit-point", enum_2_string (_edit_point));
2468         snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2469         node->add_property ("visible-track-count", buf);
2470
2471         snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2472         node->add_property ("playhead", buf);
2473         snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2474         node->add_property ("left-frame", buf);
2475         snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2476         node->add_property ("y-origin", buf);
2477
2478         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2479         node->add_property ("maximised", _maximised ? "yes" : "no");
2480         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2481         node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2482         node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2483         node->add_property ("mouse-mode", enum2str(mouse_mode));
2484         node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2485         node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2486
2487         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2488         if (act) {
2489                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2490                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2491         }
2492
2493         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2494         if (act) {
2495                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2496                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2497         }
2498
2499         snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2500         node->add_property (X_("editor-list-page"), buf);
2501
2502         if (button_bindings) {
2503                 XMLNode* bb = new XMLNode (X_("Buttons"));
2504                 button_bindings->save (*bb);
2505                 node->add_child_nocopy (*bb);
2506         }
2507
2508         node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2509
2510         node->add_child_nocopy (selection->get_state ());
2511         node->add_child_nocopy (_regions->get_state ());
2512
2513         snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2514         node->add_property ("nudge-clock-value", buf);
2515
2516         return *node;
2517 }
2518
2519 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2520  *  if @param trackview_relative_offset is false, @param y y is a global canvas *  coordinate, in pixel units
2521  *
2522  *  @return pair: TimeAxisView that y is over, layer index.
2523  *
2524  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2525  *  in stacked or expanded region display mode, otherwise 0.
2526  */
2527 std::pair<TimeAxisView *, double>
2528 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2529 {
2530         if (!trackview_relative_offset) {
2531                 y -= _trackview_group->canvas_origin().y;
2532         }
2533
2534         if (y < 0) {
2535                 return std::make_pair ( (TimeAxisView *) 0, 0);
2536         }
2537
2538         for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2539                         
2540                 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2541                         
2542                 if (r.first) {
2543                         return r;
2544                 }
2545         }
2546
2547         return std::make_pair ( (TimeAxisView *) 0, 0);
2548 }
2549
2550 /** Snap a position to the grid, if appropriate, taking into account current
2551  *  grid settings and also the state of any snap modifier keys that may be pressed.
2552  *  @param start Position to snap.
2553  *  @param event Event to get current key modifier information from, or 0.
2554  */
2555 void
2556 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2557 {
2558         if (!_session || !event) {
2559                 return;
2560         }
2561
2562         if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2563                 if (_snap_mode == SnapOff) {
2564                         snap_to_internal (start, direction, for_mark);
2565                 }
2566         } else {
2567                 if (_snap_mode != SnapOff) {
2568                         snap_to_internal (start, direction, for_mark);
2569                 }
2570         }
2571 }
2572
2573 void
2574 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2575 {
2576         if (!_session || _snap_mode == SnapOff) {
2577                 return;
2578         }
2579
2580         snap_to_internal (start, direction, for_mark);
2581 }
2582
2583 void
2584 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2585 {
2586         const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2587         framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2588
2589         switch (_snap_type) {
2590         case SnapToTimecodeFrame:
2591                 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2592                         start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2593                 } else {
2594                         start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) *  _session->frames_per_timecode_frame());
2595                 }
2596                 break;
2597
2598         case SnapToTimecodeSeconds:
2599                 if (_session->config.get_timecode_offset_negative()) {
2600                         start += _session->config.get_timecode_offset ();
2601                 } else {
2602                         start -= _session->config.get_timecode_offset ();
2603                 }
2604                 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2605                         start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2606                 } else {
2607                         start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2608                 }
2609
2610                 if (_session->config.get_timecode_offset_negative()) {
2611                         start -= _session->config.get_timecode_offset ();
2612                 } else {
2613                         start += _session->config.get_timecode_offset ();
2614                 }
2615                 break;
2616
2617         case SnapToTimecodeMinutes:
2618                 if (_session->config.get_timecode_offset_negative()) {
2619                         start += _session->config.get_timecode_offset ();
2620                 } else {
2621                         start -= _session->config.get_timecode_offset ();
2622                 }
2623                 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2624                         start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2625                 } else {
2626                         start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2627                 }
2628                 if (_session->config.get_timecode_offset_negative()) {
2629                         start -= _session->config.get_timecode_offset ();
2630                 } else {
2631                         start += _session->config.get_timecode_offset ();
2632                 }
2633                 break;
2634         default:
2635                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2636                 abort(); /*NOTREACHED*/
2637         }
2638 }
2639
2640 void
2641 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2642 {
2643         const framepos_t one_second = _session->frame_rate();
2644         const framepos_t one_minute = _session->frame_rate() * 60;
2645         framepos_t presnap = start;
2646         framepos_t before;
2647         framepos_t after;
2648
2649         switch (_snap_type) {
2650         case SnapToTimecodeFrame:
2651         case SnapToTimecodeSeconds:
2652         case SnapToTimecodeMinutes:
2653                 return timecode_snap_to_internal (start, direction, for_mark);
2654
2655         case SnapToCDFrame:
2656                 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2657                         start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2658                 } else {
2659                         start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2660                 }
2661                 break;
2662
2663         case SnapToSeconds:
2664                 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2665                         start = (framepos_t) ceil ((double) start / one_second) * one_second;
2666                 } else {
2667                         start = (framepos_t) floor ((double) start / one_second) * one_second;
2668                 }
2669                 break;
2670
2671         case SnapToMinutes:
2672                 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2673                         start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2674                 } else {
2675                         start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2676                 }
2677                 break;
2678
2679         case SnapToBar:
2680                 start = _session->tempo_map().round_to_bar (start, direction);
2681                 break;
2682
2683         case SnapToBeat:
2684                 start = _session->tempo_map().round_to_beat (start, direction);
2685                 break;
2686
2687         case SnapToBeatDiv128:
2688                 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2689                 break;
2690         case SnapToBeatDiv64:
2691                 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2692                 break;
2693         case SnapToBeatDiv32:
2694                 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2695                 break;
2696         case SnapToBeatDiv28:
2697                 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2698                 break;
2699         case SnapToBeatDiv24:
2700                 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2701                 break;
2702         case SnapToBeatDiv20:
2703                 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2704                 break;
2705         case SnapToBeatDiv16:
2706                 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2707                 break;
2708         case SnapToBeatDiv14:
2709                 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2710                 break;
2711         case SnapToBeatDiv12:
2712                 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2713                 break;
2714         case SnapToBeatDiv10:
2715                 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2716                 break;
2717         case SnapToBeatDiv8:
2718                 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2719                 break;
2720         case SnapToBeatDiv7:
2721                 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2722                 break;
2723         case SnapToBeatDiv6:
2724                 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2725                 break;
2726         case SnapToBeatDiv5:
2727                 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2728                 break;
2729         case SnapToBeatDiv4:
2730                 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2731                 break;
2732         case SnapToBeatDiv3:
2733                 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2734                 break;
2735         case SnapToBeatDiv2:
2736                 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2737                 break;
2738
2739         case SnapToMark:
2740                 if (for_mark) {
2741                         return;
2742                 }
2743
2744                 _session->locations()->marks_either_side (start, before, after);
2745
2746                 if (before == max_framepos && after == max_framepos) {
2747                         /* No marks to snap to, so just don't snap */
2748                         return;
2749                 } else if (before == max_framepos) {
2750                         start = after;
2751                 } else if (after == max_framepos) {
2752                         start = before;
2753                 } else if (before != max_framepos && after != max_framepos) {
2754                         /* have before and after */
2755                         if ((start - before) < (after - start)) {
2756                                 start = before;
2757                         } else {
2758                                 start = after;
2759                         }
2760                 }
2761
2762                 break;
2763
2764         case SnapToRegionStart:
2765         case SnapToRegionEnd:
2766         case SnapToRegionSync:
2767         case SnapToRegionBoundary:
2768                 if (!region_boundary_cache.empty()) {
2769
2770                         vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2771                         vector<framepos_t>::iterator next = region_boundary_cache.end ();
2772
2773                         if (direction > 0) {
2774                                 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2775                         } else {
2776                                 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2777                         }
2778
2779                         if (next != region_boundary_cache.begin ()) {
2780                                 prev = next;
2781                                 prev--;
2782                         }
2783
2784                         framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2785                         framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2786
2787                         if (start > (p + n) / 2) {
2788                                 start = n;
2789                         } else {
2790                                 start = p;
2791                         }
2792                 }
2793                 break;
2794         }
2795
2796         switch (_snap_mode) {
2797         case SnapNormal:
2798                 return;
2799
2800         case SnapMagnetic:
2801
2802                 if (presnap > start) {
2803                         if (presnap > (start + pixel_to_sample(snap_threshold))) {
2804                                 start = presnap;
2805                         }
2806
2807                 } else if (presnap < start) {
2808                         if (presnap < (start - pixel_to_sample(snap_threshold))) {
2809                                 start = presnap;
2810                         }
2811                 }
2812
2813         default:
2814                 /* handled at entry */
2815                 return;
2816
2817         }
2818 }
2819
2820
2821 void
2822 Editor::setup_toolbar ()
2823 {
2824         HBox* mode_box = manage(new HBox);
2825         mode_box->set_border_width (2);
2826         mode_box->set_spacing(2);
2827
2828         HBox* mouse_mode_box = manage (new HBox);
2829         HBox* mouse_mode_hbox = manage (new HBox);
2830         VBox* mouse_mode_vbox = manage (new VBox);
2831         Alignment* mouse_mode_align = manage (new Alignment);
2832
2833         Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2834         mouse_mode_size_group->add_widget (smart_mode_button);
2835         mouse_mode_size_group->add_widget (mouse_move_button);
2836         mouse_mode_size_group->add_widget (mouse_cut_button);
2837         mouse_mode_size_group->add_widget (mouse_select_button);
2838         mouse_mode_size_group->add_widget (mouse_gain_button);
2839         mouse_mode_size_group->add_widget (mouse_timefx_button);
2840         mouse_mode_size_group->add_widget (mouse_audition_button);
2841         mouse_mode_size_group->add_widget (mouse_draw_button);
2842         mouse_mode_size_group->add_widget (internal_edit_button);
2843
2844         mouse_mode_size_group->add_widget (zoom_in_button);
2845         mouse_mode_size_group->add_widget (zoom_out_button);
2846         mouse_mode_size_group->add_widget (zoom_preset_selector);
2847         mouse_mode_size_group->add_widget (zoom_out_full_button);
2848         mouse_mode_size_group->add_widget (zoom_focus_selector);
2849
2850         mouse_mode_size_group->add_widget (tav_shrink_button);
2851         mouse_mode_size_group->add_widget (tav_expand_button);
2852         mouse_mode_size_group->add_widget (visible_tracks_selector);
2853
2854         mouse_mode_size_group->add_widget (snap_type_selector);
2855         mouse_mode_size_group->add_widget (snap_mode_selector);
2856
2857         mouse_mode_size_group->add_widget (edit_point_selector);
2858         mouse_mode_size_group->add_widget (edit_mode_selector);
2859
2860         mouse_mode_size_group->add_widget (*nudge_clock);
2861         mouse_mode_size_group->add_widget (nudge_forward_button);
2862         mouse_mode_size_group->add_widget (nudge_backward_button);
2863
2864         mouse_mode_hbox->set_spacing (2);
2865
2866         if (!ARDOUR::Profile->get_trx()) {
2867                 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2868         }
2869
2870         mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2871         mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2872
2873         if (!ARDOUR::Profile->get_mixbus()) {
2874                 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2875         }
2876         
2877         if (!ARDOUR::Profile->get_trx()) {
2878                 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2879                 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2880                 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2881                 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2882                 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2883         }
2884
2885         mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2886
2887         mouse_mode_align->add (*mouse_mode_vbox);
2888         mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2889
2890         mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2891
2892         edit_mode_selector.set_name ("mouse mode button");
2893
2894         if (!ARDOUR::Profile->get_trx()) {
2895                 mode_box->pack_start (edit_mode_selector, false, false);
2896         }
2897         mode_box->pack_start (*mouse_mode_box, false, false);
2898
2899         _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2900         _mouse_mode_tearoff->set_name ("MouseModeBase");
2901         _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2902
2903         if (Profile->get_sae() || Profile->get_mixbus() ) {
2904                 _mouse_mode_tearoff->set_can_be_torn_off (false);
2905         }
2906
2907         _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2908                                                          &_mouse_mode_tearoff->tearoff_window()));
2909         _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2910                                                          &_mouse_mode_tearoff->tearoff_window(), 1));
2911         _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2912                                                          &_mouse_mode_tearoff->tearoff_window()));
2913         _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2914                                                           &_mouse_mode_tearoff->tearoff_window(), 1));
2915
2916         /* Zoom */
2917
2918         _zoom_box.set_spacing (2);
2919         _zoom_box.set_border_width (2);
2920
2921         RefPtr<Action> act;
2922
2923         zoom_preset_selector.set_name ("zoom button");
2924         zoom_preset_selector.set_image(::get_icon ("time_exp"));
2925         zoom_preset_selector.set_size_request (42, -1);
2926
2927         zoom_in_button.set_name ("zoom button");
2928         zoom_in_button.set_image(::get_icon ("zoom_in"));
2929         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2930         zoom_in_button.set_related_action (act);
2931
2932         zoom_out_button.set_name ("zoom button");
2933         zoom_out_button.set_image(::get_icon ("zoom_out"));
2934         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2935         zoom_out_button.set_related_action (act);
2936
2937         zoom_out_full_button.set_name ("zoom button");
2938         zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2939         act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2940         zoom_out_full_button.set_related_action (act);
2941
2942         zoom_focus_selector.set_name ("zoom button");
2943
2944         if (ARDOUR::Profile->get_mixbus()) {
2945                 _zoom_box.pack_start (zoom_preset_selector, false, false);
2946         } else if (ARDOUR::Profile->get_trx()) {
2947                 mode_box->pack_start (zoom_out_button, false, false);
2948                 mode_box->pack_start (zoom_in_button, false, false);
2949         } else {
2950                 _zoom_box.pack_start (zoom_out_button, false, false);
2951                 _zoom_box.pack_start (zoom_in_button, false, false);
2952                 _zoom_box.pack_start (zoom_out_full_button, false, false);
2953                 _zoom_box.pack_start (zoom_focus_selector, false, false);
2954         }
2955
2956         /* Track zoom buttons */
2957         visible_tracks_selector.set_name ("zoom button");
2958         if (Profile->get_mixbus()) {
2959                 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2960                 visible_tracks_selector.set_size_request (42, -1);
2961         } else {
2962                 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2963         }
2964
2965         tav_expand_button.set_name ("zoom button");
2966         tav_expand_button.set_image(::get_icon ("tav_exp"));
2967         act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2968         tav_expand_button.set_related_action (act);
2969
2970         tav_shrink_button.set_name ("zoom button");
2971         tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2972         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2973         tav_shrink_button.set_related_action (act);
2974
2975         if (ARDOUR::Profile->get_mixbus()) {
2976                 _zoom_box.pack_start (visible_tracks_selector);
2977         } else if (ARDOUR::Profile->get_trx()) {
2978                 _zoom_box.pack_start (tav_shrink_button);
2979                 _zoom_box.pack_start (tav_expand_button);
2980         } else {
2981                 _zoom_box.pack_start (visible_tracks_selector);
2982                 _zoom_box.pack_start (tav_shrink_button);
2983                 _zoom_box.pack_start (tav_expand_button);
2984         }
2985
2986         if (!ARDOUR::Profile->get_trx()) {
2987                 _zoom_tearoff = manage (new TearOff (_zoom_box));
2988                 
2989                 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2990                                                            &_zoom_tearoff->tearoff_window()));
2991                 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2992                                                            &_zoom_tearoff->tearoff_window(), 0));
2993                 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2994                                                            &_zoom_tearoff->tearoff_window()));
2995                 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2996                                                             &_zoom_tearoff->tearoff_window(), 0));
2997         } 
2998
2999         if (Profile->get_sae() || Profile->get_mixbus() ) {
3000                 _zoom_tearoff->set_can_be_torn_off (false);
3001         }
3002
3003         snap_box.set_spacing (2);
3004         snap_box.set_border_width (2);
3005
3006         snap_type_selector.set_name ("mouse mode button");
3007
3008         snap_mode_selector.set_name ("mouse mode button");
3009
3010         edit_point_selector.set_name ("mouse mode button");
3011
3012         snap_box.pack_start (snap_mode_selector, false, false);
3013         snap_box.pack_start (snap_type_selector, false, false);
3014         snap_box.pack_start (edit_point_selector, false, false);
3015
3016         /* Nudge */
3017
3018         HBox *nudge_box = manage (new HBox);
3019         nudge_box->set_spacing (2);
3020         nudge_box->set_border_width (2);
3021
3022         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3023         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3024
3025         nudge_box->pack_start (nudge_backward_button, false, false);
3026         nudge_box->pack_start (nudge_forward_button, false, false);
3027         nudge_box->pack_start (*nudge_clock, false, false);
3028
3029
3030         /* Pack everything in... */
3031
3032         HBox* hbox = manage (new HBox);
3033         hbox->set_spacing(2);
3034
3035         _tools_tearoff = manage (new TearOff (*hbox));
3036         _tools_tearoff->set_name ("MouseModeBase");
3037         _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3038
3039         if (Profile->get_sae() || Profile->get_mixbus()) {
3040                 _tools_tearoff->set_can_be_torn_off (false);
3041         }
3042
3043         _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3044                                                     &_tools_tearoff->tearoff_window()));
3045         _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3046                                                     &_tools_tearoff->tearoff_window(), 0));
3047         _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3048                                                     &_tools_tearoff->tearoff_window()));
3049         _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3050                                                      &_tools_tearoff->tearoff_window(), 0));
3051
3052         toolbar_hbox.set_spacing (2);
3053         toolbar_hbox.set_border_width (1);
3054
3055         toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3056         if (!ARDOUR::Profile->get_trx()) {
3057                 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3058                 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3059         }
3060
3061         if (!ARDOUR::Profile->get_trx()) {
3062                 hbox->pack_start (snap_box, false, false);
3063                 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3064                         hbox->pack_start (*nudge_box, false, false);
3065                 } else {
3066                         ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3067                 }
3068         }
3069         hbox->pack_start (panic_box, false, false);
3070
3071         hbox->show_all ();
3072
3073         toolbar_base.set_name ("ToolBarBase");
3074         toolbar_base.add (toolbar_hbox);
3075
3076         _toolbar_viewport.add (toolbar_base);
3077         /* stick to the required height but allow width to vary if there's not enough room */
3078         _toolbar_viewport.set_size_request (1, -1);
3079
3080         toolbar_frame.set_shadow_type (SHADOW_OUT);
3081         toolbar_frame.set_name ("BaseFrame");
3082         toolbar_frame.add (_toolbar_viewport);
3083 }
3084
3085 void
3086 Editor::build_edit_point_menu ()
3087 {
3088         using namespace Menu_Helpers;
3089
3090         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3091         if(!Profile->get_mixbus())
3092                 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3093         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3094
3095         set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3096 }
3097
3098 void
3099 Editor::build_edit_mode_menu ()
3100 {
3101         using namespace Menu_Helpers;
3102         
3103         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3104 //      edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3105         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3106         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
3107
3108         set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3109 }
3110
3111 void
3112 Editor::build_snap_mode_menu ()
3113 {
3114         using namespace Menu_Helpers;
3115
3116         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3117         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3118         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3119
3120         set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3121 }
3122
3123 void
3124 Editor::build_snap_type_menu ()
3125 {
3126         using namespace Menu_Helpers;
3127
3128         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3129         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3130         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3131         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3132         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3133         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3134         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3135         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3136         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3137         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3138         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3139         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3140         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3141         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3142         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3143         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3144         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3145         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3146         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3147         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3148         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3149         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3150         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3151         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3152         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3153         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3154         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3155         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3156         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3157         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3158
3159         set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3160
3161 }
3162
3163 void
3164 Editor::setup_tooltips ()
3165 {
3166         ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3167         ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3168         ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3169         ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3170         ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3171         ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3172         ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3173         ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3174         ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3175         ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3176         ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3177         ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3178         ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3179         ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3180         ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3181         ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3182         ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3183         ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3184         ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3185         ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3186         ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3187         ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3188         ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3189         ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3190         ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3191 }
3192
3193 int
3194 Editor::convert_drop_to_paths (
3195                 vector<string>&                paths,
3196                 const RefPtr<Gdk::DragContext>& /*context*/,
3197                 gint                            /*x*/,
3198                 gint                            /*y*/,
3199                 const SelectionData&            data,
3200                 guint                           /*info*/,
3201                 guint                           /*time*/)
3202 {
3203         if (_session == 0) {
3204                 return -1;
3205         }
3206
3207         vector<string> uris = data.get_uris();
3208
3209         if (uris.empty()) {
3210
3211                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3212                    are actually URI lists. So do it by hand.
3213                 */
3214
3215                 if (data.get_target() != "text/plain") {
3216                         return -1;
3217                 }
3218
3219                 /* Parse the "uri-list" format that Nautilus provides,
3220                    where each pathname is delimited by \r\n.
3221
3222                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3223                 */
3224
3225                 string txt = data.get_text();
3226                 char* p;
3227                 const char* q;
3228
3229                 p = (char *) malloc (txt.length() + 1);
3230                 txt.copy (p, txt.length(), 0);
3231                 p[txt.length()] = '\0';
3232
3233                 while (p)
3234                 {
3235                         if (*p != '#')
3236                         {
3237                                 while (g_ascii_isspace (*p))
3238                                         p++;
3239
3240                                 q = p;
3241                                 while (*q && (*q != '\n') && (*q != '\r')) {
3242                                         q++;
3243                                 }
3244
3245                                 if (q > p)
3246                                 {
3247                                         q--;
3248                                         while (q > p && g_ascii_isspace (*q))
3249                                                 q--;
3250
3251                                         if (q > p)
3252                                         {
3253                                                 uris.push_back (string (p, q - p + 1));
3254                                         }
3255                                 }
3256                         }
3257                         p = strchr (p, '\n');
3258                         if (p)
3259                                 p++;
3260                 }
3261
3262                 free ((void*)p);
3263
3264                 if (uris.empty()) {
3265                         return -1;
3266                 }
3267         }
3268
3269         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3270                 if ((*i).substr (0,7) == "file://") {
3271                         paths.push_back (Glib::filename_from_uri (*i));
3272                 }
3273         }
3274
3275         return 0;
3276 }
3277
3278 void
3279 Editor::new_tempo_section ()
3280 {
3281 }
3282
3283 void
3284 Editor::map_transport_state ()
3285 {
3286         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3287
3288         if (_session && _session->transport_stopped()) {
3289                 have_pending_keyboard_selection = false;
3290         }
3291
3292         update_loop_range_view ();
3293 }
3294
3295 /* UNDO/REDO */
3296
3297 void
3298 Editor::begin_reversible_command (string name)
3299 {
3300         if (_session) {
3301                 _session->begin_reversible_command (name);
3302         }
3303 }
3304
3305 void
3306 Editor::begin_reversible_command (GQuark q)
3307 {
3308         if (_session) {
3309                 _session->begin_reversible_command (q);
3310         }
3311 }
3312
3313 void
3314 Editor::commit_reversible_command ()
3315 {
3316         if (_session) {
3317                 _session->commit_reversible_command ();
3318         }
3319 }
3320
3321 void
3322 Editor::history_changed ()
3323 {
3324         string label;
3325
3326         if (undo_action && _session) {
3327                 if (_session->undo_depth() == 0) {
3328                         label = S_("Command|Undo");
3329                 } else {
3330                         label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3331                 }
3332                 undo_action->property_label() = label;
3333         }
3334
3335         if (redo_action && _session) {
3336                 if (_session->redo_depth() == 0) {
3337                         label = _("Redo");
3338                 } else {
3339                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3340                 }
3341                 redo_action->property_label() = label;
3342         }
3343 }
3344
3345 void
3346 Editor::duplicate_range (bool with_dialog)
3347 {
3348         float times = 1.0f;
3349
3350         RegionSelection rs = get_regions_from_selection_and_entered ();
3351
3352         if ( selection->time.length() == 0 && rs.empty()) {
3353                 return;
3354         }
3355
3356         if (with_dialog) {
3357
3358                 ArdourDialog win (_("Duplicate"));
3359                 Label label (_("Number of duplications:"));
3360                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3361                 SpinButton spinner (adjustment, 0.0, 1);
3362                 HBox hbox;
3363
3364                 win.get_vbox()->set_spacing (12);
3365                 win.get_vbox()->pack_start (hbox);
3366                 hbox.set_border_width (6);
3367                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3368
3369                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3370                    place, visually. so do this by hand.
3371                 */
3372
3373                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3374                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3375                 spinner.grab_focus();
3376
3377                 hbox.show ();
3378                 label.show ();
3379                 spinner.show ();
3380
3381                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3382                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3383                 win.set_default_response (RESPONSE_ACCEPT);
3384
3385                 spinner.grab_focus ();
3386
3387                 switch (win.run ()) {
3388                 case RESPONSE_ACCEPT:
3389                         break;
3390                 default:
3391                         return;
3392                 }
3393
3394                 times = adjustment.get_value();
3395         }
3396
3397         if ((current_mouse_mode() == Editing::MouseRange)) {
3398                 if (selection->time.length()) {
3399                         duplicate_selection (times);
3400                 }
3401         } else if (get_smart_mode()) {
3402                 if (selection->time.length()) {
3403                         duplicate_selection (times);
3404                 } else 
3405                         duplicate_some_regions (rs, times);
3406         } else {
3407                 duplicate_some_regions (rs, times);
3408         }
3409 }
3410
3411 void
3412 Editor::set_edit_mode (EditMode m)
3413 {
3414         Config->set_edit_mode (m);
3415 }
3416
3417 void
3418 Editor::cycle_edit_mode ()
3419 {
3420         switch (Config->get_edit_mode()) {
3421         case Slide:
3422                 if (Profile->get_sae()) {
3423                         Config->set_edit_mode (Lock);
3424                 } else {
3425                         Config->set_edit_mode (Ripple);
3426                 }
3427                 break;
3428         case Splice:
3429         case Ripple:
3430                 Config->set_edit_mode (Lock);
3431                 break;
3432         case Lock:
3433                 Config->set_edit_mode (Slide);
3434                 break;
3435         }
3436 }
3437
3438 void
3439 Editor::edit_mode_selection_done ( EditMode m )
3440 {
3441         Config->set_edit_mode ( m );
3442 }
3443
3444 void
3445 Editor::snap_type_selection_done (SnapType snaptype)
3446 {
3447         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3448         if (ract) {
3449                 ract->set_active ();
3450         }
3451 }
3452
3453 void
3454 Editor::snap_mode_selection_done (SnapMode mode)
3455 {
3456         RefPtr<RadioAction> ract = snap_mode_action (mode);
3457
3458         if (ract) {
3459                 ract->set_active (true);
3460         }
3461 }
3462
3463 void
3464 Editor::cycle_edit_point (bool with_marker)
3465 {
3466         if(Profile->get_mixbus())
3467                 with_marker = false;
3468
3469         switch (_edit_point) {
3470         case EditAtMouse:
3471                 set_edit_point_preference (EditAtPlayhead);
3472                 break;
3473         case EditAtPlayhead:
3474                 if (with_marker) {
3475                         set_edit_point_preference (EditAtSelectedMarker);
3476                 } else {
3477                         set_edit_point_preference (EditAtMouse);
3478                 }
3479                 break;
3480         case EditAtSelectedMarker:
3481                 set_edit_point_preference (EditAtMouse);
3482                 break;
3483         }
3484 }
3485
3486 void
3487 Editor::edit_point_selection_done (EditPoint ep)
3488 {
3489         set_edit_point_preference ( ep );
3490 }
3491
3492 void
3493 Editor::build_zoom_focus_menu ()
3494 {
3495         using namespace Menu_Helpers;
3496
3497         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3498         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3499         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3500         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3501         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3502         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3503
3504         set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3505 }
3506
3507 void
3508 Editor::zoom_focus_selection_done ( ZoomFocus f )
3509 {
3510         RefPtr<RadioAction> ract = zoom_focus_action (f);
3511         if (ract) {
3512                 ract->set_active ();
3513         }
3514 }
3515
3516 void
3517 Editor::build_track_count_menu ()
3518 {
3519         using namespace Menu_Helpers;
3520
3521         if (!Profile->get_mixbus()) {
3522                 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3523                 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3524                 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3525                 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3526                 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3527                 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3528                 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3529                 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3530                 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3531                 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3532                 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3533                 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3534                 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3535         } else {
3536                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3537                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3538                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3539                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3540                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3541                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3542                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3543                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3544                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3545                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3546
3547                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3548                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3549                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3550                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3551                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3552                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3553                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3554                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3555                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3556                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3557                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3558         }
3559 }
3560
3561 void
3562 Editor::set_zoom_preset (int64_t ms)
3563 {
3564         if ( ms <= 0 ) {
3565                 temporal_zoom_session();
3566                 return;
3567         }
3568         
3569         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3570         temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3571 }
3572
3573 void
3574 Editor::set_visible_track_count (int32_t n)
3575 {
3576         _visible_track_count = n;
3577
3578         /* if the canvas hasn't really been allocated any size yet, just
3579            record the desired number of visible tracks and return. when canvas
3580            allocation happens, we will get called again and then we can do the
3581            real work.
3582         */
3583         
3584         if (_visible_canvas_height <= 1) {
3585                 return;
3586         }
3587
3588         int h;
3589         string str;
3590         
3591         if (_visible_track_count > 0) {
3592                 h = trackviews_height() / _visible_track_count;
3593                 std::ostringstream s;
3594                 s << _visible_track_count;
3595                 str = s.str();
3596         } else if (_visible_track_count == 0) {
3597                 uint32_t n = 0;
3598                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3599                         if ((*i)->marked_for_display()) {
3600                                 ++n;
3601                         }
3602                 }
3603                 h = trackviews_height() / n;
3604                 str = _("All");
3605         } else {
3606                 /* negative value means that the visible track count has 
3607                    been overridden by explicit track height changes.
3608                 */
3609                 visible_tracks_selector.set_text (X_("*"));
3610                 return;
3611         }
3612
3613         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3614                 (*i)->set_height (h);
3615         }
3616         
3617         if (str != visible_tracks_selector.get_text()) {
3618                 visible_tracks_selector.set_text (str);
3619         }
3620 }
3621
3622 void
3623 Editor::override_visible_track_count ()
3624 {
3625         _visible_track_count = -1;
3626         visible_tracks_selector.set_text ( _("*") );
3627 }
3628
3629 bool
3630 Editor::edit_controls_button_release (GdkEventButton* ev)
3631 {
3632         if (Keyboard::is_context_menu_event (ev)) {
3633                 ARDOUR_UI::instance()->add_route (this);
3634         } else if (ev->button == 1) {
3635                 selection->clear_tracks ();
3636         }
3637
3638         return true;
3639 }
3640
3641 bool
3642 Editor::mouse_select_button_release (GdkEventButton* ev)
3643 {
3644         /* this handles just right-clicks */
3645
3646         if (ev->button != 3) {
3647                 return false;
3648         }
3649
3650         return true;
3651 }
3652
3653 void
3654 Editor::set_zoom_focus (ZoomFocus f)
3655 {
3656         string str = zoom_focus_strings[(int)f];
3657
3658         if (str != zoom_focus_selector.get_text()) {
3659                 zoom_focus_selector.set_text (str);
3660         }
3661
3662         if (zoom_focus != f) {
3663                 zoom_focus = f;
3664                 instant_save ();
3665         }
3666 }
3667
3668 void
3669 Editor::cycle_zoom_focus ()
3670 {
3671         switch (zoom_focus) {
3672         case ZoomFocusLeft:
3673                 set_zoom_focus (ZoomFocusRight);
3674                 break;
3675         case ZoomFocusRight:
3676                 set_zoom_focus (ZoomFocusCenter);
3677                 break;
3678         case ZoomFocusCenter:
3679                 set_zoom_focus (ZoomFocusPlayhead);
3680                 break;
3681         case ZoomFocusPlayhead:
3682                 set_zoom_focus (ZoomFocusMouse);
3683                 break;
3684         case ZoomFocusMouse:
3685                 set_zoom_focus (ZoomFocusEdit);
3686                 break;
3687         case ZoomFocusEdit:
3688                 set_zoom_focus (ZoomFocusLeft);
3689                 break;
3690         }
3691 }
3692
3693 void
3694 Editor::ensure_float (Window& win)
3695 {
3696         win.set_transient_for (*this);
3697 }
3698
3699 void
3700 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3701 {
3702         /* recover or initialize pane positions. do this here rather than earlier because
3703            we don't want the positions to change the child allocations, which they seem to do.
3704          */
3705
3706         int pos;
3707         XMLProperty* prop;
3708         char buf[32];
3709         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3710
3711         enum Pane {
3712                 Horizontal = 0x1,
3713                 Vertical = 0x2
3714         };
3715
3716         static Pane done;
3717
3718         XMLNode* geometry = find_named_node (*node, "geometry");
3719
3720         if (which == static_cast<Paned*> (&edit_pane)) {
3721
3722                 if (done & Horizontal) {
3723                         return;
3724                 }
3725
3726                 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3727                         _notebook_shrunk = string_is_affirmative (prop->value ());
3728                 }
3729
3730                 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3731                         /* initial allocation is 90% to canvas, 10% to notebook */
3732                         pos = (int) floor (alloc.get_width() * 0.90f);
3733                         snprintf (buf, sizeof(buf), "%d", pos);
3734                 } else {
3735                         pos = atoi (prop->value());
3736                 }
3737
3738                 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3739                         edit_pane.set_position (pos);
3740                 }
3741
3742                 done = (Pane) (done | Horizontal);
3743
3744         } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3745
3746                 if (done & Vertical) {
3747                         return;
3748                 }
3749
3750                 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3751                         /* initial allocation is 90% to canvas, 10% to summary */
3752                         pos = (int) floor (alloc.get_height() * 0.90f);
3753                         snprintf (buf, sizeof(buf), "%d", pos);
3754                 } else {
3755
3756                         pos = atoi (prop->value());
3757                 }
3758
3759                 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3760                         editor_summary_pane.set_position (pos);
3761                 }
3762
3763                 done = (Pane) (done | Vertical);
3764         }
3765 }
3766
3767 void
3768 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3769 {
3770         if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) && 
3771             (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) && 
3772             (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3773                 top_hbox.remove (toolbar_frame);
3774         }
3775 }
3776
3777 void
3778 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3779 {
3780         if (toolbar_frame.get_parent() == 0) {
3781                 top_hbox.pack_end (toolbar_frame);
3782         }
3783 }
3784
3785 void
3786 Editor::set_show_measures (bool yn)
3787 {
3788         if (_show_measures != yn) {
3789                 hide_measures ();
3790
3791                 if ((_show_measures = yn) == true) {
3792                         if (tempo_lines) {
3793                                 tempo_lines->show();
3794                         }
3795
3796                         ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3797                         ARDOUR::TempoMap::BBTPointList::const_iterator end;
3798                         
3799                         compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3800                         draw_measures (begin, end);
3801                 } 
3802
3803                 instant_save ();
3804         }
3805 }
3806
3807 void
3808 Editor::toggle_follow_playhead ()
3809 {
3810         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3811         if (act) {
3812                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3813                 set_follow_playhead (tact->get_active());
3814         }
3815 }
3816
3817 /** @param yn true to follow playhead, otherwise false.
3818  *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3819  */
3820 void
3821 Editor::set_follow_playhead (bool yn, bool catch_up)
3822 {
3823         if (_follow_playhead != yn) {
3824                 if ((_follow_playhead = yn) == true && catch_up) {
3825                         /* catch up */
3826                         reset_x_origin_to_follow_playhead ();
3827                 }
3828                 instant_save ();
3829         }
3830 }
3831
3832 void
3833 Editor::toggle_stationary_playhead ()
3834 {
3835         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3836         if (act) {
3837                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3838                 set_stationary_playhead (tact->get_active());
3839         }
3840 }
3841
3842 void
3843 Editor::set_stationary_playhead (bool yn)
3844 {
3845         if (_stationary_playhead != yn) {
3846                 if ((_stationary_playhead = yn) == true) {
3847                         /* catch up */
3848                         // FIXME need a 3.0 equivalent of this 2.X call
3849                         // update_current_screen ();
3850                 }
3851                 instant_save ();
3852         }
3853 }
3854
3855 PlaylistSelector&
3856 Editor::playlist_selector () const
3857 {
3858         return *_playlist_selector;
3859 }
3860
3861 framecnt_t
3862 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3863 {
3864         if (paste_count == 0) {
3865                 /* don't bother calculating an offset that will be zero anyway */
3866                 return 0;
3867         }
3868
3869         /* calculate basic unsnapped multi-paste offset */
3870         framecnt_t offset = paste_count * duration;
3871
3872         bool   success    = true;
3873         double snap_beats = get_grid_type_as_beats(success, pos);
3874         if (success) {
3875                 /* we're snapped to something musical, round duration up */
3876                 BeatsFramesConverter      conv(_session->tempo_map(), pos);
3877                 const Evoral::MusicalTime dur_beats      = conv.from(duration);
3878                 const framecnt_t          snap_dur_beats = ceil(dur_beats / snap_beats) * snap_beats;
3879
3880                 offset = paste_count * conv.to(snap_dur_beats);
3881         }
3882
3883         return offset;
3884 }
3885
3886 Evoral::MusicalTime
3887 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3888 {
3889         success = true;
3890
3891         switch (_snap_type) {
3892         case SnapToBeat:
3893                 return 1.0;
3894                 break;
3895
3896         case SnapToBeatDiv128:
3897                 return 1.0/128.0;
3898                 break;
3899         case SnapToBeatDiv64:
3900                 return 1.0/64.0;
3901                 break;
3902         case SnapToBeatDiv32:
3903                 return 1.0/32.0;
3904                 break;
3905         case SnapToBeatDiv28:
3906                 return 1.0/28.0;
3907                 break;
3908         case SnapToBeatDiv24:
3909                 return 1.0/24.0;
3910                 break;
3911         case SnapToBeatDiv20:
3912                 return 1.0/20.0;
3913                 break;
3914         case SnapToBeatDiv16:
3915                 return 1.0/16.0;
3916                 break;
3917         case SnapToBeatDiv14:
3918                 return 1.0/14.0;
3919                 break;
3920         case SnapToBeatDiv12:
3921                 return 1.0/12.0;
3922                 break;
3923         case SnapToBeatDiv10:
3924                 return 1.0/10.0;
3925                 break;
3926         case SnapToBeatDiv8:
3927                 return 1.0/8.0;
3928                 break;
3929         case SnapToBeatDiv7:
3930                 return 1.0/7.0;
3931                 break;
3932         case SnapToBeatDiv6:
3933                 return 1.0/6.0;
3934                 break;
3935         case SnapToBeatDiv5:
3936                 return 1.0/5.0;
3937                 break;
3938         case SnapToBeatDiv4:
3939                 return 1.0/4.0;
3940                 break;
3941         case SnapToBeatDiv3:
3942                 return 1.0/3.0;
3943                 break;
3944         case SnapToBeatDiv2:
3945                 return 1.0/2.0;
3946                 break;
3947
3948         case SnapToBar:
3949                 if (_session) {
3950                         return _session->tempo_map().meter_at (position).divisions_per_bar();
3951                 }
3952                 break;
3953
3954         case SnapToCDFrame:
3955         case SnapToTimecodeFrame:
3956         case SnapToTimecodeSeconds:
3957         case SnapToTimecodeMinutes:
3958         case SnapToSeconds:
3959         case SnapToMinutes:
3960         case SnapToRegionStart:
3961         case SnapToRegionEnd:
3962         case SnapToRegionSync:
3963         case SnapToRegionBoundary:
3964         default:
3965                 success = false;
3966                 break;
3967         }
3968
3969         return 0.0;
3970 }
3971
3972 framecnt_t
3973 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3974 {
3975         framecnt_t ret;
3976
3977         ret = nudge_clock->current_duration (pos);
3978         next = ret + 1; /* XXXX fix me */
3979
3980         return ret;
3981 }
3982
3983 int
3984 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3985 {
3986         ArdourDialog dialog (_("Playlist Deletion"));
3987         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
3988                                         "If it is kept, its audio files will not be cleaned.\n"
3989                                         "If it is deleted, audio files used by it alone will be cleaned."),
3990                                       pl->name()));
3991
3992         dialog.set_position (WIN_POS_CENTER);
3993         dialog.get_vbox()->pack_start (label);
3994
3995         label.show ();
3996
3997         dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3998         dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3999         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4000
4001         switch (dialog.run ()) {
4002         case RESPONSE_ACCEPT:
4003                 /* delete the playlist */
4004                 return 0;
4005                 break;
4006
4007         case RESPONSE_REJECT:
4008                 /* keep the playlist */
4009                 return 1;
4010                 break;
4011
4012         default:
4013                 break;
4014         }
4015
4016         return -1;
4017 }
4018
4019 bool
4020 Editor::audio_region_selection_covers (framepos_t where)
4021 {
4022         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4023                 if ((*a)->region()->covers (where)) {
4024                         return true;
4025                 }
4026         }
4027
4028         return false;
4029 }
4030
4031 void
4032 Editor::prepare_for_cleanup ()
4033 {
4034         cut_buffer->clear_regions ();
4035         cut_buffer->clear_playlists ();
4036
4037         selection->clear_regions ();
4038         selection->clear_playlists ();
4039
4040         _regions->suspend_redisplay ();
4041 }
4042
4043 void
4044 Editor::finish_cleanup ()
4045 {
4046         _regions->resume_redisplay ();
4047 }
4048
4049 Location*
4050 Editor::transport_loop_location()
4051 {
4052         if (_session) {
4053                 return _session->locations()->auto_loop_location();
4054         } else {
4055                 return 0;
4056         }
4057 }
4058
4059 Location*
4060 Editor::transport_punch_location()
4061 {
4062         if (_session) {
4063                 return _session->locations()->auto_punch_location();
4064         } else {
4065                 return 0;
4066         }
4067 }
4068
4069 bool
4070 Editor::control_layout_scroll (GdkEventScroll* ev)
4071 {
4072         /* Just forward to the normal canvas scroll method. The coordinate
4073            systems are different but since the canvas is always larger than the
4074            track headers, and aligned with the trackview area, this will work.
4075
4076            In the not too distant future this layout is going away anyway and
4077            headers will be on the canvas.
4078         */
4079         return canvas_scroll_event (ev, false);
4080 }
4081
4082 void
4083 Editor::session_state_saved (string)
4084 {
4085         update_title ();
4086         _snapshots->redisplay ();
4087 }
4088
4089 void
4090 Editor::update_tearoff_visibility()
4091 {
4092         bool visible = Config->get_keep_tearoffs();
4093         _mouse_mode_tearoff->set_visible (visible);
4094         _tools_tearoff->set_visible (visible);
4095         if (_zoom_tearoff) {
4096                 _zoom_tearoff->set_visible (visible);
4097         }
4098 }
4099
4100 void
4101 Editor::reattach_all_tearoffs ()
4102 {
4103         if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4104         if (_tools_tearoff) _tools_tearoff->put_it_back ();
4105         if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4106 }
4107
4108 void
4109 Editor::maximise_editing_space ()
4110 {
4111         if (_maximised) {
4112                 return;
4113         }
4114
4115         fullscreen ();
4116
4117         _maximised = true;
4118 }
4119
4120 void
4121 Editor::restore_editing_space ()
4122 {
4123         if (!_maximised) {
4124                 return;
4125         }
4126
4127         unfullscreen();
4128
4129         _maximised = false;
4130 }
4131
4132 /**
4133  *  Make new playlists for a given track and also any others that belong
4134  *  to the same active route group with the `select' property.
4135  *  @param v Track.
4136  */
4137
4138 void
4139 Editor::new_playlists (TimeAxisView* v)
4140 {
4141         begin_reversible_command (_("new playlists"));
4142         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4143         _session->playlists->get (playlists);
4144         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4145         commit_reversible_command ();
4146 }
4147
4148 /**
4149  *  Use a copy of the current playlist for a given track and also any others that belong
4150  *  to the same active route group with the `select' property.
4151  *  @param v Track.
4152  */
4153
4154 void
4155 Editor::copy_playlists (TimeAxisView* v)
4156 {
4157         begin_reversible_command (_("copy playlists"));
4158         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4159         _session->playlists->get (playlists);
4160         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4161         commit_reversible_command ();
4162 }
4163
4164 /** Clear the current playlist for a given track and also any others that belong
4165  *  to the same active route group with the `select' property.
4166  *  @param v Track.
4167  */
4168
4169 void
4170 Editor::clear_playlists (TimeAxisView* v)
4171 {
4172         begin_reversible_command (_("clear playlists"));
4173         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4174         _session->playlists->get (playlists);
4175         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4176         commit_reversible_command ();
4177 }
4178
4179 void
4180 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4181 {
4182         atv.use_new_playlist (sz > 1 ? false : true, playlists);
4183 }
4184
4185 void
4186 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4187 {
4188         atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4189 }
4190
4191 void
4192 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4193 {
4194         atv.clear_playlist ();
4195 }
4196
4197 bool
4198 Editor::on_key_press_event (GdkEventKey* ev)
4199 {
4200         return key_press_focus_accelerator_handler (*this, ev);
4201 }
4202
4203 bool
4204 Editor::on_key_release_event (GdkEventKey* ev)
4205 {
4206         return Gtk::Window::on_key_release_event (ev);
4207         // return key_press_focus_accelerator_handler (*this, ev);
4208 }
4209
4210 /** Queue up a change to the viewport x origin.
4211  *  @param frame New x origin.
4212  */
4213 void
4214 Editor::reset_x_origin (framepos_t frame)
4215 {
4216         pending_visual_change.add (VisualChange::TimeOrigin);
4217         pending_visual_change.time_origin = frame;
4218         ensure_visual_change_idle_handler ();
4219 }
4220
4221 void
4222 Editor::reset_y_origin (double y)
4223 {
4224         pending_visual_change.add (VisualChange::YOrigin);
4225         pending_visual_change.y_origin = y;
4226         ensure_visual_change_idle_handler ();
4227 }
4228
4229 void
4230 Editor::reset_zoom (framecnt_t spp)
4231 {
4232         if (spp == samples_per_pixel) {
4233                 return;
4234         }
4235
4236         pending_visual_change.add (VisualChange::ZoomLevel);
4237         pending_visual_change.samples_per_pixel = spp;
4238         ensure_visual_change_idle_handler ();
4239 }
4240
4241 void
4242 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4243 {
4244         reset_x_origin (frame);
4245         reset_zoom (fpu);
4246
4247         if (!no_save_visual) {
4248                 undo_visual_stack.push_back (current_visual_state(false));
4249         }
4250 }
4251
4252 Editor::VisualState::VisualState (bool with_tracks)
4253         : gui_state (with_tracks ? new GUIObjectState : 0)
4254 {
4255 }
4256
4257 Editor::VisualState::~VisualState ()
4258 {
4259         delete gui_state;
4260 }
4261
4262 Editor::VisualState*
4263 Editor::current_visual_state (bool with_tracks)
4264 {
4265         VisualState* vs = new VisualState (with_tracks);
4266         vs->y_position = vertical_adjustment.get_value();
4267         vs->samples_per_pixel = samples_per_pixel;
4268         vs->leftmost_frame = leftmost_frame;
4269         vs->zoom_focus = zoom_focus;
4270
4271         if (with_tracks) {      
4272                 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4273         }
4274
4275         return vs;
4276 }
4277
4278 void
4279 Editor::undo_visual_state ()
4280 {
4281         if (undo_visual_stack.empty()) {
4282                 return;
4283         }
4284
4285         VisualState* vs = undo_visual_stack.back();
4286         undo_visual_stack.pop_back();
4287
4288
4289         redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4290
4291         use_visual_state (*vs);
4292 }
4293
4294 void
4295 Editor::redo_visual_state ()
4296 {
4297         if (redo_visual_stack.empty()) {
4298                 return;
4299         }
4300
4301         VisualState* vs = redo_visual_stack.back();
4302         redo_visual_stack.pop_back();
4303
4304         undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4305
4306         use_visual_state (*vs);
4307 }
4308
4309 void
4310 Editor::swap_visual_state ()
4311 {
4312         if (undo_visual_stack.empty()) {
4313                 redo_visual_state ();
4314         } else {
4315                 undo_visual_state ();
4316         }
4317 }
4318
4319 void
4320 Editor::use_visual_state (VisualState& vs)
4321 {
4322         PBD::Unwinder<bool> nsv (no_save_visual, true);
4323         DisplaySuspender ds;
4324
4325         vertical_adjustment.set_value (vs.y_position);
4326
4327         set_zoom_focus (vs.zoom_focus);
4328         reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4329         
4330         if (vs.gui_state) {
4331                 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4332                 
4333                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {    
4334                         (*i)->reset_visual_state ();
4335                 }
4336         }
4337
4338         _routes->update_visibility ();
4339 }
4340
4341 /** This is the core function that controls the zoom level of the canvas. It is called
4342  *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
4343  *  @param spp new number of samples per pixel
4344  */
4345 void
4346 Editor::set_samples_per_pixel (framecnt_t spp)
4347 {
4348         if (spp < 1) {
4349                 return;
4350         }
4351
4352         const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4353         const framecnt_t lots_of_pixels = 4000;
4354
4355         /* if the zoom level is greater than what you'd get trying to display 3
4356          * days of audio on a really big screen, then it's too big.
4357          */
4358
4359         if (spp * lots_of_pixels > three_days) {
4360                 return;
4361         }
4362
4363         samples_per_pixel = spp;
4364
4365         if (tempo_lines) {
4366                 tempo_lines->tempo_map_changed();
4367         }
4368
4369         bool const showing_time_selection = selection->time.length() > 0;
4370
4371         if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4372                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4373                         (*i)->reshow_selection (selection->time);
4374                 }
4375         }
4376
4377         ZoomChanged (); /* EMIT_SIGNAL */
4378
4379         ArdourCanvas::GtkCanvasViewport* c;
4380
4381         c = get_track_canvas();
4382         if (c) {
4383                 c->canvas()->zoomed ();
4384         }
4385
4386         if (playhead_cursor) {
4387                 playhead_cursor->set_position (playhead_cursor->current_frame ());
4388         }
4389
4390         refresh_location_display();
4391         _summary->set_overlays_dirty ();
4392
4393         update_marker_labels ();
4394
4395         instant_save ();
4396 }
4397
4398 void
4399 Editor::queue_visual_videotimeline_update ()
4400 {
4401         /* TODO:
4402          * pending_visual_change.add (VisualChange::VideoTimeline);
4403          * or maybe even more specific: which videotimeline-image
4404          * currently it calls update_video_timeline() to update
4405          * _all outdated_ images on the video-timeline.
4406          * see 'exposeimg()' in video_image_frame.cc
4407          */
4408         ensure_visual_change_idle_handler ();
4409 }
4410
4411 void
4412 Editor::ensure_visual_change_idle_handler ()
4413 {
4414         if (pending_visual_change.idle_handler_id < 0) {
4415                 // see comment in add_to_idle_resize above.
4416                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4417                 pending_visual_change.being_handled = false;
4418         }
4419 }
4420
4421 int
4422 Editor::_idle_visual_changer (void* arg)
4423 {
4424         return static_cast<Editor*>(arg)->idle_visual_changer ();
4425 }
4426
4427 int
4428 Editor::idle_visual_changer ()
4429 {
4430         /* set_horizontal_position() below (and maybe other calls) call
4431            gtk_main_iteration(), so it's possible that a signal will be handled
4432            half-way through this method.  If this signal wants an
4433            idle_visual_changer we must schedule another one after this one, so
4434            mark the idle_handler_id as -1 here to allow that.  Also make a note
4435            that we are doing the visual change, so that changes in response to
4436            super-rapid-screen-update can be dropped if we are still processing
4437            the last one.
4438         */
4439
4440         pending_visual_change.idle_handler_id = -1;
4441         pending_visual_change.being_handled = true;
4442         
4443         VisualChange vc = pending_visual_change;
4444
4445         pending_visual_change.pending = (VisualChange::Type) 0;
4446
4447         visual_changer (vc);
4448
4449         pending_visual_change.being_handled = false;
4450
4451         return 0; /* this is always a one-shot call */
4452 }
4453
4454 void
4455 Editor::visual_changer (const VisualChange& vc)
4456 {
4457         double const last_time_origin = horizontal_position ();
4458
4459         if (vc.pending & VisualChange::ZoomLevel) {
4460                 set_samples_per_pixel (vc.samples_per_pixel);
4461
4462                 compute_fixed_ruler_scale ();
4463
4464                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4465                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4466                 
4467                 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4468                                             current_bbt_points_begin, current_bbt_points_end);
4469                 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4470                                          current_bbt_points_begin, current_bbt_points_end);
4471                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4472
4473                 update_video_timeline();
4474         }
4475
4476         if (vc.pending & VisualChange::TimeOrigin) {
4477                 set_horizontal_position (vc.time_origin / samples_per_pixel);
4478         }
4479
4480         if (vc.pending & VisualChange::YOrigin) {
4481                 vertical_adjustment.set_value (vc.y_origin);
4482         }
4483
4484         if (last_time_origin == horizontal_position ()) {
4485                 /* changed signal not emitted */
4486                 update_fixed_rulers ();
4487                 redisplay_tempo (true);
4488         }
4489
4490         if (!(vc.pending & VisualChange::ZoomLevel)) {
4491                 update_video_timeline();
4492         }
4493
4494         _summary->set_overlays_dirty ();
4495 }
4496
4497 struct EditorOrderTimeAxisSorter {
4498     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4499             return a->order () < b->order ();
4500     }
4501 };
4502
4503 void
4504 Editor::sort_track_selection (TrackViewList& sel)
4505 {
4506         EditorOrderTimeAxisSorter cmp;
4507         sel.sort (cmp);
4508 }
4509
4510 framepos_t
4511 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4512 {
4513         bool ignored;
4514         framepos_t where = 0;
4515         EditPoint ep = _edit_point;
4516
4517         if(Profile->get_mixbus())
4518                 if (ep == EditAtSelectedMarker)
4519                         ep=EditAtPlayhead;
4520                 
4521         if (from_context_menu && (ep == EditAtMouse)) {
4522                 return  canvas_event_sample (&context_click_event, 0, 0);
4523         }
4524
4525         if (entered_marker) {
4526                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4527                 return entered_marker->position();
4528         }
4529
4530         if (ignore_playhead && ep == EditAtPlayhead) {
4531                 ep = EditAtSelectedMarker;
4532         }
4533
4534         switch (ep) {
4535         case EditAtPlayhead:
4536                 where = _session->audible_frame();
4537                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4538                 break;
4539
4540         case EditAtSelectedMarker:
4541                 if (!selection->markers.empty()) {
4542                         bool is_start;
4543                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4544                         if (loc) {
4545                                 if (is_start) {
4546                                         where =  loc->start();
4547                                 } else {
4548                                         where = loc->end();
4549                                 }
4550                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4551                                 break;
4552                         }
4553                 }
4554                 /* fallthru */
4555
4556         default:
4557         case EditAtMouse:
4558                 if (!mouse_frame (where, ignored)) {
4559                         /* XXX not right but what can we do ? */
4560                         return 0;
4561                 }
4562                 snap_to (where);
4563                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4564                 break;
4565         }
4566
4567         return where;
4568 }
4569
4570 void
4571 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4572 {
4573         if (!_session) return;
4574
4575         begin_reversible_command (cmd);
4576
4577         Location* tll;
4578
4579         if ((tll = transport_loop_location()) == 0) {
4580                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4581                 XMLNode &before = _session->locations()->get_state();
4582                 _session->locations()->add (loc, true);
4583                 _session->set_auto_loop_location (loc);
4584                 XMLNode &after = _session->locations()->get_state();
4585                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4586         } else {
4587                 XMLNode &before = tll->get_state();
4588                 tll->set_hidden (false, this);
4589                 tll->set (start, end);
4590                 XMLNode &after = tll->get_state();
4591                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4592         }
4593
4594         commit_reversible_command ();
4595 }
4596
4597 void
4598 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4599 {
4600         if (!_session) return;
4601
4602         begin_reversible_command (cmd);
4603
4604         Location* tpl;
4605
4606         if ((tpl = transport_punch_location()) == 0) {
4607                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
4608                 XMLNode &before = _session->locations()->get_state();
4609                 _session->locations()->add (loc, true);
4610                 _session->set_auto_punch_location (loc);
4611                 XMLNode &after = _session->locations()->get_state();
4612                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4613         }
4614         else {
4615                 XMLNode &before = tpl->get_state();
4616                 tpl->set_hidden (false, this);
4617                 tpl->set (start, end);
4618                 XMLNode &after = tpl->get_state();
4619                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4620         }
4621
4622         commit_reversible_command ();
4623 }
4624
4625 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4626  *  @param rs List to which found regions are added.
4627  *  @param where Time to look at.
4628  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4629  */
4630 void
4631 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4632 {
4633         const TrackViewList* tracks;
4634
4635         if (ts.empty()) {
4636                 tracks = &track_views;
4637         } else {
4638                 tracks = &ts;
4639         }
4640
4641         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4642
4643                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4644
4645                 if (rtv) {
4646                         boost::shared_ptr<Track> tr;
4647                         boost::shared_ptr<Playlist> pl;
4648
4649                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4650
4651                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4652                                                 (framepos_t) floor ( (double) where * tr->speed()));
4653
4654                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4655                                         RegionView* rv = rtv->view()->find_view (*i);
4656                                         if (rv) {
4657                                                 rs.add (rv);
4658                                         }
4659                                 }
4660                         }
4661                 }
4662         }
4663 }
4664
4665 void
4666 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4667 {
4668         const TrackViewList* tracks;
4669
4670         if (ts.empty()) {
4671                 tracks = &track_views;
4672         } else {
4673                 tracks = &ts;
4674         }
4675
4676         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4677                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4678                 if (rtv) {
4679                         boost::shared_ptr<Track> tr;
4680                         boost::shared_ptr<Playlist> pl;
4681
4682                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4683
4684                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4685                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4686
4687                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4688
4689                                         RegionView* rv = rtv->view()->find_view (*i);
4690
4691                                         if (rv) {
4692                                                 rs.add (rv);
4693                                         }
4694                                 }
4695                         }
4696                 }
4697         }
4698 }
4699
4700 /** Get regions using the following method:
4701  *
4702  *  Make a region list using:
4703  *   (a) any selected regions
4704  *   (b) the intersection of any selected tracks and the edit point(*)
4705  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4706  *
4707  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4708  *
4709  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4710  */
4711
4712 RegionSelection
4713 Editor::get_regions_from_selection_and_edit_point ()
4714 {
4715         RegionSelection regions;
4716
4717         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4718                 regions.add (entered_regionview);
4719         } else {
4720                 regions = selection->regions;
4721         }
4722
4723         if ( regions.empty() ) {
4724                 TrackViewList tracks = selection->tracks;
4725
4726                 if (!tracks.empty()) {
4727                         /* no region selected or entered, but some selected tracks:
4728                          * act on all regions on the selected tracks at the edit point
4729                          */ 
4730                         framepos_t const where = get_preferred_edit_position ();
4731                         get_regions_at(regions, where, tracks);
4732                 }
4733         }
4734
4735         return regions;
4736 }
4737
4738 /** Get regions using the following method:
4739  *
4740  *  Make a region list using:
4741  *   (a) any selected regions
4742  *   (b) the intersection of any selected tracks and the edit point(*)
4743  *   (c) if neither exists, then whatever region is under the mouse
4744  *
4745  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4746  *
4747  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4748  */
4749 RegionSelection
4750 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4751 {
4752         RegionSelection regions;
4753
4754         if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4755                 regions.add (entered_regionview);
4756         } else {
4757                 regions = selection->regions;
4758         }
4759
4760         if ( regions.empty() ) {
4761                 TrackViewList tracks = selection->tracks;
4762
4763                 if (!tracks.empty()) {
4764                         /* no region selected or entered, but some selected tracks:
4765                          * act on all regions on the selected tracks at the edit point
4766                          */ 
4767                         get_regions_at(regions, pos, tracks);
4768                 }
4769         }
4770
4771         return regions;
4772 }
4773
4774 /** Start with regions that are selected, or the entered regionview if none are selected.
4775  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4776  *  of the regions that we started with.
4777  */
4778
4779 RegionSelection
4780 Editor::get_regions_from_selection_and_entered ()
4781 {
4782         RegionSelection regions = selection->regions;
4783
4784         if (regions.empty() && entered_regionview) {
4785                 regions.add (entered_regionview);
4786         }
4787
4788         return regions;
4789 }
4790
4791 void
4792 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4793 {
4794         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4795
4796                 RouteTimeAxisView* tatv;
4797
4798                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4799
4800                         boost::shared_ptr<Playlist> pl;
4801                         vector<boost::shared_ptr<Region> > results;
4802                         RegionView* marv;
4803                         boost::shared_ptr<Track> tr;
4804
4805                         if ((tr = tatv->track()) == 0) {
4806                                 /* bus */
4807                                 continue;
4808                         }
4809
4810                         if ((pl = (tr->playlist())) != 0) {
4811                                 if (src_comparison) {
4812                                         pl->get_source_equivalent_regions (region, results);
4813                                 } else {
4814                                         pl->get_region_list_equivalent_regions (region, results);
4815                                 }
4816                         }
4817
4818                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4819                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4820                                         regions.push_back (marv);
4821                                 }
4822                         }
4823
4824                 }
4825         }
4826 }
4827
4828 void
4829 Editor::show_rhythm_ferret ()
4830 {
4831         if (rhythm_ferret == 0) {
4832                 rhythm_ferret = new RhythmFerret(*this);
4833         }
4834
4835         rhythm_ferret->set_session (_session);
4836         rhythm_ferret->show ();
4837         rhythm_ferret->present ();
4838 }
4839
4840 void
4841 Editor::first_idle ()
4842 {
4843         MessageDialog* dialog = 0;
4844         
4845         if (track_views.size() > 1) {
4846                 dialog = new MessageDialog (
4847                         *this,
4848                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4849                         true
4850                         );
4851                 dialog->present ();
4852                 ARDOUR_UI::instance()->flush_pending ();
4853         }
4854
4855         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4856                 (*t)->first_idle();
4857         }
4858
4859         // first idle adds route children (automation tracks), so we need to redisplay here
4860         _routes->redisplay ();
4861
4862         delete dialog;
4863         _have_idled = true;
4864 }
4865
4866 gboolean
4867 Editor::_idle_resize (gpointer arg)
4868 {
4869         return ((Editor*)arg)->idle_resize ();
4870 }
4871
4872 void
4873 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4874 {
4875         if (resize_idle_id < 0) {
4876                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4877                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4878                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4879                  */
4880                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4881                 _pending_resize_amount = 0;
4882         }
4883
4884         /* make a note of the smallest resulting height, so that we can clamp the
4885            lower limit at TimeAxisView::hSmall */
4886
4887         int32_t min_resulting = INT32_MAX;
4888
4889         _pending_resize_amount += h;
4890         _pending_resize_view = view;
4891
4892         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4893
4894         if (selection->tracks.contains (_pending_resize_view)) {
4895                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4896                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4897                 }
4898         }
4899
4900         if (min_resulting < 0) {
4901                 min_resulting = 0;
4902         }
4903
4904         /* clamp */
4905         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4906                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4907         }
4908 }
4909
4910 /** Handle pending resizing of tracks */
4911 bool
4912 Editor::idle_resize ()
4913 {
4914         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4915
4916         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4917             selection->tracks.contains (_pending_resize_view)) {
4918
4919                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4920                         if (*i != _pending_resize_view) {
4921                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4922                         }
4923                 }
4924         }
4925
4926         _pending_resize_amount = 0;
4927         _group_tabs->set_dirty ();
4928         resize_idle_id = -1;
4929
4930         return false;
4931 }
4932
4933 void
4934 Editor::located ()
4935 {
4936         ENSURE_GUI_THREAD (*this, &Editor::located);
4937
4938         if (_session) {
4939                 playhead_cursor->set_position (_session->audible_frame ());
4940                 if (_follow_playhead && !_pending_initial_locate) {
4941                         reset_x_origin_to_follow_playhead ();
4942                 }
4943         }
4944
4945         _pending_locate_request = false;
4946         _pending_initial_locate = false;
4947 }
4948
4949 void
4950 Editor::region_view_added (RegionView *)
4951 {
4952         _summary->set_background_dirty ();
4953 }
4954
4955 void
4956 Editor::region_view_removed ()
4957 {
4958         _summary->set_background_dirty ();
4959 }
4960
4961 RouteTimeAxisView*
4962 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4963 {
4964         TrackViewList::const_iterator j = track_views.begin ();
4965         while (j != track_views.end()) {
4966                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4967                 if (rtv && rtv->route() == r) {
4968                         return rtv;
4969                 }
4970                 ++j;
4971         }
4972
4973         return 0;
4974 }
4975
4976
4977 TrackViewList
4978 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4979 {
4980         TrackViewList t;
4981
4982         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4983                 TimeAxisView* tv = axis_view_from_route (*i);
4984                 if (tv) {
4985                         t.push_back (tv);
4986                 }
4987         }
4988
4989         return t;
4990 }
4991
4992 void
4993 Editor::suspend_route_redisplay ()
4994 {
4995         if (_routes) {
4996                 _routes->suspend_redisplay();
4997         }
4998 }
4999
5000 void
5001 Editor::resume_route_redisplay ()
5002 {
5003         if (_routes) {
5004                 _routes->resume_redisplay();
5005         }
5006 }
5007
5008 void
5009 Editor::add_routes (RouteList& routes)
5010 {
5011         ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5012
5013         RouteTimeAxisView *rtv;
5014         list<RouteTimeAxisView*> new_views;
5015
5016         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5017                 boost::shared_ptr<Route> route = (*x);
5018
5019                 if (route->is_auditioner() || route->is_monitor()) {
5020                         continue;
5021                 }
5022
5023                 DataType dt = route->input()->default_type();
5024
5025                 if (dt == ARDOUR::DataType::AUDIO) {
5026                         rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5027                         rtv->set_route (route);
5028                 } else if (dt == ARDOUR::DataType::MIDI) {
5029                         rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5030                         rtv->set_route (route);
5031                 } else {
5032                         throw unknown_type();
5033                 }
5034
5035                 new_views.push_back (rtv);
5036                 track_views.push_back (rtv);
5037
5038                 rtv->effective_gain_display ();
5039
5040                 if (internal_editing()) {
5041                         rtv->enter_internal_edit_mode ();
5042                 } else {
5043                         rtv->leave_internal_edit_mode ();
5044                 }
5045
5046                 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5047                 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5048         }
5049
5050         if (new_views.size() > 0) {
5051                 _routes->routes_added (new_views);
5052                 _summary->routes_added (new_views);
5053         }
5054
5055         if (show_editor_mixer_when_tracks_arrive) {
5056                 show_editor_mixer (true);
5057         }
5058
5059         editor_list_button.set_sensitive (true);
5060 }
5061
5062 void
5063 Editor::timeaxisview_deleted (TimeAxisView *tv)
5064 {
5065         if (tv == entered_track) {
5066                 entered_track = 0;
5067         }
5068
5069         if (_session && _session->deletion_in_progress()) {
5070                 /* the situation is under control */
5071                 return;
5072         }
5073
5074         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5075
5076         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5077
5078         _routes->route_removed (tv);
5079
5080         TimeAxisView::Children c = tv->get_child_list ();
5081         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5082                 if (entered_track == i->get()) {
5083                         entered_track = 0;
5084                 }
5085         }
5086
5087         /* remove it from the list of track views */
5088
5089         TrackViewList::iterator i;
5090
5091         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5092                 i = track_views.erase (i);
5093         }
5094
5095         /* update whatever the current mixer strip is displaying, if revelant */
5096
5097         boost::shared_ptr<Route> route;
5098
5099         if (rtav) {
5100                 route = rtav->route ();
5101         }
5102
5103         if (current_mixer_strip && current_mixer_strip->route() == route) {
5104
5105                 TimeAxisView* next_tv;
5106
5107                 if (track_views.empty()) {
5108                         next_tv = 0;
5109                 } else if (i == track_views.end()) {
5110                         next_tv = track_views.front();
5111                 } else {
5112                         next_tv = (*i);
5113                 }
5114
5115
5116                 if (next_tv) {
5117                         set_selected_mixer_strip (*next_tv);
5118                 } else {
5119                         /* make the editor mixer strip go away setting the
5120                          * button to inactive (which also unticks the menu option)
5121                          */
5122
5123                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5124                 }
5125         }
5126 }
5127
5128 void
5129 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5130 {
5131         if (apply_to_selection) {
5132                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5133
5134                         TrackSelection::iterator j = i;
5135                         ++j;
5136
5137                         hide_track_in_display (*i, false);
5138
5139                         i = j;
5140                 }
5141         } else {
5142                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5143
5144                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5145                         // this will hide the mixer strip
5146                         set_selected_mixer_strip (*tv);
5147                 }
5148
5149                 _routes->hide_track_in_display (*tv);
5150         }
5151 }
5152
5153 bool
5154 Editor::sync_track_view_list_and_routes ()
5155 {
5156         track_views = TrackViewList (_routes->views ());
5157
5158         _summary->set_dirty ();
5159         _group_tabs->set_dirty ();
5160
5161         return false; // do not call again (until needed)
5162 }
5163
5164 void
5165 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5166 {
5167         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5168                 theslot (**i);
5169         }
5170 }
5171
5172 /** Find a RouteTimeAxisView by the ID of its route */
5173 RouteTimeAxisView*
5174 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5175 {
5176         RouteTimeAxisView* v;
5177
5178         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5179                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5180                         if(v->route()->id() == id) {
5181                                 return v;
5182                         }
5183                 }
5184         }
5185
5186         return 0;
5187 }
5188
5189 void
5190 Editor::fit_route_group (RouteGroup *g)
5191 {
5192         TrackViewList ts = axis_views_from_routes (g->route_list ());
5193         fit_tracks (ts);
5194 }
5195
5196 void
5197 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5198 {
5199         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5200
5201         if (r == 0) {
5202                 _session->cancel_audition ();
5203                 return;
5204         }
5205
5206         if (_session->is_auditioning()) {
5207                 _session->cancel_audition ();
5208                 if (r == last_audition_region) {
5209                         return;
5210                 }
5211         }
5212
5213         _session->audition_region (r);
5214         last_audition_region = r;
5215 }
5216
5217
5218 void
5219 Editor::hide_a_region (boost::shared_ptr<Region> r)
5220 {
5221         r->set_hidden (true);
5222 }
5223
5224 void
5225 Editor::show_a_region (boost::shared_ptr<Region> r)
5226 {
5227         r->set_hidden (false);
5228 }
5229
5230 void
5231 Editor::audition_region_from_region_list ()
5232 {
5233         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5234 }
5235
5236 void
5237 Editor::hide_region_from_region_list ()
5238 {
5239         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5240 }
5241
5242 void
5243 Editor::show_region_in_region_list ()
5244 {
5245         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5246 }
5247
5248 void
5249 Editor::step_edit_status_change (bool yn)
5250 {
5251         if (yn) {
5252                 start_step_editing ();
5253         } else {
5254                 stop_step_editing ();
5255         }
5256 }
5257
5258 void
5259 Editor::start_step_editing ()
5260 {
5261         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5262 }
5263
5264 void
5265 Editor::stop_step_editing ()
5266 {
5267         step_edit_connection.disconnect ();
5268 }
5269
5270 bool
5271 Editor::check_step_edit ()
5272 {
5273         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5274                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5275                 if (mtv) {
5276                         mtv->check_step_edit ();
5277                 }
5278         }
5279
5280         return true; // do it again, till we stop
5281 }
5282
5283 bool
5284 Editor::scroll_press (Direction dir)
5285 {
5286         ++_scroll_callbacks;
5287
5288         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5289                 /* delay the first auto-repeat */
5290                 return true;
5291         }
5292
5293         switch (dir) {
5294         case LEFT:
5295                 scroll_backward (1);
5296                 break;
5297
5298         case RIGHT:
5299                 scroll_forward (1);
5300                 break;
5301
5302         case UP:
5303                 scroll_up_one_track ();
5304                 break;
5305
5306         case DOWN:
5307                 scroll_down_one_track ();
5308                 break;
5309         }
5310
5311         /* do hacky auto-repeat */
5312         if (!_scroll_connection.connected ()) {
5313
5314                 _scroll_connection = Glib::signal_timeout().connect (
5315                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5316                         );
5317
5318                 _scroll_callbacks = 0;
5319         }
5320
5321         return true;
5322 }
5323
5324 void
5325 Editor::scroll_release ()
5326 {
5327         _scroll_connection.disconnect ();
5328 }
5329
5330 /** Queue a change for the Editor viewport x origin to follow the playhead */
5331 void
5332 Editor::reset_x_origin_to_follow_playhead ()
5333 {
5334         framepos_t const frame = playhead_cursor->current_frame ();
5335
5336         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5337
5338                 if (_session->transport_speed() < 0) {
5339
5340                         if (frame > (current_page_samples() / 2)) {
5341                                 center_screen (frame-(current_page_samples()/2));
5342                         } else {
5343                                 center_screen (current_page_samples()/2);
5344                         }
5345
5346                 } else {
5347
5348                         framepos_t l = 0;
5349                         
5350                         if (frame < leftmost_frame) {
5351                                 /* moving left */
5352                                 if (_session->transport_rolling()) {
5353                                         /* rolling; end up with the playhead at the right of the page */
5354                                         l = frame - current_page_samples ();
5355                                 } else {
5356                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5357                                         l = frame - current_page_samples() / 4;
5358                                 }
5359                         } else {
5360                                 /* moving right */
5361                                 if (_session->transport_rolling()) {
5362                                         /* rolling: end up with the playhead on the left of the page */
5363                                         l = frame;
5364                                 } else {
5365                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5366                                         l = frame - 3 * current_page_samples() / 4;
5367                                 }
5368                         }
5369
5370                         if (l < 0) {
5371                                 l = 0;
5372                         }
5373                         
5374                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5375                 }
5376         }
5377 }
5378
5379 void
5380 Editor::super_rapid_screen_update ()
5381 {
5382         if (!_session || !_session->engine().running()) {
5383                 return;
5384         }
5385
5386         /* METERING / MIXER STRIPS */
5387
5388         /* update track meters, if required */
5389         if (is_mapped() && meters_running) {
5390                 RouteTimeAxisView* rtv;
5391                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5392                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5393                                 rtv->fast_update ();
5394                         }
5395                 }
5396         }
5397
5398         /* and any current mixer strip */
5399         if (current_mixer_strip) {
5400                 current_mixer_strip->fast_update ();
5401         }
5402
5403         /* PLAYHEAD AND VIEWPORT */
5404
5405         framepos_t const frame = _session->audible_frame();
5406
5407         /* There are a few reasons why we might not update the playhead / viewport stuff:
5408          *
5409          * 1.  we don't update things when there's a pending locate request, otherwise
5410          *     when the editor requests a locate there is a chance that this method
5411          *     will move the playhead before the locate request is processed, causing
5412          *     a visual glitch.
5413          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5414          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5415          */
5416
5417         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5418
5419                 last_update_frame = frame;
5420
5421                 if (!_dragging_playhead) {
5422                         playhead_cursor->set_position (frame);
5423                 }
5424
5425                 if (!_stationary_playhead) {
5426
5427                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5428                                 /* We only do this if we aren't already
5429                                    handling a visual change (ie if
5430                                    pending_visual_change.being_handled is
5431                                    false) so that these requests don't stack
5432                                    up there are too many of them to handle in
5433                                    time.
5434                                 */
5435                                 reset_x_origin_to_follow_playhead ();
5436                         }
5437
5438                 } else {
5439
5440                         /* don't do continuous scroll till the new position is in the rightmost quarter of the
5441                            editor canvas
5442                         */
5443 #if 0
5444                         // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5445                         double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5446                         if (target <= 0.0) {
5447                                 target = 0.0;
5448                         }
5449                         if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5450                                 target = (target * 0.15) + (current * 0.85);
5451                         } else {
5452                                 /* relax */
5453                         }
5454
5455                         current = target;
5456                         set_horizontal_position (current);
5457 #endif
5458                 }
5459
5460         }
5461 }
5462
5463
5464 void
5465 Editor::session_going_away ()
5466 {
5467         _have_idled = false;
5468
5469         _session_connections.drop_connections ();
5470
5471         super_rapid_screen_update_connection.disconnect ();
5472
5473         selection->clear ();
5474         cut_buffer->clear ();
5475
5476         clicked_regionview = 0;
5477         clicked_axisview = 0;
5478         clicked_routeview = 0;
5479         entered_regionview = 0;
5480         entered_track = 0;
5481         last_update_frame = 0;
5482         _drags->abort ();
5483
5484         playhead_cursor->hide ();
5485
5486         /* rip everything out of the list displays */
5487
5488         _regions->clear ();
5489         _routes->clear ();
5490         _route_groups->clear ();
5491
5492         /* do this first so that deleting a track doesn't reset cms to null
5493            and thus cause a leak.
5494         */
5495
5496         if (current_mixer_strip) {
5497                 if (current_mixer_strip->get_parent() != 0) {
5498                         global_hpacker.remove (*current_mixer_strip);
5499                 }
5500                 delete current_mixer_strip;
5501                 current_mixer_strip = 0;
5502         }
5503
5504         /* delete all trackviews */
5505
5506         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5507                 delete *i;
5508         }
5509         track_views.clear ();
5510
5511         nudge_clock->set_session (0);
5512
5513         editor_list_button.set_active(false);
5514         editor_list_button.set_sensitive(false);
5515
5516         /* clear tempo/meter rulers */
5517         remove_metric_marks ();
5518         hide_measures ();
5519         clear_marker_display ();
5520
5521         stop_step_editing ();
5522         
5523         /* get rid of any existing editor mixer strip */
5524
5525         WindowTitle title(Glib::get_application_name());
5526         title += _("Editor");
5527
5528         set_title (title.get_string());
5529
5530         SessionHandlePtr::session_going_away ();
5531 }
5532
5533
5534 void
5535 Editor::show_editor_list (bool yn)
5536 {
5537         if (yn) {
5538                 _the_notebook.show ();
5539         } else {
5540                 _the_notebook.hide ();
5541         }
5542 }
5543
5544 void
5545 Editor::change_region_layering_order (bool from_context_menu)
5546 {
5547         const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5548
5549         if (!clicked_routeview) {
5550                 if (layering_order_editor) {
5551                         layering_order_editor->hide ();
5552                 }
5553                 return;
5554         }
5555
5556         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5557
5558         if (!track) {
5559                 return;
5560         }
5561
5562         boost::shared_ptr<Playlist> pl = track->playlist();
5563
5564         if (!pl) {
5565                 return;
5566         }
5567
5568         if (layering_order_editor == 0) {
5569                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5570         }
5571
5572         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5573         layering_order_editor->maybe_present ();
5574 }
5575
5576 void
5577 Editor::update_region_layering_order_editor ()
5578 {
5579         if (layering_order_editor && layering_order_editor->is_visible ()) {
5580                 change_region_layering_order (true);
5581         }
5582 }
5583
5584 void
5585 Editor::setup_fade_images ()
5586 {
5587         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5588         _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5589         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5590         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5591         _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5592
5593         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5594         _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5595         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5596         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5597         _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5598         
5599         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5600         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5601         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5602         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5603         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5604
5605         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5606         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5607         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5608         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5609         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5610
5611 }
5612
5613 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5614 Gtk::MenuItem&
5615 Editor::action_menu_item (std::string const & name)
5616 {
5617         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5618         assert (a);
5619
5620         return *manage (a->create_menu_item ());
5621 }
5622
5623 void
5624 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5625 {
5626         EventBox* b = manage (new EventBox);
5627         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5628         Label* l = manage (new Label (name));
5629         l->set_angle (-90);
5630         b->add (*l);
5631         b->show_all ();
5632         _the_notebook.append_page (widget, *b);
5633 }
5634
5635 bool
5636 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5637 {
5638         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5639                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5640         }
5641
5642         if (ev->type == GDK_2BUTTON_PRESS) {
5643
5644                 /* double-click on a notebook tab shrinks or expands the notebook */
5645
5646                 if (_notebook_shrunk) {
5647                         if (pre_notebook_shrink_pane_width) {
5648                                 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5649                         }
5650                         _notebook_shrunk = false;
5651                 } else {
5652                         pre_notebook_shrink_pane_width = edit_pane.get_position();
5653
5654                         /* this expands the LHS of the edit pane to cover the notebook
5655                            PAGE but leaves the tabs visible.
5656                          */
5657                         edit_pane.set_position (edit_pane.get_position() + page->get_width());
5658                         _notebook_shrunk = true;
5659                 }
5660         }
5661
5662         return true;
5663 }
5664
5665 void
5666 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5667 {
5668         using namespace Menu_Helpers;
5669         
5670         MenuList& items = _control_point_context_menu.items ();
5671         items.clear ();
5672         
5673         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5674         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5675         if (!can_remove_control_point (item)) {
5676                 items.back().set_sensitive (false);
5677         }
5678
5679         _control_point_context_menu.popup (event->button.button, event->button.time);
5680 }
5681
5682 void
5683 Editor::zoom_vertical_modifier_released()
5684 {
5685         _stepping_axis_view = 0;
5686 }
5687
5688 void
5689 Editor::ui_parameter_changed (string parameter)
5690 {
5691         if (parameter == "icon-set") {
5692                 while (!_cursor_stack.empty()) {
5693                         _cursor_stack.pop();
5694                 }
5695                 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5696         } else if (parameter == "draggable-playhead") {
5697                 if (_verbose_cursor) {
5698                         playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());
5699                 }
5700         }
5701 }