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