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