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