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         ArdourCanvas::GtkCanvasViewport* c;
4273
4274         c = get_time_bars_canvas();
4275         if (c) {
4276                 c->canvas()->zoomed ();
4277         }
4278         c = get_track_canvas();
4279         if (c) {
4280                 c->canvas()->zoomed ();
4281         }
4282
4283         if (playhead_cursor) {
4284                 playhead_cursor->set_position (playhead_cursor->current_frame ());
4285         }
4286
4287         refresh_location_display();
4288         _summary->set_overlays_dirty ();
4289
4290         update_marker_labels ();
4291
4292         instant_save ();
4293 }
4294
4295 void
4296 Editor::queue_visual_videotimeline_update ()
4297 {
4298         /* TODO:
4299          * pending_visual_change.add (VisualChange::VideoTimeline);
4300          * or maybe even more specific: which videotimeline-image
4301          * currently it calls update_video_timeline() to update
4302          * _all outdated_ images on the video-timeline.
4303          * see 'exposeimg()' in video_image_frame.cc
4304          */
4305         ensure_visual_change_idle_handler ();
4306 }
4307
4308 void
4309 Editor::ensure_visual_change_idle_handler ()
4310 {
4311         if (pending_visual_change.idle_handler_id < 0) {
4312                 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4313                 pending_visual_change.being_handled = false;
4314         }
4315 }
4316
4317 int
4318 Editor::_idle_visual_changer (void* arg)
4319 {
4320         return static_cast<Editor*>(arg)->idle_visual_changer ();
4321 }
4322
4323 int
4324 Editor::idle_visual_changer ()
4325 {
4326         /* set_horizontal_position() below (and maybe other calls) call
4327            gtk_main_iteration(), so it's possible that a signal will be handled
4328            half-way through this method.  If this signal wants an
4329            idle_visual_changer we must schedule another one after this one, so
4330            mark the idle_handler_id as -1 here to allow that.  Also make a note
4331            that we are doing the visual change, so that changes in response to
4332            super-rapid-screen-update can be dropped if we are still processing
4333            the last one.
4334         */
4335
4336         pending_visual_change.idle_handler_id = -1;
4337         pending_visual_change.being_handled = true;
4338         
4339         VisualChange::Type p = pending_visual_change.pending;
4340         pending_visual_change.pending = (VisualChange::Type) 0;
4341
4342         double const last_time_origin = horizontal_position ();
4343
4344
4345         if (p & VisualChange::ZoomLevel) {
4346                 set_samples_per_pixel (pending_visual_change.samples_per_pixel);
4347
4348                 compute_fixed_ruler_scale ();
4349
4350                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4351                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4352                 
4353                 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4354                                             current_bbt_points_begin, current_bbt_points_end);
4355                 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4356                                          current_bbt_points_begin, current_bbt_points_end);
4357                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4358
4359                 update_video_timeline();
4360         }
4361
4362         if (p & VisualChange::TimeOrigin) {
4363                 set_horizontal_position (pending_visual_change.time_origin / samples_per_pixel);
4364         }
4365
4366         if (p & VisualChange::YOrigin) {
4367                 vertical_adjustment.set_value (pending_visual_change.y_origin);
4368         }
4369
4370         if (last_time_origin == horizontal_position ()) {
4371                 /* changed signal not emitted */
4372                 update_fixed_rulers ();
4373                 redisplay_tempo (true);
4374         }
4375
4376         if (!(p & VisualChange::ZoomLevel)) {
4377                 update_video_timeline();
4378         }
4379
4380         _summary->set_overlays_dirty ();
4381
4382         pending_visual_change.being_handled = false;
4383         return 0; /* this is always a one-shot call */
4384 }
4385
4386 struct EditorOrderTimeAxisSorter {
4387     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4388             return a->order () < b->order ();
4389     }
4390 };
4391
4392 void
4393 Editor::sort_track_selection (TrackViewList& sel)
4394 {
4395         EditorOrderTimeAxisSorter cmp;
4396         sel.sort (cmp);
4397 }
4398
4399 framepos_t
4400 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4401 {
4402         bool ignored;
4403         framepos_t where = 0;
4404         EditPoint ep = _edit_point;
4405
4406         if (from_context_menu && (ep == EditAtMouse)) {
4407                 return  canvas_event_frame (&context_click_event, 0, 0);
4408         }
4409
4410         if (entered_marker) {
4411                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4412                 return entered_marker->position();
4413         }
4414
4415         if (ignore_playhead && ep == EditAtPlayhead) {
4416                 ep = EditAtSelectedMarker;
4417         }
4418
4419         switch (ep) {
4420         case EditAtPlayhead:
4421                 where = _session->audible_frame();
4422                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4423                 break;
4424
4425         case EditAtSelectedMarker:
4426                 if (!selection->markers.empty()) {
4427                         bool is_start;
4428                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4429                         if (loc) {
4430                                 if (is_start) {
4431                                         where =  loc->start();
4432                                 } else {
4433                                         where = loc->end();
4434                                 }
4435                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4436                                 break;
4437                         }
4438                 }
4439                 /* fallthru */
4440
4441         default:
4442         case EditAtMouse:
4443                 if (!mouse_frame (where, ignored)) {
4444                         /* XXX not right but what can we do ? */
4445                         return 0;
4446                 }
4447                 snap_to (where);
4448                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4449                 break;
4450         }
4451
4452         return where;
4453 }
4454
4455 void
4456 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4457 {
4458         if (!_session) return;
4459
4460         begin_reversible_command (cmd);
4461
4462         Location* tll;
4463
4464         if ((tll = transport_loop_location()) == 0) {
4465                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4466                 XMLNode &before = _session->locations()->get_state();
4467                 _session->locations()->add (loc, true);
4468                 _session->set_auto_loop_location (loc);
4469                 XMLNode &after = _session->locations()->get_state();
4470                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4471         } else {
4472                 XMLNode &before = tll->get_state();
4473                 tll->set_hidden (false, this);
4474                 tll->set (start, end);
4475                 XMLNode &after = tll->get_state();
4476                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4477         }
4478
4479         commit_reversible_command ();
4480 }
4481
4482 void
4483 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4484 {
4485         if (!_session) return;
4486
4487         begin_reversible_command (cmd);
4488
4489         Location* tpl;
4490
4491         if ((tpl = transport_punch_location()) == 0) {
4492                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
4493                 XMLNode &before = _session->locations()->get_state();
4494                 _session->locations()->add (loc, true);
4495                 _session->set_auto_loop_location (loc);
4496                 XMLNode &after = _session->locations()->get_state();
4497                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4498         }
4499         else {
4500                 XMLNode &before = tpl->get_state();
4501                 tpl->set_hidden (false, this);
4502                 tpl->set (start, end);
4503                 XMLNode &after = tpl->get_state();
4504                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4505         }
4506
4507         commit_reversible_command ();
4508 }
4509
4510 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4511  *  @param rs List to which found regions are added.
4512  *  @param where Time to look at.
4513  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4514  */
4515 void
4516 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4517 {
4518         const TrackViewList* tracks;
4519
4520         if (ts.empty()) {
4521                 tracks = &track_views;
4522         } else {
4523                 tracks = &ts;
4524         }
4525
4526         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4527
4528                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4529
4530                 if (rtv) {
4531                         boost::shared_ptr<Track> tr;
4532                         boost::shared_ptr<Playlist> pl;
4533
4534                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4535
4536                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4537                                                 (framepos_t) floor ( (double) where * tr->speed()));
4538
4539                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4540                                         RegionView* rv = rtv->view()->find_view (*i);
4541                                         if (rv) {
4542                                                 rs.add (rv);
4543                                         }
4544                                 }
4545                         }
4546                 }
4547         }
4548 }
4549
4550 void
4551 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4552 {
4553         const TrackViewList* tracks;
4554
4555         if (ts.empty()) {
4556                 tracks = &track_views;
4557         } else {
4558                 tracks = &ts;
4559         }
4560
4561         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4562                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4563                 if (rtv) {
4564                         boost::shared_ptr<Track> tr;
4565                         boost::shared_ptr<Playlist> pl;
4566
4567                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4568
4569                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4570                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4571
4572                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4573
4574                                         RegionView* rv = rtv->view()->find_view (*i);
4575
4576                                         if (rv) {
4577                                                 rs.add (rv);
4578                                         }
4579                                 }
4580                         }
4581                 }
4582         }
4583 }
4584
4585 /** Get regions using the following method:
4586  *
4587  *  Make a region list using the selected regions, unless
4588  *  the edit point is `mouse' and the mouse is over an unselected
4589  *  region.  In this case, use just that region.
4590  *
4591  *  If the edit point is not 'mouse', and there are no regions selected,
4592  *  search the list of selected tracks and return regions that are under
4593  *  the edit point on these tracks. If there are no selected tracks and
4594  *  'No Selection = All Tracks' is active, search all tracks,
4595  *
4596  *  The rationale here is that the mouse edit point is special in that
4597  *  its position describes both a time and a track; the other edit
4598  *  modes only describe a time.  Hence if the edit point is `mouse' we
4599  *  ignore selected tracks, as we assume the user means something by
4600  *  pointing at a particular track.  Also in this case we take note of
4601  *  the region directly under the edit point, as there is always just one
4602  *  (rather than possibly several with non-mouse edit points).
4603  */
4604
4605 RegionSelection
4606 Editor::get_regions_from_selection_and_edit_point ()
4607 {
4608         RegionSelection regions;
4609
4610         if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4611                 regions.add (entered_regionview);
4612         } else {
4613                 regions = selection->regions;
4614         }
4615
4616
4617         if (regions.empty() && _edit_point != EditAtMouse) {
4618                 TrackViewList tracks = selection->tracks;
4619
4620                 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4621                         /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4622                          * is enabled, so consider all tracks
4623                          */
4624                         tracks = track_views; 
4625                 }
4626
4627                 if (!tracks.empty()) {
4628                         /* no region selected or entered, but some selected tracks:
4629                          * act on all regions on the selected tracks at the edit point
4630                          */ 
4631                         framepos_t const where = get_preferred_edit_position ();
4632                         get_regions_at(regions, where, tracks);
4633                 }
4634         }
4635         return regions;
4636 }
4637
4638 /** Start with regions that are selected, or the entered regionview if none are selected.
4639  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4640  *  of the regions that we started with.
4641  */
4642
4643 RegionSelection
4644 Editor::get_regions_from_selection_and_entered ()
4645 {
4646         RegionSelection regions = selection->regions;
4647
4648         if (regions.empty() && entered_regionview) {
4649                 regions.add (entered_regionview);
4650         }
4651
4652         return regions;
4653 }
4654
4655 void
4656 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4657 {
4658         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4659
4660                 RouteTimeAxisView* tatv;
4661
4662                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4663
4664                         boost::shared_ptr<Playlist> pl;
4665                         vector<boost::shared_ptr<Region> > results;
4666                         RegionView* marv;
4667                         boost::shared_ptr<Track> tr;
4668
4669                         if ((tr = tatv->track()) == 0) {
4670                                 /* bus */
4671                                 continue;
4672                         }
4673
4674                         if ((pl = (tr->playlist())) != 0) {
4675                                 if (src_comparison) {
4676                                         pl->get_source_equivalent_regions (region, results);
4677                                 } else {
4678                                         pl->get_region_list_equivalent_regions (region, results);
4679                                 }
4680                         }
4681
4682                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4683                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4684                                         regions.push_back (marv);
4685                                 }
4686                         }
4687
4688                 }
4689         }
4690 }
4691
4692 void
4693 Editor::show_rhythm_ferret ()
4694 {
4695         if (rhythm_ferret == 0) {
4696                 rhythm_ferret = new RhythmFerret(*this);
4697         }
4698
4699         rhythm_ferret->set_session (_session);
4700         rhythm_ferret->show ();
4701         rhythm_ferret->present ();
4702 }
4703
4704 void
4705 Editor::first_idle ()
4706 {
4707         MessageDialog* dialog = 0;
4708         
4709         if (track_views.size() > 1) {
4710                 dialog = new MessageDialog (
4711                         *this,
4712                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4713                         true
4714                         );
4715                 dialog->present ();
4716                 ARDOUR_UI::instance()->flush_pending ();
4717         }
4718
4719         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4720                 (*t)->first_idle();
4721         }
4722
4723         // first idle adds route children (automation tracks), so we need to redisplay here
4724         _routes->redisplay ();
4725
4726         delete dialog;
4727         _have_idled = true;
4728 }
4729
4730 gboolean
4731 Editor::_idle_resize (gpointer arg)
4732 {
4733         return ((Editor*)arg)->idle_resize ();
4734 }
4735
4736 void
4737 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4738 {
4739         if (resize_idle_id < 0) {
4740                 resize_idle_id = g_idle_add (_idle_resize, this);
4741                 _pending_resize_amount = 0;
4742         }
4743
4744         /* make a note of the smallest resulting height, so that we can clamp the
4745            lower limit at TimeAxisView::hSmall */
4746
4747         int32_t min_resulting = INT32_MAX;
4748
4749         _pending_resize_amount += h;
4750         _pending_resize_view = view;
4751
4752         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4753
4754         if (selection->tracks.contains (_pending_resize_view)) {
4755                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4756                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4757                 }
4758         }
4759
4760         if (min_resulting < 0) {
4761                 min_resulting = 0;
4762         }
4763
4764         /* clamp */
4765         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4766                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4767         }
4768 }
4769
4770 /** Handle pending resizing of tracks */
4771 bool
4772 Editor::idle_resize ()
4773 {
4774         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4775
4776         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4777             selection->tracks.contains (_pending_resize_view)) {
4778
4779                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4780                         if (*i != _pending_resize_view) {
4781                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4782                         }
4783                 }
4784         }
4785
4786         _pending_resize_amount = 0;
4787         _group_tabs->set_dirty ();
4788         resize_idle_id = -1;
4789
4790         return false;
4791 }
4792
4793 void
4794 Editor::located ()
4795 {
4796         ENSURE_GUI_THREAD (*this, &Editor::located);
4797
4798         if (_session) {
4799                 playhead_cursor->set_position (_session->audible_frame ());
4800                 if (_follow_playhead && !_pending_initial_locate) {
4801                         reset_x_origin_to_follow_playhead ();
4802                 }
4803         }
4804
4805         _pending_locate_request = false;
4806         _pending_initial_locate = false;
4807 }
4808
4809 void
4810 Editor::region_view_added (RegionView *)
4811 {
4812         _summary->set_dirty ();
4813 }
4814
4815 void
4816 Editor::region_view_removed ()
4817 {
4818         _summary->set_dirty ();
4819 }
4820
4821 TimeAxisView*
4822 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4823 {
4824         TrackViewList::const_iterator j = track_views.begin ();
4825         while (j != track_views.end()) {
4826                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4827                 if (rtv && rtv->route() == r) {
4828                         return rtv;
4829                 }
4830                 ++j;
4831         }
4832
4833         return 0;
4834 }
4835
4836
4837 TrackViewList
4838 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4839 {
4840         TrackViewList t;
4841
4842         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4843                 TimeAxisView* tv = axis_view_from_route (*i);
4844                 if (tv) {
4845                         t.push_back (tv);
4846                 }
4847         }
4848
4849         return t;
4850 }
4851
4852 void
4853 Editor::add_routes (RouteList& routes)
4854 {
4855         ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4856
4857         RouteTimeAxisView *rtv;
4858         list<RouteTimeAxisView*> new_views;
4859
4860         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4861                 boost::shared_ptr<Route> route = (*x);
4862
4863                 if (route->is_auditioner() || route->is_monitor()) {
4864                         continue;
4865                 }
4866
4867                 DataType dt = route->input()->default_type();
4868
4869                 if (dt == ARDOUR::DataType::AUDIO) {
4870                         rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4871                         rtv->set_route (route);
4872                 } else if (dt == ARDOUR::DataType::MIDI) {
4873                         rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4874                         rtv->set_route (route);
4875                 } else {
4876                         throw unknown_type();
4877                 }
4878
4879                 new_views.push_back (rtv);
4880                 track_views.push_back (rtv);
4881
4882                 rtv->effective_gain_display ();
4883
4884                 if (internal_editing()) {
4885                         rtv->enter_internal_edit_mode ();
4886                 } else {
4887                         rtv->leave_internal_edit_mode ();
4888                 }
4889
4890                 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4891                 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4892         }
4893
4894         if (new_views.size() > 0) {
4895                 _routes->routes_added (new_views);
4896                 _summary->routes_added (new_views);
4897         }
4898
4899         if (show_editor_mixer_when_tracks_arrive) {
4900                 show_editor_mixer (true);
4901         }
4902
4903         editor_list_button.set_sensitive (true);
4904 }
4905
4906 void
4907 Editor::timeaxisview_deleted (TimeAxisView *tv)
4908 {
4909         if (_session && _session->deletion_in_progress()) {
4910                 /* the situation is under control */
4911                 return;
4912         }
4913
4914         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4915
4916         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4917
4918         _routes->route_removed (tv);
4919
4920         if (tv == entered_track) {
4921                 entered_track = 0;
4922         }
4923
4924         TimeAxisView::Children c = tv->get_child_list ();
4925         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4926                 if (entered_track == i->get()) {
4927                         entered_track = 0;
4928                 }
4929         }
4930
4931         /* remove it from the list of track views */
4932
4933         TrackViewList::iterator i;
4934
4935         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4936                 i = track_views.erase (i);
4937         }
4938
4939         /* update whatever the current mixer strip is displaying, if revelant */
4940
4941         boost::shared_ptr<Route> route;
4942
4943         if (rtav) {
4944                 route = rtav->route ();
4945         }
4946
4947         if (current_mixer_strip && current_mixer_strip->route() == route) {
4948
4949                 TimeAxisView* next_tv;
4950
4951                 if (track_views.empty()) {
4952                         next_tv = 0;
4953                 } else if (i == track_views.end()) {
4954                         next_tv = track_views.front();
4955                 } else {
4956                         next_tv = (*i);
4957                 }
4958
4959
4960                 if (next_tv) {
4961                         set_selected_mixer_strip (*next_tv);
4962                 } else {
4963                         /* make the editor mixer strip go away setting the
4964                          * button to inactive (which also unticks the menu option)
4965                          */
4966
4967                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4968                 }
4969         }
4970 }
4971
4972 void
4973 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4974 {
4975         if (apply_to_selection) {
4976                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4977
4978                         TrackSelection::iterator j = i;
4979                         ++j;
4980
4981                         hide_track_in_display (*i, false);
4982
4983                         i = j;
4984                 }
4985         } else {
4986                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4987
4988                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4989                         // this will hide the mixer strip
4990                         set_selected_mixer_strip (*tv);
4991                 }
4992
4993                 _routes->hide_track_in_display (*tv);
4994         }
4995 }
4996
4997 bool
4998 Editor::sync_track_view_list_and_routes ()
4999 {
5000         track_views = TrackViewList (_routes->views ());
5001
5002         _summary->set_dirty ();
5003         _group_tabs->set_dirty ();
5004
5005         return false; // do not call again (until needed)
5006 }
5007
5008 void
5009 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5010 {
5011         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5012                 theslot (**i);
5013         }
5014 }
5015
5016 /** Find a RouteTimeAxisView by the ID of its route */
5017 RouteTimeAxisView*
5018 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5019 {
5020         RouteTimeAxisView* v;
5021
5022         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5023                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5024                         if(v->route()->id() == id) {
5025                                 return v;
5026                         }
5027                 }
5028         }
5029
5030         return 0;
5031 }
5032
5033 void
5034 Editor::fit_route_group (RouteGroup *g)
5035 {
5036         TrackViewList ts = axis_views_from_routes (g->route_list ());
5037         fit_tracks (ts);
5038 }
5039
5040 void
5041 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5042 {
5043         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5044
5045         if (r == 0) {
5046                 _session->cancel_audition ();
5047                 return;
5048         }
5049
5050         if (_session->is_auditioning()) {
5051                 _session->cancel_audition ();
5052                 if (r == last_audition_region) {
5053                         return;
5054                 }
5055         }
5056
5057         _session->audition_region (r);
5058         last_audition_region = r;
5059 }
5060
5061
5062 void
5063 Editor::hide_a_region (boost::shared_ptr<Region> r)
5064 {
5065         r->set_hidden (true);
5066 }
5067
5068 void
5069 Editor::show_a_region (boost::shared_ptr<Region> r)
5070 {
5071         r->set_hidden (false);
5072 }
5073
5074 void
5075 Editor::audition_region_from_region_list ()
5076 {
5077         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5078 }
5079
5080 void
5081 Editor::hide_region_from_region_list ()
5082 {
5083         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5084 }
5085
5086 void
5087 Editor::show_region_in_region_list ()
5088 {
5089         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5090 }
5091
5092 void
5093 Editor::step_edit_status_change (bool yn)
5094 {
5095         if (yn) {
5096                 start_step_editing ();
5097         } else {
5098                 stop_step_editing ();
5099         }
5100 }
5101
5102 void
5103 Editor::start_step_editing ()
5104 {
5105         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5106 }
5107
5108 void
5109 Editor::stop_step_editing ()
5110 {
5111         step_edit_connection.disconnect ();
5112 }
5113
5114 bool
5115 Editor::check_step_edit ()
5116 {
5117         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5118                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5119                 if (mtv) {
5120                         mtv->check_step_edit ();
5121                 }
5122         }
5123
5124         return true; // do it again, till we stop
5125 }
5126
5127 bool
5128 Editor::scroll_press (Direction dir)
5129 {
5130         ++_scroll_callbacks;
5131
5132         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5133                 /* delay the first auto-repeat */
5134                 return true;
5135         }
5136
5137         switch (dir) {
5138         case LEFT:
5139                 scroll_backward (1);
5140                 break;
5141
5142         case RIGHT:
5143                 scroll_forward (1);
5144                 break;
5145
5146         case UP:
5147                 scroll_tracks_up_line ();
5148                 break;
5149
5150         case DOWN:
5151                 scroll_tracks_down_line ();
5152                 break;
5153         }
5154
5155         /* do hacky auto-repeat */
5156         if (!_scroll_connection.connected ()) {
5157
5158                 _scroll_connection = Glib::signal_timeout().connect (
5159                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5160                         );
5161
5162                 _scroll_callbacks = 0;
5163         }
5164
5165         return true;
5166 }
5167
5168 void
5169 Editor::scroll_release ()
5170 {
5171         _scroll_connection.disconnect ();
5172 }
5173
5174 /** Queue a change for the Editor viewport x origin to follow the playhead */
5175 void
5176 Editor::reset_x_origin_to_follow_playhead ()
5177 {
5178         framepos_t const frame = playhead_cursor->current_frame ();
5179
5180         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5181
5182                 if (_session->transport_speed() < 0) {
5183
5184                         if (frame > (current_page_samples() / 2)) {
5185                                 center_screen (frame-(current_page_samples()/2));
5186                         } else {
5187                                 center_screen (current_page_samples()/2);
5188                         }
5189
5190                 } else {
5191
5192                         framepos_t l = 0;
5193                         
5194                         if (frame < leftmost_frame) {
5195                                 /* moving left */
5196                                 if (_session->transport_rolling()) {
5197                                         /* rolling; end up with the playhead at the right of the page */
5198                                         l = frame - current_page_samples ();
5199                                 } else {
5200                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5201                                         l = frame - current_page_samples() / 4;
5202                                 }
5203                         } else {
5204                                 /* moving right */
5205                                 if (_session->transport_rolling()) {
5206                                         /* rolling: end up with the playhead on the left of the page */
5207                                         l = frame;
5208                                 } else {
5209                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5210                                         l = frame - 3 * current_page_samples() / 4;
5211                                 }
5212                         }
5213
5214                         if (l < 0) {
5215                                 l = 0;
5216                         }
5217                         
5218                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5219                 }
5220         }
5221 }
5222
5223 void
5224 Editor::super_rapid_screen_update ()
5225 {
5226         if (!_session || !_session->engine().running()) {
5227                 return;
5228         }
5229
5230         /* METERING / MIXER STRIPS */
5231
5232         /* update track meters, if required */
5233         if (is_mapped() && meters_running) {
5234                 RouteTimeAxisView* rtv;
5235                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5236                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5237                                 rtv->fast_update ();
5238                         }
5239                 }
5240         }
5241
5242         /* and any current mixer strip */
5243         if (current_mixer_strip) {
5244                 current_mixer_strip->fast_update ();
5245         }
5246
5247         /* PLAYHEAD AND VIEWPORT */
5248
5249         framepos_t const frame = _session->audible_frame();
5250
5251         /* There are a few reasons why we might not update the playhead / viewport stuff:
5252          *
5253          * 1.  we don't update things when there's a pending locate request, otherwise
5254          *     when the editor requests a locate there is a chance that this method
5255          *     will move the playhead before the locate request is processed, causing
5256          *     a visual glitch.
5257          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5258          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5259          */
5260
5261         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5262
5263                 last_update_frame = frame;
5264
5265                 if (!_dragging_playhead) {
5266                         playhead_cursor->set_position (frame);
5267                 }
5268
5269                 if (!_stationary_playhead) {
5270
5271                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5272                                 /* We only do this if we aren't already
5273                                    handling a visual change (ie if
5274                                    pending_visual_change.being_handled is
5275                                    false) so that these requests don't stack
5276                                    up there are too many of them to handle in
5277                                    time.
5278                                 */
5279                                 reset_x_origin_to_follow_playhead ();
5280                         }
5281
5282                 } else {
5283
5284                         /* don't do continuous scroll till the new position is in the rightmost quarter of the
5285                            editor canvas
5286                         */
5287 #if 0
5288                         // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5289                         double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5290                         if (target <= 0.0) {
5291                                 target = 0.0;
5292                         }
5293                         if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5294                                 target = (target * 0.15) + (current * 0.85);
5295                         } else {
5296                                 /* relax */
5297                         }
5298
5299                         current = target;
5300                         set_horizontal_position (current);
5301 #endif
5302                 }
5303
5304         }
5305 }
5306
5307
5308 void
5309 Editor::session_going_away ()
5310 {
5311         _have_idled = false;
5312
5313         _session_connections.drop_connections ();
5314
5315         super_rapid_screen_update_connection.disconnect ();
5316
5317         selection->clear ();
5318         cut_buffer->clear ();
5319
5320         clicked_regionview = 0;
5321         clicked_axisview = 0;
5322         clicked_routeview = 0;
5323         entered_regionview = 0;
5324         entered_track = 0;
5325         last_update_frame = 0;
5326         _drags->abort ();
5327
5328         playhead_cursor->hide ();
5329
5330         /* rip everything out of the list displays */
5331
5332         _regions->clear ();
5333         _routes->clear ();
5334         _route_groups->clear ();
5335
5336         /* do this first so that deleting a track doesn't reset cms to null
5337            and thus cause a leak.
5338         */
5339
5340         if (current_mixer_strip) {
5341                 if (current_mixer_strip->get_parent() != 0) {
5342                         global_hpacker.remove (*current_mixer_strip);
5343                 }
5344                 delete current_mixer_strip;
5345                 current_mixer_strip = 0;
5346         }
5347
5348         /* delete all trackviews */
5349
5350         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5351                 delete *i;
5352         }
5353         track_views.clear ();
5354
5355         zoom_range_clock->set_session (0);
5356         nudge_clock->set_session (0);
5357
5358         editor_list_button.set_active(false);
5359         editor_list_button.set_sensitive(false);
5360
5361         /* clear tempo/meter rulers */
5362         remove_metric_marks ();
5363         hide_measures ();
5364         clear_marker_display ();
5365
5366         stop_step_editing ();
5367         
5368         /* get rid of any existing editor mixer strip */
5369
5370         WindowTitle title(Glib::get_application_name());
5371         title += _("Editor");
5372
5373         set_title (title.get_string());
5374
5375         SessionHandlePtr::session_going_away ();
5376 }
5377
5378
5379 void
5380 Editor::show_editor_list (bool yn)
5381 {
5382         if (yn) {
5383                 _the_notebook.show ();
5384         } else {
5385                 _the_notebook.hide ();
5386         }
5387 }
5388
5389 void
5390 Editor::change_region_layering_order (bool from_context_menu)
5391 {
5392         const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5393
5394         if (!clicked_routeview) {
5395                 if (layering_order_editor) {
5396                         layering_order_editor->hide ();
5397                 }
5398                 return;
5399         }
5400
5401         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5402
5403         if (!track) {
5404                 return;
5405         }
5406
5407         boost::shared_ptr<Playlist> pl = track->playlist();
5408
5409         if (!pl) {
5410                 return;
5411         }
5412
5413         if (layering_order_editor == 0) {
5414                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5415         }
5416
5417         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5418         layering_order_editor->maybe_present ();
5419 }
5420
5421 void
5422 Editor::update_region_layering_order_editor ()
5423 {
5424         if (layering_order_editor && layering_order_editor->is_visible ()) {
5425                 change_region_layering_order (true);
5426         }
5427 }
5428
5429 void
5430 Editor::setup_fade_images ()
5431 {
5432         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5433         _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5434         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5435         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5436         _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5437
5438         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5439         _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5440         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5441         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5442         _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5443         
5444         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5445         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5446         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5447         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5448         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5449
5450         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5451         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5452         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5453         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5454         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5455
5456 }
5457
5458 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5459 Gtk::MenuItem&
5460 Editor::action_menu_item (std::string const & name)
5461 {
5462         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5463         assert (a);
5464
5465         return *manage (a->create_menu_item ());
5466 }
5467
5468 void
5469 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5470 {
5471         EventBox* b = manage (new EventBox);
5472         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5473         Label* l = manage (new Label (name));
5474         l->set_angle (-90);
5475         b->add (*l);
5476         b->show_all ();
5477         _the_notebook.append_page (widget, *b);
5478 }
5479
5480 bool
5481 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5482 {
5483         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5484                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5485         }
5486
5487         if (ev->type == GDK_2BUTTON_PRESS) {
5488
5489                 /* double-click on a notebook tab shrinks or expands the notebook */
5490
5491                 if (_notebook_shrunk) {
5492                         if (pre_notebook_shrink_pane_width) {
5493                                 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5494                         }
5495                         _notebook_shrunk = false;
5496                 } else {
5497                         pre_notebook_shrink_pane_width = edit_pane.get_position();
5498
5499                         /* this expands the LHS of the edit pane to cover the notebook
5500                            PAGE but leaves the tabs visible.
5501                          */
5502                         edit_pane.set_position (edit_pane.get_position() + page->get_width());
5503                         _notebook_shrunk = true;
5504                 }
5505         }
5506
5507         return true;
5508 }
5509
5510 void
5511 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5512 {
5513         using namespace Menu_Helpers;
5514         
5515         MenuList& items = _control_point_context_menu.items ();
5516         items.clear ();
5517         
5518         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5519         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5520         if (!can_remove_control_point (item)) {
5521                 items.back().set_sensitive (false);
5522         }
5523
5524         _control_point_context_menu.popup (event->button.button, event->button.time);
5525 }
5526
5527 void
5528 Editor::zoom_vertical_modifier_released()
5529 {
5530         _stepping_axis_view = 0;
5531 }