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