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