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