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