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