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