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