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