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