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