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