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