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