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