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