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