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