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