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