remove "canvasvar_" from all functions related to obtaining values from ARDOUR_UI...
[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                 playhead_cursor->set_position (pos);
2207         } else {
2208                 playhead_cursor->set_position (0);
2209         }
2210
2211         if ((prop = node.property ("mixer-width"))) {
2212                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2213         }
2214
2215         if ((prop = node.property ("zoom-focus"))) {
2216                 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2217         }
2218
2219         if ((prop = node.property ("zoom"))) {
2220                 /* older versions of ardour used floating point samples_per_pixel */
2221                 double f = PBD::atof (prop->value());
2222                 reset_zoom (llrintf (f));
2223         } else {
2224                 reset_zoom (samples_per_pixel);
2225         }
2226
2227         if ((prop = node.property ("visible-track-count"))) {
2228                 set_visible_track_count (PBD::atoi (prop->value()));
2229         }
2230
2231         if ((prop = node.property ("snap-to"))) {
2232                 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2233         }
2234
2235         if ((prop = node.property ("snap-mode"))) {
2236                 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2237         }
2238
2239         if ((prop = node.property ("internal-snap-to"))) {
2240                 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2241         }
2242
2243         if ((prop = node.property ("internal-snap-mode"))) {
2244                 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2245         }
2246
2247         if ((prop = node.property ("pre-internal-snap-to"))) {
2248                 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2249         }
2250
2251
2252         if ((prop = node.property ("pre-internal-snap-mode"))) {
2253                 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2254         }
2255
2256         if ((prop = node.property ("mouse-mode"))) {
2257                 MouseMode m = str2mousemode(prop->value());
2258                 set_mouse_mode (m, true);
2259         } else {
2260                 set_mouse_mode (MouseObject, true);
2261         }
2262
2263         if ((prop = node.property ("left-frame")) != 0) {
2264                 framepos_t pos;
2265                 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2266                         if (pos < 0) {
2267                                 pos = 0;
2268                         }
2269                         reset_x_origin (pos);
2270                 }
2271         }
2272
2273         if ((prop = node.property ("y-origin")) != 0) {
2274                 reset_y_origin (atof (prop->value ()));
2275         }
2276
2277         if ((prop = node.property ("internal-edit"))) {
2278                 bool yn = string_is_affirmative (prop->value());
2279                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2280                 if (act) {
2281                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2282                         tact->set_active (!yn);
2283                         tact->set_active (yn);
2284                 }
2285         }
2286
2287         if ((prop = node.property ("join-object-range"))) {
2288                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2289                 bool yn = string_is_affirmative (prop->value());
2290                 if (act) {
2291                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2292                         tact->set_active (!yn);
2293                         tact->set_active (yn);
2294                 }
2295                 set_mouse_mode(mouse_mode, true);
2296         }
2297
2298         if ((prop = node.property ("edit-point"))) {
2299                 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2300         }
2301
2302         if ((prop = node.property ("show-measures"))) {
2303                 bool yn = string_is_affirmative (prop->value());
2304                 _show_measures = yn;
2305                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2306                 if (act) {
2307                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2308                         /* do it twice to force the change */
2309                         tact->set_active (!yn);
2310                         tact->set_active (yn);
2311                 }
2312         }
2313
2314         if ((prop = node.property ("follow-playhead"))) {
2315                 bool yn = string_is_affirmative (prop->value());
2316                 set_follow_playhead (yn);
2317                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2318                 if (act) {
2319                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2320                         if (tact->get_active() != yn) {
2321                                 tact->set_active (yn);
2322                         }
2323                 }
2324         }
2325
2326         if ((prop = node.property ("stationary-playhead"))) {
2327                 bool yn = string_is_affirmative (prop->value());
2328                 set_stationary_playhead (yn);
2329                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2330                 if (act) {
2331                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2332                         if (tact->get_active() != yn) {
2333                                 tact->set_active (yn);
2334                         }
2335                 }
2336         }
2337
2338         if ((prop = node.property ("region-list-sort-type"))) {
2339                 RegionListSortType st;
2340                 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2341         }
2342
2343         if ((prop = node.property ("show-editor-mixer"))) {
2344
2345                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2346                 assert (act);
2347
2348                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2349                 bool yn = string_is_affirmative (prop->value());
2350
2351                 /* do it twice to force the change */
2352
2353                 tact->set_active (!yn);
2354                 tact->set_active (yn);
2355         }
2356
2357         if ((prop = node.property ("show-editor-list"))) {
2358
2359                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2360                 assert (act);
2361
2362                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2363                 bool yn = string_is_affirmative (prop->value());
2364
2365                 /* do it twice to force the change */
2366
2367                 tact->set_active (!yn);
2368                 tact->set_active (yn);
2369         }
2370
2371         if ((prop = node.property (X_("editor-list-page")))) {
2372                 _the_notebook.set_current_page (atoi (prop->value ()));
2373         }
2374
2375         if ((prop = node.property (X_("show-marker-lines")))) {
2376                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2377                 assert (act);
2378                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2379                 bool yn = string_is_affirmative (prop->value ());
2380
2381                 tact->set_active (!yn);
2382                 tact->set_active (yn);
2383         }
2384
2385         XMLNodeList children = node.children ();
2386         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2387                 selection->set_state (**i, Stateful::current_state_version);
2388                 _regions->set_state (**i);
2389         }
2390
2391         if ((prop = node.property ("maximised"))) {
2392                 bool yn = string_is_affirmative (prop->value());
2393                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2394                 assert (act);
2395                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2396                 bool fs = tact && tact->get_active();
2397                 if (yn ^ fs) {
2398                         ActionManager::do_action ("Common", "ToggleMaximalEditor");
2399                 }
2400         }
2401
2402         if ((prop = node.property ("nudge-clock-value"))) {
2403                 framepos_t f;
2404                 sscanf (prop->value().c_str(), "%" PRId64, &f);
2405                 nudge_clock->set (f);
2406         } else {
2407                 nudge_clock->set_mode (AudioClock::Timecode);
2408                 nudge_clock->set (_session->frame_rate() * 5, true);
2409         }
2410
2411         return 0;
2412 }
2413
2414 XMLNode&
2415 Editor::get_state ()
2416 {
2417         XMLNode* node = new XMLNode ("Editor");
2418         char buf[32];
2419
2420         id().print (buf, sizeof (buf));
2421         node->add_property ("id", buf);
2422
2423         if (is_realized()) {
2424                 Glib::RefPtr<Gdk::Window> win = get_window();
2425
2426                 int x, y, width, height;
2427                 win->get_root_origin(x, y);
2428                 win->get_size(width, height);
2429
2430                 XMLNode* geometry = new XMLNode ("geometry");
2431
2432                 snprintf(buf, sizeof(buf), "%d", width);
2433                 geometry->add_property("x-size", string(buf));
2434                 snprintf(buf, sizeof(buf), "%d", height);
2435                 geometry->add_property("y-size", string(buf));
2436                 snprintf(buf, sizeof(buf), "%d", x);
2437                 geometry->add_property("x-pos", string(buf));
2438                 snprintf(buf, sizeof(buf), "%d", y);
2439                 geometry->add_property("y-pos", string(buf));
2440                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2441                 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2442                 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2443                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2444                 geometry->add_property("edit-vertical-pane-pos", string(buf));
2445
2446                 node->add_child_nocopy (*geometry);
2447         }
2448
2449         maybe_add_mixer_strip_width (*node);
2450
2451         node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2452
2453         snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2454         node->add_property ("zoom", buf);
2455         node->add_property ("snap-to", enum_2_string (_snap_type));
2456         node->add_property ("snap-mode", enum_2_string (_snap_mode));
2457         node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2458         node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2459         node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2460         node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2461         node->add_property ("edit-point", enum_2_string (_edit_point));
2462         snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2463         node->add_property ("visible-track-count", buf);
2464
2465         snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2466         node->add_property ("playhead", buf);
2467         snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2468         node->add_property ("left-frame", buf);
2469         snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2470         node->add_property ("y-origin", buf);
2471
2472         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2473         node->add_property ("maximised", _maximised ? "yes" : "no");
2474         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2475         node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2476         node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2477         node->add_property ("mouse-mode", enum2str(mouse_mode));
2478         node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2479         node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2480
2481         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2482         if (act) {
2483                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2484                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2485         }
2486
2487         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2488         if (act) {
2489                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2490                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2491         }
2492
2493         snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2494         node->add_property (X_("editor-list-page"), buf);
2495
2496         if (button_bindings) {
2497                 XMLNode* bb = new XMLNode (X_("Buttons"));
2498                 button_bindings->save (*bb);
2499                 node->add_child_nocopy (*bb);
2500         }
2501
2502         node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2503
2504         node->add_child_nocopy (selection->get_state ());
2505         node->add_child_nocopy (_regions->get_state ());
2506
2507         snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2508         node->add_property ("nudge-clock-value", buf);
2509
2510         return *node;
2511 }
2512
2513 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2514  *  if @param trackview_relative_offset is false, @param y y is a global canvas *  coordinate, in pixel units
2515  *
2516  *  @return pair: TimeAxisView that y is over, layer index.
2517  *
2518  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2519  *  in stacked or expanded region display mode, otherwise 0.
2520  */
2521 std::pair<TimeAxisView *, double>
2522 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2523 {
2524         if (!trackview_relative_offset) {
2525                 y -= _trackview_group->canvas_origin().y;
2526         }
2527
2528         if (y < 0) {
2529                 return std::make_pair ( (TimeAxisView *) 0, 0);
2530         }
2531
2532         for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2533                         
2534                 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2535                         
2536                 if (r.first) {
2537                         return r;
2538                 }
2539         }
2540
2541         return std::make_pair ( (TimeAxisView *) 0, 0);
2542 }
2543
2544 /** Snap a position to the grid, if appropriate, taking into account current
2545  *  grid settings and also the state of any snap modifier keys that may be pressed.
2546  *  @param start Position to snap.
2547  *  @param event Event to get current key modifier information from, or 0.
2548  */
2549 void
2550 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2551 {
2552         if (!_session || !event) {
2553                 return;
2554         }
2555
2556         if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2557                 if (_snap_mode == SnapOff) {
2558                         snap_to_internal (start, direction, for_mark);
2559                 }
2560         } else {
2561                 if (_snap_mode != SnapOff) {
2562                         snap_to_internal (start, direction, for_mark);
2563                 }
2564         }
2565 }
2566
2567 void
2568 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2569 {
2570         if (!_session || _snap_mode == SnapOff) {
2571                 return;
2572         }
2573
2574         snap_to_internal (start, direction, for_mark);
2575 }
2576
2577 void
2578 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2579 {
2580         const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2581         framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2582
2583         switch (_snap_type) {
2584         case SnapToTimecodeFrame:
2585                 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2586                         start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2587                 } else {
2588                         start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) *  _session->frames_per_timecode_frame());
2589                 }
2590                 break;
2591
2592         case SnapToTimecodeSeconds:
2593                 if (_session->config.get_timecode_offset_negative()) {
2594                         start += _session->config.get_timecode_offset ();
2595                 } else {
2596                         start -= _session->config.get_timecode_offset ();
2597                 }
2598                 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2599                         start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2600                 } else {
2601                         start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2602                 }
2603
2604                 if (_session->config.get_timecode_offset_negative()) {
2605                         start -= _session->config.get_timecode_offset ();
2606                 } else {
2607                         start += _session->config.get_timecode_offset ();
2608                 }
2609                 break;
2610
2611         case SnapToTimecodeMinutes:
2612                 if (_session->config.get_timecode_offset_negative()) {
2613                         start += _session->config.get_timecode_offset ();
2614                 } else {
2615                         start -= _session->config.get_timecode_offset ();
2616                 }
2617                 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2618                         start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2619                 } else {
2620                         start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2621                 }
2622                 if (_session->config.get_timecode_offset_negative()) {
2623                         start -= _session->config.get_timecode_offset ();
2624                 } else {
2625                         start += _session->config.get_timecode_offset ();
2626                 }
2627                 break;
2628         default:
2629                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2630                 /*NOTREACHED*/
2631         }
2632 }
2633
2634 void
2635 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2636 {
2637         const framepos_t one_second = _session->frame_rate();
2638         const framepos_t one_minute = _session->frame_rate() * 60;
2639         framepos_t presnap = start;
2640         framepos_t before;
2641         framepos_t after;
2642
2643         switch (_snap_type) {
2644         case SnapToTimecodeFrame:
2645         case SnapToTimecodeSeconds:
2646         case SnapToTimecodeMinutes:
2647                 return timecode_snap_to_internal (start, direction, for_mark);
2648
2649         case SnapToCDFrame:
2650                 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2651                         start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2652                 } else {
2653                         start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2654                 }
2655                 break;
2656
2657         case SnapToSeconds:
2658                 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2659                         start = (framepos_t) ceil ((double) start / one_second) * one_second;
2660                 } else {
2661                         start = (framepos_t) floor ((double) start / one_second) * one_second;
2662                 }
2663                 break;
2664
2665         case SnapToMinutes:
2666                 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2667                         start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2668                 } else {
2669                         start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2670                 }
2671                 break;
2672
2673         case SnapToBar:
2674                 start = _session->tempo_map().round_to_bar (start, direction);
2675                 break;
2676
2677         case SnapToBeat:
2678                 start = _session->tempo_map().round_to_beat (start, direction);
2679                 break;
2680
2681         case SnapToBeatDiv128:
2682                 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2683                 break;
2684         case SnapToBeatDiv64:
2685                 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2686                 break;
2687         case SnapToBeatDiv32:
2688                 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2689                 break;
2690         case SnapToBeatDiv28:
2691                 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2692                 break;
2693         case SnapToBeatDiv24:
2694                 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2695                 break;
2696         case SnapToBeatDiv20:
2697                 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2698                 break;
2699         case SnapToBeatDiv16:
2700                 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2701                 break;
2702         case SnapToBeatDiv14:
2703                 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2704                 break;
2705         case SnapToBeatDiv12:
2706                 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2707                 break;
2708         case SnapToBeatDiv10:
2709                 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2710                 break;
2711         case SnapToBeatDiv8:
2712                 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2713                 break;
2714         case SnapToBeatDiv7:
2715                 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2716                 break;
2717         case SnapToBeatDiv6:
2718                 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2719                 break;
2720         case SnapToBeatDiv5:
2721                 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2722                 break;
2723         case SnapToBeatDiv4:
2724                 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2725                 break;
2726         case SnapToBeatDiv3:
2727                 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2728                 break;
2729         case SnapToBeatDiv2:
2730                 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2731                 break;
2732
2733         case SnapToMark:
2734                 if (for_mark) {
2735                         return;
2736                 }
2737
2738                 _session->locations()->marks_either_side (start, before, after);
2739
2740                 if (before == max_framepos && after == max_framepos) {
2741                         /* No marks to snap to, so just don't snap */
2742                         return;
2743                 } else if (before == max_framepos) {
2744                         start = after;
2745                 } else if (after == max_framepos) {
2746                         start = before;
2747                 } else if (before != max_framepos && after != max_framepos) {
2748                         /* have before and after */
2749                         if ((start - before) < (after - start)) {
2750                                 start = before;
2751                         } else {
2752                                 start = after;
2753                         }
2754                 }
2755
2756                 break;
2757
2758         case SnapToRegionStart:
2759         case SnapToRegionEnd:
2760         case SnapToRegionSync:
2761         case SnapToRegionBoundary:
2762                 if (!region_boundary_cache.empty()) {
2763
2764                         vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2765                         vector<framepos_t>::iterator next = region_boundary_cache.end ();
2766
2767                         if (direction > 0) {
2768                                 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2769                         } else {
2770                                 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2771                         }
2772
2773                         if (next != region_boundary_cache.begin ()) {
2774                                 prev = next;
2775                                 prev--;
2776                         }
2777
2778                         framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2779                         framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2780
2781                         if (start > (p + n) / 2) {
2782                                 start = n;
2783                         } else {
2784                                 start = p;
2785                         }
2786                 }
2787                 break;
2788         }
2789
2790         switch (_snap_mode) {
2791         case SnapNormal:
2792                 return;
2793
2794         case SnapMagnetic:
2795
2796                 if (presnap > start) {
2797                         if (presnap > (start + pixel_to_sample(snap_threshold))) {
2798                                 start = presnap;
2799                         }
2800
2801                 } else if (presnap < start) {
2802                         if (presnap < (start - pixel_to_sample(snap_threshold))) {
2803                                 start = presnap;
2804                         }
2805                 }
2806
2807         default:
2808                 /* handled at entry */
2809                 return;
2810
2811         }
2812 }
2813
2814
2815 void
2816 Editor::setup_toolbar ()
2817 {
2818         HBox* mode_box = manage(new HBox);
2819         mode_box->set_border_width (2);
2820         mode_box->set_spacing(2);
2821
2822         HBox* mouse_mode_box = manage (new HBox);
2823         HBox* mouse_mode_hbox = manage (new HBox);
2824         VBox* mouse_mode_vbox = manage (new VBox);
2825         Alignment* mouse_mode_align = manage (new Alignment);
2826
2827         Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2828         mouse_mode_size_group->add_widget (smart_mode_button);
2829         mouse_mode_size_group->add_widget (mouse_move_button);
2830         mouse_mode_size_group->add_widget (mouse_cut_button);
2831         mouse_mode_size_group->add_widget (mouse_select_button);
2832         mouse_mode_size_group->add_widget (mouse_gain_button);
2833         mouse_mode_size_group->add_widget (mouse_timefx_button);
2834         mouse_mode_size_group->add_widget (mouse_audition_button);
2835         mouse_mode_size_group->add_widget (mouse_draw_button);
2836         mouse_mode_size_group->add_widget (internal_edit_button);
2837
2838         mouse_mode_size_group->add_widget (zoom_in_button);
2839         mouse_mode_size_group->add_widget (zoom_out_button);
2840         mouse_mode_size_group->add_widget (zoom_preset_selector);
2841         mouse_mode_size_group->add_widget (zoom_out_full_button);
2842         mouse_mode_size_group->add_widget (zoom_focus_selector);
2843
2844         mouse_mode_size_group->add_widget (tav_shrink_button);
2845         mouse_mode_size_group->add_widget (tav_expand_button);
2846         mouse_mode_size_group->add_widget (visible_tracks_selector);
2847
2848         mouse_mode_size_group->add_widget (snap_type_selector);
2849         mouse_mode_size_group->add_widget (snap_mode_selector);
2850
2851         mouse_mode_size_group->add_widget (edit_point_selector);
2852         mouse_mode_size_group->add_widget (edit_mode_selector);
2853
2854         mouse_mode_size_group->add_widget (*nudge_clock);
2855         mouse_mode_size_group->add_widget (nudge_forward_button);
2856         mouse_mode_size_group->add_widget (nudge_backward_button);
2857
2858         mouse_mode_hbox->set_spacing (2);
2859
2860         if (!ARDOUR::Profile->get_trx()) {
2861                 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2862         }
2863
2864         mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2865         mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2866
2867         if (!ARDOUR::Profile->get_mixbus()) {
2868                 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2869         }
2870         
2871         if (!ARDOUR::Profile->get_trx()) {
2872                 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2873                 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2874                 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2875                 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2876                 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2877         }
2878
2879         mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2880
2881         mouse_mode_align->add (*mouse_mode_vbox);
2882         mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2883
2884         mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2885
2886         edit_mode_selector.set_name ("mouse mode button");
2887
2888         if (!ARDOUR::Profile->get_trx()) {
2889                 mode_box->pack_start (edit_mode_selector, false, false);
2890         }
2891         mode_box->pack_start (*mouse_mode_box, false, false);
2892
2893         _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2894         _mouse_mode_tearoff->set_name ("MouseModeBase");
2895         _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2896
2897         if (Profile->get_sae() || Profile->get_mixbus() ) {
2898                 _mouse_mode_tearoff->set_can_be_torn_off (false);
2899         }
2900
2901         _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2902                                                          &_mouse_mode_tearoff->tearoff_window()));
2903         _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2904                                                          &_mouse_mode_tearoff->tearoff_window(), 1));
2905         _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2906                                                          &_mouse_mode_tearoff->tearoff_window()));
2907         _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2908                                                           &_mouse_mode_tearoff->tearoff_window(), 1));
2909
2910         /* Zoom */
2911
2912         _zoom_box.set_spacing (2);
2913         _zoom_box.set_border_width (2);
2914
2915         RefPtr<Action> act;
2916
2917         zoom_preset_selector.set_name ("zoom button");
2918         zoom_preset_selector.set_image(::get_icon ("time_exp"));
2919         zoom_preset_selector.set_size_request (42, -1);
2920
2921         zoom_in_button.set_name ("zoom button");
2922         zoom_in_button.set_image(::get_icon ("zoom_in"));
2923         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2924         zoom_in_button.set_related_action (act);
2925
2926         zoom_out_button.set_name ("zoom button");
2927         zoom_out_button.set_image(::get_icon ("zoom_out"));
2928         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2929         zoom_out_button.set_related_action (act);
2930
2931         zoom_out_full_button.set_name ("zoom button");
2932         zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2933         act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2934         zoom_out_full_button.set_related_action (act);
2935
2936         zoom_focus_selector.set_name ("zoom button");
2937
2938         if (ARDOUR::Profile->get_mixbus()) {
2939                 _zoom_box.pack_start (zoom_preset_selector, false, false);
2940         } else if (ARDOUR::Profile->get_trx()) {
2941                 mode_box->pack_start (zoom_out_button, false, false);
2942                 mode_box->pack_start (zoom_in_button, false, false);
2943         } else {
2944                 _zoom_box.pack_start (zoom_out_button, false, false);
2945                 _zoom_box.pack_start (zoom_in_button, false, false);
2946                 _zoom_box.pack_start (zoom_out_full_button, false, false);
2947                 _zoom_box.pack_start (zoom_focus_selector, false, false);
2948         }
2949
2950         /* Track zoom buttons */
2951         visible_tracks_selector.set_name ("zoom button");
2952         if (Profile->get_mixbus()) {
2953                 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2954                 visible_tracks_selector.set_size_request (42, -1);
2955         } else {
2956                 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2957         }
2958
2959         tav_expand_button.set_name ("zoom button");
2960         tav_expand_button.set_image(::get_icon ("tav_exp"));
2961         act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2962         tav_expand_button.set_related_action (act);
2963
2964         tav_shrink_button.set_name ("zoom button");
2965         tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2966         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2967         tav_shrink_button.set_related_action (act);
2968
2969         if (ARDOUR::Profile->get_mixbus()) {
2970                 _zoom_box.pack_start (visible_tracks_selector);
2971         } else if (ARDOUR::Profile->get_trx()) {
2972                 _zoom_box.pack_start (tav_shrink_button);
2973                 _zoom_box.pack_start (tav_expand_button);
2974         } else {
2975                 _zoom_box.pack_start (visible_tracks_selector);
2976                 _zoom_box.pack_start (tav_shrink_button);
2977                 _zoom_box.pack_start (tav_expand_button);
2978         }
2979
2980         if (!ARDOUR::Profile->get_trx()) {
2981                 _zoom_tearoff = manage (new TearOff (_zoom_box));
2982                 
2983                 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2984                                                            &_zoom_tearoff->tearoff_window()));
2985                 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2986                                                            &_zoom_tearoff->tearoff_window(), 0));
2987                 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2988                                                            &_zoom_tearoff->tearoff_window()));
2989                 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2990                                                             &_zoom_tearoff->tearoff_window(), 0));
2991         } 
2992
2993         if (Profile->get_sae() || Profile->get_mixbus() ) {
2994                 _zoom_tearoff->set_can_be_torn_off (false);
2995         }
2996
2997         snap_box.set_spacing (2);
2998         snap_box.set_border_width (2);
2999
3000         snap_type_selector.set_name ("mouse mode button");
3001
3002         snap_mode_selector.set_name ("mouse mode button");
3003
3004         edit_point_selector.set_name ("mouse mode button");
3005
3006         snap_box.pack_start (snap_mode_selector, false, false);
3007         snap_box.pack_start (snap_type_selector, false, false);
3008         snap_box.pack_start (edit_point_selector, false, false);
3009
3010         /* Nudge */
3011
3012         HBox *nudge_box = manage (new HBox);
3013         nudge_box->set_spacing (2);
3014         nudge_box->set_border_width (2);
3015
3016         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3017         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3018
3019         nudge_box->pack_start (nudge_backward_button, false, false);
3020         nudge_box->pack_start (nudge_forward_button, false, false);
3021         nudge_box->pack_start (*nudge_clock, false, false);
3022
3023
3024         /* Pack everything in... */
3025
3026         HBox* hbox = manage (new HBox);
3027         hbox->set_spacing(2);
3028
3029         _tools_tearoff = manage (new TearOff (*hbox));
3030         _tools_tearoff->set_name ("MouseModeBase");
3031         _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3032
3033         if (Profile->get_sae() || Profile->get_mixbus()) {
3034                 _tools_tearoff->set_can_be_torn_off (false);
3035         }
3036
3037         _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3038                                                     &_tools_tearoff->tearoff_window()));
3039         _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3040                                                     &_tools_tearoff->tearoff_window(), 0));
3041         _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3042                                                     &_tools_tearoff->tearoff_window()));
3043         _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3044                                                      &_tools_tearoff->tearoff_window(), 0));
3045
3046         toolbar_hbox.set_spacing (2);
3047         toolbar_hbox.set_border_width (1);
3048
3049         toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3050         if (!ARDOUR::Profile->get_trx()) {
3051                 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3052                 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3053         }
3054
3055         if (!ARDOUR::Profile->get_trx()) {
3056                 hbox->pack_start (snap_box, false, false);
3057                 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3058                         hbox->pack_start (*nudge_box, false, false);
3059                 } else {
3060                         ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3061                 }
3062         }
3063         hbox->pack_start (panic_box, false, false);
3064
3065         hbox->show_all ();
3066
3067         toolbar_base.set_name ("ToolBarBase");
3068         toolbar_base.add (toolbar_hbox);
3069
3070         _toolbar_viewport.add (toolbar_base);
3071         /* stick to the required height but allow width to vary if there's not enough room */
3072         _toolbar_viewport.set_size_request (1, -1);
3073
3074         toolbar_frame.set_shadow_type (SHADOW_OUT);
3075         toolbar_frame.set_name ("BaseFrame");
3076         toolbar_frame.add (_toolbar_viewport);
3077 }
3078
3079 void
3080 Editor::build_edit_point_menu ()
3081 {
3082         using namespace Menu_Helpers;
3083
3084         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3085         if(!Profile->get_mixbus())
3086                 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3087         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3088
3089         set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3090 }
3091
3092 void
3093 Editor::build_edit_mode_menu ()
3094 {
3095         using namespace Menu_Helpers;
3096         
3097         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3098 //      edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3099         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3100         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
3101
3102         set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3103 }
3104
3105 void
3106 Editor::build_snap_mode_menu ()
3107 {
3108         using namespace Menu_Helpers;
3109
3110         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3111         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3112         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3113
3114         set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3115 }
3116
3117 void
3118 Editor::build_snap_type_menu ()
3119 {
3120         using namespace Menu_Helpers;
3121
3122         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3123         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3124         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3125         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3126         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3127         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3128         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3129         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3130         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3131         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3132         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3133         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3134         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3135         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3136         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3137         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3138         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3139         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3140         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3141         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3142         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3143         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3144         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3145         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3146         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3147         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3148         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3149         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3150         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3151         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3152
3153         set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3154
3155 }
3156
3157 void
3158 Editor::setup_tooltips ()
3159 {
3160         ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3161         ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3162         ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3163         ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3164         ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3165         ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3166         ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3167         ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3168         ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3169         ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3170         ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3171         ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3172         ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3173         ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3174         ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3175         ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3176         ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3177         ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3178         ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3179         ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3180         ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3181         ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3182         ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3183         ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3184         ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3185 }
3186
3187 int
3188 Editor::convert_drop_to_paths (
3189                 vector<string>&                paths,
3190                 const RefPtr<Gdk::DragContext>& /*context*/,
3191                 gint                            /*x*/,
3192                 gint                            /*y*/,
3193                 const SelectionData&            data,
3194                 guint                           /*info*/,
3195                 guint                           /*time*/)
3196 {
3197         if (_session == 0) {
3198                 return -1;
3199         }
3200
3201         vector<string> uris = data.get_uris();
3202
3203         if (uris.empty()) {
3204
3205                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3206                    are actually URI lists. So do it by hand.
3207                 */
3208
3209                 if (data.get_target() != "text/plain") {
3210                         return -1;
3211                 }
3212
3213                 /* Parse the "uri-list" format that Nautilus provides,
3214                    where each pathname is delimited by \r\n.
3215
3216                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3217                 */
3218
3219                 string txt = data.get_text();
3220                 char* p;
3221                 const char* q;
3222
3223                 p = (char *) malloc (txt.length() + 1);
3224                 txt.copy (p, txt.length(), 0);
3225                 p[txt.length()] = '\0';
3226
3227                 while (p)
3228                 {
3229                         if (*p != '#')
3230                         {
3231                                 while (g_ascii_isspace (*p))
3232                                         p++;
3233
3234                                 q = p;
3235                                 while (*q && (*q != '\n') && (*q != '\r')) {
3236                                         q++;
3237                                 }
3238
3239                                 if (q > p)
3240                                 {
3241                                         q--;
3242                                         while (q > p && g_ascii_isspace (*q))
3243                                                 q--;
3244
3245                                         if (q > p)
3246                                         {
3247                                                 uris.push_back (string (p, q - p + 1));
3248                                         }
3249                                 }
3250                         }
3251                         p = strchr (p, '\n');
3252                         if (p)
3253                                 p++;
3254                 }
3255
3256                 free ((void*)p);
3257
3258                 if (uris.empty()) {
3259                         return -1;
3260                 }
3261         }
3262
3263         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3264                 if ((*i).substr (0,7) == "file://") {
3265                         paths.push_back (Glib::filename_from_uri (*i));
3266                 }
3267         }
3268
3269         return 0;
3270 }
3271
3272 void
3273 Editor::new_tempo_section ()
3274 {
3275 }
3276
3277 void
3278 Editor::map_transport_state ()
3279 {
3280         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3281
3282         if (_session && _session->transport_stopped()) {
3283                 have_pending_keyboard_selection = false;
3284         }
3285
3286         update_loop_range_view ();
3287 }
3288
3289 /* UNDO/REDO */
3290
3291 void
3292 Editor::begin_reversible_command (string name)
3293 {
3294         if (_session) {
3295                 _session->begin_reversible_command (name);
3296         }
3297 }
3298
3299 void
3300 Editor::begin_reversible_command (GQuark q)
3301 {
3302         if (_session) {
3303                 _session->begin_reversible_command (q);
3304         }
3305 }
3306
3307 void
3308 Editor::commit_reversible_command ()
3309 {
3310         if (_session) {
3311                 _session->commit_reversible_command ();
3312         }
3313 }
3314
3315 void
3316 Editor::history_changed ()
3317 {
3318         string label;
3319
3320         if (undo_action && _session) {
3321                 if (_session->undo_depth() == 0) {
3322                         label = S_("Command|Undo");
3323                 } else {
3324                         label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3325                 }
3326                 undo_action->property_label() = label;
3327         }
3328
3329         if (redo_action && _session) {
3330                 if (_session->redo_depth() == 0) {
3331                         label = _("Redo");
3332                 } else {
3333                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3334                 }
3335                 redo_action->property_label() = label;
3336         }
3337 }
3338
3339 void
3340 Editor::duplicate_range (bool with_dialog)
3341 {
3342         float times = 1.0f;
3343
3344         RegionSelection rs = get_regions_from_selection_and_entered ();
3345
3346         if ( selection->time.length() == 0 && rs.empty()) {
3347                 return;
3348         }
3349
3350         if (with_dialog) {
3351
3352                 ArdourDialog win (_("Duplicate"));
3353                 Label label (_("Number of duplications:"));
3354                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3355                 SpinButton spinner (adjustment, 0.0, 1);
3356                 HBox hbox;
3357
3358                 win.get_vbox()->set_spacing (12);
3359                 win.get_vbox()->pack_start (hbox);
3360                 hbox.set_border_width (6);
3361                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3362
3363                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3364                    place, visually. so do this by hand.
3365                 */
3366
3367                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3368                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3369                 spinner.grab_focus();
3370
3371                 hbox.show ();
3372                 label.show ();
3373                 spinner.show ();
3374
3375                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3376                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3377                 win.set_default_response (RESPONSE_ACCEPT);
3378
3379                 spinner.grab_focus ();
3380
3381                 switch (win.run ()) {
3382                 case RESPONSE_ACCEPT:
3383                         break;
3384                 default:
3385                         return;
3386                 }
3387
3388                 times = adjustment.get_value();
3389         }
3390
3391         if ((current_mouse_mode() == Editing::MouseRange)) {
3392                 if (selection->time.length()) {
3393                         duplicate_selection (times);
3394                 }
3395         } else if (get_smart_mode()) {
3396                 if (selection->time.length()) {
3397                         duplicate_selection (times);
3398                 } else 
3399                         duplicate_some_regions (rs, times);
3400         } else {
3401                 duplicate_some_regions (rs, times);
3402         }
3403 }
3404
3405 void
3406 Editor::set_edit_mode (EditMode m)
3407 {
3408         Config->set_edit_mode (m);
3409 }
3410
3411 void
3412 Editor::cycle_edit_mode ()
3413 {
3414         switch (Config->get_edit_mode()) {
3415         case Slide:
3416                 if (Profile->get_sae()) {
3417                         Config->set_edit_mode (Lock);
3418                 } else {
3419                         Config->set_edit_mode (Ripple);
3420                 }
3421                 break;
3422         case Splice:
3423         case Ripple:
3424                 Config->set_edit_mode (Lock);
3425                 break;
3426         case Lock:
3427                 Config->set_edit_mode (Slide);
3428                 break;
3429         }
3430 }
3431
3432 void
3433 Editor::edit_mode_selection_done ( EditMode m )
3434 {
3435         Config->set_edit_mode ( m );
3436 }
3437
3438 void
3439 Editor::snap_type_selection_done (SnapType snaptype)
3440 {
3441         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3442         if (ract) {
3443                 ract->set_active ();
3444         }
3445 }
3446
3447 void
3448 Editor::snap_mode_selection_done (SnapMode mode)
3449 {
3450         RefPtr<RadioAction> ract = snap_mode_action (mode);
3451
3452         if (ract) {
3453                 ract->set_active (true);
3454         }
3455 }
3456
3457 void
3458 Editor::cycle_edit_point (bool with_marker)
3459 {
3460         if(Profile->get_mixbus())
3461                 with_marker = false;
3462
3463         switch (_edit_point) {
3464         case EditAtMouse:
3465                 set_edit_point_preference (EditAtPlayhead);
3466                 break;
3467         case EditAtPlayhead:
3468                 if (with_marker) {
3469                         set_edit_point_preference (EditAtSelectedMarker);
3470                 } else {
3471                         set_edit_point_preference (EditAtMouse);
3472                 }
3473                 break;
3474         case EditAtSelectedMarker:
3475                 set_edit_point_preference (EditAtMouse);
3476                 break;
3477         }
3478 }
3479
3480 void
3481 Editor::edit_point_selection_done (EditPoint ep)
3482 {
3483         set_edit_point_preference ( ep );
3484 }
3485
3486 void
3487 Editor::build_zoom_focus_menu ()
3488 {
3489         using namespace Menu_Helpers;
3490
3491         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3492         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3493         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3494         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3495         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3496         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3497
3498         set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3499 }
3500
3501 void
3502 Editor::zoom_focus_selection_done ( ZoomFocus f )
3503 {
3504         RefPtr<RadioAction> ract = zoom_focus_action (f);
3505         if (ract) {
3506                 ract->set_active ();
3507         }
3508 }
3509
3510 void
3511 Editor::build_track_count_menu ()
3512 {
3513         using namespace Menu_Helpers;
3514
3515         if (!Profile->get_mixbus()) {
3516                 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3517                 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3518                 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3519                 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3520                 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3521                 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3522                 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3523                 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3524                 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3525                 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3526                 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3527                 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3528                 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3529         } else {
3530                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3531                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3532                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3533                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3534                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3535                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3536                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3537                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3538                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3539                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3540
3541                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3542                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3543                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3544                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3545                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3546                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3547                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3548                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3549                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3550                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3551                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3552         }
3553 }
3554
3555 void
3556 Editor::set_zoom_preset (int64_t ms)
3557 {
3558         if ( ms <= 0 ) {
3559                 temporal_zoom_session();
3560                 return;
3561         }
3562         
3563         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3564         temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3565 }
3566
3567 void
3568 Editor::set_visible_track_count (int32_t n)
3569 {
3570         _visible_track_count = n;
3571
3572         /* if the canvas hasn't really been allocated any size yet, just
3573            record the desired number of visible tracks and return. when canvas
3574            allocation happens, we will get called again and then we can do the
3575            real work.
3576         */
3577         
3578         if (_visible_canvas_height <= 1) {
3579                 return;
3580         }
3581
3582         int h;
3583         string str;
3584         
3585         if (_visible_track_count > 0) {
3586                 h = trackviews_height() / _visible_track_count;
3587                 std::ostringstream s;
3588                 s << _visible_track_count;
3589                 str = s.str();
3590         } else if (_visible_track_count == 0) {
3591                 uint32_t n = 0;
3592                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3593                         if ((*i)->marked_for_display()) {
3594                                 ++n;
3595                         }
3596                 }
3597                 h = trackviews_height() / n;
3598                 str = _("All");
3599         } else {
3600                 /* negative value means that the visible track count has 
3601                    been overridden by explicit track height changes.
3602                 */
3603                 visible_tracks_selector.set_text (X_("*"));
3604                 return;
3605         }
3606
3607         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3608                 (*i)->set_height (h);
3609         }
3610         
3611         if (str != visible_tracks_selector.get_text()) {
3612                 visible_tracks_selector.set_text (str);
3613         }
3614 }
3615
3616 void
3617 Editor::override_visible_track_count ()
3618 {
3619         _visible_track_count = -1;
3620         visible_tracks_selector.set_text ( _("*") );
3621 }
3622
3623 bool
3624 Editor::edit_controls_button_release (GdkEventButton* ev)
3625 {
3626         if (Keyboard::is_context_menu_event (ev)) {
3627                 ARDOUR_UI::instance()->add_route (this);
3628         } else if (ev->button == 1) {
3629                 selection->clear_tracks ();
3630         }
3631
3632         return true;
3633 }
3634
3635 bool
3636 Editor::mouse_select_button_release (GdkEventButton* ev)
3637 {
3638         /* this handles just right-clicks */
3639
3640         if (ev->button != 3) {
3641                 return false;
3642         }
3643
3644         return true;
3645 }
3646
3647 void
3648 Editor::set_zoom_focus (ZoomFocus f)
3649 {
3650         string str = zoom_focus_strings[(int)f];
3651
3652         if (str != zoom_focus_selector.get_text()) {
3653                 zoom_focus_selector.set_text (str);
3654         }
3655
3656         if (zoom_focus != f) {
3657                 zoom_focus = f;
3658                 instant_save ();
3659         }
3660 }
3661
3662 void
3663 Editor::cycle_zoom_focus ()
3664 {
3665         switch (zoom_focus) {
3666         case ZoomFocusLeft:
3667                 set_zoom_focus (ZoomFocusRight);
3668                 break;
3669         case ZoomFocusRight:
3670                 set_zoom_focus (ZoomFocusCenter);
3671                 break;
3672         case ZoomFocusCenter:
3673                 set_zoom_focus (ZoomFocusPlayhead);
3674                 break;
3675         case ZoomFocusPlayhead:
3676                 set_zoom_focus (ZoomFocusMouse);
3677                 break;
3678         case ZoomFocusMouse:
3679                 set_zoom_focus (ZoomFocusEdit);
3680                 break;
3681         case ZoomFocusEdit:
3682                 set_zoom_focus (ZoomFocusLeft);
3683                 break;
3684         }
3685 }
3686
3687 void
3688 Editor::ensure_float (Window& win)
3689 {
3690         win.set_transient_for (*this);
3691 }
3692
3693 void
3694 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3695 {
3696         /* recover or initialize pane positions. do this here rather than earlier because
3697            we don't want the positions to change the child allocations, which they seem to do.
3698          */
3699
3700         int pos;
3701         XMLProperty* prop;
3702         char buf[32];
3703         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3704
3705         enum Pane {
3706                 Horizontal = 0x1,
3707                 Vertical = 0x2
3708         };
3709
3710         static Pane done;
3711
3712         XMLNode* geometry = find_named_node (*node, "geometry");
3713
3714         if (which == static_cast<Paned*> (&edit_pane)) {
3715
3716                 if (done & Horizontal) {
3717                         return;
3718                 }
3719
3720                 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3721                         _notebook_shrunk = string_is_affirmative (prop->value ());
3722                 }
3723
3724                 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3725                         /* initial allocation is 90% to canvas, 10% to notebook */
3726                         pos = (int) floor (alloc.get_width() * 0.90f);
3727                         snprintf (buf, sizeof(buf), "%d", pos);
3728                 } else {
3729                         pos = atoi (prop->value());
3730                 }
3731
3732                 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3733                         edit_pane.set_position (pos);
3734                 }
3735
3736                 done = (Pane) (done | Horizontal);
3737
3738         } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3739
3740                 if (done & Vertical) {
3741                         return;
3742                 }
3743
3744                 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3745                         /* initial allocation is 90% to canvas, 10% to summary */
3746                         pos = (int) floor (alloc.get_height() * 0.90f);
3747                         snprintf (buf, sizeof(buf), "%d", pos);
3748                 } else {
3749
3750                         pos = atoi (prop->value());
3751                 }
3752
3753                 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3754                         editor_summary_pane.set_position (pos);
3755                 }
3756
3757                 done = (Pane) (done | Vertical);
3758         }
3759 }
3760
3761 void
3762 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3763 {
3764         if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) && 
3765             (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) && 
3766             (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3767                 top_hbox.remove (toolbar_frame);
3768         }
3769 }
3770
3771 void
3772 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3773 {
3774         if (toolbar_frame.get_parent() == 0) {
3775                 top_hbox.pack_end (toolbar_frame);
3776         }
3777 }
3778
3779 void
3780 Editor::set_show_measures (bool yn)
3781 {
3782         if (_show_measures != yn) {
3783                 hide_measures ();
3784
3785                 if ((_show_measures = yn) == true) {
3786                         if (tempo_lines) {
3787                                 tempo_lines->show();
3788                         }
3789
3790                         ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3791                         ARDOUR::TempoMap::BBTPointList::const_iterator end;
3792                         
3793                         compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3794                         draw_measures (begin, end);
3795                 } 
3796
3797                 instant_save ();
3798         }
3799 }
3800
3801 void
3802 Editor::toggle_follow_playhead ()
3803 {
3804         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3805         if (act) {
3806                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3807                 set_follow_playhead (tact->get_active());
3808         }
3809 }
3810
3811 /** @param yn true to follow playhead, otherwise false.
3812  *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3813  */
3814 void
3815 Editor::set_follow_playhead (bool yn, bool catch_up)
3816 {
3817         if (_follow_playhead != yn) {
3818                 if ((_follow_playhead = yn) == true && catch_up) {
3819                         /* catch up */
3820                         reset_x_origin_to_follow_playhead ();
3821                 }
3822                 instant_save ();
3823         }
3824 }
3825
3826 void
3827 Editor::toggle_stationary_playhead ()
3828 {
3829         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3830         if (act) {
3831                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3832                 set_stationary_playhead (tact->get_active());
3833         }
3834 }
3835
3836 void
3837 Editor::set_stationary_playhead (bool yn)
3838 {
3839         if (_stationary_playhead != yn) {
3840                 if ((_stationary_playhead = yn) == true) {
3841                         /* catch up */
3842                         // FIXME need a 3.0 equivalent of this 2.X call
3843                         // update_current_screen ();
3844                 }
3845                 instant_save ();
3846         }
3847 }
3848
3849 PlaylistSelector&
3850 Editor::playlist_selector () const
3851 {
3852         return *_playlist_selector;
3853 }
3854
3855 Evoral::MusicalTime
3856 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3857 {
3858         success = true;
3859
3860         switch (_snap_type) {
3861         case SnapToBeat:
3862                 return 1.0;
3863                 break;
3864
3865         case SnapToBeatDiv128:
3866                 return 1.0/128.0;
3867                 break;
3868         case SnapToBeatDiv64:
3869                 return 1.0/64.0;
3870                 break;
3871         case SnapToBeatDiv32:
3872                 return 1.0/32.0;
3873                 break;
3874         case SnapToBeatDiv28:
3875                 return 1.0/28.0;
3876                 break;
3877         case SnapToBeatDiv24:
3878                 return 1.0/24.0;
3879                 break;
3880         case SnapToBeatDiv20:
3881                 return 1.0/20.0;
3882                 break;
3883         case SnapToBeatDiv16:
3884                 return 1.0/16.0;
3885                 break;
3886         case SnapToBeatDiv14:
3887                 return 1.0/14.0;
3888                 break;
3889         case SnapToBeatDiv12:
3890                 return 1.0/12.0;
3891                 break;
3892         case SnapToBeatDiv10:
3893                 return 1.0/10.0;
3894                 break;
3895         case SnapToBeatDiv8:
3896                 return 1.0/8.0;
3897                 break;
3898         case SnapToBeatDiv7:
3899                 return 1.0/7.0;
3900                 break;
3901         case SnapToBeatDiv6:
3902                 return 1.0/6.0;
3903                 break;
3904         case SnapToBeatDiv5:
3905                 return 1.0/5.0;
3906                 break;
3907         case SnapToBeatDiv4:
3908                 return 1.0/4.0;
3909                 break;
3910         case SnapToBeatDiv3:
3911                 return 1.0/3.0;
3912                 break;
3913         case SnapToBeatDiv2:
3914                 return 1.0/2.0;
3915                 break;
3916
3917         case SnapToBar:
3918                 if (_session) {
3919                         return _session->tempo_map().meter_at (position).divisions_per_bar();
3920                 }
3921                 break;
3922
3923         case SnapToCDFrame:
3924         case SnapToTimecodeFrame:
3925         case SnapToTimecodeSeconds:
3926         case SnapToTimecodeMinutes:
3927         case SnapToSeconds:
3928         case SnapToMinutes:
3929         case SnapToRegionStart:
3930         case SnapToRegionEnd:
3931         case SnapToRegionSync:
3932         case SnapToRegionBoundary:
3933         default:
3934                 success = false;
3935                 break;
3936         }
3937
3938         return 0.0;
3939 }
3940
3941 framecnt_t
3942 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3943 {
3944         framecnt_t ret;
3945
3946         ret = nudge_clock->current_duration (pos);
3947         next = ret + 1; /* XXXX fix me */
3948
3949         return ret;
3950 }
3951
3952 int
3953 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3954 {
3955         ArdourDialog dialog (_("Playlist Deletion"));
3956         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
3957                                         "If it is kept, its audio files will not be cleaned.\n"
3958                                         "If it is deleted, audio files used by it alone will be cleaned."),
3959                                       pl->name()));
3960
3961         dialog.set_position (WIN_POS_CENTER);
3962         dialog.get_vbox()->pack_start (label);
3963
3964         label.show ();
3965
3966         dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3967         dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3968         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3969
3970         switch (dialog.run ()) {
3971         case RESPONSE_ACCEPT:
3972                 /* delete the playlist */
3973                 return 0;
3974                 break;
3975
3976         case RESPONSE_REJECT:
3977                 /* keep the playlist */
3978                 return 1;
3979                 break;
3980
3981         default:
3982                 break;
3983         }
3984
3985         return -1;
3986 }
3987
3988 bool
3989 Editor::audio_region_selection_covers (framepos_t where)
3990 {
3991         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3992                 if ((*a)->region()->covers (where)) {
3993                         return true;
3994                 }
3995         }
3996
3997         return false;
3998 }
3999
4000 void
4001 Editor::prepare_for_cleanup ()
4002 {
4003         cut_buffer->clear_regions ();
4004         cut_buffer->clear_playlists ();
4005
4006         selection->clear_regions ();
4007         selection->clear_playlists ();
4008
4009         _regions->suspend_redisplay ();
4010 }
4011
4012 void
4013 Editor::finish_cleanup ()
4014 {
4015         _regions->resume_redisplay ();
4016 }
4017
4018 Location*
4019 Editor::transport_loop_location()
4020 {
4021         if (_session) {
4022                 return _session->locations()->auto_loop_location();
4023         } else {
4024                 return 0;
4025         }
4026 }
4027
4028 Location*
4029 Editor::transport_punch_location()
4030 {
4031         if (_session) {
4032                 return _session->locations()->auto_punch_location();
4033         } else {
4034                 return 0;
4035         }
4036 }
4037
4038 bool
4039 Editor::control_layout_scroll (GdkEventScroll* ev)
4040 {
4041         /* Just forward to the normal canvas scroll method. The coordinate
4042            systems are different but since the canvas is always larger than the
4043            track headers, and aligned with the trackview area, this will work.
4044
4045            In the not too distant future this layout is going away anyway and
4046            headers will be on the canvas.
4047         */
4048         return canvas_scroll_event (ev, false);
4049 }
4050
4051 void
4052 Editor::session_state_saved (string)
4053 {
4054         update_title ();
4055         _snapshots->redisplay ();
4056 }
4057
4058 void
4059 Editor::update_tearoff_visibility()
4060 {
4061         bool visible = Config->get_keep_tearoffs();
4062         _mouse_mode_tearoff->set_visible (visible);
4063         _tools_tearoff->set_visible (visible);
4064         if (_zoom_tearoff) {
4065                 _zoom_tearoff->set_visible (visible);
4066         }
4067 }
4068
4069 void
4070 Editor::reattach_all_tearoffs ()
4071 {
4072         if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4073         if (_tools_tearoff) _tools_tearoff->put_it_back ();
4074         if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4075 }
4076
4077 void
4078 Editor::maximise_editing_space ()
4079 {
4080         if (_maximised) {
4081                 return;
4082         }
4083
4084         fullscreen ();
4085
4086         _maximised = true;
4087 }
4088
4089 void
4090 Editor::restore_editing_space ()
4091 {
4092         if (!_maximised) {
4093                 return;
4094         }
4095
4096         unfullscreen();
4097
4098         _maximised = false;
4099 }
4100
4101 /**
4102  *  Make new playlists for a given track and also any others that belong
4103  *  to the same active route group with the `select' property.
4104  *  @param v Track.
4105  */
4106
4107 void
4108 Editor::new_playlists (TimeAxisView* v)
4109 {
4110         begin_reversible_command (_("new playlists"));
4111         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4112         _session->playlists->get (playlists);
4113         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4114         commit_reversible_command ();
4115 }
4116
4117 /**
4118  *  Use a copy of the current playlist for a given track and also any others that belong
4119  *  to the same active route group with the `select' property.
4120  *  @param v Track.
4121  */
4122
4123 void
4124 Editor::copy_playlists (TimeAxisView* v)
4125 {
4126         begin_reversible_command (_("copy playlists"));
4127         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4128         _session->playlists->get (playlists);
4129         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4130         commit_reversible_command ();
4131 }
4132
4133 /** Clear the current playlist for a given track and also any others that belong
4134  *  to the same active route group with the `select' property.
4135  *  @param v Track.
4136  */
4137
4138 void
4139 Editor::clear_playlists (TimeAxisView* v)
4140 {
4141         begin_reversible_command (_("clear playlists"));
4142         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4143         _session->playlists->get (playlists);
4144         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4145         commit_reversible_command ();
4146 }
4147
4148 void
4149 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4150 {
4151         atv.use_new_playlist (sz > 1 ? false : true, playlists);
4152 }
4153
4154 void
4155 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4156 {
4157         atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4158 }
4159
4160 void
4161 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4162 {
4163         atv.clear_playlist ();
4164 }
4165
4166 bool
4167 Editor::on_key_press_event (GdkEventKey* ev)
4168 {
4169         return key_press_focus_accelerator_handler (*this, ev);
4170 }
4171
4172 bool
4173 Editor::on_key_release_event (GdkEventKey* ev)
4174 {
4175         return Gtk::Window::on_key_release_event (ev);
4176         // return key_press_focus_accelerator_handler (*this, ev);
4177 }
4178
4179 /** Queue up a change to the viewport x origin.
4180  *  @param frame New x origin.
4181  */
4182 void
4183 Editor::reset_x_origin (framepos_t frame)
4184 {
4185         pending_visual_change.add (VisualChange::TimeOrigin);
4186         pending_visual_change.time_origin = frame;
4187         ensure_visual_change_idle_handler ();
4188 }
4189
4190 void
4191 Editor::reset_y_origin (double y)
4192 {
4193         pending_visual_change.add (VisualChange::YOrigin);
4194         pending_visual_change.y_origin = y;
4195         ensure_visual_change_idle_handler ();
4196 }
4197
4198 void
4199 Editor::reset_zoom (framecnt_t spp)
4200 {
4201         if (spp == samples_per_pixel) {
4202                 return;
4203         }
4204
4205         pending_visual_change.add (VisualChange::ZoomLevel);
4206         pending_visual_change.samples_per_pixel = spp;
4207         ensure_visual_change_idle_handler ();
4208 }
4209
4210 void
4211 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4212 {
4213         reset_x_origin (frame);
4214         reset_zoom (fpu);
4215
4216         if (!no_save_visual) {
4217                 undo_visual_stack.push_back (current_visual_state(false));
4218         }
4219 }
4220
4221 Editor::VisualState::VisualState (bool with_tracks)
4222         : gui_state (with_tracks ? new GUIObjectState : 0)
4223 {
4224 }
4225
4226 Editor::VisualState::~VisualState ()
4227 {
4228         delete gui_state;
4229 }
4230
4231 Editor::VisualState*
4232 Editor::current_visual_state (bool with_tracks)
4233 {
4234         VisualState* vs = new VisualState (with_tracks);
4235         vs->y_position = vertical_adjustment.get_value();
4236         vs->samples_per_pixel = samples_per_pixel;
4237         vs->leftmost_frame = leftmost_frame;
4238         vs->zoom_focus = zoom_focus;
4239
4240         if (with_tracks) {      
4241                 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4242         }
4243
4244         return vs;
4245 }
4246
4247 void
4248 Editor::undo_visual_state ()
4249 {
4250         if (undo_visual_stack.empty()) {
4251                 return;
4252         }
4253
4254         VisualState* vs = undo_visual_stack.back();
4255         undo_visual_stack.pop_back();
4256
4257
4258         redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4259
4260         use_visual_state (*vs);
4261 }
4262
4263 void
4264 Editor::redo_visual_state ()
4265 {
4266         if (redo_visual_stack.empty()) {
4267                 return;
4268         }
4269
4270         VisualState* vs = redo_visual_stack.back();
4271         redo_visual_stack.pop_back();
4272
4273         undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4274
4275         use_visual_state (*vs);
4276 }
4277
4278 void
4279 Editor::swap_visual_state ()
4280 {
4281         if (undo_visual_stack.empty()) {
4282                 redo_visual_state ();
4283         } else {
4284                 undo_visual_state ();
4285         }
4286 }
4287
4288 void
4289 Editor::use_visual_state (VisualState& vs)
4290 {
4291         PBD::Unwinder<bool> nsv (no_save_visual, true);
4292         DisplaySuspender ds;
4293
4294         vertical_adjustment.set_value (vs.y_position);
4295
4296         set_zoom_focus (vs.zoom_focus);
4297         reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4298         
4299         if (vs.gui_state) {
4300                 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4301                 
4302                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {    
4303                         (*i)->reset_visual_state ();
4304                 }
4305         }
4306
4307         _routes->update_visibility ();
4308 }
4309
4310 /** This is the core function that controls the zoom level of the canvas. It is called
4311  *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
4312  *  @param spp new number of samples per pixel
4313  */
4314 void
4315 Editor::set_samples_per_pixel (framecnt_t spp)
4316 {
4317         if (spp < 1) {
4318                 return;
4319         }
4320
4321         const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4322         const framecnt_t lots_of_pixels = 4000;
4323
4324         /* if the zoom level is greater than what you'd get trying to display 3
4325          * days of audio on a really big screen, then it's too big.
4326          */
4327
4328         if (spp * lots_of_pixels > three_days) {
4329                 return;
4330         }
4331
4332         samples_per_pixel = spp;
4333
4334         if (tempo_lines) {
4335                 tempo_lines->tempo_map_changed();
4336         }
4337
4338         bool const showing_time_selection = selection->time.length() > 0;
4339
4340         if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4341                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4342                         (*i)->reshow_selection (selection->time);
4343                 }
4344         }
4345
4346         ZoomChanged (); /* EMIT_SIGNAL */
4347
4348         ArdourCanvas::GtkCanvasViewport* c;
4349
4350         c = get_track_canvas();
4351         if (c) {
4352                 c->canvas()->zoomed ();
4353         }
4354
4355         if (playhead_cursor) {
4356                 playhead_cursor->set_position (playhead_cursor->current_frame ());
4357         }
4358
4359         refresh_location_display();
4360         _summary->set_overlays_dirty ();
4361
4362         update_marker_labels ();
4363
4364         instant_save ();
4365 }
4366
4367 void
4368 Editor::queue_visual_videotimeline_update ()
4369 {
4370         /* TODO:
4371          * pending_visual_change.add (VisualChange::VideoTimeline);
4372          * or maybe even more specific: which videotimeline-image
4373          * currently it calls update_video_timeline() to update
4374          * _all outdated_ images on the video-timeline.
4375          * see 'exposeimg()' in video_image_frame.cc
4376          */
4377         ensure_visual_change_idle_handler ();
4378 }
4379
4380 void
4381 Editor::ensure_visual_change_idle_handler ()
4382 {
4383         if (pending_visual_change.idle_handler_id < 0) {
4384                 // see comment in add_to_idle_resize above.
4385                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 20, _idle_visual_changer, this, NULL);
4386                 pending_visual_change.being_handled = false;
4387         }
4388 }
4389
4390 int
4391 Editor::_idle_visual_changer (void* arg)
4392 {
4393         return static_cast<Editor*>(arg)->idle_visual_changer ();
4394 }
4395
4396 int
4397 Editor::idle_visual_changer ()
4398 {
4399         /* set_horizontal_position() below (and maybe other calls) call
4400            gtk_main_iteration(), so it's possible that a signal will be handled
4401            half-way through this method.  If this signal wants an
4402            idle_visual_changer we must schedule another one after this one, so
4403            mark the idle_handler_id as -1 here to allow that.  Also make a note
4404            that we are doing the visual change, so that changes in response to
4405            super-rapid-screen-update can be dropped if we are still processing
4406            the last one.
4407         */
4408
4409         pending_visual_change.idle_handler_id = -1;
4410         pending_visual_change.being_handled = true;
4411         
4412         VisualChange vc = pending_visual_change;
4413
4414         pending_visual_change.pending = (VisualChange::Type) 0;
4415
4416         visual_changer (vc);
4417
4418         pending_visual_change.being_handled = false;
4419
4420         return 0; /* this is always a one-shot call */
4421 }
4422
4423 void
4424 Editor::visual_changer (const VisualChange& vc)
4425 {
4426         double const last_time_origin = horizontal_position ();
4427
4428         if (vc.pending & VisualChange::ZoomLevel) {
4429                 set_samples_per_pixel (vc.samples_per_pixel);
4430
4431                 compute_fixed_ruler_scale ();
4432
4433                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4434                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4435                 
4436                 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4437                                             current_bbt_points_begin, current_bbt_points_end);
4438                 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4439                                          current_bbt_points_begin, current_bbt_points_end);
4440                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4441
4442                 update_video_timeline();
4443         }
4444
4445         if (vc.pending & VisualChange::TimeOrigin) {
4446                 set_horizontal_position (vc.time_origin / samples_per_pixel);
4447         }
4448
4449         if (vc.pending & VisualChange::YOrigin) {
4450                 vertical_adjustment.set_value (vc.y_origin);
4451         }
4452
4453         if (last_time_origin == horizontal_position ()) {
4454                 /* changed signal not emitted */
4455                 update_fixed_rulers ();
4456                 redisplay_tempo (true);
4457         }
4458
4459         if (!(vc.pending & VisualChange::ZoomLevel)) {
4460                 update_video_timeline();
4461         }
4462
4463         _summary->set_overlays_dirty ();
4464 }
4465
4466 struct EditorOrderTimeAxisSorter {
4467     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4468             return a->order () < b->order ();
4469     }
4470 };
4471
4472 void
4473 Editor::sort_track_selection (TrackViewList& sel)
4474 {
4475         EditorOrderTimeAxisSorter cmp;
4476         sel.sort (cmp);
4477 }
4478
4479 framepos_t
4480 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4481 {
4482         bool ignored;
4483         framepos_t where = 0;
4484         EditPoint ep = _edit_point;
4485
4486         if(Profile->get_mixbus())
4487                 if (ep == EditAtSelectedMarker)
4488                         ep=EditAtPlayhead;
4489                 
4490         if (from_context_menu && (ep == EditAtMouse)) {
4491                 return  canvas_event_sample (&context_click_event, 0, 0);
4492         }
4493
4494         if (entered_marker) {
4495                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4496                 return entered_marker->position();
4497         }
4498
4499         if (ignore_playhead && ep == EditAtPlayhead) {
4500                 ep = EditAtSelectedMarker;
4501         }
4502
4503         switch (ep) {
4504         case EditAtPlayhead:
4505                 where = _session->audible_frame();
4506                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4507                 break;
4508
4509         case EditAtSelectedMarker:
4510                 if (!selection->markers.empty()) {
4511                         bool is_start;
4512                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4513                         if (loc) {
4514                                 if (is_start) {
4515                                         where =  loc->start();
4516                                 } else {
4517                                         where = loc->end();
4518                                 }
4519                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4520                                 break;
4521                         }
4522                 }
4523                 /* fallthru */
4524
4525         default:
4526         case EditAtMouse:
4527                 if (!mouse_frame (where, ignored)) {
4528                         /* XXX not right but what can we do ? */
4529                         return 0;
4530                 }
4531                 snap_to (where);
4532                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4533                 break;
4534         }
4535
4536         return where;
4537 }
4538
4539 void
4540 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4541 {
4542         if (!_session) return;
4543
4544         begin_reversible_command (cmd);
4545
4546         Location* tll;
4547
4548         if ((tll = transport_loop_location()) == 0) {
4549                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4550                 XMLNode &before = _session->locations()->get_state();
4551                 _session->locations()->add (loc, true);
4552                 _session->set_auto_loop_location (loc);
4553                 XMLNode &after = _session->locations()->get_state();
4554                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4555         } else {
4556                 XMLNode &before = tll->get_state();
4557                 tll->set_hidden (false, this);
4558                 tll->set (start, end);
4559                 XMLNode &after = tll->get_state();
4560                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4561         }
4562
4563         commit_reversible_command ();
4564 }
4565
4566 void
4567 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4568 {
4569         if (!_session) return;
4570
4571         begin_reversible_command (cmd);
4572
4573         Location* tpl;
4574
4575         if ((tpl = transport_punch_location()) == 0) {
4576                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
4577                 XMLNode &before = _session->locations()->get_state();
4578                 _session->locations()->add (loc, true);
4579                 _session->set_auto_punch_location (loc);
4580                 XMLNode &after = _session->locations()->get_state();
4581                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4582         }
4583         else {
4584                 XMLNode &before = tpl->get_state();
4585                 tpl->set_hidden (false, this);
4586                 tpl->set (start, end);
4587                 XMLNode &after = tpl->get_state();
4588                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4589         }
4590
4591         commit_reversible_command ();
4592 }
4593
4594 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4595  *  @param rs List to which found regions are added.
4596  *  @param where Time to look at.
4597  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4598  */
4599 void
4600 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4601 {
4602         const TrackViewList* tracks;
4603
4604         if (ts.empty()) {
4605                 tracks = &track_views;
4606         } else {
4607                 tracks = &ts;
4608         }
4609
4610         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4611
4612                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4613
4614                 if (rtv) {
4615                         boost::shared_ptr<Track> tr;
4616                         boost::shared_ptr<Playlist> pl;
4617
4618                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4619
4620                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4621                                                 (framepos_t) floor ( (double) where * tr->speed()));
4622
4623                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4624                                         RegionView* rv = rtv->view()->find_view (*i);
4625                                         if (rv) {
4626                                                 rs.add (rv);
4627                                         }
4628                                 }
4629                         }
4630                 }
4631         }
4632 }
4633
4634 void
4635 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4636 {
4637         const TrackViewList* tracks;
4638
4639         if (ts.empty()) {
4640                 tracks = &track_views;
4641         } else {
4642                 tracks = &ts;
4643         }
4644
4645         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4646                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4647                 if (rtv) {
4648                         boost::shared_ptr<Track> tr;
4649                         boost::shared_ptr<Playlist> pl;
4650
4651                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4652
4653                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4654                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4655
4656                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4657
4658                                         RegionView* rv = rtv->view()->find_view (*i);
4659
4660                                         if (rv) {
4661                                                 rs.add (rv);
4662                                         }
4663                                 }
4664                         }
4665                 }
4666         }
4667 }
4668
4669 /** Get regions using the following method:
4670  *
4671  *  Make a region list using:
4672  *   (a) any selected regions
4673  *   (b) the intersection of any selected tracks and the edit point(*)
4674  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4675  *
4676  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4677  *
4678  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4679  */
4680
4681 RegionSelection
4682 Editor::get_regions_from_selection_and_edit_point ()
4683 {
4684         RegionSelection regions;
4685
4686         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4687                 regions.add (entered_regionview);
4688         } else {
4689                 regions = selection->regions;
4690         }
4691
4692         if ( regions.empty() ) {
4693                 TrackViewList tracks = selection->tracks;
4694
4695                 if (!tracks.empty()) {
4696                         /* no region selected or entered, but some selected tracks:
4697                          * act on all regions on the selected tracks at the edit point
4698                          */ 
4699                         framepos_t const where = get_preferred_edit_position ();
4700                         get_regions_at(regions, where, tracks);
4701                 }
4702         }
4703
4704         return regions;
4705 }
4706
4707 /** Get regions using the following method:
4708  *
4709  *  Make a region list using:
4710  *   (a) any selected regions
4711  *   (b) the intersection of any selected tracks and the edit point(*)
4712  *   (c) if neither exists, then whatever region is under the mouse
4713  *
4714  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4715  *
4716  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4717  */
4718 RegionSelection
4719 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4720 {
4721         RegionSelection regions;
4722
4723         if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4724                 regions.add (entered_regionview);
4725         } else {
4726                 regions = selection->regions;
4727         }
4728
4729         if ( regions.empty() ) {
4730                 TrackViewList tracks = selection->tracks;
4731
4732                 if (!tracks.empty()) {
4733                         /* no region selected or entered, but some selected tracks:
4734                          * act on all regions on the selected tracks at the edit point
4735                          */ 
4736                         get_regions_at(regions, pos, tracks);
4737                 }
4738         }
4739
4740         return regions;
4741 }
4742
4743 /** Start with regions that are selected, or the entered regionview if none are selected.
4744  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4745  *  of the regions that we started with.
4746  */
4747
4748 RegionSelection
4749 Editor::get_regions_from_selection_and_entered ()
4750 {
4751         RegionSelection regions = selection->regions;
4752
4753         if (regions.empty() && entered_regionview) {
4754                 regions.add (entered_regionview);
4755         }
4756
4757         return regions;
4758 }
4759
4760 void
4761 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4762 {
4763         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4764
4765                 RouteTimeAxisView* tatv;
4766
4767                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4768
4769                         boost::shared_ptr<Playlist> pl;
4770                         vector<boost::shared_ptr<Region> > results;
4771                         RegionView* marv;
4772                         boost::shared_ptr<Track> tr;
4773
4774                         if ((tr = tatv->track()) == 0) {
4775                                 /* bus */
4776                                 continue;
4777                         }
4778
4779                         if ((pl = (tr->playlist())) != 0) {
4780                                 if (src_comparison) {
4781                                         pl->get_source_equivalent_regions (region, results);
4782                                 } else {
4783                                         pl->get_region_list_equivalent_regions (region, results);
4784                                 }
4785                         }
4786
4787                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4788                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4789                                         regions.push_back (marv);
4790                                 }
4791                         }
4792
4793                 }
4794         }
4795 }
4796
4797 void
4798 Editor::show_rhythm_ferret ()
4799 {
4800         if (rhythm_ferret == 0) {
4801                 rhythm_ferret = new RhythmFerret(*this);
4802         }
4803
4804         rhythm_ferret->set_session (_session);
4805         rhythm_ferret->show ();
4806         rhythm_ferret->present ();
4807 }
4808
4809 void
4810 Editor::first_idle ()
4811 {
4812         MessageDialog* dialog = 0;
4813         
4814         if (track_views.size() > 1) {
4815                 dialog = new MessageDialog (
4816                         *this,
4817                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4818                         true
4819                         );
4820                 dialog->present ();
4821                 ARDOUR_UI::instance()->flush_pending ();
4822         }
4823
4824         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4825                 (*t)->first_idle();
4826         }
4827
4828         // first idle adds route children (automation tracks), so we need to redisplay here
4829         _routes->redisplay ();
4830
4831         delete dialog;
4832         _have_idled = true;
4833 }
4834
4835 gboolean
4836 Editor::_idle_resize (gpointer arg)
4837 {
4838         return ((Editor*)arg)->idle_resize ();
4839 }
4840
4841 void
4842 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4843 {
4844         if (resize_idle_id < 0) {
4845                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4846                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4847                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4848                  */
4849                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4850                 _pending_resize_amount = 0;
4851         }
4852
4853         /* make a note of the smallest resulting height, so that we can clamp the
4854            lower limit at TimeAxisView::hSmall */
4855
4856         int32_t min_resulting = INT32_MAX;
4857
4858         _pending_resize_amount += h;
4859         _pending_resize_view = view;
4860
4861         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4862
4863         if (selection->tracks.contains (_pending_resize_view)) {
4864                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4865                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4866                 }
4867         }
4868
4869         if (min_resulting < 0) {
4870                 min_resulting = 0;
4871         }
4872
4873         /* clamp */
4874         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4875                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4876         }
4877 }
4878
4879 /** Handle pending resizing of tracks */
4880 bool
4881 Editor::idle_resize ()
4882 {
4883         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4884
4885         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4886             selection->tracks.contains (_pending_resize_view)) {
4887
4888                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4889                         if (*i != _pending_resize_view) {
4890                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4891                         }
4892                 }
4893         }
4894
4895         _pending_resize_amount = 0;
4896         _group_tabs->set_dirty ();
4897         resize_idle_id = -1;
4898
4899         return false;
4900 }
4901
4902 void
4903 Editor::located ()
4904 {
4905         ENSURE_GUI_THREAD (*this, &Editor::located);
4906
4907         if (_session) {
4908                 playhead_cursor->set_position (_session->audible_frame ());
4909                 if (_follow_playhead && !_pending_initial_locate) {
4910                         reset_x_origin_to_follow_playhead ();
4911                 }
4912         }
4913
4914         _pending_locate_request = false;
4915         _pending_initial_locate = false;
4916 }
4917
4918 void
4919 Editor::region_view_added (RegionView *)
4920 {
4921         _summary->set_background_dirty ();
4922 }
4923
4924 void
4925 Editor::region_view_removed ()
4926 {
4927         _summary->set_background_dirty ();
4928 }
4929
4930 RouteTimeAxisView*
4931 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4932 {
4933         TrackViewList::const_iterator j = track_views.begin ();
4934         while (j != track_views.end()) {
4935                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4936                 if (rtv && rtv->route() == r) {
4937                         return rtv;
4938                 }
4939                 ++j;
4940         }
4941
4942         return 0;
4943 }
4944
4945
4946 TrackViewList
4947 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4948 {
4949         TrackViewList t;
4950
4951         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4952                 TimeAxisView* tv = axis_view_from_route (*i);
4953                 if (tv) {
4954                         t.push_back (tv);
4955                 }
4956         }
4957
4958         return t;
4959 }
4960
4961 void
4962 Editor::suspend_route_redisplay ()
4963 {
4964         if (_routes) {
4965                 _routes->suspend_redisplay();
4966         }
4967 }
4968
4969 void
4970 Editor::resume_route_redisplay ()
4971 {
4972         if (_routes) {
4973                 _routes->resume_redisplay();
4974         }
4975 }
4976
4977 void
4978 Editor::add_routes (RouteList& routes)
4979 {
4980         ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4981
4982         RouteTimeAxisView *rtv;
4983         list<RouteTimeAxisView*> new_views;
4984
4985         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4986                 boost::shared_ptr<Route> route = (*x);
4987
4988                 if (route->is_auditioner() || route->is_monitor()) {
4989                         continue;
4990                 }
4991
4992                 DataType dt = route->input()->default_type();
4993
4994                 if (dt == ARDOUR::DataType::AUDIO) {
4995                         rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4996                         rtv->set_route (route);
4997                 } else if (dt == ARDOUR::DataType::MIDI) {
4998                         rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4999                         rtv->set_route (route);
5000                 } else {
5001                         throw unknown_type();
5002                 }
5003
5004                 new_views.push_back (rtv);
5005                 track_views.push_back (rtv);
5006
5007                 rtv->effective_gain_display ();
5008
5009                 if (internal_editing()) {
5010                         rtv->enter_internal_edit_mode ();
5011                 } else {
5012                         rtv->leave_internal_edit_mode ();
5013                 }
5014
5015                 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5016                 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5017         }
5018
5019         if (new_views.size() > 0) {
5020                 _routes->routes_added (new_views);
5021                 _summary->routes_added (new_views);
5022         }
5023
5024         if (show_editor_mixer_when_tracks_arrive) {
5025                 show_editor_mixer (true);
5026         }
5027
5028         editor_list_button.set_sensitive (true);
5029 }
5030
5031 void
5032 Editor::timeaxisview_deleted (TimeAxisView *tv)
5033 {
5034         if (tv == entered_track) {
5035                 entered_track = 0;
5036         }
5037
5038         if (_session && _session->deletion_in_progress()) {
5039                 /* the situation is under control */
5040                 return;
5041         }
5042
5043         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5044
5045         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5046
5047         _routes->route_removed (tv);
5048
5049         TimeAxisView::Children c = tv->get_child_list ();
5050         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5051                 if (entered_track == i->get()) {
5052                         entered_track = 0;
5053                 }
5054         }
5055
5056         /* remove it from the list of track views */
5057
5058         TrackViewList::iterator i;
5059
5060         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5061                 i = track_views.erase (i);
5062         }
5063
5064         /* update whatever the current mixer strip is displaying, if revelant */
5065
5066         boost::shared_ptr<Route> route;
5067
5068         if (rtav) {
5069                 route = rtav->route ();
5070         }
5071
5072         if (current_mixer_strip && current_mixer_strip->route() == route) {
5073
5074                 TimeAxisView* next_tv;
5075
5076                 if (track_views.empty()) {
5077                         next_tv = 0;
5078                 } else if (i == track_views.end()) {
5079                         next_tv = track_views.front();
5080                 } else {
5081                         next_tv = (*i);
5082                 }
5083
5084
5085                 if (next_tv) {
5086                         set_selected_mixer_strip (*next_tv);
5087                 } else {
5088                         /* make the editor mixer strip go away setting the
5089                          * button to inactive (which also unticks the menu option)
5090                          */
5091
5092                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5093                 }
5094         }
5095 }
5096
5097 void
5098 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5099 {
5100         if (apply_to_selection) {
5101                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5102
5103                         TrackSelection::iterator j = i;
5104                         ++j;
5105
5106                         hide_track_in_display (*i, false);
5107
5108                         i = j;
5109                 }
5110         } else {
5111                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5112
5113                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5114                         // this will hide the mixer strip
5115                         set_selected_mixer_strip (*tv);
5116                 }
5117
5118                 _routes->hide_track_in_display (*tv);
5119         }
5120 }
5121
5122 bool
5123 Editor::sync_track_view_list_and_routes ()
5124 {
5125         track_views = TrackViewList (_routes->views ());
5126
5127         _summary->set_dirty ();
5128         _group_tabs->set_dirty ();
5129
5130         return false; // do not call again (until needed)
5131 }
5132
5133 void
5134 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5135 {
5136         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5137                 theslot (**i);
5138         }
5139 }
5140
5141 /** Find a RouteTimeAxisView by the ID of its route */
5142 RouteTimeAxisView*
5143 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5144 {
5145         RouteTimeAxisView* v;
5146
5147         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5148                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5149                         if(v->route()->id() == id) {
5150                                 return v;
5151                         }
5152                 }
5153         }
5154
5155         return 0;
5156 }
5157
5158 void
5159 Editor::fit_route_group (RouteGroup *g)
5160 {
5161         TrackViewList ts = axis_views_from_routes (g->route_list ());
5162         fit_tracks (ts);
5163 }
5164
5165 void
5166 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5167 {
5168         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5169
5170         if (r == 0) {
5171                 _session->cancel_audition ();
5172                 return;
5173         }
5174
5175         if (_session->is_auditioning()) {
5176                 _session->cancel_audition ();
5177                 if (r == last_audition_region) {
5178                         return;
5179                 }
5180         }
5181
5182         _session->audition_region (r);
5183         last_audition_region = r;
5184 }
5185
5186
5187 void
5188 Editor::hide_a_region (boost::shared_ptr<Region> r)
5189 {
5190         r->set_hidden (true);
5191 }
5192
5193 void
5194 Editor::show_a_region (boost::shared_ptr<Region> r)
5195 {
5196         r->set_hidden (false);
5197 }
5198
5199 void
5200 Editor::audition_region_from_region_list ()
5201 {
5202         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5203 }
5204
5205 void
5206 Editor::hide_region_from_region_list ()
5207 {
5208         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5209 }
5210
5211 void
5212 Editor::show_region_in_region_list ()
5213 {
5214         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5215 }
5216
5217 void
5218 Editor::step_edit_status_change (bool yn)
5219 {
5220         if (yn) {
5221                 start_step_editing ();
5222         } else {
5223                 stop_step_editing ();
5224         }
5225 }
5226
5227 void
5228 Editor::start_step_editing ()
5229 {
5230         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5231 }
5232
5233 void
5234 Editor::stop_step_editing ()
5235 {
5236         step_edit_connection.disconnect ();
5237 }
5238
5239 bool
5240 Editor::check_step_edit ()
5241 {
5242         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5243                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5244                 if (mtv) {
5245                         mtv->check_step_edit ();
5246                 }
5247         }
5248
5249         return true; // do it again, till we stop
5250 }
5251
5252 bool
5253 Editor::scroll_press (Direction dir)
5254 {
5255         ++_scroll_callbacks;
5256
5257         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5258                 /* delay the first auto-repeat */
5259                 return true;
5260         }
5261
5262         switch (dir) {
5263         case LEFT:
5264                 scroll_backward (1);
5265                 break;
5266
5267         case RIGHT:
5268                 scroll_forward (1);
5269                 break;
5270
5271         case UP:
5272                 scroll_up_one_track ();
5273                 break;
5274
5275         case DOWN:
5276                 scroll_down_one_track ();
5277                 break;
5278         }
5279
5280         /* do hacky auto-repeat */
5281         if (!_scroll_connection.connected ()) {
5282
5283                 _scroll_connection = Glib::signal_timeout().connect (
5284                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5285                         );
5286
5287                 _scroll_callbacks = 0;
5288         }
5289
5290         return true;
5291 }
5292
5293 void
5294 Editor::scroll_release ()
5295 {
5296         _scroll_connection.disconnect ();
5297 }
5298
5299 /** Queue a change for the Editor viewport x origin to follow the playhead */
5300 void
5301 Editor::reset_x_origin_to_follow_playhead ()
5302 {
5303         framepos_t const frame = playhead_cursor->current_frame ();
5304
5305         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5306
5307                 if (_session->transport_speed() < 0) {
5308
5309                         if (frame > (current_page_samples() / 2)) {
5310                                 center_screen (frame-(current_page_samples()/2));
5311                         } else {
5312                                 center_screen (current_page_samples()/2);
5313                         }
5314
5315                 } else {
5316
5317                         framepos_t l = 0;
5318                         
5319                         if (frame < leftmost_frame) {
5320                                 /* moving left */
5321                                 if (_session->transport_rolling()) {
5322                                         /* rolling; end up with the playhead at the right of the page */
5323                                         l = frame - current_page_samples ();
5324                                 } else {
5325                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5326                                         l = frame - current_page_samples() / 4;
5327                                 }
5328                         } else {
5329                                 /* moving right */
5330                                 if (_session->transport_rolling()) {
5331                                         /* rolling: end up with the playhead on the left of the page */
5332                                         l = frame;
5333                                 } else {
5334                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5335                                         l = frame - 3 * current_page_samples() / 4;
5336                                 }
5337                         }
5338
5339                         if (l < 0) {
5340                                 l = 0;
5341                         }
5342                         
5343                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5344                 }
5345         }
5346 }
5347
5348 void
5349 Editor::super_rapid_screen_update ()
5350 {
5351         if (!_session || !_session->engine().running()) {
5352                 return;
5353         }
5354
5355         /* METERING / MIXER STRIPS */
5356
5357         /* update track meters, if required */
5358         if (is_mapped() && meters_running) {
5359                 RouteTimeAxisView* rtv;
5360                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5361                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5362                                 rtv->fast_update ();
5363                         }
5364                 }
5365         }
5366
5367         /* and any current mixer strip */
5368         if (current_mixer_strip) {
5369                 current_mixer_strip->fast_update ();
5370         }
5371
5372         /* PLAYHEAD AND VIEWPORT */
5373
5374         framepos_t const frame = _session->audible_frame();
5375
5376         /* There are a few reasons why we might not update the playhead / viewport stuff:
5377          *
5378          * 1.  we don't update things when there's a pending locate request, otherwise
5379          *     when the editor requests a locate there is a chance that this method
5380          *     will move the playhead before the locate request is processed, causing
5381          *     a visual glitch.
5382          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5383          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5384          */
5385
5386         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5387
5388                 last_update_frame = frame;
5389
5390                 if (!_dragging_playhead) {
5391                         playhead_cursor->set_position (frame);
5392                 }
5393
5394                 if (!_stationary_playhead) {
5395
5396                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5397                                 /* We only do this if we aren't already
5398                                    handling a visual change (ie if
5399                                    pending_visual_change.being_handled is
5400                                    false) so that these requests don't stack
5401                                    up there are too many of them to handle in
5402                                    time.
5403                                 */
5404                                 reset_x_origin_to_follow_playhead ();
5405                         }
5406
5407                 } else {
5408
5409                         /* don't do continuous scroll till the new position is in the rightmost quarter of the
5410                            editor canvas
5411                         */
5412 #if 0
5413                         // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5414                         double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5415                         if (target <= 0.0) {
5416                                 target = 0.0;
5417                         }
5418                         if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5419                                 target = (target * 0.15) + (current * 0.85);
5420                         } else {
5421                                 /* relax */
5422                         }
5423
5424                         current = target;
5425                         set_horizontal_position (current);
5426 #endif
5427                 }
5428
5429         }
5430 }
5431
5432
5433 void
5434 Editor::session_going_away ()
5435 {
5436         _have_idled = false;
5437
5438         _session_connections.drop_connections ();
5439
5440         super_rapid_screen_update_connection.disconnect ();
5441
5442         selection->clear ();
5443         cut_buffer->clear ();
5444
5445         clicked_regionview = 0;
5446         clicked_axisview = 0;
5447         clicked_routeview = 0;
5448         entered_regionview = 0;
5449         entered_track = 0;
5450         last_update_frame = 0;
5451         _drags->abort ();
5452
5453         playhead_cursor->hide ();
5454
5455         /* rip everything out of the list displays */
5456
5457         _regions->clear ();
5458         _routes->clear ();
5459         _route_groups->clear ();
5460
5461         /* do this first so that deleting a track doesn't reset cms to null
5462            and thus cause a leak.
5463         */
5464
5465         if (current_mixer_strip) {
5466                 if (current_mixer_strip->get_parent() != 0) {
5467                         global_hpacker.remove (*current_mixer_strip);
5468                 }
5469                 delete current_mixer_strip;
5470                 current_mixer_strip = 0;
5471         }
5472
5473         /* delete all trackviews */
5474
5475         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5476                 delete *i;
5477         }
5478         track_views.clear ();
5479
5480         nudge_clock->set_session (0);
5481
5482         editor_list_button.set_active(false);
5483         editor_list_button.set_sensitive(false);
5484
5485         /* clear tempo/meter rulers */
5486         remove_metric_marks ();
5487         hide_measures ();
5488         clear_marker_display ();
5489
5490         stop_step_editing ();
5491         
5492         /* get rid of any existing editor mixer strip */
5493
5494         WindowTitle title(Glib::get_application_name());
5495         title += _("Editor");
5496
5497         set_title (title.get_string());
5498
5499         SessionHandlePtr::session_going_away ();
5500 }
5501
5502
5503 void
5504 Editor::show_editor_list (bool yn)
5505 {
5506         if (yn) {
5507                 _the_notebook.show ();
5508         } else {
5509                 _the_notebook.hide ();
5510         }
5511 }
5512
5513 void
5514 Editor::change_region_layering_order (bool from_context_menu)
5515 {
5516         const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5517
5518         if (!clicked_routeview) {
5519                 if (layering_order_editor) {
5520                         layering_order_editor->hide ();
5521                 }
5522                 return;
5523         }
5524
5525         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5526
5527         if (!track) {
5528                 return;
5529         }
5530
5531         boost::shared_ptr<Playlist> pl = track->playlist();
5532
5533         if (!pl) {
5534                 return;
5535         }
5536
5537         if (layering_order_editor == 0) {
5538                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5539         }
5540
5541         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5542         layering_order_editor->maybe_present ();
5543 }
5544
5545 void
5546 Editor::update_region_layering_order_editor ()
5547 {
5548         if (layering_order_editor && layering_order_editor->is_visible ()) {
5549                 change_region_layering_order (true);
5550         }
5551 }
5552
5553 void
5554 Editor::setup_fade_images ()
5555 {
5556         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5557         _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5558         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5559         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5560         _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5561
5562         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5563         _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5564         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5565         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5566         _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5567         
5568         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5569         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5570         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5571         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5572         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5573
5574         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5575         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5576         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5577         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5578         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5579
5580 }
5581
5582 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5583 Gtk::MenuItem&
5584 Editor::action_menu_item (std::string const & name)
5585 {
5586         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5587         assert (a);
5588
5589         return *manage (a->create_menu_item ());
5590 }
5591
5592 void
5593 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5594 {
5595         EventBox* b = manage (new EventBox);
5596         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5597         Label* l = manage (new Label (name));
5598         l->set_angle (-90);
5599         b->add (*l);
5600         b->show_all ();
5601         _the_notebook.append_page (widget, *b);
5602 }
5603
5604 bool
5605 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5606 {
5607         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5608                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5609         }
5610
5611         if (ev->type == GDK_2BUTTON_PRESS) {
5612
5613                 /* double-click on a notebook tab shrinks or expands the notebook */
5614
5615                 if (_notebook_shrunk) {
5616                         if (pre_notebook_shrink_pane_width) {
5617                                 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5618                         }
5619                         _notebook_shrunk = false;
5620                 } else {
5621                         pre_notebook_shrink_pane_width = edit_pane.get_position();
5622
5623                         /* this expands the LHS of the edit pane to cover the notebook
5624                            PAGE but leaves the tabs visible.
5625                          */
5626                         edit_pane.set_position (edit_pane.get_position() + page->get_width());
5627                         _notebook_shrunk = true;
5628                 }
5629         }
5630
5631         return true;
5632 }
5633
5634 void
5635 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5636 {
5637         using namespace Menu_Helpers;
5638         
5639         MenuList& items = _control_point_context_menu.items ();
5640         items.clear ();
5641         
5642         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5643         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5644         if (!can_remove_control_point (item)) {
5645                 items.back().set_sensitive (false);
5646         }
5647
5648         _control_point_context_menu.popup (event->button.button, event->button.time);
5649 }
5650
5651 void
5652 Editor::zoom_vertical_modifier_released()
5653 {
5654         _stepping_axis_view = 0;
5655 }
5656
5657 void
5658 Editor::ui_parameter_changed (string parameter)
5659 {
5660         if (parameter == "icon-set") {
5661                 while (!_cursor_stack.empty()) {
5662                         _cursor_stack.pop();
5663                 }
5664                 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5665         } else if (parameter == "draggable-playhead") {
5666                 if (_verbose_cursor) {
5667                         playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());
5668                 }
5669         }
5670 }