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