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