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