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