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