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