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