Add "maybe" rounding modes for rounding only if necessary.
[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()->get_LocationMarker();
394         location_range_color = ARDOUR_UI::config()->get_LocationRange();
395         location_cd_marker_color = ARDOUR_UI::config()->get_LocationCDMarker();
396         location_loop_color = ARDOUR_UI::config()->get_LocationLoop();
397         location_punch_color = ARDOUR_UI::config()->get_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
1849         edit_items.push_back (SeparatorElem());
1850         edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1851
1852         edit_items.push_back (SeparatorElem());
1853         edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1854         edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1855         edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1856
1857         edit_items.push_back (SeparatorElem());
1858         edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1859         edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1860         edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1861         edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1862         edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1863         if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1864                 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1865         }
1866 }
1867
1868
1869 void
1870 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1871 {
1872         using namespace Menu_Helpers;
1873
1874         /* Playback */
1875
1876         Menu *play_menu = manage (new Menu);
1877         MenuList& play_items = play_menu->items();
1878         play_menu->set_name ("ArdourContextMenu");
1879
1880         play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1881         play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1882         play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1883         play_items.push_back (SeparatorElem());
1884         play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1885
1886         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1887
1888         /* Selection */
1889
1890         Menu *select_menu = manage (new Menu);
1891         MenuList& select_items = select_menu->items();
1892         select_menu->set_name ("ArdourContextMenu");
1893
1894         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1895         select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1896         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1897         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1898         select_items.push_back (SeparatorElem());
1899         select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1900         select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1901         select_items.push_back (SeparatorElem());
1902         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1903         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1904         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1905         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1906         select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1907         select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1908         select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1909
1910         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1911
1912         /* Cut-n-Paste */
1913
1914         Menu *cutnpaste_menu = manage (new Menu);
1915         MenuList& cutnpaste_items = cutnpaste_menu->items();
1916         cutnpaste_menu->set_name ("ArdourContextMenu");
1917
1918         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1919         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1920         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1921
1922         cutnpaste_items.push_back (SeparatorElem());
1923
1924         cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1925         cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1926
1927         edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1928
1929         /* Adding new material */
1930
1931         edit_items.push_back (SeparatorElem());
1932         edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1933         edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1934
1935         /* Nudge track */
1936
1937         Menu *nudge_menu = manage (new Menu());
1938         MenuList& nudge_items = nudge_menu->items();
1939         nudge_menu->set_name ("ArdourContextMenu");
1940
1941         edit_items.push_back (SeparatorElem());
1942         nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1943         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1944         nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1945         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1946
1947         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1948 }
1949
1950 void
1951 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1952 {
1953         using namespace Menu_Helpers;
1954
1955         /* Playback */
1956
1957         Menu *play_menu = manage (new Menu);
1958         MenuList& play_items = play_menu->items();
1959         play_menu->set_name ("ArdourContextMenu");
1960
1961         play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1962         play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1963         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1964
1965         /* Selection */
1966
1967         Menu *select_menu = manage (new Menu);
1968         MenuList& select_items = select_menu->items();
1969         select_menu->set_name ("ArdourContextMenu");
1970
1971         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1972         select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1973         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1974         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1975         select_items.push_back (SeparatorElem());
1976         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1977         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1978         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1979         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1980
1981         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1982
1983         /* Cut-n-Paste */
1984
1985         Menu *cutnpaste_menu = manage (new Menu);
1986         MenuList& cutnpaste_items = cutnpaste_menu->items();
1987         cutnpaste_menu->set_name ("ArdourContextMenu");
1988
1989         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1990         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1991         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1992
1993         Menu *nudge_menu = manage (new Menu());
1994         MenuList& nudge_items = nudge_menu->items();
1995         nudge_menu->set_name ("ArdourContextMenu");
1996
1997         edit_items.push_back (SeparatorElem());
1998         nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1999         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2000         nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2001         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2002
2003         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2004 }
2005
2006 SnapType
2007 Editor::snap_type() const
2008 {
2009         return _snap_type;
2010 }
2011
2012 SnapMode
2013 Editor::snap_mode() const
2014 {
2015         return _snap_mode;
2016 }
2017
2018 void
2019 Editor::set_snap_to (SnapType st)
2020 {
2021         unsigned int snap_ind = (unsigned int)st;
2022
2023         _snap_type = st;
2024
2025         if (snap_ind > snap_type_strings.size() - 1) {
2026                 snap_ind = 0;
2027                 _snap_type = (SnapType)snap_ind;
2028         }
2029
2030         string str = snap_type_strings[snap_ind];
2031
2032         if (str != snap_type_selector.get_text()) {
2033                 snap_type_selector.set_text (str);
2034         }
2035
2036         instant_save ();
2037
2038         switch (_snap_type) {
2039         case SnapToBeatDiv128:
2040         case SnapToBeatDiv64:
2041         case SnapToBeatDiv32:
2042         case SnapToBeatDiv28:
2043         case SnapToBeatDiv24:
2044         case SnapToBeatDiv20:
2045         case SnapToBeatDiv16:
2046         case SnapToBeatDiv14:
2047         case SnapToBeatDiv12:
2048         case SnapToBeatDiv10:
2049         case SnapToBeatDiv8:
2050         case SnapToBeatDiv7:
2051         case SnapToBeatDiv6:
2052         case SnapToBeatDiv5:
2053         case SnapToBeatDiv4:
2054         case SnapToBeatDiv3:
2055         case SnapToBeatDiv2: {
2056                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2057                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2058                 
2059                 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2060                                             current_bbt_points_begin, current_bbt_points_end);
2061                 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2062                                          current_bbt_points_begin, current_bbt_points_end);
2063                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2064                 break;
2065         }
2066
2067         case SnapToRegionStart:
2068         case SnapToRegionEnd:
2069         case SnapToRegionSync:
2070         case SnapToRegionBoundary:
2071                 build_region_boundary_cache ();
2072                 break;
2073
2074         default:
2075                 /* relax */
2076                 break;
2077         }
2078
2079         SnapChanged (); /* EMIT SIGNAL */
2080 }
2081
2082 void
2083 Editor::set_snap_mode (SnapMode mode)
2084 {
2085         string str = snap_mode_strings[(int)mode];
2086
2087         if (_internal_editing) {
2088                 internal_snap_mode = mode;
2089         } else {
2090                 pre_internal_snap_mode = mode;
2091         }
2092
2093         _snap_mode = mode;
2094
2095         if (str != snap_mode_selector.get_text ()) {
2096                 snap_mode_selector.set_text (str);
2097         }
2098
2099         instant_save ();
2100 }
2101 void
2102 Editor::set_edit_point_preference (EditPoint ep, bool force)
2103 {
2104         bool changed = (_edit_point != ep);
2105
2106         _edit_point = ep;
2107         string str = edit_point_strings[(int)ep];
2108
2109         if (Profile->get_mixbus())
2110                 if (ep == EditAtSelectedMarker)
2111                         ep = EditAtPlayhead;
2112         
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_gain_button);
2857         mouse_mode_size_group->add_widget (mouse_timefx_button);
2858         mouse_mode_size_group->add_widget (mouse_audition_button);
2859         mouse_mode_size_group->add_widget (mouse_draw_button);
2860         mouse_mode_size_group->add_widget (internal_edit_button);
2861
2862         mouse_mode_size_group->add_widget (zoom_in_button);
2863         mouse_mode_size_group->add_widget (zoom_out_button);
2864         mouse_mode_size_group->add_widget (zoom_preset_selector);
2865         mouse_mode_size_group->add_widget (zoom_out_full_button);
2866         mouse_mode_size_group->add_widget (zoom_focus_selector);
2867
2868         mouse_mode_size_group->add_widget (tav_shrink_button);
2869         mouse_mode_size_group->add_widget (tav_expand_button);
2870         mouse_mode_size_group->add_widget (visible_tracks_selector);
2871
2872         mouse_mode_size_group->add_widget (snap_type_selector);
2873         mouse_mode_size_group->add_widget (snap_mode_selector);
2874
2875         mouse_mode_size_group->add_widget (edit_point_selector);
2876         mouse_mode_size_group->add_widget (edit_mode_selector);
2877
2878         mouse_mode_size_group->add_widget (*nudge_clock);
2879         mouse_mode_size_group->add_widget (nudge_forward_button);
2880         mouse_mode_size_group->add_widget (nudge_backward_button);
2881
2882         mouse_mode_hbox->set_spacing (2);
2883
2884         if (!ARDOUR::Profile->get_trx()) {
2885                 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2886         }
2887
2888         mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2889         mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2890
2891         if (!ARDOUR::Profile->get_mixbus()) {
2892                 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2893         }
2894         
2895         if (!ARDOUR::Profile->get_trx()) {
2896                 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2897                 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2898                 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2899                 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2900                 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2901         }
2902
2903         mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2904
2905         mouse_mode_align->add (*mouse_mode_vbox);
2906         mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2907
2908         mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2909
2910         edit_mode_selector.set_name ("mouse mode button");
2911
2912         if (!ARDOUR::Profile->get_trx()) {
2913                 mode_box->pack_start (edit_mode_selector, false, false);
2914         }
2915         mode_box->pack_start (*mouse_mode_box, false, false);
2916
2917         _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2918         _mouse_mode_tearoff->set_name ("MouseModeBase");
2919         _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2920
2921         if (Profile->get_sae() || Profile->get_mixbus() ) {
2922                 _mouse_mode_tearoff->set_can_be_torn_off (false);
2923         }
2924
2925         _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2926                                                          &_mouse_mode_tearoff->tearoff_window()));
2927         _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2928                                                          &_mouse_mode_tearoff->tearoff_window(), 1));
2929         _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2930                                                          &_mouse_mode_tearoff->tearoff_window()));
2931         _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2932                                                           &_mouse_mode_tearoff->tearoff_window(), 1));
2933
2934         /* Zoom */
2935
2936         _zoom_box.set_spacing (2);
2937         _zoom_box.set_border_width (2);
2938
2939         RefPtr<Action> act;
2940
2941         zoom_preset_selector.set_name ("zoom button");
2942         zoom_preset_selector.set_image(::get_icon ("time_exp"));
2943         zoom_preset_selector.set_size_request (42, -1);
2944
2945         zoom_in_button.set_name ("zoom button");
2946         zoom_in_button.set_image(::get_icon ("zoom_in"));
2947         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2948         zoom_in_button.set_related_action (act);
2949
2950         zoom_out_button.set_name ("zoom button");
2951         zoom_out_button.set_image(::get_icon ("zoom_out"));
2952         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2953         zoom_out_button.set_related_action (act);
2954
2955         zoom_out_full_button.set_name ("zoom button");
2956         zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2957         act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2958         zoom_out_full_button.set_related_action (act);
2959
2960         zoom_focus_selector.set_name ("zoom button");
2961
2962         if (ARDOUR::Profile->get_mixbus()) {
2963                 _zoom_box.pack_start (zoom_preset_selector, false, false);
2964         } else if (ARDOUR::Profile->get_trx()) {
2965                 mode_box->pack_start (zoom_out_button, false, false);
2966                 mode_box->pack_start (zoom_in_button, false, false);
2967         } else {
2968                 _zoom_box.pack_start (zoom_out_button, false, false);
2969                 _zoom_box.pack_start (zoom_in_button, false, false);
2970                 _zoom_box.pack_start (zoom_out_full_button, false, false);
2971                 _zoom_box.pack_start (zoom_focus_selector, false, false);
2972         }
2973
2974         /* Track zoom buttons */
2975         visible_tracks_selector.set_name ("zoom button");
2976         if (Profile->get_mixbus()) {
2977                 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2978                 visible_tracks_selector.set_size_request (42, -1);
2979         } else {
2980                 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2981         }
2982
2983         tav_expand_button.set_name ("zoom button");
2984         tav_expand_button.set_image(::get_icon ("tav_exp"));
2985         act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2986         tav_expand_button.set_related_action (act);
2987
2988         tav_shrink_button.set_name ("zoom button");
2989         tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2990         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2991         tav_shrink_button.set_related_action (act);
2992
2993         if (ARDOUR::Profile->get_mixbus()) {
2994                 _zoom_box.pack_start (visible_tracks_selector);
2995         } else if (ARDOUR::Profile->get_trx()) {
2996                 _zoom_box.pack_start (tav_shrink_button);
2997                 _zoom_box.pack_start (tav_expand_button);
2998         } else {
2999                 _zoom_box.pack_start (visible_tracks_selector);
3000                 _zoom_box.pack_start (tav_shrink_button);
3001                 _zoom_box.pack_start (tav_expand_button);
3002         }
3003
3004         if (!ARDOUR::Profile->get_trx()) {
3005                 _zoom_tearoff = manage (new TearOff (_zoom_box));
3006                 
3007                 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3008                                                            &_zoom_tearoff->tearoff_window()));
3009                 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3010                                                            &_zoom_tearoff->tearoff_window(), 0));
3011                 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3012                                                            &_zoom_tearoff->tearoff_window()));
3013                 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3014                                                             &_zoom_tearoff->tearoff_window(), 0));
3015         } 
3016
3017         if (Profile->get_sae() || Profile->get_mixbus() ) {
3018                 _zoom_tearoff->set_can_be_torn_off (false);
3019         }
3020
3021         snap_box.set_spacing (2);
3022         snap_box.set_border_width (2);
3023
3024         snap_type_selector.set_name ("mouse mode button");
3025
3026         snap_mode_selector.set_name ("mouse mode button");
3027
3028         edit_point_selector.set_name ("mouse mode button");
3029
3030         snap_box.pack_start (snap_mode_selector, false, false);
3031         snap_box.pack_start (snap_type_selector, false, false);
3032         snap_box.pack_start (edit_point_selector, false, false);
3033
3034         /* Nudge */
3035
3036         HBox *nudge_box = manage (new HBox);
3037         nudge_box->set_spacing (2);
3038         nudge_box->set_border_width (2);
3039
3040         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3041         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3042
3043         nudge_box->pack_start (nudge_backward_button, false, false);
3044         nudge_box->pack_start (nudge_forward_button, false, false);
3045         nudge_box->pack_start (*nudge_clock, false, false);
3046
3047
3048         /* Pack everything in... */
3049
3050         HBox* hbox = manage (new HBox);
3051         hbox->set_spacing(2);
3052
3053         _tools_tearoff = manage (new TearOff (*hbox));
3054         _tools_tearoff->set_name ("MouseModeBase");
3055         _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3056
3057         if (Profile->get_sae() || Profile->get_mixbus()) {
3058                 _tools_tearoff->set_can_be_torn_off (false);
3059         }
3060
3061         _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3062                                                     &_tools_tearoff->tearoff_window()));
3063         _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3064                                                     &_tools_tearoff->tearoff_window(), 0));
3065         _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3066                                                     &_tools_tearoff->tearoff_window()));
3067         _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3068                                                      &_tools_tearoff->tearoff_window(), 0));
3069
3070         toolbar_hbox.set_spacing (2);
3071         toolbar_hbox.set_border_width (1);
3072
3073         toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3074         if (!ARDOUR::Profile->get_trx()) {
3075                 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3076                 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3077         }
3078
3079         if (!ARDOUR::Profile->get_trx()) {
3080                 hbox->pack_start (snap_box, false, false);
3081                 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3082                         hbox->pack_start (*nudge_box, false, false);
3083                 } else {
3084                         ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3085                 }
3086         }
3087         hbox->pack_start (panic_box, false, false);
3088
3089         hbox->show_all ();
3090
3091         toolbar_base.set_name ("ToolBarBase");
3092         toolbar_base.add (toolbar_hbox);
3093
3094         _toolbar_viewport.add (toolbar_base);
3095         /* stick to the required height but allow width to vary if there's not enough room */
3096         _toolbar_viewport.set_size_request (1, -1);
3097
3098         toolbar_frame.set_shadow_type (SHADOW_OUT);
3099         toolbar_frame.set_name ("BaseFrame");
3100         toolbar_frame.add (_toolbar_viewport);
3101 }
3102
3103 void
3104 Editor::build_edit_point_menu ()
3105 {
3106         using namespace Menu_Helpers;
3107
3108         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3109         if(!Profile->get_mixbus())
3110                 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3111         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3112
3113         set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3114 }
3115
3116 void
3117 Editor::build_edit_mode_menu ()
3118 {
3119         using namespace Menu_Helpers;
3120         
3121         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3122 //      edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3123         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3124         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
3125
3126         set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3127 }
3128
3129 void
3130 Editor::build_snap_mode_menu ()
3131 {
3132         using namespace Menu_Helpers;
3133
3134         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3135         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3136         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3137
3138         set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3139 }
3140
3141 void
3142 Editor::build_snap_type_menu ()
3143 {
3144         using namespace Menu_Helpers;
3145
3146         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3147         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3148         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3149         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3150         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3151         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3152         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3153         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3154         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3155         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3156         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3157         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3158         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3159         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3160         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3161         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3162         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3163         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3164         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3165         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3166         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3167         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3168         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3169         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3170         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3171         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3172         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3173         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3174         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3175         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3176
3177         set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3178
3179 }
3180
3181 void
3182 Editor::setup_tooltips ()
3183 {
3184         ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3185         ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3186         ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3187         ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3188         ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3189         ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3190         ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3191         ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3192         ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3193         ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3194         ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3195         ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3196         ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3197         ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3198         ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3199         ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3200         ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3201         ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3202         ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3203         ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3204         ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3205         ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3206         ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3207         ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3208         ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3209 }
3210
3211 int
3212 Editor::convert_drop_to_paths (
3213                 vector<string>&                paths,
3214                 const RefPtr<Gdk::DragContext>& /*context*/,
3215                 gint                            /*x*/,
3216                 gint                            /*y*/,
3217                 const SelectionData&            data,
3218                 guint                           /*info*/,
3219                 guint                           /*time*/)
3220 {
3221         if (_session == 0) {
3222                 return -1;
3223         }
3224
3225         vector<string> uris = data.get_uris();
3226
3227         if (uris.empty()) {
3228
3229                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3230                    are actually URI lists. So do it by hand.
3231                 */
3232
3233                 if (data.get_target() != "text/plain") {
3234                         return -1;
3235                 }
3236
3237                 /* Parse the "uri-list" format that Nautilus provides,
3238                    where each pathname is delimited by \r\n.
3239
3240                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3241                 */
3242
3243                 string txt = data.get_text();
3244                 char* p;
3245                 const char* q;
3246
3247                 p = (char *) malloc (txt.length() + 1);
3248                 txt.copy (p, txt.length(), 0);
3249                 p[txt.length()] = '\0';
3250
3251                 while (p)
3252                 {
3253                         if (*p != '#')
3254                         {
3255                                 while (g_ascii_isspace (*p))
3256                                         p++;
3257
3258                                 q = p;
3259                                 while (*q && (*q != '\n') && (*q != '\r')) {
3260                                         q++;
3261                                 }
3262
3263                                 if (q > p)
3264                                 {
3265                                         q--;
3266                                         while (q > p && g_ascii_isspace (*q))
3267                                                 q--;
3268
3269                                         if (q > p)
3270                                         {
3271                                                 uris.push_back (string (p, q - p + 1));
3272                                         }
3273                                 }
3274                         }
3275                         p = strchr (p, '\n');
3276                         if (p)
3277                                 p++;
3278                 }
3279
3280                 free ((void*)p);
3281
3282                 if (uris.empty()) {
3283                         return -1;
3284                 }
3285         }
3286
3287         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3288                 if ((*i).substr (0,7) == "file://") {
3289                         paths.push_back (Glib::filename_from_uri (*i));
3290                 }
3291         }
3292
3293         return 0;
3294 }
3295
3296 void
3297 Editor::new_tempo_section ()
3298 {
3299 }
3300
3301 void
3302 Editor::map_transport_state ()
3303 {
3304         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3305
3306         if (_session && _session->transport_stopped()) {
3307                 have_pending_keyboard_selection = false;
3308         }
3309
3310         update_loop_range_view ();
3311 }
3312
3313 /* UNDO/REDO */
3314
3315 void
3316 Editor::begin_reversible_command (string name)
3317 {
3318         if (_session) {
3319                 _session->begin_reversible_command (name);
3320         }
3321 }
3322
3323 void
3324 Editor::begin_reversible_command (GQuark q)
3325 {
3326         if (_session) {
3327                 _session->begin_reversible_command (q);
3328         }
3329 }
3330
3331 void
3332 Editor::commit_reversible_command ()
3333 {
3334         if (_session) {
3335                 _session->commit_reversible_command ();
3336         }
3337 }
3338
3339 void
3340 Editor::history_changed ()
3341 {
3342         string label;
3343
3344         if (undo_action && _session) {
3345                 if (_session->undo_depth() == 0) {
3346                         label = S_("Command|Undo");
3347                 } else {
3348                         label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3349                 }
3350                 undo_action->property_label() = label;
3351         }
3352
3353         if (redo_action && _session) {
3354                 if (_session->redo_depth() == 0) {
3355                         label = _("Redo");
3356                 } else {
3357                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3358                 }
3359                 redo_action->property_label() = label;
3360         }
3361 }
3362
3363 void
3364 Editor::duplicate_range (bool with_dialog)
3365 {
3366         float times = 1.0f;
3367
3368         RegionSelection rs = get_regions_from_selection_and_entered ();
3369
3370         if ( selection->time.length() == 0 && rs.empty()) {
3371                 return;
3372         }
3373
3374         if (with_dialog) {
3375
3376                 ArdourDialog win (_("Duplicate"));
3377                 Label label (_("Number of duplications:"));
3378                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3379                 SpinButton spinner (adjustment, 0.0, 1);
3380                 HBox hbox;
3381
3382                 win.get_vbox()->set_spacing (12);
3383                 win.get_vbox()->pack_start (hbox);
3384                 hbox.set_border_width (6);
3385                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3386
3387                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3388                    place, visually. so do this by hand.
3389                 */
3390
3391                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3392                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3393                 spinner.grab_focus();
3394
3395                 hbox.show ();
3396                 label.show ();
3397                 spinner.show ();
3398
3399                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3400                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3401                 win.set_default_response (RESPONSE_ACCEPT);
3402
3403                 spinner.grab_focus ();
3404
3405                 switch (win.run ()) {
3406                 case RESPONSE_ACCEPT:
3407                         break;
3408                 default:
3409                         return;
3410                 }
3411
3412                 times = adjustment.get_value();
3413         }
3414
3415         if ((current_mouse_mode() == Editing::MouseRange)) {
3416                 if (selection->time.length()) {
3417                         duplicate_selection (times);
3418                 }
3419         } else if (get_smart_mode()) {
3420                 if (selection->time.length()) {
3421                         duplicate_selection (times);
3422                 } else 
3423                         duplicate_some_regions (rs, times);
3424         } else {
3425                 duplicate_some_regions (rs, times);
3426         }
3427 }
3428
3429 void
3430 Editor::set_edit_mode (EditMode m)
3431 {
3432         Config->set_edit_mode (m);
3433 }
3434
3435 void
3436 Editor::cycle_edit_mode ()
3437 {
3438         switch (Config->get_edit_mode()) {
3439         case Slide:
3440                 if (Profile->get_sae()) {
3441                         Config->set_edit_mode (Lock);
3442                 } else {
3443                         Config->set_edit_mode (Ripple);
3444                 }
3445                 break;
3446         case Splice:
3447         case Ripple:
3448                 Config->set_edit_mode (Lock);
3449                 break;
3450         case Lock:
3451                 Config->set_edit_mode (Slide);
3452                 break;
3453         }
3454 }
3455
3456 void
3457 Editor::edit_mode_selection_done ( EditMode m )
3458 {
3459         Config->set_edit_mode ( m );
3460 }
3461
3462 void
3463 Editor::snap_type_selection_done (SnapType snaptype)
3464 {
3465         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3466         if (ract) {
3467                 ract->set_active ();
3468         }
3469 }
3470
3471 void
3472 Editor::snap_mode_selection_done (SnapMode mode)
3473 {
3474         RefPtr<RadioAction> ract = snap_mode_action (mode);
3475
3476         if (ract) {
3477                 ract->set_active (true);
3478         }
3479 }
3480
3481 void
3482 Editor::cycle_edit_point (bool with_marker)
3483 {
3484         if(Profile->get_mixbus())
3485                 with_marker = false;
3486
3487         switch (_edit_point) {
3488         case EditAtMouse:
3489                 set_edit_point_preference (EditAtPlayhead);
3490                 break;
3491         case EditAtPlayhead:
3492                 if (with_marker) {
3493                         set_edit_point_preference (EditAtSelectedMarker);
3494                 } else {
3495                         set_edit_point_preference (EditAtMouse);
3496                 }
3497                 break;
3498         case EditAtSelectedMarker:
3499                 set_edit_point_preference (EditAtMouse);
3500                 break;
3501         }
3502 }
3503
3504 void
3505 Editor::edit_point_selection_done (EditPoint ep)
3506 {
3507         set_edit_point_preference ( ep );
3508 }
3509
3510 void
3511 Editor::build_zoom_focus_menu ()
3512 {
3513         using namespace Menu_Helpers;
3514
3515         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3516         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3517         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3518         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3519         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3520         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3521
3522         set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3523 }
3524
3525 void
3526 Editor::zoom_focus_selection_done ( ZoomFocus f )
3527 {
3528         RefPtr<RadioAction> ract = zoom_focus_action (f);
3529         if (ract) {
3530                 ract->set_active ();
3531         }
3532 }
3533
3534 void
3535 Editor::build_track_count_menu ()
3536 {
3537         using namespace Menu_Helpers;
3538
3539         if (!Profile->get_mixbus()) {
3540                 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3541                 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3542                 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3543                 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3544                 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3545                 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3546                 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3547                 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3548                 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3549                 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3550                 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3551                 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3552                 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3553         } else {
3554                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3555                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3556                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3557                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3558                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3559                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3560                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3561                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3562                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3563                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3564
3565                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3566                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3567                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3568                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3569                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3570                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3571                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3572                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3573                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3574                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3575                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3576         }
3577 }
3578
3579 void
3580 Editor::set_zoom_preset (int64_t ms)
3581 {
3582         if ( ms <= 0 ) {
3583                 temporal_zoom_session();
3584                 return;
3585         }
3586         
3587         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3588         temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3589 }
3590
3591 void
3592 Editor::set_visible_track_count (int32_t n)
3593 {
3594         _visible_track_count = n;
3595
3596         /* if the canvas hasn't really been allocated any size yet, just
3597            record the desired number of visible tracks and return. when canvas
3598            allocation happens, we will get called again and then we can do the
3599            real work.
3600         */
3601         
3602         if (_visible_canvas_height <= 1) {
3603                 return;
3604         }
3605
3606         int h;
3607         string str;
3608         
3609         if (_visible_track_count > 0) {
3610                 h = trackviews_height() / _visible_track_count;
3611                 std::ostringstream s;
3612                 s << _visible_track_count;
3613                 str = s.str();
3614         } else if (_visible_track_count == 0) {
3615                 uint32_t n = 0;
3616                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3617                         if ((*i)->marked_for_display()) {
3618                                 ++n;
3619                         }
3620                 }
3621                 h = trackviews_height() / n;
3622                 str = _("All");
3623         } else {
3624                 /* negative value means that the visible track count has 
3625                    been overridden by explicit track height changes.
3626                 */
3627                 visible_tracks_selector.set_text (X_("*"));
3628                 return;
3629         }
3630
3631         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3632                 (*i)->set_height (h);
3633         }
3634         
3635         if (str != visible_tracks_selector.get_text()) {
3636                 visible_tracks_selector.set_text (str);
3637         }
3638 }
3639
3640 void
3641 Editor::override_visible_track_count ()
3642 {
3643         _visible_track_count = -1;
3644         visible_tracks_selector.set_text ( _("*") );
3645 }
3646
3647 bool
3648 Editor::edit_controls_button_release (GdkEventButton* ev)
3649 {
3650         if (Keyboard::is_context_menu_event (ev)) {
3651                 ARDOUR_UI::instance()->add_route (this);
3652         } else if (ev->button == 1) {
3653                 selection->clear_tracks ();
3654         }
3655
3656         return true;
3657 }
3658
3659 bool
3660 Editor::mouse_select_button_release (GdkEventButton* ev)
3661 {
3662         /* this handles just right-clicks */
3663
3664         if (ev->button != 3) {
3665                 return false;
3666         }
3667
3668         return true;
3669 }
3670
3671 void
3672 Editor::set_zoom_focus (ZoomFocus f)
3673 {
3674         string str = zoom_focus_strings[(int)f];
3675
3676         if (str != zoom_focus_selector.get_text()) {
3677                 zoom_focus_selector.set_text (str);
3678         }
3679
3680         if (zoom_focus != f) {
3681                 zoom_focus = f;
3682                 instant_save ();
3683         }
3684 }
3685
3686 void
3687 Editor::cycle_zoom_focus ()
3688 {
3689         switch (zoom_focus) {
3690         case ZoomFocusLeft:
3691                 set_zoom_focus (ZoomFocusRight);
3692                 break;
3693         case ZoomFocusRight:
3694                 set_zoom_focus (ZoomFocusCenter);
3695                 break;
3696         case ZoomFocusCenter:
3697                 set_zoom_focus (ZoomFocusPlayhead);
3698                 break;
3699         case ZoomFocusPlayhead:
3700                 set_zoom_focus (ZoomFocusMouse);
3701                 break;
3702         case ZoomFocusMouse:
3703                 set_zoom_focus (ZoomFocusEdit);
3704                 break;
3705         case ZoomFocusEdit:
3706                 set_zoom_focus (ZoomFocusLeft);
3707                 break;
3708         }
3709 }
3710
3711 void
3712 Editor::ensure_float (Window& win)
3713 {
3714         win.set_transient_for (*this);
3715 }
3716
3717 void
3718 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3719 {
3720         /* recover or initialize pane positions. do this here rather than earlier because
3721            we don't want the positions to change the child allocations, which they seem to do.
3722          */
3723
3724         int pos;
3725         XMLProperty* prop;
3726         char buf[32];
3727         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3728
3729         enum Pane {
3730                 Horizontal = 0x1,
3731                 Vertical = 0x2
3732         };
3733
3734         static Pane done;
3735
3736         XMLNode* geometry = find_named_node (*node, "geometry");
3737
3738         if (which == static_cast<Paned*> (&edit_pane)) {
3739
3740                 if (done & Horizontal) {
3741                         return;
3742                 }
3743
3744                 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3745                         _notebook_shrunk = string_is_affirmative (prop->value ());
3746                 }
3747
3748                 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3749                         /* initial allocation is 90% to canvas, 10% to notebook */
3750                         pos = (int) floor (alloc.get_width() * 0.90f);
3751                         snprintf (buf, sizeof(buf), "%d", pos);
3752                 } else {
3753                         pos = atoi (prop->value());
3754                 }
3755
3756                 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3757                         edit_pane.set_position (pos);
3758                 }
3759
3760                 done = (Pane) (done | Horizontal);
3761
3762         } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3763
3764                 if (done & Vertical) {
3765                         return;
3766                 }
3767
3768                 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3769                         /* initial allocation is 90% to canvas, 10% to summary */
3770                         pos = (int) floor (alloc.get_height() * 0.90f);
3771                         snprintf (buf, sizeof(buf), "%d", pos);
3772                 } else {
3773
3774                         pos = atoi (prop->value());
3775                 }
3776
3777                 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3778                         editor_summary_pane.set_position (pos);
3779                 }
3780
3781                 done = (Pane) (done | Vertical);
3782         }
3783 }
3784
3785 void
3786 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3787 {
3788         if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) && 
3789             (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) && 
3790             (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3791                 top_hbox.remove (toolbar_frame);
3792         }
3793 }
3794
3795 void
3796 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3797 {
3798         if (toolbar_frame.get_parent() == 0) {
3799                 top_hbox.pack_end (toolbar_frame);
3800         }
3801 }
3802
3803 void
3804 Editor::set_show_measures (bool yn)
3805 {
3806         if (_show_measures != yn) {
3807                 hide_measures ();
3808
3809                 if ((_show_measures = yn) == true) {
3810                         if (tempo_lines) {
3811                                 tempo_lines->show();
3812                         }
3813
3814                         ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3815                         ARDOUR::TempoMap::BBTPointList::const_iterator end;
3816                         
3817                         compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3818                         draw_measures (begin, end);
3819                 } 
3820
3821                 instant_save ();
3822         }
3823 }
3824
3825 void
3826 Editor::toggle_follow_playhead ()
3827 {
3828         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3829         if (act) {
3830                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3831                 set_follow_playhead (tact->get_active());
3832         }
3833 }
3834
3835 /** @param yn true to follow playhead, otherwise false.
3836  *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3837  */
3838 void
3839 Editor::set_follow_playhead (bool yn, bool catch_up)
3840 {
3841         if (_follow_playhead != yn) {
3842                 if ((_follow_playhead = yn) == true && catch_up) {
3843                         /* catch up */
3844                         reset_x_origin_to_follow_playhead ();
3845                 }
3846                 instant_save ();
3847         }
3848 }
3849
3850 void
3851 Editor::toggle_stationary_playhead ()
3852 {
3853         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3854         if (act) {
3855                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3856                 set_stationary_playhead (tact->get_active());
3857         }
3858 }
3859
3860 void
3861 Editor::set_stationary_playhead (bool yn)
3862 {
3863         if (_stationary_playhead != yn) {
3864                 if ((_stationary_playhead = yn) == true) {
3865                         /* catch up */
3866                         // FIXME need a 3.0 equivalent of this 2.X call
3867                         // update_current_screen ();
3868                 }
3869                 instant_save ();
3870         }
3871 }
3872
3873 PlaylistSelector&
3874 Editor::playlist_selector () const
3875 {
3876         return *_playlist_selector;
3877 }
3878
3879 framecnt_t
3880 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3881 {
3882         if (paste_count == 0) {
3883                 /* don't bother calculating an offset that will be zero anyway */
3884                 return 0;
3885         }
3886
3887         /* calculate basic unsnapped multi-paste offset */
3888         framecnt_t offset = paste_count * duration;
3889
3890         bool   success    = true;
3891         double snap_beats = get_grid_type_as_beats(success, pos);
3892         if (success) {
3893                 /* we're snapped to something musical, round duration up */
3894                 BeatsFramesConverter      conv(_session->tempo_map(), pos);
3895                 const Evoral::MusicalTime dur_beats      = conv.from(duration);
3896                 const framecnt_t          snap_dur_beats = ceil(dur_beats / snap_beats) * snap_beats;
3897
3898                 offset = paste_count * conv.to(snap_dur_beats);
3899         }
3900
3901         return offset;
3902 }
3903
3904 Evoral::MusicalTime
3905 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3906 {
3907         success = true;
3908
3909         switch (_snap_type) {
3910         case SnapToBeat:
3911                 return 1.0;
3912                 break;
3913
3914         case SnapToBeatDiv128:
3915                 return 1.0/128.0;
3916                 break;
3917         case SnapToBeatDiv64:
3918                 return 1.0/64.0;
3919                 break;
3920         case SnapToBeatDiv32:
3921                 return 1.0/32.0;
3922                 break;
3923         case SnapToBeatDiv28:
3924                 return 1.0/28.0;
3925                 break;
3926         case SnapToBeatDiv24:
3927                 return 1.0/24.0;
3928                 break;
3929         case SnapToBeatDiv20:
3930                 return 1.0/20.0;
3931                 break;
3932         case SnapToBeatDiv16:
3933                 return 1.0/16.0;
3934                 break;
3935         case SnapToBeatDiv14:
3936                 return 1.0/14.0;
3937                 break;
3938         case SnapToBeatDiv12:
3939                 return 1.0/12.0;
3940                 break;
3941         case SnapToBeatDiv10:
3942                 return 1.0/10.0;
3943                 break;
3944         case SnapToBeatDiv8:
3945                 return 1.0/8.0;
3946                 break;
3947         case SnapToBeatDiv7:
3948                 return 1.0/7.0;
3949                 break;
3950         case SnapToBeatDiv6:
3951                 return 1.0/6.0;
3952                 break;
3953         case SnapToBeatDiv5:
3954                 return 1.0/5.0;
3955                 break;
3956         case SnapToBeatDiv4:
3957                 return 1.0/4.0;
3958                 break;
3959         case SnapToBeatDiv3:
3960                 return 1.0/3.0;
3961                 break;
3962         case SnapToBeatDiv2:
3963                 return 1.0/2.0;
3964                 break;
3965
3966         case SnapToBar:
3967                 if (_session) {
3968                         return _session->tempo_map().meter_at (position).divisions_per_bar();
3969                 }
3970                 break;
3971
3972         case SnapToCDFrame:
3973         case SnapToTimecodeFrame:
3974         case SnapToTimecodeSeconds:
3975         case SnapToTimecodeMinutes:
3976         case SnapToSeconds:
3977         case SnapToMinutes:
3978         case SnapToRegionStart:
3979         case SnapToRegionEnd:
3980         case SnapToRegionSync:
3981         case SnapToRegionBoundary:
3982         default:
3983                 success = false;
3984                 break;
3985         }
3986
3987         return 0.0;
3988 }
3989
3990 framecnt_t
3991 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3992 {
3993         framecnt_t ret;
3994
3995         ret = nudge_clock->current_duration (pos);
3996         next = ret + 1; /* XXXX fix me */
3997
3998         return ret;
3999 }
4000
4001 int
4002 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4003 {
4004         ArdourDialog dialog (_("Playlist Deletion"));
4005         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
4006                                         "If it is kept, its audio files will not be cleaned.\n"
4007                                         "If it is deleted, audio files used by it alone will be cleaned."),
4008                                       pl->name()));
4009
4010         dialog.set_position (WIN_POS_CENTER);
4011         dialog.get_vbox()->pack_start (label);
4012
4013         label.show ();
4014
4015         dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4016         dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4017         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4018
4019         switch (dialog.run ()) {
4020         case RESPONSE_ACCEPT:
4021                 /* delete the playlist */
4022                 return 0;
4023                 break;
4024
4025         case RESPONSE_REJECT:
4026                 /* keep the playlist */
4027                 return 1;
4028                 break;
4029
4030         default:
4031                 break;
4032         }
4033
4034         return -1;
4035 }
4036
4037 bool
4038 Editor::audio_region_selection_covers (framepos_t where)
4039 {
4040         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4041                 if ((*a)->region()->covers (where)) {
4042                         return true;
4043                 }
4044         }
4045
4046         return false;
4047 }
4048
4049 void
4050 Editor::prepare_for_cleanup ()
4051 {
4052         cut_buffer->clear_regions ();
4053         cut_buffer->clear_playlists ();
4054
4055         selection->clear_regions ();
4056         selection->clear_playlists ();
4057
4058         _regions->suspend_redisplay ();
4059 }
4060
4061 void
4062 Editor::finish_cleanup ()
4063 {
4064         _regions->resume_redisplay ();
4065 }
4066
4067 Location*
4068 Editor::transport_loop_location()
4069 {
4070         if (_session) {
4071                 return _session->locations()->auto_loop_location();
4072         } else {
4073                 return 0;
4074         }
4075 }
4076
4077 Location*
4078 Editor::transport_punch_location()
4079 {
4080         if (_session) {
4081                 return _session->locations()->auto_punch_location();
4082         } else {
4083                 return 0;
4084         }
4085 }
4086
4087 bool
4088 Editor::control_layout_scroll (GdkEventScroll* ev)
4089 {
4090         /* Just forward to the normal canvas scroll method. The coordinate
4091            systems are different but since the canvas is always larger than the
4092            track headers, and aligned with the trackview area, this will work.
4093
4094            In the not too distant future this layout is going away anyway and
4095            headers will be on the canvas.
4096         */
4097         return canvas_scroll_event (ev, false);
4098 }
4099
4100 void
4101 Editor::session_state_saved (string)
4102 {
4103         update_title ();
4104         _snapshots->redisplay ();
4105 }
4106
4107 void
4108 Editor::update_tearoff_visibility()
4109 {
4110         bool visible = Config->get_keep_tearoffs();
4111         _mouse_mode_tearoff->set_visible (visible);
4112         _tools_tearoff->set_visible (visible);
4113         if (_zoom_tearoff) {
4114                 _zoom_tearoff->set_visible (visible);
4115         }
4116 }
4117
4118 void
4119 Editor::reattach_all_tearoffs ()
4120 {
4121         if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4122         if (_tools_tearoff) _tools_tearoff->put_it_back ();
4123         if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4124 }
4125
4126 void
4127 Editor::maximise_editing_space ()
4128 {
4129         if (_maximised) {
4130                 return;
4131         }
4132
4133         fullscreen ();
4134
4135         _maximised = true;
4136 }
4137
4138 void
4139 Editor::restore_editing_space ()
4140 {
4141         if (!_maximised) {
4142                 return;
4143         }
4144
4145         unfullscreen();
4146
4147         _maximised = false;
4148 }
4149
4150 /**
4151  *  Make new playlists for a given track and also any others that belong
4152  *  to the same active route group with the `select' property.
4153  *  @param v Track.
4154  */
4155
4156 void
4157 Editor::new_playlists (TimeAxisView* v)
4158 {
4159         begin_reversible_command (_("new playlists"));
4160         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4161         _session->playlists->get (playlists);
4162         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4163         commit_reversible_command ();
4164 }
4165
4166 /**
4167  *  Use a copy of the current playlist for a given track and also any others that belong
4168  *  to the same active route group with the `select' property.
4169  *  @param v Track.
4170  */
4171
4172 void
4173 Editor::copy_playlists (TimeAxisView* v)
4174 {
4175         begin_reversible_command (_("copy playlists"));
4176         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4177         _session->playlists->get (playlists);
4178         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4179         commit_reversible_command ();
4180 }
4181
4182 /** Clear the current playlist for a given track and also any others that belong
4183  *  to the same active route group with the `select' property.
4184  *  @param v Track.
4185  */
4186
4187 void
4188 Editor::clear_playlists (TimeAxisView* v)
4189 {
4190         begin_reversible_command (_("clear playlists"));
4191         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4192         _session->playlists->get (playlists);
4193         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4194         commit_reversible_command ();
4195 }
4196
4197 void
4198 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4199 {
4200         atv.use_new_playlist (sz > 1 ? false : true, playlists);
4201 }
4202
4203 void
4204 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4205 {
4206         atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4207 }
4208
4209 void
4210 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4211 {
4212         atv.clear_playlist ();
4213 }
4214
4215 bool
4216 Editor::on_key_press_event (GdkEventKey* ev)
4217 {
4218         return key_press_focus_accelerator_handler (*this, ev);
4219 }
4220
4221 bool
4222 Editor::on_key_release_event (GdkEventKey* ev)
4223 {
4224         return Gtk::Window::on_key_release_event (ev);
4225         // return key_press_focus_accelerator_handler (*this, ev);
4226 }
4227
4228 /** Queue up a change to the viewport x origin.
4229  *  @param frame New x origin.
4230  */
4231 void
4232 Editor::reset_x_origin (framepos_t frame)
4233 {
4234         pending_visual_change.add (VisualChange::TimeOrigin);
4235         pending_visual_change.time_origin = frame;
4236         ensure_visual_change_idle_handler ();
4237 }
4238
4239 void
4240 Editor::reset_y_origin (double y)
4241 {
4242         pending_visual_change.add (VisualChange::YOrigin);
4243         pending_visual_change.y_origin = y;
4244         ensure_visual_change_idle_handler ();
4245 }
4246
4247 void
4248 Editor::reset_zoom (framecnt_t spp)
4249 {
4250         if (spp == samples_per_pixel) {
4251                 return;
4252         }
4253
4254         pending_visual_change.add (VisualChange::ZoomLevel);
4255         pending_visual_change.samples_per_pixel = spp;
4256         ensure_visual_change_idle_handler ();
4257 }
4258
4259 void
4260 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4261 {
4262         reset_x_origin (frame);
4263         reset_zoom (fpu);
4264
4265         if (!no_save_visual) {
4266                 undo_visual_stack.push_back (current_visual_state(false));
4267         }
4268 }
4269
4270 Editor::VisualState::VisualState (bool with_tracks)
4271         : gui_state (with_tracks ? new GUIObjectState : 0)
4272 {
4273 }
4274
4275 Editor::VisualState::~VisualState ()
4276 {
4277         delete gui_state;
4278 }
4279
4280 Editor::VisualState*
4281 Editor::current_visual_state (bool with_tracks)
4282 {
4283         VisualState* vs = new VisualState (with_tracks);
4284         vs->y_position = vertical_adjustment.get_value();
4285         vs->samples_per_pixel = samples_per_pixel;
4286         vs->leftmost_frame = leftmost_frame;
4287         vs->zoom_focus = zoom_focus;
4288
4289         if (with_tracks) {      
4290                 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4291         }
4292
4293         return vs;
4294 }
4295
4296 void
4297 Editor::undo_visual_state ()
4298 {
4299         if (undo_visual_stack.empty()) {
4300                 return;
4301         }
4302
4303         VisualState* vs = undo_visual_stack.back();
4304         undo_visual_stack.pop_back();
4305
4306
4307         redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4308
4309         if (vs) {
4310                 use_visual_state (*vs);
4311         }
4312 }
4313
4314 void
4315 Editor::redo_visual_state ()
4316 {
4317         if (redo_visual_stack.empty()) {
4318                 return;
4319         }
4320
4321         VisualState* vs = redo_visual_stack.back();
4322         redo_visual_stack.pop_back();
4323
4324         // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4325         // why do we check here?
4326         undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4327
4328         if (vs) {
4329                 use_visual_state (*vs);
4330         }
4331 }
4332
4333 void
4334 Editor::swap_visual_state ()
4335 {
4336         if (undo_visual_stack.empty()) {
4337                 redo_visual_state ();
4338         } else {
4339                 undo_visual_state ();
4340         }
4341 }
4342
4343 void
4344 Editor::use_visual_state (VisualState& vs)
4345 {
4346         PBD::Unwinder<bool> nsv (no_save_visual, true);
4347         DisplaySuspender ds;
4348
4349         vertical_adjustment.set_value (vs.y_position);
4350
4351         set_zoom_focus (vs.zoom_focus);
4352         reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4353         
4354         if (vs.gui_state) {
4355                 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4356                 
4357                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {    
4358                         (*i)->reset_visual_state ();
4359                 }
4360         }
4361
4362         _routes->update_visibility ();
4363 }
4364
4365 /** This is the core function that controls the zoom level of the canvas. It is called
4366  *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
4367  *  @param spp new number of samples per pixel
4368  */
4369 void
4370 Editor::set_samples_per_pixel (framecnt_t spp)
4371 {
4372         if (spp < 1) {
4373                 return;
4374         }
4375
4376         const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4377         const framecnt_t lots_of_pixels = 4000;
4378
4379         /* if the zoom level is greater than what you'd get trying to display 3
4380          * days of audio on a really big screen, then it's too big.
4381          */
4382
4383         if (spp * lots_of_pixels > three_days) {
4384                 return;
4385         }
4386
4387         samples_per_pixel = spp;
4388
4389         if (tempo_lines) {
4390                 tempo_lines->tempo_map_changed();
4391         }
4392
4393         bool const showing_time_selection = selection->time.length() > 0;
4394
4395         if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4396                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4397                         (*i)->reshow_selection (selection->time);
4398                 }
4399         }
4400
4401         ZoomChanged (); /* EMIT_SIGNAL */
4402
4403         ArdourCanvas::GtkCanvasViewport* c;
4404
4405         c = get_track_canvas();
4406         if (c) {
4407                 c->canvas()->zoomed ();
4408         }
4409
4410         if (playhead_cursor) {
4411                 playhead_cursor->set_position (playhead_cursor->current_frame ());
4412         }
4413
4414         refresh_location_display();
4415         _summary->set_overlays_dirty ();
4416
4417         update_marker_labels ();
4418
4419         instant_save ();
4420 }
4421
4422 void
4423 Editor::queue_visual_videotimeline_update ()
4424 {
4425         /* TODO:
4426          * pending_visual_change.add (VisualChange::VideoTimeline);
4427          * or maybe even more specific: which videotimeline-image
4428          * currently it calls update_video_timeline() to update
4429          * _all outdated_ images on the video-timeline.
4430          * see 'exposeimg()' in video_image_frame.cc
4431          */
4432         ensure_visual_change_idle_handler ();
4433 }
4434
4435 void
4436 Editor::ensure_visual_change_idle_handler ()
4437 {
4438         if (pending_visual_change.idle_handler_id < 0) {
4439                 // see comment in add_to_idle_resize above.
4440                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4441                 pending_visual_change.being_handled = false;
4442         }
4443 }
4444
4445 int
4446 Editor::_idle_visual_changer (void* arg)
4447 {
4448         return static_cast<Editor*>(arg)->idle_visual_changer ();
4449 }
4450
4451 int
4452 Editor::idle_visual_changer ()
4453 {
4454         /* set_horizontal_position() below (and maybe other calls) call
4455            gtk_main_iteration(), so it's possible that a signal will be handled
4456            half-way through this method.  If this signal wants an
4457            idle_visual_changer we must schedule another one after this one, so
4458            mark the idle_handler_id as -1 here to allow that.  Also make a note
4459            that we are doing the visual change, so that changes in response to
4460            super-rapid-screen-update can be dropped if we are still processing
4461            the last one.
4462         */
4463
4464         pending_visual_change.idle_handler_id = -1;
4465         pending_visual_change.being_handled = true;
4466         
4467         VisualChange vc = pending_visual_change;
4468
4469         pending_visual_change.pending = (VisualChange::Type) 0;
4470
4471         visual_changer (vc);
4472
4473         pending_visual_change.being_handled = false;
4474
4475         return 0; /* this is always a one-shot call */
4476 }
4477
4478 void
4479 Editor::visual_changer (const VisualChange& vc)
4480 {
4481         double const last_time_origin = horizontal_position ();
4482
4483         if (vc.pending & VisualChange::ZoomLevel) {
4484                 set_samples_per_pixel (vc.samples_per_pixel);
4485
4486                 compute_fixed_ruler_scale ();
4487
4488                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4489                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4490                 
4491                 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4492                                             current_bbt_points_begin, current_bbt_points_end);
4493                 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4494                                          current_bbt_points_begin, current_bbt_points_end);
4495                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4496
4497                 update_video_timeline();
4498         }
4499
4500         if (vc.pending & VisualChange::TimeOrigin) {
4501                 set_horizontal_position (vc.time_origin / samples_per_pixel);
4502         }
4503
4504         if (vc.pending & VisualChange::YOrigin) {
4505                 vertical_adjustment.set_value (vc.y_origin);
4506         }
4507
4508         if (last_time_origin == horizontal_position ()) {
4509                 /* changed signal not emitted */
4510                 update_fixed_rulers ();
4511                 redisplay_tempo (true);
4512         }
4513
4514         if (!(vc.pending & VisualChange::ZoomLevel)) {
4515                 update_video_timeline();
4516         }
4517
4518         _summary->set_overlays_dirty ();
4519 }
4520
4521 struct EditorOrderTimeAxisSorter {
4522     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4523             return a->order () < b->order ();
4524     }
4525 };
4526
4527 void
4528 Editor::sort_track_selection (TrackViewList& sel)
4529 {
4530         EditorOrderTimeAxisSorter cmp;
4531         sel.sort (cmp);
4532 }
4533
4534 framepos_t
4535 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4536 {
4537         bool ignored;
4538         framepos_t where = 0;
4539         EditPoint ep = _edit_point;
4540
4541         if(Profile->get_mixbus())
4542                 if (ep == EditAtSelectedMarker)
4543                         ep=EditAtPlayhead;
4544                 
4545         if (from_context_menu && (ep == EditAtMouse)) {
4546                 return  canvas_event_sample (&context_click_event, 0, 0);
4547         }
4548
4549         if (entered_marker) {
4550                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4551                 return entered_marker->position();
4552         }
4553
4554         if (ignore_playhead && ep == EditAtPlayhead) {
4555                 ep = EditAtSelectedMarker;
4556         }
4557
4558         switch (ep) {
4559         case EditAtPlayhead:
4560                 where = _session->audible_frame();
4561                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4562                 break;
4563
4564         case EditAtSelectedMarker:
4565                 if (!selection->markers.empty()) {
4566                         bool is_start;
4567                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4568                         if (loc) {
4569                                 if (is_start) {
4570                                         where =  loc->start();
4571                                 } else {
4572                                         where = loc->end();
4573                                 }
4574                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4575                                 break;
4576                         }
4577                 }
4578                 /* fallthru */
4579
4580         default:
4581         case EditAtMouse:
4582                 if (!mouse_frame (where, ignored)) {
4583                         /* XXX not right but what can we do ? */
4584                         return 0;
4585                 }
4586                 snap_to (where);
4587                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4588                 break;
4589         }
4590
4591         return where;
4592 }
4593
4594 void
4595 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4596 {
4597         if (!_session) return;
4598
4599         begin_reversible_command (cmd);
4600
4601         Location* tll;
4602
4603         if ((tll = transport_loop_location()) == 0) {
4604                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4605                 XMLNode &before = _session->locations()->get_state();
4606                 _session->locations()->add (loc, true);
4607                 _session->set_auto_loop_location (loc);
4608                 XMLNode &after = _session->locations()->get_state();
4609                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4610         } else {
4611                 XMLNode &before = tll->get_state();
4612                 tll->set_hidden (false, this);
4613                 tll->set (start, end);
4614                 XMLNode &after = tll->get_state();
4615                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4616         }
4617
4618         commit_reversible_command ();
4619 }
4620
4621 void
4622 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4623 {
4624         if (!_session) return;
4625
4626         begin_reversible_command (cmd);
4627
4628         Location* tpl;
4629
4630         if ((tpl = transport_punch_location()) == 0) {
4631                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
4632                 XMLNode &before = _session->locations()->get_state();
4633                 _session->locations()->add (loc, true);
4634                 _session->set_auto_punch_location (loc);
4635                 XMLNode &after = _session->locations()->get_state();
4636                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4637         }
4638         else {
4639                 XMLNode &before = tpl->get_state();
4640                 tpl->set_hidden (false, this);
4641                 tpl->set (start, end);
4642                 XMLNode &after = tpl->get_state();
4643                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4644         }
4645
4646         commit_reversible_command ();
4647 }
4648
4649 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4650  *  @param rs List to which found regions are added.
4651  *  @param where Time to look at.
4652  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4653  */
4654 void
4655 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4656 {
4657         const TrackViewList* tracks;
4658
4659         if (ts.empty()) {
4660                 tracks = &track_views;
4661         } else {
4662                 tracks = &ts;
4663         }
4664
4665         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4666
4667                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4668
4669                 if (rtv) {
4670                         boost::shared_ptr<Track> tr;
4671                         boost::shared_ptr<Playlist> pl;
4672
4673                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4674
4675                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4676                                                 (framepos_t) floor ( (double) where * tr->speed()));
4677
4678                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4679                                         RegionView* rv = rtv->view()->find_view (*i);
4680                                         if (rv) {
4681                                                 rs.add (rv);
4682                                         }
4683                                 }
4684                         }
4685                 }
4686         }
4687 }
4688
4689 void
4690 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4691 {
4692         const TrackViewList* tracks;
4693
4694         if (ts.empty()) {
4695                 tracks = &track_views;
4696         } else {
4697                 tracks = &ts;
4698         }
4699
4700         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4701                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4702                 if (rtv) {
4703                         boost::shared_ptr<Track> tr;
4704                         boost::shared_ptr<Playlist> pl;
4705
4706                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4707
4708                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4709                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4710
4711                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4712
4713                                         RegionView* rv = rtv->view()->find_view (*i);
4714
4715                                         if (rv) {
4716                                                 rs.add (rv);
4717                                         }
4718                                 }
4719                         }
4720                 }
4721         }
4722 }
4723
4724 /** Get regions using the following method:
4725  *
4726  *  Make a region list using:
4727  *   (a) any selected regions
4728  *   (b) the intersection of any selected tracks and the edit point(*)
4729  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4730  *
4731  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4732  *
4733  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4734  */
4735
4736 RegionSelection
4737 Editor::get_regions_from_selection_and_edit_point ()
4738 {
4739         RegionSelection regions;
4740
4741         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4742                 regions.add (entered_regionview);
4743         } else {
4744                 regions = selection->regions;
4745         }
4746
4747         if ( regions.empty() ) {
4748                 TrackViewList tracks = selection->tracks;
4749
4750                 if (!tracks.empty()) {
4751                         /* no region selected or entered, but some selected tracks:
4752                          * act on all regions on the selected tracks at the edit point
4753                          */ 
4754                         framepos_t const where = get_preferred_edit_position ();
4755                         get_regions_at(regions, where, tracks);
4756                 }
4757         }
4758
4759         return regions;
4760 }
4761
4762 /** Get regions using the following method:
4763  *
4764  *  Make a region list using:
4765  *   (a) any selected regions
4766  *   (b) the intersection of any selected tracks and the edit point(*)
4767  *   (c) if neither exists, then whatever region is under the mouse
4768  *
4769  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4770  *
4771  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4772  */
4773 RegionSelection
4774 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4775 {
4776         RegionSelection regions;
4777
4778         if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4779                 regions.add (entered_regionview);
4780         } else {
4781                 regions = selection->regions;
4782         }
4783
4784         if ( regions.empty() ) {
4785                 TrackViewList tracks = selection->tracks;
4786
4787                 if (!tracks.empty()) {
4788                         /* no region selected or entered, but some selected tracks:
4789                          * act on all regions on the selected tracks at the edit point
4790                          */ 
4791                         get_regions_at(regions, pos, tracks);
4792                 }
4793         }
4794
4795         return regions;
4796 }
4797
4798 /** Start with regions that are selected, or the entered regionview if none are selected.
4799  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4800  *  of the regions that we started with.
4801  */
4802
4803 RegionSelection
4804 Editor::get_regions_from_selection_and_entered ()
4805 {
4806         RegionSelection regions = selection->regions;
4807
4808         if (regions.empty() && entered_regionview) {
4809                 regions.add (entered_regionview);
4810         }
4811
4812         return regions;
4813 }
4814
4815 void
4816 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4817 {
4818         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4819
4820                 RouteTimeAxisView* tatv;
4821
4822                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4823
4824                         boost::shared_ptr<Playlist> pl;
4825                         vector<boost::shared_ptr<Region> > results;
4826                         RegionView* marv;
4827                         boost::shared_ptr<Track> tr;
4828
4829                         if ((tr = tatv->track()) == 0) {
4830                                 /* bus */
4831                                 continue;
4832                         }
4833
4834                         if ((pl = (tr->playlist())) != 0) {
4835                                 if (src_comparison) {
4836                                         pl->get_source_equivalent_regions (region, results);
4837                                 } else {
4838                                         pl->get_region_list_equivalent_regions (region, results);
4839                                 }
4840                         }
4841
4842                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4843                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4844                                         regions.push_back (marv);
4845                                 }
4846                         }
4847
4848                 }
4849         }
4850 }
4851
4852 void
4853 Editor::show_rhythm_ferret ()
4854 {
4855         if (rhythm_ferret == 0) {
4856                 rhythm_ferret = new RhythmFerret(*this);
4857         }
4858
4859         rhythm_ferret->set_session (_session);
4860         rhythm_ferret->show ();
4861         rhythm_ferret->present ();
4862 }
4863
4864 void
4865 Editor::first_idle ()
4866 {
4867         MessageDialog* dialog = 0;
4868         
4869         if (track_views.size() > 1) {
4870                 dialog = new MessageDialog (
4871                         *this,
4872                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4873                         true
4874                         );
4875                 dialog->present ();
4876                 ARDOUR_UI::instance()->flush_pending ();
4877         }
4878
4879         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4880                 (*t)->first_idle();
4881         }
4882
4883         // first idle adds route children (automation tracks), so we need to redisplay here
4884         _routes->redisplay ();
4885
4886         delete dialog;
4887         _have_idled = true;
4888 }
4889
4890 gboolean
4891 Editor::_idle_resize (gpointer arg)
4892 {
4893         return ((Editor*)arg)->idle_resize ();
4894 }
4895
4896 void
4897 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4898 {
4899         if (resize_idle_id < 0) {
4900                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4901                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4902                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4903                  */
4904                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4905                 _pending_resize_amount = 0;
4906         }
4907
4908         /* make a note of the smallest resulting height, so that we can clamp the
4909            lower limit at TimeAxisView::hSmall */
4910
4911         int32_t min_resulting = INT32_MAX;
4912
4913         _pending_resize_amount += h;
4914         _pending_resize_view = view;
4915
4916         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4917
4918         if (selection->tracks.contains (_pending_resize_view)) {
4919                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4920                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4921                 }
4922         }
4923
4924         if (min_resulting < 0) {
4925                 min_resulting = 0;
4926         }
4927
4928         /* clamp */
4929         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4930                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4931         }
4932 }
4933
4934 /** Handle pending resizing of tracks */
4935 bool
4936 Editor::idle_resize ()
4937 {
4938         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4939
4940         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4941             selection->tracks.contains (_pending_resize_view)) {
4942
4943                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4944                         if (*i != _pending_resize_view) {
4945                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4946                         }
4947                 }
4948         }
4949
4950         _pending_resize_amount = 0;
4951         _group_tabs->set_dirty ();
4952         resize_idle_id = -1;
4953
4954         return false;
4955 }
4956
4957 void
4958 Editor::located ()
4959 {
4960         ENSURE_GUI_THREAD (*this, &Editor::located);
4961
4962         if (_session) {
4963                 playhead_cursor->set_position (_session->audible_frame ());
4964                 if (_follow_playhead && !_pending_initial_locate) {
4965                         reset_x_origin_to_follow_playhead ();
4966                 }
4967         }
4968
4969         _pending_locate_request = false;
4970         _pending_initial_locate = false;
4971 }
4972
4973 void
4974 Editor::region_view_added (RegionView *)
4975 {
4976         _summary->set_background_dirty ();
4977 }
4978
4979 void
4980 Editor::region_view_removed ()
4981 {
4982         _summary->set_background_dirty ();
4983 }
4984
4985 RouteTimeAxisView*
4986 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4987 {
4988         TrackViewList::const_iterator j = track_views.begin ();
4989         while (j != track_views.end()) {
4990                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4991                 if (rtv && rtv->route() == r) {
4992                         return rtv;
4993                 }
4994                 ++j;
4995         }
4996
4997         return 0;
4998 }
4999
5000
5001 TrackViewList
5002 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5003 {
5004         TrackViewList t;
5005
5006         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5007                 TimeAxisView* tv = axis_view_from_route (*i);
5008                 if (tv) {
5009                         t.push_back (tv);
5010                 }
5011         }
5012
5013         return t;
5014 }
5015
5016 void
5017 Editor::suspend_route_redisplay ()
5018 {
5019         if (_routes) {
5020                 _routes->suspend_redisplay();
5021         }
5022 }
5023
5024 void
5025 Editor::resume_route_redisplay ()
5026 {
5027         if (_routes) {
5028                 _routes->resume_redisplay();
5029         }
5030 }
5031
5032 void
5033 Editor::add_routes (RouteList& routes)
5034 {
5035         ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5036
5037         RouteTimeAxisView *rtv;
5038         list<RouteTimeAxisView*> new_views;
5039
5040         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5041                 boost::shared_ptr<Route> route = (*x);
5042
5043                 if (route->is_auditioner() || route->is_monitor()) {
5044                         continue;
5045                 }
5046
5047                 DataType dt = route->input()->default_type();
5048
5049                 if (dt == ARDOUR::DataType::AUDIO) {
5050                         rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5051                         rtv->set_route (route);
5052                 } else if (dt == ARDOUR::DataType::MIDI) {
5053                         rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5054                         rtv->set_route (route);
5055                 } else {
5056                         throw unknown_type();
5057                 }
5058
5059                 new_views.push_back (rtv);
5060                 track_views.push_back (rtv);
5061
5062                 rtv->effective_gain_display ();
5063
5064                 if (internal_editing()) {
5065                         rtv->enter_internal_edit_mode ();
5066                 } else {
5067                         rtv->leave_internal_edit_mode ();
5068                 }
5069
5070                 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5071                 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5072         }
5073
5074         if (new_views.size() > 0) {
5075                 _routes->routes_added (new_views);
5076                 _summary->routes_added (new_views);
5077         }
5078
5079         if (show_editor_mixer_when_tracks_arrive) {
5080                 show_editor_mixer (true);
5081         }
5082
5083         editor_list_button.set_sensitive (true);
5084 }
5085
5086 void
5087 Editor::timeaxisview_deleted (TimeAxisView *tv)
5088 {
5089         if (tv == entered_track) {
5090                 entered_track = 0;
5091         }
5092
5093         if (_session && _session->deletion_in_progress()) {
5094                 /* the situation is under control */
5095                 return;
5096         }
5097
5098         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5099
5100         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5101
5102         _routes->route_removed (tv);
5103
5104         TimeAxisView::Children c = tv->get_child_list ();
5105         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5106                 if (entered_track == i->get()) {
5107                         entered_track = 0;
5108                 }
5109         }
5110
5111         /* remove it from the list of track views */
5112
5113         TrackViewList::iterator i;
5114
5115         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5116                 i = track_views.erase (i);
5117         }
5118
5119         /* update whatever the current mixer strip is displaying, if revelant */
5120
5121         boost::shared_ptr<Route> route;
5122
5123         if (rtav) {
5124                 route = rtav->route ();
5125         }
5126
5127         if (current_mixer_strip && current_mixer_strip->route() == route) {
5128
5129                 TimeAxisView* next_tv;
5130
5131                 if (track_views.empty()) {
5132                         next_tv = 0;
5133                 } else if (i == track_views.end()) {
5134                         next_tv = track_views.front();
5135                 } else {
5136                         next_tv = (*i);
5137                 }
5138
5139
5140                 if (next_tv) {
5141                         set_selected_mixer_strip (*next_tv);
5142                 } else {
5143                         /* make the editor mixer strip go away setting the
5144                          * button to inactive (which also unticks the menu option)
5145                          */
5146
5147                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5148                 }
5149         }
5150 }
5151
5152 void
5153 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5154 {
5155         if (apply_to_selection) {
5156                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5157
5158                         TrackSelection::iterator j = i;
5159                         ++j;
5160
5161                         hide_track_in_display (*i, false);
5162
5163                         i = j;
5164                 }
5165         } else {
5166                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5167
5168                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5169                         // this will hide the mixer strip
5170                         set_selected_mixer_strip (*tv);
5171                 }
5172
5173                 _routes->hide_track_in_display (*tv);
5174         }
5175 }
5176
5177 bool
5178 Editor::sync_track_view_list_and_routes ()
5179 {
5180         track_views = TrackViewList (_routes->views ());
5181
5182         _summary->set_dirty ();
5183         _group_tabs->set_dirty ();
5184
5185         return false; // do not call again (until needed)
5186 }
5187
5188 void
5189 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5190 {
5191         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5192                 theslot (**i);
5193         }
5194 }
5195
5196 /** Find a RouteTimeAxisView by the ID of its route */
5197 RouteTimeAxisView*
5198 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5199 {
5200         RouteTimeAxisView* v;
5201
5202         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5203                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5204                         if(v->route()->id() == id) {
5205                                 return v;
5206                         }
5207                 }
5208         }
5209
5210         return 0;
5211 }
5212
5213 void
5214 Editor::fit_route_group (RouteGroup *g)
5215 {
5216         TrackViewList ts = axis_views_from_routes (g->route_list ());
5217         fit_tracks (ts);
5218 }
5219
5220 void
5221 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5222 {
5223         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5224
5225         if (r == 0) {
5226                 _session->cancel_audition ();
5227                 return;
5228         }
5229
5230         if (_session->is_auditioning()) {
5231                 _session->cancel_audition ();
5232                 if (r == last_audition_region) {
5233                         return;
5234                 }
5235         }
5236
5237         _session->audition_region (r);
5238         last_audition_region = r;
5239 }
5240
5241
5242 void
5243 Editor::hide_a_region (boost::shared_ptr<Region> r)
5244 {
5245         r->set_hidden (true);
5246 }
5247
5248 void
5249 Editor::show_a_region (boost::shared_ptr<Region> r)
5250 {
5251         r->set_hidden (false);
5252 }
5253
5254 void
5255 Editor::audition_region_from_region_list ()
5256 {
5257         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5258 }
5259
5260 void
5261 Editor::hide_region_from_region_list ()
5262 {
5263         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5264 }
5265
5266 void
5267 Editor::show_region_in_region_list ()
5268 {
5269         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5270 }
5271
5272 void
5273 Editor::step_edit_status_change (bool yn)
5274 {
5275         if (yn) {
5276                 start_step_editing ();
5277         } else {
5278                 stop_step_editing ();
5279         }
5280 }
5281
5282 void
5283 Editor::start_step_editing ()
5284 {
5285         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5286 }
5287
5288 void
5289 Editor::stop_step_editing ()
5290 {
5291         step_edit_connection.disconnect ();
5292 }
5293
5294 bool
5295 Editor::check_step_edit ()
5296 {
5297         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5298                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5299                 if (mtv) {
5300                         mtv->check_step_edit ();
5301                 }
5302         }
5303
5304         return true; // do it again, till we stop
5305 }
5306
5307 bool
5308 Editor::scroll_press (Direction dir)
5309 {
5310         ++_scroll_callbacks;
5311
5312         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5313                 /* delay the first auto-repeat */
5314                 return true;
5315         }
5316
5317         switch (dir) {
5318         case LEFT:
5319                 scroll_backward (1);
5320                 break;
5321
5322         case RIGHT:
5323                 scroll_forward (1);
5324                 break;
5325
5326         case UP:
5327                 scroll_up_one_track ();
5328                 break;
5329
5330         case DOWN:
5331                 scroll_down_one_track ();
5332                 break;
5333         }
5334
5335         /* do hacky auto-repeat */
5336         if (!_scroll_connection.connected ()) {
5337
5338                 _scroll_connection = Glib::signal_timeout().connect (
5339                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5340                         );
5341
5342                 _scroll_callbacks = 0;
5343         }
5344
5345         return true;
5346 }
5347
5348 void
5349 Editor::scroll_release ()
5350 {
5351         _scroll_connection.disconnect ();
5352 }
5353
5354 /** Queue a change for the Editor viewport x origin to follow the playhead */
5355 void
5356 Editor::reset_x_origin_to_follow_playhead ()
5357 {
5358         framepos_t const frame = playhead_cursor->current_frame ();
5359
5360         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5361
5362                 if (_session->transport_speed() < 0) {
5363
5364                         if (frame > (current_page_samples() / 2)) {
5365                                 center_screen (frame-(current_page_samples()/2));
5366                         } else {
5367                                 center_screen (current_page_samples()/2);
5368                         }
5369
5370                 } else {
5371
5372                         framepos_t l = 0;
5373                         
5374                         if (frame < leftmost_frame) {
5375                                 /* moving left */
5376                                 if (_session->transport_rolling()) {
5377                                         /* rolling; end up with the playhead at the right of the page */
5378                                         l = frame - current_page_samples ();
5379                                 } else {
5380                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5381                                         l = frame - current_page_samples() / 4;
5382                                 }
5383                         } else {
5384                                 /* moving right */
5385                                 if (_session->transport_rolling()) {
5386                                         /* rolling: end up with the playhead on the left of the page */
5387                                         l = frame;
5388                                 } else {
5389                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5390                                         l = frame - 3 * current_page_samples() / 4;
5391                                 }
5392                         }
5393
5394                         if (l < 0) {
5395                                 l = 0;
5396                         }
5397                         
5398                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5399                 }
5400         }
5401 }
5402
5403 void
5404 Editor::super_rapid_screen_update ()
5405 {
5406         if (!_session || !_session->engine().running()) {
5407                 return;
5408         }
5409
5410         /* METERING / MIXER STRIPS */
5411
5412         /* update track meters, if required */
5413         if (is_mapped() && meters_running) {
5414                 RouteTimeAxisView* rtv;
5415                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5416                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5417                                 rtv->fast_update ();
5418                         }
5419                 }
5420         }
5421
5422         /* and any current mixer strip */
5423         if (current_mixer_strip) {
5424                 current_mixer_strip->fast_update ();
5425         }
5426
5427         /* PLAYHEAD AND VIEWPORT */
5428
5429         framepos_t const frame = _session->audible_frame();
5430
5431         /* There are a few reasons why we might not update the playhead / viewport stuff:
5432          *
5433          * 1.  we don't update things when there's a pending locate request, otherwise
5434          *     when the editor requests a locate there is a chance that this method
5435          *     will move the playhead before the locate request is processed, causing
5436          *     a visual glitch.
5437          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5438          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5439          */
5440
5441         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5442
5443                 last_update_frame = frame;
5444
5445                 if (!_dragging_playhead) {
5446                         playhead_cursor->set_position (frame);
5447                 }
5448
5449                 if (!_stationary_playhead) {
5450
5451                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5452                                 /* We only do this if we aren't already
5453                                    handling a visual change (ie if
5454                                    pending_visual_change.being_handled is
5455                                    false) so that these requests don't stack
5456                                    up there are too many of them to handle in
5457                                    time.
5458                                 */
5459                                 reset_x_origin_to_follow_playhead ();
5460                         }
5461
5462                 } else {
5463
5464                         /* don't do continuous scroll till the new position is in the rightmost quarter of the
5465                            editor canvas
5466                         */
5467 #if 0
5468                         // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5469                         double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5470                         if (target <= 0.0) {
5471                                 target = 0.0;
5472                         }
5473                         if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5474                                 target = (target * 0.15) + (current * 0.85);
5475                         } else {
5476                                 /* relax */
5477                         }
5478
5479                         current = target;
5480                         set_horizontal_position (current);
5481 #endif
5482                 }
5483
5484         }
5485 }
5486
5487
5488 void
5489 Editor::session_going_away ()
5490 {
5491         _have_idled = false;
5492
5493         _session_connections.drop_connections ();
5494
5495         super_rapid_screen_update_connection.disconnect ();
5496
5497         selection->clear ();
5498         cut_buffer->clear ();
5499
5500         clicked_regionview = 0;
5501         clicked_axisview = 0;
5502         clicked_routeview = 0;
5503         entered_regionview = 0;
5504         entered_track = 0;
5505         last_update_frame = 0;
5506         _drags->abort ();
5507
5508         playhead_cursor->hide ();
5509
5510         /* rip everything out of the list displays */
5511
5512         _regions->clear ();
5513         _routes->clear ();
5514         _route_groups->clear ();
5515
5516         /* do this first so that deleting a track doesn't reset cms to null
5517            and thus cause a leak.
5518         */
5519
5520         if (current_mixer_strip) {
5521                 if (current_mixer_strip->get_parent() != 0) {
5522                         global_hpacker.remove (*current_mixer_strip);
5523                 }
5524                 delete current_mixer_strip;
5525                 current_mixer_strip = 0;
5526         }
5527
5528         /* delete all trackviews */
5529
5530         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5531                 delete *i;
5532         }
5533         track_views.clear ();
5534
5535         nudge_clock->set_session (0);
5536
5537         editor_list_button.set_active(false);
5538         editor_list_button.set_sensitive(false);
5539
5540         /* clear tempo/meter rulers */
5541         remove_metric_marks ();
5542         hide_measures ();
5543         clear_marker_display ();
5544
5545         stop_step_editing ();
5546         
5547         /* get rid of any existing editor mixer strip */
5548
5549         WindowTitle title(Glib::get_application_name());
5550         title += _("Editor");
5551
5552         set_title (title.get_string());
5553
5554         SessionHandlePtr::session_going_away ();
5555 }
5556
5557
5558 void
5559 Editor::show_editor_list (bool yn)
5560 {
5561         if (yn) {
5562                 _the_notebook.show ();
5563         } else {
5564                 _the_notebook.hide ();
5565         }
5566 }
5567
5568 void
5569 Editor::change_region_layering_order (bool from_context_menu)
5570 {
5571         const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5572
5573         if (!clicked_routeview) {
5574                 if (layering_order_editor) {
5575                         layering_order_editor->hide ();
5576                 }
5577                 return;
5578         }
5579
5580         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5581
5582         if (!track) {
5583                 return;
5584         }
5585
5586         boost::shared_ptr<Playlist> pl = track->playlist();
5587
5588         if (!pl) {
5589                 return;
5590         }
5591
5592         if (layering_order_editor == 0) {
5593                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5594         }
5595
5596         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5597         layering_order_editor->maybe_present ();
5598 }
5599
5600 void
5601 Editor::update_region_layering_order_editor ()
5602 {
5603         if (layering_order_editor && layering_order_editor->is_visible ()) {
5604                 change_region_layering_order (true);
5605         }
5606 }
5607
5608 void
5609 Editor::setup_fade_images ()
5610 {
5611         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5612         _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5613         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5614         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5615         _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5616
5617         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5618         _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5619         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5620         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5621         _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5622         
5623         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5624         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5625         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5626         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5627         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5628
5629         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5630         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5631         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5632         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5633         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5634
5635 }
5636
5637 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5638 Gtk::MenuItem&
5639 Editor::action_menu_item (std::string const & name)
5640 {
5641         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5642         assert (a);
5643
5644         return *manage (a->create_menu_item ());
5645 }
5646
5647 void
5648 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5649 {
5650         EventBox* b = manage (new EventBox);
5651         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5652         Label* l = manage (new Label (name));
5653         l->set_angle (-90);
5654         b->add (*l);
5655         b->show_all ();
5656         _the_notebook.append_page (widget, *b);
5657 }
5658
5659 bool
5660 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5661 {
5662         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5663                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5664         }
5665
5666         if (ev->type == GDK_2BUTTON_PRESS) {
5667
5668                 /* double-click on a notebook tab shrinks or expands the notebook */
5669
5670                 if (_notebook_shrunk) {
5671                         if (pre_notebook_shrink_pane_width) {
5672                                 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5673                         }
5674                         _notebook_shrunk = false;
5675                 } else {
5676                         pre_notebook_shrink_pane_width = edit_pane.get_position();
5677
5678                         /* this expands the LHS of the edit pane to cover the notebook
5679                            PAGE but leaves the tabs visible.
5680                          */
5681                         edit_pane.set_position (edit_pane.get_position() + page->get_width());
5682                         _notebook_shrunk = true;
5683                 }
5684         }
5685
5686         return true;
5687 }
5688
5689 void
5690 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5691 {
5692         using namespace Menu_Helpers;
5693         
5694         MenuList& items = _control_point_context_menu.items ();
5695         items.clear ();
5696         
5697         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5698         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5699         if (!can_remove_control_point (item)) {
5700                 items.back().set_sensitive (false);
5701         }
5702
5703         _control_point_context_menu.popup (event->button.button, event->button.time);
5704 }
5705
5706 void
5707 Editor::zoom_vertical_modifier_released()
5708 {
5709         _stepping_axis_view = 0;
5710 }
5711
5712 void
5713 Editor::ui_parameter_changed (string parameter)
5714 {
5715         if (parameter == "icon-set") {
5716                 while (!_cursor_stack.empty()) {
5717                         _cursor_stack.pop();
5718                 }
5719                 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5720         } else if (parameter == "draggable-playhead") {
5721                 if (_verbose_cursor) {
5722                         playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());
5723                 }
5724         }
5725 }