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