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