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