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