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