Draw beat sudivisions according to snap setting.
[ardour.git] / gtk2_ardour / editor.cc
1 /*
2     Copyright (C) 2000-2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <stdint.h>
23 #include <unistd.h>
24 #include <cstdlib>
25 #include <cmath>
26 #include <string>
27 #include <algorithm>
28 #include <map>
29
30 #include "ardour_ui.h"
31 /*
32  * ardour_ui.h include was moved to the top of the list
33  * due to a conflicting definition of 'Style' between
34  * Apple's MacTypes.h and BarController.
35  */
36
37 #include <boost/none.hpp>
38
39 #include <sigc++/bind.h>
40
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
49
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
55
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
58
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
67
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
77
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
80
81 #include "control_protocol/control_protocol.h"
82
83 #include "actions.h"
84 #include "actions.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
93 #include "debug.h"
94 #include "editing.h"
95 #include "editor.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
109 #include "marker.h"
110 #include "midi_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           /* time display buttons */
255         , minsec_label (_("Mins:Secs"))
256         , bbt_label (_("Bars:Beats"))
257         , timecode_label (_("Timecode"))
258         , samples_label (_("Samples"))
259         , tempo_label (_("Tempo"))
260         , meter_label (_("Meter"))
261         , mark_label (_("Location Markers"))
262         , range_mark_label (_("Range Markers"))
263         , transport_mark_label (_("Loop/Punch Ranges"))
264         , cd_mark_label (_("CD Markers"))
265         , videotl_label (_("Video Timeline"))
266         , edit_packer (4, 4, true)
267
268           /* the values here don't matter: layout widgets
269              reset them as needed.
270           */
271
272         , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
273         , horizontal_adjustment (0.0, 0.0, 1e16)
274         , unused_adjustment (0.0, 0.0, 10.0, 400.0)
275
276         , controls_layout (unused_adjustment, vertical_adjustment)
277
278           /* tool bar related */
279
280         , toolbar_selection_clock_table (2,3)
281         , _mouse_mode_tearoff (0)
282         , automation_mode_button (_("mode"))
283         , _zoom_tearoff (0)
284         , _tools_tearoff (0)
285
286         , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
287         , selection_op_cmd_depth (0)
288         , selection_op_history_it (0)
289
290           /* nudge */
291
292         , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
293         , meters_running(false)
294         , _pending_locate_request (false)
295         , _pending_initial_locate (false)
296         , _last_cut_copy_source_track (0)
297
298         , _region_selection_change_updates_region_list (true)
299         , _following_mixer_selection (false)
300         , _control_point_toggled_on_press (false)
301         , _stepping_axis_view (0)
302 {
303         constructed = false;
304
305         /* we are a singleton */
306
307         PublicEditor::_instance = this;
308
309         _have_idled = false;
310         
311         selection = new Selection (this);
312         cut_buffer = new Selection (this);
313         _selection_memento = new SelectionMemento ();
314         selection_op_history.clear();
315         before.clear();
316
317         clicked_regionview = 0;
318         clicked_axisview = 0;
319         clicked_routeview = 0;
320         clicked_control_point = 0;
321         last_update_frame = 0;
322         last_paste_pos = 0;
323         paste_count = 0;
324         _drags = new DragManager (this);
325         lock_dialog = 0;
326         ruler_dialog = 0;
327         current_mixer_strip = 0;
328         tempo_lines = 0;
329
330         snap_type_strings =  I18N (_snap_type_strings);
331         snap_mode_strings =  I18N (_snap_mode_strings);
332         zoom_focus_strings = I18N (_zoom_focus_strings);
333         edit_mode_strings = I18N (_edit_mode_strings);
334         edit_point_strings = I18N (_edit_point_strings);
335 #ifdef USE_RUBBERBAND
336         rb_opt_strings = I18N (_rb_opt_strings);
337         rb_current_opt = 4;
338 #endif
339
340         build_edit_mode_menu();
341         build_zoom_focus_menu();
342         build_track_count_menu();
343         build_snap_mode_menu();
344         build_snap_type_menu();
345         build_edit_point_menu();
346
347         snap_threshold = 5.0;
348         bbt_beat_subdivision = 4;
349         _visible_canvas_width = 0;
350         _visible_canvas_height = 0;
351         autoscroll_horizontal_allowed = false;
352         autoscroll_vertical_allowed = false;
353         logo_item = 0;
354
355         analysis_window = 0;
356
357         current_interthread_info = 0;
358         _show_measures = true;
359         _maximised = false;
360         show_gain_after_trim = false;
361
362         have_pending_keyboard_selection = false;
363         _follow_playhead = true;
364         _stationary_playhead = false;
365         editor_ruler_menu = 0;
366         no_ruler_shown_update = false;
367         marker_menu = 0;
368         range_marker_menu = 0;
369         marker_menu_item = 0;
370         tempo_or_meter_marker_menu = 0;
371         transport_marker_menu = 0;
372         new_transport_marker_menu = 0;
373         editor_mixer_strip_width = Wide;
374         show_editor_mixer_when_tracks_arrive = false;
375         region_edit_menu_split_multichannel_item = 0;
376         region_edit_menu_split_item = 0;
377         temp_location = 0;
378         leftmost_frame = 0;
379         current_stepping_trackview = 0;
380         entered_track = 0;
381         entered_regionview = 0;
382         entered_marker = 0;
383         clear_entered_track = false;
384         current_timefx = 0;
385         playhead_cursor = 0;
386         button_release_can_deselect = true;
387         _dragging_playhead = false;
388         _dragging_edit_point = false;
389         select_new_marker = false;
390         rhythm_ferret = 0;
391         layering_order_editor = 0;
392         no_save_visual = false;
393         resize_idle_id = -1;
394         within_track_canvas = false;
395
396         scrubbing_direction = 0;
397
398         sfbrowser = 0;
399
400         location_marker_color = ARDOUR_UI::config()->color ("location marker");
401         location_range_color = ARDOUR_UI::config()->color ("location range");
402         location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
403         location_loop_color = ARDOUR_UI::config()->color ("location loop");
404         location_punch_color = ARDOUR_UI::config()->color ("location punch");
405
406         zoom_focus = ZoomFocusLeft;
407         _edit_point = EditAtMouse;
408         _visible_track_count = -1;
409
410         samples_per_pixel = 2048; /* too early to use reset_zoom () */
411
412         timebar_height = std::max(12., ceil (15. * ARDOUR_UI::config()->get_font_scale() / 102400.));
413         TimeAxisView::setup_sizes ();
414         Marker::setup_sizes (timebar_height);
415
416         _scroll_callbacks = 0;
417
418         bbt_label.set_name ("EditorRulerLabel");
419         bbt_label.set_size_request (-1, (int)timebar_height);
420         bbt_label.set_alignment (1.0, 0.5);
421         bbt_label.set_padding (5,0);
422         bbt_label.hide ();
423         bbt_label.set_no_show_all();
424         minsec_label.set_name ("EditorRulerLabel");
425         minsec_label.set_size_request (-1, (int)timebar_height);
426         minsec_label.set_alignment (1.0, 0.5);
427         minsec_label.set_padding (5,0);
428         minsec_label.hide ();
429         minsec_label.set_no_show_all();
430         timecode_label.set_name ("EditorRulerLabel");
431         timecode_label.set_size_request (-1, (int)timebar_height);
432         timecode_label.set_alignment (1.0, 0.5);
433         timecode_label.set_padding (5,0);
434         timecode_label.hide ();
435         timecode_label.set_no_show_all();
436         samples_label.set_name ("EditorRulerLabel");
437         samples_label.set_size_request (-1, (int)timebar_height);
438         samples_label.set_alignment (1.0, 0.5);
439         samples_label.set_padding (5,0);
440         samples_label.hide ();
441         samples_label.set_no_show_all();
442
443         tempo_label.set_name ("EditorRulerLabel");
444         tempo_label.set_size_request (-1, (int)timebar_height);
445         tempo_label.set_alignment (1.0, 0.5);
446         tempo_label.set_padding (5,0);
447         tempo_label.hide();
448         tempo_label.set_no_show_all();
449
450         meter_label.set_name ("EditorRulerLabel");
451         meter_label.set_size_request (-1, (int)timebar_height);
452         meter_label.set_alignment (1.0, 0.5);
453         meter_label.set_padding (5,0);
454         meter_label.hide();
455         meter_label.set_no_show_all();
456
457         if (Profile->get_trx()) {
458                 mark_label.set_text (_("Markers"));
459         }
460         mark_label.set_name ("EditorRulerLabel");
461         mark_label.set_size_request (-1, (int)timebar_height);
462         mark_label.set_alignment (1.0, 0.5);
463         mark_label.set_padding (5,0);
464         mark_label.hide();
465         mark_label.set_no_show_all();
466
467         cd_mark_label.set_name ("EditorRulerLabel");
468         cd_mark_label.set_size_request (-1, (int)timebar_height);
469         cd_mark_label.set_alignment (1.0, 0.5);
470         cd_mark_label.set_padding (5,0);
471         cd_mark_label.hide();
472         cd_mark_label.set_no_show_all();
473
474         videotl_bar_height = 4;
475         videotl_label.set_name ("EditorRulerLabel");
476         videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
477         videotl_label.set_alignment (1.0, 0.5);
478         videotl_label.set_padding (5,0);
479         videotl_label.hide();
480         videotl_label.set_no_show_all();
481
482         range_mark_label.set_name ("EditorRulerLabel");
483         range_mark_label.set_size_request (-1, (int)timebar_height);
484         range_mark_label.set_alignment (1.0, 0.5);
485         range_mark_label.set_padding (5,0);
486         range_mark_label.hide();
487         range_mark_label.set_no_show_all();
488
489         transport_mark_label.set_name ("EditorRulerLabel");
490         transport_mark_label.set_size_request (-1, (int)timebar_height);
491         transport_mark_label.set_alignment (1.0, 0.5);
492         transport_mark_label.set_padding (5,0);
493         transport_mark_label.hide();
494         transport_mark_label.set_no_show_all();
495
496         initialize_canvas ();
497
498         CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
499
500         _summary = new EditorSummary (this);
501
502         selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
503         selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
504
505         editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
506
507         selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
508         selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
509
510         edit_controls_vbox.set_spacing (0);
511         vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
512         _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
513
514         HBox* h = manage (new HBox);
515         _group_tabs = new EditorGroupTabs (this);
516         if (!ARDOUR::Profile->get_trx()) {
517                 h->pack_start (*_group_tabs, PACK_SHRINK);
518         }
519         h->pack_start (edit_controls_vbox);
520         controls_layout.add (*h);
521
522         controls_layout.set_name ("EditControlsBase");
523         controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
524         controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
525         controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
526
527         _cursors = new MouseCursors;
528         _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
529         cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
530
531         /* Push default cursor to ever-present bottom of cursor stack. */
532         push_canvas_cursor(_cursors->grabber);
533
534         ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
535
536         ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
537         pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
538         pad_line_1->set_outline_color (0xFF0000FF);
539         pad_line_1->show();
540
541         // CAIROCANVAS
542         time_pad->show();
543
544         edit_packer.set_col_spacings (0);
545         edit_packer.set_row_spacings (0);
546         edit_packer.set_homogeneous (false);
547         edit_packer.set_border_width (0);
548         edit_packer.set_name ("EditorWindow");
549
550         time_bars_event_box.add (time_bars_vbox);
551         time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
552         time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
553
554         /* labels for the time bars */
555         edit_packer.attach (time_bars_event_box,     0, 1, 0, 1,    FILL,        SHRINK, 0, 0);
556         /* track controls */
557         edit_packer.attach (controls_layout,         0, 1, 1, 2,    FILL,        FILL|EXPAND, 0, 0);
558         /* canvas */
559         edit_packer.attach (*_track_canvas_viewport,  1, 2, 0, 2,    FILL|EXPAND, FILL|EXPAND, 0, 0);
560
561         bottom_hbox.set_border_width (2);
562         bottom_hbox.set_spacing (3);
563
564         _route_groups = new EditorRouteGroups (this);
565         _routes = new EditorRoutes (this);
566         _regions = new EditorRegions (this);
567         _snapshots = new EditorSnapshots (this);
568         _locations = new EditorLocations (this);
569
570         /* these are static location signals */
571
572         Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
573         Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
574         Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
575
576         add_notebook_page (_("Regions"), _regions->widget ());
577         add_notebook_page (_("Tracks & Busses"), _routes->widget ());
578         add_notebook_page (_("Snapshots"), _snapshots->widget ());
579         add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
580         add_notebook_page (_("Ranges & Marks"), _locations->widget ());
581
582         _the_notebook.set_show_tabs (true);
583         _the_notebook.set_scrollable (true);
584         _the_notebook.popup_disable ();
585         _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
586         _the_notebook.show_all ();
587
588         _notebook_shrunk = false;
589
590         editor_summary_pane.pack1(edit_packer);
591
592         Button* summary_arrows_left_left = manage (new Button);
593         summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
594         summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
595         summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
596
597         Button* summary_arrows_left_right = manage (new Button);
598         summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
599         summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
600         summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
601
602         VBox* summary_arrows_left = manage (new VBox);
603         summary_arrows_left->pack_start (*summary_arrows_left_left);
604         summary_arrows_left->pack_start (*summary_arrows_left_right);
605
606         Button* summary_arrows_right_up = manage (new Button);
607         summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
608         summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
609         summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
610
611         Button* summary_arrows_right_down = manage (new Button);
612         summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
613         summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
614         summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
615
616         VBox* summary_arrows_right = manage (new VBox);
617         summary_arrows_right->pack_start (*summary_arrows_right_up);
618         summary_arrows_right->pack_start (*summary_arrows_right_down);
619
620         Frame* summary_frame = manage (new Frame);
621         summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
622
623         summary_frame->add (*_summary);
624         summary_frame->show ();
625
626         _summary_hbox.pack_start (*summary_arrows_left, false, false);
627         _summary_hbox.pack_start (*summary_frame, true, true);
628         _summary_hbox.pack_start (*summary_arrows_right, false, false);
629
630         if (!ARDOUR::Profile->get_trx()) {
631                 editor_summary_pane.pack2 (_summary_hbox);
632         }
633
634         edit_pane.pack1 (editor_summary_pane, true, true);
635         if (!ARDOUR::Profile->get_trx()) {
636                 edit_pane.pack2 (_the_notebook, false, true);
637         }
638
639         editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
640
641         /* XXX: editor_summary_pane might need similar to the edit_pane */
642
643         edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
644
645         Glib::PropertyProxy<int> proxy = edit_pane.property_position();
646         proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
647
648         top_hbox.pack_start (toolbar_frame);
649
650         HBox *hbox = manage (new HBox);
651         hbox->pack_start (edit_pane, true, true);
652
653         global_vpacker.pack_start (top_hbox, false, false);
654         global_vpacker.pack_start (*hbox, true, true);
655
656         global_hpacker.pack_start (global_vpacker, true, true);
657
658         set_name ("EditorWindow");
659         add_accel_group (ActionManager::ui_manager->get_accel_group());
660
661         status_bar_hpacker.show ();
662
663         vpacker.pack_end (status_bar_hpacker, false, false);
664         vpacker.pack_end (global_hpacker, true, true);
665
666         /* register actions now so that set_state() can find them and set toggles/checks etc */
667
668         register_actions ();
669         /* when we start using our own keybinding system for the editor, this
670          * will be uncommented
671          */
672         // load_bindings ();
673
674         setup_toolbar ();
675
676         set_zoom_focus (zoom_focus);
677         set_visible_track_count (_visible_track_count);
678         _snap_type = SnapToBeat;
679         set_snap_to (_snap_type);
680         _snap_mode = SnapOff;
681         set_snap_mode (_snap_mode);
682         set_mouse_mode (MouseObject, true);
683         pre_internal_mouse_mode = MouseObject;
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 (false, 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(*this, &Editor::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 (SeparatorElem());
1920         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1921         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1922         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1923         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1924         select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1925         select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1926         select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1927
1928         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1929
1930         /* Cut-n-Paste */
1931
1932         Menu *cutnpaste_menu = manage (new Menu);
1933         MenuList& cutnpaste_items = cutnpaste_menu->items();
1934         cutnpaste_menu->set_name ("ArdourContextMenu");
1935
1936         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1937         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1938         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1939
1940         cutnpaste_items.push_back (SeparatorElem());
1941
1942         cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1943         cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1944
1945         edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1946
1947         /* Adding new material */
1948
1949         edit_items.push_back (SeparatorElem());
1950         edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1951         edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1952
1953         /* Nudge track */
1954
1955         Menu *nudge_menu = manage (new Menu());
1956         MenuList& nudge_items = nudge_menu->items();
1957         nudge_menu->set_name ("ArdourContextMenu");
1958
1959         edit_items.push_back (SeparatorElem());
1960         nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1961         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1962         nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1963         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1964
1965         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1966 }
1967
1968 void
1969 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1970 {
1971         using namespace Menu_Helpers;
1972
1973         /* Playback */
1974
1975         Menu *play_menu = manage (new Menu);
1976         MenuList& play_items = play_menu->items();
1977         play_menu->set_name ("ArdourContextMenu");
1978
1979         play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1980         play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1981         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1982
1983         /* Selection */
1984
1985         Menu *select_menu = manage (new Menu);
1986         MenuList& select_items = select_menu->items();
1987         select_menu->set_name ("ArdourContextMenu");
1988
1989         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1990         select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1991         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1992         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1993         select_items.push_back (SeparatorElem());
1994         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1995         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1996         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1997         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1998
1999         edit_items.push_back (MenuElem (_("Select"), *select_menu));
2000
2001         /* Cut-n-Paste */
2002
2003         Menu *cutnpaste_menu = manage (new Menu);
2004         MenuList& cutnpaste_items = cutnpaste_menu->items();
2005         cutnpaste_menu->set_name ("ArdourContextMenu");
2006
2007         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2008         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2009         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2010
2011         Menu *nudge_menu = manage (new Menu());
2012         MenuList& nudge_items = nudge_menu->items();
2013         nudge_menu->set_name ("ArdourContextMenu");
2014
2015         edit_items.push_back (SeparatorElem());
2016         nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2017         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2018         nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2019         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2020
2021         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2022 }
2023
2024 SnapType
2025 Editor::snap_type() const
2026 {
2027         return _snap_type;
2028 }
2029
2030 SnapMode
2031 Editor::snap_mode() const
2032 {
2033         return _snap_mode;
2034 }
2035
2036 void
2037 Editor::set_snap_to (SnapType st)
2038 {
2039         unsigned int snap_ind = (unsigned int)st;
2040
2041         _snap_type = st;
2042
2043         if (snap_ind > snap_type_strings.size() - 1) {
2044                 snap_ind = 0;
2045                 _snap_type = (SnapType)snap_ind;
2046         }
2047
2048         string str = snap_type_strings[snap_ind];
2049
2050         if (str != snap_type_selector.get_text()) {
2051                 snap_type_selector.set_text (str);
2052         }
2053
2054         instant_save ();
2055
2056         switch (_snap_type) {
2057         case SnapToBeatDiv128:
2058         case SnapToBeatDiv64:
2059         case SnapToBeatDiv32:
2060         case SnapToBeatDiv28:
2061         case SnapToBeatDiv24:
2062         case SnapToBeatDiv20:
2063         case SnapToBeatDiv16:
2064         case SnapToBeatDiv14:
2065         case SnapToBeatDiv12:
2066         case SnapToBeatDiv10:
2067         case SnapToBeatDiv8:
2068         case SnapToBeatDiv7:
2069         case SnapToBeatDiv6:
2070         case SnapToBeatDiv5:
2071         case SnapToBeatDiv4:
2072         case SnapToBeatDiv3:
2073         case SnapToBeatDiv2: {
2074                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2075                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2076                 
2077                 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2078                                             current_bbt_points_begin, current_bbt_points_end);
2079                 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2080                                          current_bbt_points_begin, current_bbt_points_end);
2081                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2082                 break;
2083         }
2084
2085         case SnapToRegionStart:
2086         case SnapToRegionEnd:
2087         case SnapToRegionSync:
2088         case SnapToRegionBoundary:
2089                 build_region_boundary_cache ();
2090                 break;
2091
2092         default:
2093                 /* relax */
2094                 break;
2095         }
2096
2097         redisplay_tempo (false);
2098
2099         SnapChanged (); /* EMIT SIGNAL */
2100 }
2101
2102 void
2103 Editor::set_snap_mode (SnapMode mode)
2104 {
2105         string str = snap_mode_strings[(int)mode];
2106
2107         if (internal_editing()) {
2108                 internal_snap_mode = mode;
2109         } else {
2110                 pre_internal_snap_mode = mode;
2111         }
2112
2113         _snap_mode = mode;
2114
2115         if (str != snap_mode_selector.get_text ()) {
2116                 snap_mode_selector.set_text (str);
2117         }
2118
2119         instant_save ();
2120 }
2121 void
2122 Editor::set_edit_point_preference (EditPoint ep, bool force)
2123 {
2124         bool changed = (_edit_point != ep);
2125
2126         _edit_point = ep;
2127         if (Profile->get_mixbus())
2128                 if (ep == EditAtSelectedMarker)
2129                         ep = EditAtPlayhead;
2130
2131         string str = edit_point_strings[(int)ep];
2132         if (str != edit_point_selector.get_text ()) {
2133                 edit_point_selector.set_text (str);
2134         }
2135
2136         update_all_enter_cursors();
2137
2138         if (!force && !changed) {
2139                 return;
2140         }
2141
2142         const char* action=NULL;
2143
2144         switch (_edit_point) {
2145         case EditAtPlayhead:
2146                 action = "edit-at-playhead";
2147                 break;
2148         case EditAtSelectedMarker:
2149                 action = "edit-at-marker";
2150                 break;
2151         case EditAtMouse:
2152                 action = "edit-at-mouse";
2153                 break;
2154         }
2155
2156         Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2157         if (act) {
2158                 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2159         }
2160
2161         framepos_t foo;
2162         bool in_track_canvas;
2163
2164         if (!mouse_frame (foo, in_track_canvas)) {
2165                 in_track_canvas = false;
2166         }
2167
2168         reset_canvas_action_sensitivity (in_track_canvas);
2169
2170         instant_save ();
2171 }
2172
2173 int
2174 Editor::set_state (const XMLNode& node, int /*version*/)
2175 {
2176         const XMLProperty* prop;
2177         XMLNode* geometry;
2178         int x, y;
2179         Gdk::Geometry g;
2180
2181         set_id (node);
2182
2183         g.base_width = default_width;
2184         g.base_height = default_height;
2185         x = 1;
2186         y = 1;
2187
2188         if ((geometry = find_named_node (node, "geometry")) != 0) {
2189
2190                 XMLProperty* prop;
2191
2192                 if ((prop = geometry->property("x_size")) == 0) {
2193                         prop = geometry->property ("x-size");
2194                 }
2195                 if (prop) {
2196                         g.base_width = atoi(prop->value());
2197                 }
2198                 if ((prop = geometry->property("y_size")) == 0) {
2199                         prop = geometry->property ("y-size");
2200                 }
2201                 if (prop) {
2202                         g.base_height = atoi(prop->value());
2203                 }
2204
2205                 if ((prop = geometry->property ("x_pos")) == 0) {
2206                         prop = geometry->property ("x-pos");
2207                 }
2208                 if (prop) {
2209                         x = atoi (prop->value());
2210
2211                 }
2212                 if ((prop = geometry->property ("y_pos")) == 0) {
2213                         prop = geometry->property ("y-pos");
2214                 }
2215                 if (prop) {
2216                         y = atoi (prop->value());
2217                 }
2218         }
2219
2220         set_default_size (g.base_width, g.base_height);
2221         move (x, y);
2222
2223         if (_session && (prop = node.property ("playhead"))) {
2224                 framepos_t pos;
2225                 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2226                 if (pos >= 0) {
2227                         playhead_cursor->set_position (pos);
2228                 } else {
2229                         warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2230                         playhead_cursor->set_position (0);
2231                 }
2232         } else {
2233                 playhead_cursor->set_position (0);
2234         }
2235
2236         if ((prop = node.property ("mixer-width"))) {
2237                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2238         }
2239
2240         if ((prop = node.property ("zoom-focus"))) {
2241                 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2242         }
2243
2244         if ((prop = node.property ("zoom"))) {
2245                 /* older versions of ardour used floating point samples_per_pixel */
2246                 double f = PBD::atof (prop->value());
2247                 reset_zoom (llrintf (f));
2248         } else {
2249                 reset_zoom (samples_per_pixel);
2250         }
2251
2252         if ((prop = node.property ("visible-track-count"))) {
2253                 set_visible_track_count (PBD::atoi (prop->value()));
2254         }
2255
2256         if ((prop = node.property ("snap-to"))) {
2257                 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2258         }
2259
2260         if ((prop = node.property ("snap-mode"))) {
2261                 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2262         }
2263
2264         if ((prop = node.property ("internal-snap-to"))) {
2265                 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2266         }
2267
2268         if ((prop = node.property ("internal-snap-mode"))) {
2269                 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2270         }
2271
2272         if ((prop = node.property ("pre-internal-snap-to"))) {
2273                 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2274         }
2275
2276         if ((prop = node.property ("pre-internal-snap-mode"))) {
2277                 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2278         }
2279
2280         if ((prop = node.property ("mouse-mode"))) {
2281                 MouseMode m = str2mousemode(prop->value());
2282                 set_mouse_mode (m, true);
2283         } else {
2284                 set_mouse_mode (MouseObject, true);
2285         }
2286
2287         if ((prop = node.property ("left-frame")) != 0) {
2288                 framepos_t pos;
2289                 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2290                         if (pos < 0) {
2291                                 pos = 0;
2292                         }
2293                         reset_x_origin (pos);
2294                 }
2295         }
2296
2297         if ((prop = node.property ("y-origin")) != 0) {
2298                 reset_y_origin (atof (prop->value ()));
2299         }
2300
2301         if ((prop = node.property ("join-object-range"))) {
2302                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2303                 bool yn = string_is_affirmative (prop->value());
2304                 if (act) {
2305                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2306                         tact->set_active (!yn);
2307                         tact->set_active (yn);
2308                 }
2309                 set_mouse_mode(mouse_mode, true);
2310         }
2311
2312         if ((prop = node.property ("edit-point"))) {
2313                 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2314         }
2315
2316         if ((prop = node.property ("show-measures"))) {
2317                 bool yn = string_is_affirmative (prop->value());
2318                 _show_measures = yn;
2319                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2320                 if (act) {
2321                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2322                         /* do it twice to force the change */
2323                         tact->set_active (!yn);
2324                         tact->set_active (yn);
2325                 }
2326         }
2327
2328         if ((prop = node.property ("follow-playhead"))) {
2329                 bool yn = string_is_affirmative (prop->value());
2330                 set_follow_playhead (yn);
2331                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2332                 if (act) {
2333                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2334                         if (tact->get_active() != yn) {
2335                                 tact->set_active (yn);
2336                         }
2337                 }
2338         }
2339
2340         if ((prop = node.property ("stationary-playhead"))) {
2341                 bool yn = string_is_affirmative (prop->value());
2342                 set_stationary_playhead (yn);
2343                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2344                 if (act) {
2345                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2346                         if (tact->get_active() != yn) {
2347                                 tact->set_active (yn);
2348                         }
2349                 }
2350         }
2351
2352         if ((prop = node.property ("region-list-sort-type"))) {
2353                 RegionListSortType st;
2354                 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2355         }
2356
2357         if ((prop = node.property ("show-editor-mixer"))) {
2358
2359                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
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 ("show-editor-list"))) {
2372
2373                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2374                 assert (act);
2375
2376                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2377                 bool yn = string_is_affirmative (prop->value());
2378
2379                 /* do it twice to force the change */
2380
2381                 tact->set_active (!yn);
2382                 tact->set_active (yn);
2383         }
2384
2385         if ((prop = node.property (X_("editor-list-page")))) {
2386                 _the_notebook.set_current_page (atoi (prop->value ()));
2387         }
2388
2389         if ((prop = node.property (X_("show-marker-lines")))) {
2390                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2391                 assert (act);
2392                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2393                 bool yn = string_is_affirmative (prop->value ());
2394
2395                 tact->set_active (!yn);
2396                 tact->set_active (yn);
2397         }
2398
2399         XMLNodeList children = node.children ();
2400         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2401                 selection->set_state (**i, Stateful::current_state_version);
2402                 _regions->set_state (**i);
2403         }
2404
2405         if ((prop = node.property ("maximised"))) {
2406                 bool yn = string_is_affirmative (prop->value());
2407                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2408                 assert (act);
2409                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2410                 bool fs = tact && tact->get_active();
2411                 if (yn ^ fs) {
2412                         ActionManager::do_action ("Common", "ToggleMaximalEditor");
2413                 }
2414         }
2415
2416         if ((prop = node.property ("nudge-clock-value"))) {
2417                 framepos_t f;
2418                 sscanf (prop->value().c_str(), "%" PRId64, &f);
2419                 nudge_clock->set (f);
2420         } else {
2421                 nudge_clock->set_mode (AudioClock::Timecode);
2422                 nudge_clock->set (_session->frame_rate() * 5, true);
2423         }
2424
2425         return 0;
2426 }
2427
2428 XMLNode&
2429 Editor::get_state ()
2430 {
2431         XMLNode* node = new XMLNode ("Editor");
2432         char buf[32];
2433
2434         id().print (buf, sizeof (buf));
2435         node->add_property ("id", buf);
2436
2437         if (is_realized()) {
2438                 Glib::RefPtr<Gdk::Window> win = get_window();
2439
2440                 int x, y, width, height;
2441                 win->get_root_origin(x, y);
2442                 win->get_size(width, height);
2443
2444                 XMLNode* geometry = new XMLNode ("geometry");
2445
2446                 snprintf(buf, sizeof(buf), "%d", width);
2447                 geometry->add_property("x-size", string(buf));
2448                 snprintf(buf, sizeof(buf), "%d", height);
2449                 geometry->add_property("y-size", string(buf));
2450                 snprintf(buf, sizeof(buf), "%d", x);
2451                 geometry->add_property("x-pos", string(buf));
2452                 snprintf(buf, sizeof(buf), "%d", y);
2453                 geometry->add_property("y-pos", string(buf));
2454                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2455                 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2456                 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2457                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2458                 geometry->add_property("edit-vertical-pane-pos", string(buf));
2459
2460                 node->add_child_nocopy (*geometry);
2461         }
2462
2463         maybe_add_mixer_strip_width (*node);
2464
2465         node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2466
2467         snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2468         node->add_property ("zoom", buf);
2469         node->add_property ("snap-to", enum_2_string (_snap_type));
2470         node->add_property ("snap-mode", enum_2_string (_snap_mode));
2471         node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2472         node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2473         node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2474         node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2475         node->add_property ("edit-point", enum_2_string (_edit_point));
2476         snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2477         node->add_property ("visible-track-count", buf);
2478
2479         snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2480         node->add_property ("playhead", buf);
2481         snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2482         node->add_property ("left-frame", buf);
2483         snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2484         node->add_property ("y-origin", buf);
2485
2486         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2487         node->add_property ("maximised", _maximised ? "yes" : "no");
2488         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2489         node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2490         node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2491         node->add_property ("mouse-mode", enum2str(mouse_mode));
2492         node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2493
2494         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2495         if (act) {
2496                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2497                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2498         }
2499
2500         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2501         if (act) {
2502                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2503                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2504         }
2505
2506         snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2507         node->add_property (X_("editor-list-page"), buf);
2508
2509         if (button_bindings) {
2510                 XMLNode* bb = new XMLNode (X_("Buttons"));
2511                 button_bindings->save (*bb);
2512                 node->add_child_nocopy (*bb);
2513         }
2514
2515         node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2516
2517         node->add_child_nocopy (selection->get_state ());
2518         node->add_child_nocopy (_regions->get_state ());
2519
2520         snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2521         node->add_property ("nudge-clock-value", buf);
2522
2523         return *node;
2524 }
2525
2526 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2527  *  if @param trackview_relative_offset is false, @param y y is a global canvas *  coordinate, in pixel units
2528  *
2529  *  @return pair: TimeAxisView that y is over, layer index.
2530  *
2531  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2532  *  in stacked or expanded region display mode, otherwise 0.
2533  */
2534 std::pair<TimeAxisView *, double>
2535 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2536 {
2537         if (!trackview_relative_offset) {
2538                 y -= _trackview_group->canvas_origin().y;
2539         }
2540
2541         if (y < 0) {
2542                 return std::make_pair ( (TimeAxisView *) 0, 0);
2543         }
2544
2545         for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2546                         
2547                 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2548                         
2549                 if (r.first) {
2550                         return r;
2551                 }
2552         }
2553
2554         return std::make_pair ( (TimeAxisView *) 0, 0);
2555 }
2556
2557 /** Snap a position to the grid, if appropriate, taking into account current
2558  *  grid settings and also the state of any snap modifier keys that may be pressed.
2559  *  @param start Position to snap.
2560  *  @param event Event to get current key modifier information from, or 0.
2561  */
2562 void
2563 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2564 {
2565         if (!_session || !event) {
2566                 return;
2567         }
2568
2569         if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2570                 if (_snap_mode == SnapOff) {
2571                         snap_to_internal (start, direction, for_mark);
2572                 }
2573         } else {
2574                 if (_snap_mode != SnapOff) {
2575                         snap_to_internal (start, direction, for_mark);
2576                 }
2577         }
2578 }
2579
2580 void
2581 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2582 {
2583         if (!_session || _snap_mode == SnapOff) {
2584                 return;
2585         }
2586
2587         snap_to_internal (start, direction, for_mark);
2588 }
2589
2590 void
2591 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2592 {
2593         const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2594         framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2595
2596         switch (_snap_type) {
2597         case SnapToTimecodeFrame:
2598                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2599                     fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2600                         /* start is already on a whole timecode frame, do nothing */
2601                 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2602                         start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2603                 } else {
2604                         start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) *  _session->frames_per_timecode_frame());
2605                 }
2606                 break;
2607
2608         case SnapToTimecodeSeconds:
2609                 if (_session->config.get_timecode_offset_negative()) {
2610                         start += _session->config.get_timecode_offset ();
2611                 } else {
2612                         start -= _session->config.get_timecode_offset ();
2613                 }
2614                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2615                     (start % one_timecode_second == 0)) {
2616                         /* start is already on a whole second, do nothing */
2617                 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2618                         start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2619                 } else {
2620                         start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2621                 }
2622
2623                 if (_session->config.get_timecode_offset_negative()) {
2624                         start -= _session->config.get_timecode_offset ();
2625                 } else {
2626                         start += _session->config.get_timecode_offset ();
2627                 }
2628                 break;
2629
2630         case SnapToTimecodeMinutes:
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_minute == 0)) {
2638                         /* start is already on a whole minute, do nothing */
2639                 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2640                         start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2641                 } else {
2642                         start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2643                 }
2644                 if (_session->config.get_timecode_offset_negative()) {
2645                         start -= _session->config.get_timecode_offset ();
2646                 } else {
2647                         start += _session->config.get_timecode_offset ();
2648                 }
2649                 break;
2650         default:
2651                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2652                 abort(); /*NOTREACHED*/
2653         }
2654 }
2655
2656 void
2657 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2658 {
2659         const framepos_t one_second = _session->frame_rate();
2660         const framepos_t one_minute = _session->frame_rate() * 60;
2661         framepos_t presnap = start;
2662         framepos_t before;
2663         framepos_t after;
2664
2665         switch (_snap_type) {
2666         case SnapToTimecodeFrame:
2667         case SnapToTimecodeSeconds:
2668         case SnapToTimecodeMinutes:
2669                 return timecode_snap_to_internal (start, direction, for_mark);
2670
2671         case SnapToCDFrame:
2672                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2673                     start % (one_second/75) == 0) {
2674                         /* start is already on a whole CD frame, do nothing */
2675                 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2676                         start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2677                 } else {
2678                         start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2679                 }
2680                 break;
2681
2682         case SnapToSeconds:
2683                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2684                     start % one_second == 0) {
2685                         /* start is already on a whole second, do nothing */
2686                 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2687                         start = (framepos_t) ceil ((double) start / one_second) * one_second;
2688                 } else {
2689                         start = (framepos_t) floor ((double) start / one_second) * one_second;
2690                 }
2691                 break;
2692
2693         case SnapToMinutes:
2694                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2695                     start % one_minute == 0) {
2696                         /* start is already on a whole minute, do nothing */
2697                 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2698                         start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2699                 } else {
2700                         start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2701                 }
2702                 break;
2703
2704         case SnapToBar:
2705                 start = _session->tempo_map().round_to_bar (start, direction);
2706                 break;
2707
2708         case SnapToBeat:
2709                 start = _session->tempo_map().round_to_beat (start, direction);
2710                 break;
2711
2712         case SnapToBeatDiv128:
2713                 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2714                 break;
2715         case SnapToBeatDiv64:
2716                 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2717                 break;
2718         case SnapToBeatDiv32:
2719                 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2720                 break;
2721         case SnapToBeatDiv28:
2722                 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2723                 break;
2724         case SnapToBeatDiv24:
2725                 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2726                 break;
2727         case SnapToBeatDiv20:
2728                 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2729                 break;
2730         case SnapToBeatDiv16:
2731                 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2732                 break;
2733         case SnapToBeatDiv14:
2734                 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2735                 break;
2736         case SnapToBeatDiv12:
2737                 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2738                 break;
2739         case SnapToBeatDiv10:
2740                 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2741                 break;
2742         case SnapToBeatDiv8:
2743                 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2744                 break;
2745         case SnapToBeatDiv7:
2746                 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2747                 break;
2748         case SnapToBeatDiv6:
2749                 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2750                 break;
2751         case SnapToBeatDiv5:
2752                 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2753                 break;
2754         case SnapToBeatDiv4:
2755                 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2756                 break;
2757         case SnapToBeatDiv3:
2758                 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2759                 break;
2760         case SnapToBeatDiv2:
2761                 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2762                 break;
2763
2764         case SnapToMark:
2765                 if (for_mark) {
2766                         return;
2767                 }
2768
2769                 _session->locations()->marks_either_side (start, before, after);
2770
2771                 if (before == max_framepos && after == max_framepos) {
2772                         /* No marks to snap to, so just don't snap */
2773                         return;
2774                 } else if (before == max_framepos) {
2775                         start = after;
2776                 } else if (after == max_framepos) {
2777                         start = before;
2778                 } else if (before != max_framepos && after != max_framepos) {
2779                         /* have before and after */
2780                         if ((start - before) < (after - start)) {
2781                                 start = before;
2782                         } else {
2783                                 start = after;
2784                         }
2785                 }
2786
2787                 break;
2788
2789         case SnapToRegionStart:
2790         case SnapToRegionEnd:
2791         case SnapToRegionSync:
2792         case SnapToRegionBoundary:
2793                 if (!region_boundary_cache.empty()) {
2794
2795                         vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2796                         vector<framepos_t>::iterator next = region_boundary_cache.end ();
2797
2798                         if (direction > 0) {
2799                                 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2800                         } else {
2801                                 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2802                         }
2803
2804                         if (next != region_boundary_cache.begin ()) {
2805                                 prev = next;
2806                                 prev--;
2807                         }
2808
2809                         framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2810                         framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2811
2812                         if (start > (p + n) / 2) {
2813                                 start = n;
2814                         } else {
2815                                 start = p;
2816                         }
2817                 }
2818                 break;
2819         }
2820
2821         switch (_snap_mode) {
2822         case SnapNormal:
2823                 return;
2824
2825         case SnapMagnetic:
2826
2827                 if (presnap > start) {
2828                         if (presnap > (start + pixel_to_sample(snap_threshold))) {
2829                                 start = presnap;
2830                         }
2831
2832                 } else if (presnap < start) {
2833                         if (presnap < (start - pixel_to_sample(snap_threshold))) {
2834                                 start = presnap;
2835                         }
2836                 }
2837
2838         default:
2839                 /* handled at entry */
2840                 return;
2841
2842         }
2843 }
2844
2845
2846 void
2847 Editor::setup_toolbar ()
2848 {
2849         HBox* mode_box = manage(new HBox);
2850         mode_box->set_border_width (2);
2851         mode_box->set_spacing(2);
2852
2853         HBox* mouse_mode_box = manage (new HBox);
2854         HBox* mouse_mode_hbox = manage (new HBox);
2855         VBox* mouse_mode_vbox = manage (new VBox);
2856         Alignment* mouse_mode_align = manage (new Alignment);
2857
2858         Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2859         mouse_mode_size_group->add_widget (smart_mode_button);
2860         mouse_mode_size_group->add_widget (mouse_move_button);
2861         mouse_mode_size_group->add_widget (mouse_cut_button);
2862         mouse_mode_size_group->add_widget (mouse_select_button);
2863         mouse_mode_size_group->add_widget (mouse_timefx_button);
2864         mouse_mode_size_group->add_widget (mouse_audition_button);
2865         mouse_mode_size_group->add_widget (mouse_draw_button);
2866         mouse_mode_size_group->add_widget (mouse_content_button);
2867
2868         mouse_mode_size_group->add_widget (zoom_in_button);
2869         mouse_mode_size_group->add_widget (zoom_out_button);
2870         mouse_mode_size_group->add_widget (zoom_preset_selector);
2871         mouse_mode_size_group->add_widget (zoom_out_full_button);
2872         mouse_mode_size_group->add_widget (zoom_focus_selector);
2873
2874         mouse_mode_size_group->add_widget (tav_shrink_button);
2875         mouse_mode_size_group->add_widget (tav_expand_button);
2876         mouse_mode_size_group->add_widget (visible_tracks_selector);
2877
2878         mouse_mode_size_group->add_widget (snap_type_selector);
2879         mouse_mode_size_group->add_widget (snap_mode_selector);
2880
2881         mouse_mode_size_group->add_widget (edit_point_selector);
2882         mouse_mode_size_group->add_widget (edit_mode_selector);
2883
2884         mouse_mode_size_group->add_widget (*nudge_clock);
2885         mouse_mode_size_group->add_widget (nudge_forward_button);
2886         mouse_mode_size_group->add_widget (nudge_backward_button);
2887
2888         mouse_mode_hbox->set_spacing (2);
2889
2890         if (!ARDOUR::Profile->get_trx()) {
2891                 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2892         }
2893
2894         mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2895         mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2896
2897         if (!ARDOUR::Profile->get_mixbus()) {
2898                 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2899         }
2900         
2901         if (!ARDOUR::Profile->get_trx()) {
2902                 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2903                 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2904                 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2905                 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2906         }
2907
2908         mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2909
2910         mouse_mode_align->add (*mouse_mode_vbox);
2911         mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2912
2913         mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2914
2915         edit_mode_selector.set_name ("mouse mode button");
2916
2917         if (!ARDOUR::Profile->get_trx()) {
2918                 mode_box->pack_start (edit_mode_selector, false, false);
2919         }
2920         mode_box->pack_start (*mouse_mode_box, false, false);
2921
2922         _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2923         _mouse_mode_tearoff->set_name ("MouseModeBase");
2924         _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2925
2926         if (Profile->get_sae() || Profile->get_mixbus() ) {
2927                 _mouse_mode_tearoff->set_can_be_torn_off (false);
2928         }
2929
2930         _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2931                                                          &_mouse_mode_tearoff->tearoff_window()));
2932         _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2933                                                          &_mouse_mode_tearoff->tearoff_window(), 1));
2934         _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2935                                                          &_mouse_mode_tearoff->tearoff_window()));
2936         _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2937                                                           &_mouse_mode_tearoff->tearoff_window(), 1));
2938
2939         /* Zoom */
2940
2941         _zoom_box.set_spacing (2);
2942         _zoom_box.set_border_width (2);
2943
2944         RefPtr<Action> act;
2945
2946         zoom_preset_selector.set_name ("zoom button");
2947         zoom_preset_selector.set_image(::get_icon ("time_exp"));
2948         zoom_preset_selector.set_size_request (42, -1);
2949
2950         zoom_in_button.set_name ("zoom button");
2951         zoom_in_button.set_image(::get_icon ("zoom_in"));
2952         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2953         zoom_in_button.set_related_action (act);
2954
2955         zoom_out_button.set_name ("zoom button");
2956         zoom_out_button.set_image(::get_icon ("zoom_out"));
2957         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2958         zoom_out_button.set_related_action (act);
2959
2960         zoom_out_full_button.set_name ("zoom button");
2961         zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2962         act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2963         zoom_out_full_button.set_related_action (act);
2964
2965         zoom_focus_selector.set_name ("zoom button");
2966
2967         if (ARDOUR::Profile->get_mixbus()) {
2968                 _zoom_box.pack_start (zoom_preset_selector, false, false);
2969         } else if (ARDOUR::Profile->get_trx()) {
2970                 mode_box->pack_start (zoom_out_button, false, false);
2971                 mode_box->pack_start (zoom_in_button, false, false);
2972         } else {
2973                 _zoom_box.pack_start (zoom_out_button, false, false);
2974                 _zoom_box.pack_start (zoom_in_button, false, false);
2975                 _zoom_box.pack_start (zoom_out_full_button, false, false);
2976                 _zoom_box.pack_start (zoom_focus_selector, false, false);
2977         }
2978
2979         /* Track zoom buttons */
2980         visible_tracks_selector.set_name ("zoom button");
2981         if (Profile->get_mixbus()) {
2982                 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2983                 visible_tracks_selector.set_size_request (42, -1);
2984         } else {
2985                 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2986         }
2987
2988         tav_expand_button.set_name ("zoom button");
2989         tav_expand_button.set_image(::get_icon ("tav_exp"));
2990         act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2991         tav_expand_button.set_related_action (act);
2992
2993         tav_shrink_button.set_name ("zoom button");
2994         tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2995         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2996         tav_shrink_button.set_related_action (act);
2997
2998         if (ARDOUR::Profile->get_mixbus()) {
2999                 _zoom_box.pack_start (visible_tracks_selector);
3000         } else if (ARDOUR::Profile->get_trx()) {
3001                 _zoom_box.pack_start (tav_shrink_button);
3002                 _zoom_box.pack_start (tav_expand_button);
3003         } else {
3004                 _zoom_box.pack_start (visible_tracks_selector);
3005                 _zoom_box.pack_start (tav_shrink_button);
3006                 _zoom_box.pack_start (tav_expand_button);
3007         }
3008
3009         if (!ARDOUR::Profile->get_trx()) {
3010                 _zoom_tearoff = manage (new TearOff (_zoom_box));
3011                 
3012                 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3013                                                            &_zoom_tearoff->tearoff_window()));
3014                 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3015                                                            &_zoom_tearoff->tearoff_window(), 0));
3016                 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3017                                                            &_zoom_tearoff->tearoff_window()));
3018                 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3019                                                             &_zoom_tearoff->tearoff_window(), 0));
3020         } 
3021
3022         if (Profile->get_sae() || Profile->get_mixbus() ) {
3023                 _zoom_tearoff->set_can_be_torn_off (false);
3024         }
3025
3026         snap_box.set_spacing (2);
3027         snap_box.set_border_width (2);
3028
3029         snap_type_selector.set_name ("mouse mode button");
3030
3031         snap_mode_selector.set_name ("mouse mode button");
3032
3033         edit_point_selector.set_name ("mouse mode button");
3034
3035         snap_box.pack_start (snap_mode_selector, false, false);
3036         snap_box.pack_start (snap_type_selector, false, false);
3037         snap_box.pack_start (edit_point_selector, false, false);
3038
3039         /* Nudge */
3040
3041         HBox *nudge_box = manage (new HBox);
3042         nudge_box->set_spacing (2);
3043         nudge_box->set_border_width (2);
3044
3045         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3046         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3047
3048         nudge_box->pack_start (nudge_backward_button, false, false);
3049         nudge_box->pack_start (nudge_forward_button, false, false);
3050         nudge_box->pack_start (*nudge_clock, false, false);
3051
3052
3053         /* Pack everything in... */
3054
3055         HBox* hbox = manage (new HBox);
3056         hbox->set_spacing(2);
3057
3058         _tools_tearoff = manage (new TearOff (*hbox));
3059         _tools_tearoff->set_name ("MouseModeBase");
3060         _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3061
3062         if (Profile->get_sae() || Profile->get_mixbus()) {
3063                 _tools_tearoff->set_can_be_torn_off (false);
3064         }
3065
3066         _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3067                                                     &_tools_tearoff->tearoff_window()));
3068         _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3069                                                     &_tools_tearoff->tearoff_window(), 0));
3070         _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3071                                                     &_tools_tearoff->tearoff_window()));
3072         _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3073                                                      &_tools_tearoff->tearoff_window(), 0));
3074
3075         toolbar_hbox.set_spacing (2);
3076         toolbar_hbox.set_border_width (1);
3077
3078         toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3079         if (!ARDOUR::Profile->get_trx()) {
3080                 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3081                 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3082         }
3083
3084         if (!ARDOUR::Profile->get_trx()) {
3085                 hbox->pack_start (snap_box, false, false);
3086                 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3087                         hbox->pack_start (*nudge_box, false, false);
3088                 } else {
3089                         ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3090                 }
3091         }
3092         hbox->pack_start (panic_box, false, false);
3093
3094         hbox->show_all ();
3095
3096         toolbar_base.set_name ("ToolBarBase");
3097         toolbar_base.add (toolbar_hbox);
3098
3099         _toolbar_viewport.add (toolbar_base);
3100         /* stick to the required height but allow width to vary if there's not enough room */
3101         _toolbar_viewport.set_size_request (1, -1);
3102
3103         toolbar_frame.set_shadow_type (SHADOW_OUT);
3104         toolbar_frame.set_name ("BaseFrame");
3105         toolbar_frame.add (_toolbar_viewport);
3106 }
3107
3108 void
3109 Editor::build_edit_point_menu ()
3110 {
3111         using namespace Menu_Helpers;
3112
3113         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3114         if(!Profile->get_mixbus())
3115                 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3116         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3117
3118         set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3119 }
3120
3121 void
3122 Editor::build_edit_mode_menu ()
3123 {
3124         using namespace Menu_Helpers;
3125         
3126         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3127 //      edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3128         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3129         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
3130
3131         set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3132 }
3133
3134 void
3135 Editor::build_snap_mode_menu ()
3136 {
3137         using namespace Menu_Helpers;
3138
3139         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3140         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3141         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3142
3143         set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3144 }
3145
3146 void
3147 Editor::build_snap_type_menu ()
3148 {
3149         using namespace Menu_Helpers;
3150
3151         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3152         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3153         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3154         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3155         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3156         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3157         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3158         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3159         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3160         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3161         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3162         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3163         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3164         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3165         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3166         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3167         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3168         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3169         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3170         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3171         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3172         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3173         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3174         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3175         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3176         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3177         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3178         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3179         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3180         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3181
3182         set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3183
3184 }
3185
3186 void
3187 Editor::setup_tooltips ()
3188 {
3189         ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3190         ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3191         ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3192         ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Grab/Select Objects"));
3193         ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3194         ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3195         ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3196         ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Edit Contents (notes and automation)"));
3197         ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3198         ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3199         ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3200         ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3201         ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3202         ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3203         ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3204         ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3205         ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3206         ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3207         ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3208         ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3209         ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3210         ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3211         ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3212         ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3213 }
3214
3215 int
3216 Editor::convert_drop_to_paths (
3217                 vector<string>&                paths,
3218                 const RefPtr<Gdk::DragContext>& /*context*/,
3219                 gint                            /*x*/,
3220                 gint                            /*y*/,
3221                 const SelectionData&            data,
3222                 guint                           /*info*/,
3223                 guint                           /*time*/)
3224 {
3225         if (_session == 0) {
3226                 return -1;
3227         }
3228
3229         vector<string> uris = data.get_uris();
3230
3231         if (uris.empty()) {
3232
3233                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3234                    are actually URI lists. So do it by hand.
3235                 */
3236
3237                 if (data.get_target() != "text/plain") {
3238                         return -1;
3239                 }
3240
3241                 /* Parse the "uri-list" format that Nautilus provides,
3242                    where each pathname is delimited by \r\n.
3243
3244                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3245                 */
3246
3247                 string txt = data.get_text();
3248                 char* p;
3249                 const char* q;
3250
3251                 p = (char *) malloc (txt.length() + 1);
3252                 txt.copy (p, txt.length(), 0);
3253                 p[txt.length()] = '\0';
3254
3255                 while (p)
3256                 {
3257                         if (*p != '#')
3258                         {
3259                                 while (g_ascii_isspace (*p))
3260                                         p++;
3261
3262                                 q = p;
3263                                 while (*q && (*q != '\n') && (*q != '\r')) {
3264                                         q++;
3265                                 }
3266
3267                                 if (q > p)
3268                                 {
3269                                         q--;
3270                                         while (q > p && g_ascii_isspace (*q))
3271                                                 q--;
3272
3273                                         if (q > p)
3274                                         {
3275                                                 uris.push_back (string (p, q - p + 1));
3276                                         }
3277                                 }
3278                         }
3279                         p = strchr (p, '\n');
3280                         if (p)
3281                                 p++;
3282                 }
3283
3284                 free ((void*)p);
3285
3286                 if (uris.empty()) {
3287                         return -1;
3288                 }
3289         }
3290
3291         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3292                 if ((*i).substr (0,7) == "file://") {
3293                         paths.push_back (Glib::filename_from_uri (*i));
3294                 }
3295         }
3296
3297         return 0;
3298 }
3299
3300 void
3301 Editor::new_tempo_section ()
3302 {
3303 }
3304
3305 void
3306 Editor::map_transport_state ()
3307 {
3308         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3309
3310         if (_session && _session->transport_stopped()) {
3311                 have_pending_keyboard_selection = false;
3312         }
3313
3314         update_loop_range_view ();
3315 }
3316
3317 /* UNDO/REDO */
3318
3319 void
3320 Editor::begin_selection_op_history ()
3321 {
3322         selection_op_cmd_depth = 0;
3323         selection_op_history_it = 0;
3324         selection_op_history.clear();
3325         selection_undo_action->set_sensitive (false);
3326         selection_redo_action->set_sensitive (false);
3327         selection_op_history.push_front (&_selection_memento->get_state ());
3328 }
3329
3330 void
3331 Editor::begin_reversible_selection_op (string name)
3332 {
3333         if (_session) {
3334                 //cerr << name << endl;
3335                 /* begin/commit pairs can be nested */
3336                 selection_op_cmd_depth++;
3337         }
3338 }
3339
3340 void
3341 Editor::commit_reversible_selection_op ()
3342 {
3343         if (_session) {
3344                 if (selection_op_cmd_depth == 1) {
3345
3346                         if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3347                                 list<XMLNode *>::iterator it = selection_op_history.begin();
3348                                 advance (it, selection_op_history_it);
3349                                 selection_op_history.erase (selection_op_history.begin(), it);
3350                         }
3351                         selection_op_history.push_front (&_selection_memento->get_state ());
3352                         selection_op_history_it = 0;
3353                 }
3354
3355                 if (selection_op_cmd_depth > 0) {
3356                         selection_op_cmd_depth--;
3357                 }
3358
3359                 selection_undo_action->set_sensitive (true);
3360                 selection_redo_action->set_sensitive (false);
3361         }
3362 }
3363
3364 void
3365 Editor::undo_selection_op ()
3366 {
3367         if (_session) {
3368                 selection_op_history_it++;
3369                 uint32_t n = 0;
3370                 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3371                         if (n == selection_op_history_it) {
3372                                 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3373                                 selection_redo_action->set_sensitive (true);
3374                         }
3375                         ++n;
3376
3377                 }
3378                 /* is there an earlier entry? */
3379                 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3380                         selection_undo_action->set_sensitive (false);
3381                 }
3382         }
3383 }
3384
3385 void
3386 Editor::redo_selection_op ()
3387 {
3388         if (_session) {
3389                 if (selection_op_history_it > 0) {
3390                         selection_op_history_it--;
3391                 }
3392                 uint32_t n = 0;
3393                 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3394                         if (n == selection_op_history_it) {
3395                                 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3396                                 selection_undo_action->set_sensitive (true);
3397                         }
3398                         ++n;
3399
3400                 }
3401
3402                 if (selection_op_history_it == 0) {
3403                         selection_redo_action->set_sensitive (false);
3404                 }
3405         }
3406 }
3407
3408 void
3409 Editor::begin_reversible_command (string name)
3410 {
3411         if (_session) {
3412                 before.push_back (&_selection_memento->get_state ());
3413                 _session->begin_reversible_command (name);
3414         }
3415 }
3416
3417 void
3418 Editor::begin_reversible_command (GQuark q)
3419 {
3420         if (_session) {
3421                 before.push_back (&_selection_memento->get_state ());
3422                 _session->begin_reversible_command (q);
3423         }
3424 }
3425
3426 void
3427 Editor::commit_reversible_command ()
3428 {
3429         if (_session) {
3430                 if (before.size() == 1) {
3431                         _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3432                         undo_action->set_sensitive(true);
3433                         begin_selection_op_history ();
3434                 }
3435
3436                 if (before.empty()) {
3437                         cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3438                 } else {
3439                         before.pop_back();
3440                 }
3441
3442                 _session->commit_reversible_command ();
3443         }
3444 }
3445
3446 void
3447 Editor::history_changed ()
3448 {
3449         string label;
3450
3451         if (undo_action && _session) {
3452                 if (_session->undo_depth() == 0) {
3453                         label = S_("Command|Undo");
3454                 } else {
3455                         label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3456                 }
3457                 undo_action->property_label() = label;
3458         }
3459
3460         if (redo_action && _session) {
3461                 if (_session->redo_depth() == 0) {
3462                         label = _("Redo");
3463                 } else {
3464                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3465                 }
3466                 redo_action->property_label() = label;
3467         }
3468 }
3469
3470 void
3471 Editor::duplicate_range (bool with_dialog)
3472 {
3473         float times = 1.0f;
3474
3475         RegionSelection rs = get_regions_from_selection_and_entered ();
3476
3477         if ( selection->time.length() == 0 && rs.empty()) {
3478                 return;
3479         }
3480
3481         if (with_dialog) {
3482
3483                 ArdourDialog win (_("Duplicate"));
3484                 Label label (_("Number of duplications:"));
3485                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3486                 SpinButton spinner (adjustment, 0.0, 1);
3487                 HBox hbox;
3488
3489                 win.get_vbox()->set_spacing (12);
3490                 win.get_vbox()->pack_start (hbox);
3491                 hbox.set_border_width (6);
3492                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3493
3494                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3495                    place, visually. so do this by hand.
3496                 */
3497
3498                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3499                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3500                 spinner.grab_focus();
3501
3502                 hbox.show ();
3503                 label.show ();
3504                 spinner.show ();
3505
3506                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3507                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3508                 win.set_default_response (RESPONSE_ACCEPT);
3509
3510                 spinner.grab_focus ();
3511
3512                 switch (win.run ()) {
3513                 case RESPONSE_ACCEPT:
3514                         break;
3515                 default:
3516                         return;
3517                 }
3518
3519                 times = adjustment.get_value();
3520         }
3521
3522         if ((current_mouse_mode() == Editing::MouseRange)) {
3523                 if (selection->time.length()) {
3524                         duplicate_selection (times);
3525                 }
3526         } else if (get_smart_mode()) {
3527                 if (selection->time.length()) {
3528                         duplicate_selection (times);
3529                 } else 
3530                         duplicate_some_regions (rs, times);
3531         } else {
3532                 duplicate_some_regions (rs, times);
3533         }
3534 }
3535
3536 void
3537 Editor::set_edit_mode (EditMode m)
3538 {
3539         Config->set_edit_mode (m);
3540 }
3541
3542 void
3543 Editor::cycle_edit_mode ()
3544 {
3545         switch (Config->get_edit_mode()) {
3546         case Slide:
3547                 if (Profile->get_sae()) {
3548                         Config->set_edit_mode (Lock);
3549                 } else {
3550                         Config->set_edit_mode (Ripple);
3551                 }
3552                 break;
3553         case Splice:
3554         case Ripple:
3555                 Config->set_edit_mode (Lock);
3556                 break;
3557         case Lock:
3558                 Config->set_edit_mode (Slide);
3559                 break;
3560         }
3561 }
3562
3563 void
3564 Editor::edit_mode_selection_done ( EditMode m )
3565 {
3566         Config->set_edit_mode ( m );
3567 }
3568
3569 void
3570 Editor::snap_type_selection_done (SnapType snaptype)
3571 {
3572         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3573         if (ract) {
3574                 ract->set_active ();
3575         }
3576 }
3577
3578 void
3579 Editor::snap_mode_selection_done (SnapMode mode)
3580 {
3581         RefPtr<RadioAction> ract = snap_mode_action (mode);
3582
3583         if (ract) {
3584                 ract->set_active (true);
3585         }
3586 }
3587
3588 void
3589 Editor::cycle_edit_point (bool with_marker)
3590 {
3591         if(Profile->get_mixbus())
3592                 with_marker = false;
3593
3594         switch (_edit_point) {
3595         case EditAtMouse:
3596                 set_edit_point_preference (EditAtPlayhead);
3597                 break;
3598         case EditAtPlayhead:
3599                 if (with_marker) {
3600                         set_edit_point_preference (EditAtSelectedMarker);
3601                 } else {
3602                         set_edit_point_preference (EditAtMouse);
3603                 }
3604                 break;
3605         case EditAtSelectedMarker:
3606                 set_edit_point_preference (EditAtMouse);
3607                 break;
3608         }
3609 }
3610
3611 void
3612 Editor::edit_point_selection_done (EditPoint ep)
3613 {
3614         set_edit_point_preference ( ep );
3615 }
3616
3617 void
3618 Editor::build_zoom_focus_menu ()
3619 {
3620         using namespace Menu_Helpers;
3621
3622         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3623         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3624         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3625         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3626         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3627         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3628
3629         set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3630 }
3631
3632 void
3633 Editor::zoom_focus_selection_done ( ZoomFocus f )
3634 {
3635         RefPtr<RadioAction> ract = zoom_focus_action (f);
3636         if (ract) {
3637                 ract->set_active ();
3638         }
3639 }
3640
3641 void
3642 Editor::build_track_count_menu ()
3643 {
3644         using namespace Menu_Helpers;
3645
3646         if (!Profile->get_mixbus()) {
3647                 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3648                 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3649                 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3650                 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3651                 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3652                 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3653                 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3654                 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3655                 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3656                 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3657                 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3658                 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3659                 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3660         } else {
3661                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3662                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3663                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3664                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3665                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3666                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3667                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3668                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3669                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3670                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3671
3672                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3673                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3674                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3675                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3676                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3677                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3678                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3679                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3680                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3681                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3682                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3683         }
3684 }
3685
3686 void
3687 Editor::set_zoom_preset (int64_t ms)
3688 {
3689         if ( ms <= 0 ) {
3690                 temporal_zoom_session();
3691                 return;
3692         }
3693         
3694         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3695         temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3696 }
3697
3698 void
3699 Editor::set_visible_track_count (int32_t n)
3700 {
3701         _visible_track_count = n;
3702
3703         /* if the canvas hasn't really been allocated any size yet, just
3704            record the desired number of visible tracks and return. when canvas
3705            allocation happens, we will get called again and then we can do the
3706            real work.
3707         */
3708         
3709         if (_visible_canvas_height <= 1) {
3710                 return;
3711         }
3712
3713         int h;
3714         string str;
3715         DisplaySuspender ds;
3716         
3717         if (_visible_track_count > 0) {
3718                 h = trackviews_height() / _visible_track_count;
3719                 std::ostringstream s;
3720                 s << _visible_track_count;
3721                 str = s.str();
3722         } else if (_visible_track_count == 0) {
3723                 uint32_t n = 0;
3724                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3725                         if ((*i)->marked_for_display()) {
3726                                 ++n;
3727                         }
3728                 }
3729                 h = trackviews_height() / n;
3730                 str = _("All");
3731         } else {
3732                 /* negative value means that the visible track count has 
3733                    been overridden by explicit track height changes.
3734                 */
3735                 visible_tracks_selector.set_text (X_("*"));
3736                 return;
3737         }
3738
3739         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3740                 (*i)->set_height (h);
3741         }
3742         
3743         if (str != visible_tracks_selector.get_text()) {
3744                 visible_tracks_selector.set_text (str);
3745         }
3746 }
3747
3748 void
3749 Editor::override_visible_track_count ()
3750 {
3751         _visible_track_count = -1;
3752         visible_tracks_selector.set_text ( _("*") );
3753 }
3754
3755 bool
3756 Editor::edit_controls_button_release (GdkEventButton* ev)
3757 {
3758         if (Keyboard::is_context_menu_event (ev)) {
3759                 ARDOUR_UI::instance()->add_route (this);
3760         } else if (ev->button == 1) {
3761                 selection->clear_tracks ();
3762         }
3763
3764         return true;
3765 }
3766
3767 bool
3768 Editor::mouse_select_button_release (GdkEventButton* ev)
3769 {
3770         /* this handles just right-clicks */
3771
3772         if (ev->button != 3) {
3773                 return false;
3774         }
3775
3776         return true;
3777 }
3778
3779 void
3780 Editor::set_zoom_focus (ZoomFocus f)
3781 {
3782         string str = zoom_focus_strings[(int)f];
3783
3784         if (str != zoom_focus_selector.get_text()) {
3785                 zoom_focus_selector.set_text (str);
3786         }
3787
3788         if (zoom_focus != f) {
3789                 zoom_focus = f;
3790                 instant_save ();
3791         }
3792 }
3793
3794 void
3795 Editor::cycle_zoom_focus ()
3796 {
3797         switch (zoom_focus) {
3798         case ZoomFocusLeft:
3799                 set_zoom_focus (ZoomFocusRight);
3800                 break;
3801         case ZoomFocusRight:
3802                 set_zoom_focus (ZoomFocusCenter);
3803                 break;
3804         case ZoomFocusCenter:
3805                 set_zoom_focus (ZoomFocusPlayhead);
3806                 break;
3807         case ZoomFocusPlayhead:
3808                 set_zoom_focus (ZoomFocusMouse);
3809                 break;
3810         case ZoomFocusMouse:
3811                 set_zoom_focus (ZoomFocusEdit);
3812                 break;
3813         case ZoomFocusEdit:
3814                 set_zoom_focus (ZoomFocusLeft);
3815                 break;
3816         }
3817 }
3818
3819 void
3820 Editor::ensure_float (Window& win)
3821 {
3822         win.set_transient_for (*this);
3823 }
3824
3825 void
3826 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3827 {
3828         /* recover or initialize pane positions. do this here rather than earlier because
3829            we don't want the positions to change the child allocations, which they seem to do.
3830          */
3831
3832         int pos;
3833         XMLProperty* prop;
3834         char buf[32];
3835         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3836
3837         enum Pane {
3838                 Horizontal = 0x1,
3839                 Vertical = 0x2
3840         };
3841
3842         static Pane done;
3843
3844         XMLNode* geometry = find_named_node (*node, "geometry");
3845
3846         if (which == static_cast<Paned*> (&edit_pane)) {
3847
3848                 if (done & Horizontal) {
3849                         return;
3850                 }
3851
3852                 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3853                         _notebook_shrunk = string_is_affirmative (prop->value ());
3854                 }
3855
3856                 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3857                         /* initial allocation is 90% to canvas, 10% to notebook */
3858                         pos = (int) floor (alloc.get_width() * 0.90f);
3859                         snprintf (buf, sizeof(buf), "%d", pos);
3860                 } else {
3861                         pos = atoi (prop->value());
3862                 }
3863
3864                 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3865                         edit_pane.set_position (pos);
3866                 }
3867
3868                 done = (Pane) (done | Horizontal);
3869
3870         } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3871
3872                 if (done & Vertical) {
3873                         return;
3874                 }
3875
3876                 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3877                         /* initial allocation is 90% to canvas, 10% to summary */
3878                         pos = (int) floor (alloc.get_height() * 0.90f);
3879                         snprintf (buf, sizeof(buf), "%d", pos);
3880                 } else {
3881
3882                         pos = atoi (prop->value());
3883                 }
3884
3885                 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3886                         editor_summary_pane.set_position (pos);
3887                 }
3888
3889                 done = (Pane) (done | Vertical);
3890         }
3891 }
3892
3893 void
3894 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3895 {
3896         if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) && 
3897             (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) && 
3898             (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3899                 top_hbox.remove (toolbar_frame);
3900         }
3901 }
3902
3903 void
3904 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3905 {
3906         if (toolbar_frame.get_parent() == 0) {
3907                 top_hbox.pack_end (toolbar_frame);
3908         }
3909 }
3910
3911 void
3912 Editor::set_show_measures (bool yn)
3913 {
3914         if (_show_measures != yn) {
3915                 hide_measures ();
3916
3917                 if ((_show_measures = yn) == true) {
3918                         if (tempo_lines) {
3919                                 tempo_lines->show();
3920                         }
3921
3922                         ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3923                         ARDOUR::TempoMap::BBTPointList::const_iterator end;
3924                         
3925                         compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3926                         draw_measures (begin, end);
3927                 } 
3928
3929                 instant_save ();
3930         }
3931 }
3932
3933 void
3934 Editor::toggle_follow_playhead ()
3935 {
3936         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3937         if (act) {
3938                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3939                 set_follow_playhead (tact->get_active());
3940         }
3941 }
3942
3943 /** @param yn true to follow playhead, otherwise false.
3944  *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3945  */
3946 void
3947 Editor::set_follow_playhead (bool yn, bool catch_up)
3948 {
3949         if (_follow_playhead != yn) {
3950                 if ((_follow_playhead = yn) == true && catch_up) {
3951                         /* catch up */
3952                         reset_x_origin_to_follow_playhead ();
3953                 }
3954                 instant_save ();
3955         }
3956 }
3957
3958 void
3959 Editor::toggle_stationary_playhead ()
3960 {
3961         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3962         if (act) {
3963                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3964                 set_stationary_playhead (tact->get_active());
3965         }
3966 }
3967
3968 void
3969 Editor::set_stationary_playhead (bool yn)
3970 {
3971         if (_stationary_playhead != yn) {
3972                 if ((_stationary_playhead = yn) == true) {
3973                         /* catch up */
3974                         // FIXME need a 3.0 equivalent of this 2.X call
3975                         // update_current_screen ();
3976                 }
3977                 instant_save ();
3978         }
3979 }
3980
3981 PlaylistSelector&
3982 Editor::playlist_selector () const
3983 {
3984         return *_playlist_selector;
3985 }
3986
3987 framecnt_t
3988 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3989 {
3990         if (paste_count == 0) {
3991                 /* don't bother calculating an offset that will be zero anyway */
3992                 return 0;
3993         }
3994
3995         /* calculate basic unsnapped multi-paste offset */
3996         framecnt_t offset = paste_count * duration;
3997
3998         /* snap offset so pos + offset is aligned to the grid */
3999         framepos_t offset_pos = pos + offset;
4000         snap_to(offset_pos, RoundUpMaybe);
4001         offset = offset_pos - pos;
4002
4003         return offset;
4004 }
4005
4006 unsigned
4007 Editor::get_grid_beat_divisions(framepos_t position)
4008 {
4009         switch (_snap_type) {
4010         case SnapToBeatDiv128: return 128;
4011         case SnapToBeatDiv64:  return 64;
4012         case SnapToBeatDiv32:  return 32;
4013         case SnapToBeatDiv28:  return 28;
4014         case SnapToBeatDiv24:  return 24;
4015         case SnapToBeatDiv20:  return 20;
4016         case SnapToBeatDiv16:  return 16;
4017         case SnapToBeatDiv14:  return 14;
4018         case SnapToBeatDiv12:  return 12;
4019         case SnapToBeatDiv10:  return 10;
4020         case SnapToBeatDiv8:   return 8;
4021         case SnapToBeatDiv7:   return 7;
4022         case SnapToBeatDiv6:   return 6;
4023         case SnapToBeatDiv5:   return 5;
4024         case SnapToBeatDiv4:   return 4;
4025         case SnapToBeatDiv3:   return 3;
4026         case SnapToBeatDiv2:   return 2;
4027         default:               return 0;
4028         }
4029         return 0;
4030 }
4031
4032 Evoral::Beats
4033 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4034 {
4035         success = true;
4036
4037         const unsigned divisions = get_grid_beat_divisions(position);
4038         if (divisions) {
4039                 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4040         }
4041
4042         switch (_snap_type) {
4043         case SnapToBeat:
4044                 return Evoral::Beats(1.0);
4045         case SnapToBar:
4046                 if (_session) {
4047                         return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4048                 }
4049                 break;
4050         default:
4051                 success = false;
4052                 break;
4053         }
4054
4055         return Evoral::Beats();
4056 }
4057
4058 framecnt_t
4059 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4060 {
4061         framecnt_t ret;
4062
4063         ret = nudge_clock->current_duration (pos);
4064         next = ret + 1; /* XXXX fix me */
4065
4066         return ret;
4067 }
4068
4069 int
4070 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4071 {
4072         ArdourDialog dialog (_("Playlist Deletion"));
4073         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
4074                                         "If it is kept, its audio files will not be cleaned.\n"
4075                                         "If it is deleted, audio files used by it alone will be cleaned."),
4076                                       pl->name()));
4077
4078         dialog.set_position (WIN_POS_CENTER);
4079         dialog.get_vbox()->pack_start (label);
4080
4081         label.show ();
4082
4083         dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4084         dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4085         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4086
4087         switch (dialog.run ()) {
4088         case RESPONSE_ACCEPT:
4089                 /* delete the playlist */
4090                 return 0;
4091                 break;
4092
4093         case RESPONSE_REJECT:
4094                 /* keep the playlist */
4095                 return 1;
4096                 break;
4097
4098         default:
4099                 break;
4100         }
4101
4102         return -1;
4103 }
4104
4105 bool
4106 Editor::audio_region_selection_covers (framepos_t where)
4107 {
4108         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4109                 if ((*a)->region()->covers (where)) {
4110                         return true;
4111                 }
4112         }
4113
4114         return false;
4115 }
4116
4117 void
4118 Editor::prepare_for_cleanup ()
4119 {
4120         cut_buffer->clear_regions ();
4121         cut_buffer->clear_playlists ();
4122
4123         selection->clear_regions ();
4124         selection->clear_playlists ();
4125
4126         _regions->suspend_redisplay ();
4127 }
4128
4129 void
4130 Editor::finish_cleanup ()
4131 {
4132         _regions->resume_redisplay ();
4133 }
4134
4135 Location*
4136 Editor::transport_loop_location()
4137 {
4138         if (_session) {
4139                 return _session->locations()->auto_loop_location();
4140         } else {
4141                 return 0;
4142         }
4143 }
4144
4145 Location*
4146 Editor::transport_punch_location()
4147 {
4148         if (_session) {
4149                 return _session->locations()->auto_punch_location();
4150         } else {
4151                 return 0;
4152         }
4153 }
4154
4155 bool
4156 Editor::control_layout_scroll (GdkEventScroll* ev)
4157 {
4158         /* Just forward to the normal canvas scroll method. The coordinate
4159            systems are different but since the canvas is always larger than the
4160            track headers, and aligned with the trackview area, this will work.
4161
4162            In the not too distant future this layout is going away anyway and
4163            headers will be on the canvas.
4164         */
4165         return canvas_scroll_event (ev, false);
4166 }
4167
4168 void
4169 Editor::session_state_saved (string)
4170 {
4171         update_title ();
4172         _snapshots->redisplay ();
4173 }
4174
4175 void
4176 Editor::update_tearoff_visibility()
4177 {
4178         bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4179         _mouse_mode_tearoff->set_visible (visible);
4180         _tools_tearoff->set_visible (visible);
4181         if (_zoom_tearoff) {
4182                 _zoom_tearoff->set_visible (visible);
4183         }
4184 }
4185
4186 void
4187 Editor::reattach_all_tearoffs ()
4188 {
4189         if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4190         if (_tools_tearoff) _tools_tearoff->put_it_back ();
4191         if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4192 }
4193
4194 void
4195 Editor::maximise_editing_space ()
4196 {
4197         if (_maximised) {
4198                 return;
4199         }
4200
4201         fullscreen ();
4202
4203         _maximised = true;
4204 }
4205
4206 void
4207 Editor::restore_editing_space ()
4208 {
4209         if (!_maximised) {
4210                 return;
4211         }
4212
4213         unfullscreen();
4214
4215         _maximised = false;
4216 }
4217
4218 /**
4219  *  Make new playlists for a given track and also any others that belong
4220  *  to the same active route group with the `select' property.
4221  *  @param v Track.
4222  */
4223
4224 void
4225 Editor::new_playlists (TimeAxisView* v)
4226 {
4227         begin_reversible_command (_("new playlists"));
4228         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4229         _session->playlists->get (playlists);
4230         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4231         commit_reversible_command ();
4232 }
4233
4234 /**
4235  *  Use a copy of the current playlist for a given track and also any others that belong
4236  *  to the same active route group with the `select' property.
4237  *  @param v Track.
4238  */
4239
4240 void
4241 Editor::copy_playlists (TimeAxisView* v)
4242 {
4243         begin_reversible_command (_("copy playlists"));
4244         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4245         _session->playlists->get (playlists);
4246         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4247         commit_reversible_command ();
4248 }
4249
4250 /** Clear the current playlist for a given track and also any others that belong
4251  *  to the same active route group with the `select' property.
4252  *  @param v Track.
4253  */
4254
4255 void
4256 Editor::clear_playlists (TimeAxisView* v)
4257 {
4258         begin_reversible_command (_("clear playlists"));        
4259         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4260         _session->playlists->get (playlists);
4261         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4262         commit_reversible_command ();
4263 }
4264
4265 void
4266 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4267 {
4268         atv.use_new_playlist (sz > 1 ? false : true, playlists);
4269 }
4270
4271 void
4272 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4273 {
4274         atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4275 }
4276
4277 void
4278 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4279 {
4280         atv.clear_playlist ();
4281 }
4282
4283 bool
4284 Editor::on_key_press_event (GdkEventKey* ev)
4285 {
4286         return key_press_focus_accelerator_handler (*this, ev);
4287 }
4288
4289 bool
4290 Editor::on_key_release_event (GdkEventKey* ev)
4291 {
4292         return Gtk::Window::on_key_release_event (ev);
4293         // return key_press_focus_accelerator_handler (*this, ev);
4294 }
4295
4296 double
4297 Editor::get_y_origin () const
4298 {
4299         return vertical_adjustment.get_value ();
4300 }
4301
4302 /** Queue up a change to the viewport x origin.
4303  *  @param frame New x origin.
4304  */
4305 void
4306 Editor::reset_x_origin (framepos_t frame)
4307 {
4308         pending_visual_change.add (VisualChange::TimeOrigin);
4309         pending_visual_change.time_origin = frame;
4310         ensure_visual_change_idle_handler ();
4311 }
4312
4313 void
4314 Editor::reset_y_origin (double y)
4315 {
4316         pending_visual_change.add (VisualChange::YOrigin);
4317         pending_visual_change.y_origin = y;
4318         ensure_visual_change_idle_handler ();
4319 }
4320
4321 void
4322 Editor::reset_zoom (framecnt_t spp)
4323 {
4324         if (spp == samples_per_pixel) {
4325                 return;
4326         }
4327
4328         pending_visual_change.add (VisualChange::ZoomLevel);
4329         pending_visual_change.samples_per_pixel = spp;
4330         ensure_visual_change_idle_handler ();
4331 }
4332
4333 void
4334 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4335 {
4336         reset_x_origin (frame);
4337         reset_zoom (fpu);
4338
4339         if (!no_save_visual) {
4340                 undo_visual_stack.push_back (current_visual_state(false));
4341         }
4342 }
4343
4344 Editor::VisualState::VisualState (bool with_tracks)
4345         : gui_state (with_tracks ? new GUIObjectState : 0)
4346 {
4347 }
4348
4349 Editor::VisualState::~VisualState ()
4350 {
4351         delete gui_state;
4352 }
4353
4354 Editor::VisualState*
4355 Editor::current_visual_state (bool with_tracks)
4356 {
4357         VisualState* vs = new VisualState (with_tracks);
4358         vs->y_position = vertical_adjustment.get_value();
4359         vs->samples_per_pixel = samples_per_pixel;
4360         vs->leftmost_frame = leftmost_frame;
4361         vs->zoom_focus = zoom_focus;
4362
4363         if (with_tracks) {      
4364                 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4365         }
4366
4367         return vs;
4368 }
4369
4370 void
4371 Editor::undo_visual_state ()
4372 {
4373         if (undo_visual_stack.empty()) {
4374                 return;
4375         }
4376
4377         VisualState* vs = undo_visual_stack.back();
4378         undo_visual_stack.pop_back();
4379
4380
4381         redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4382
4383         if (vs) {
4384                 use_visual_state (*vs);
4385         }
4386 }
4387
4388 void
4389 Editor::redo_visual_state ()
4390 {
4391         if (redo_visual_stack.empty()) {
4392                 return;
4393         }
4394
4395         VisualState* vs = redo_visual_stack.back();
4396         redo_visual_stack.pop_back();
4397
4398         // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4399         // why do we check here?
4400         undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4401
4402         if (vs) {
4403                 use_visual_state (*vs);
4404         }
4405 }
4406
4407 void
4408 Editor::swap_visual_state ()
4409 {
4410         if (undo_visual_stack.empty()) {
4411                 redo_visual_state ();
4412         } else {
4413                 undo_visual_state ();
4414         }
4415 }
4416
4417 void
4418 Editor::use_visual_state (VisualState& vs)
4419 {
4420         PBD::Unwinder<bool> nsv (no_save_visual, true);
4421         DisplaySuspender ds;
4422
4423         vertical_adjustment.set_value (vs.y_position);
4424
4425         set_zoom_focus (vs.zoom_focus);
4426         reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4427         
4428         if (vs.gui_state) {
4429                 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4430                 
4431                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {    
4432                         (*i)->reset_visual_state ();
4433                 }
4434         }
4435
4436         _routes->update_visibility ();
4437 }
4438
4439 /** This is the core function that controls the zoom level of the canvas. It is called
4440  *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
4441  *  @param spp new number of samples per pixel
4442  */
4443 void
4444 Editor::set_samples_per_pixel (framecnt_t spp)
4445 {
4446         if (spp < 1) {
4447                 return;
4448         }
4449
4450         const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4451         const framecnt_t lots_of_pixels = 4000;
4452
4453         /* if the zoom level is greater than what you'd get trying to display 3
4454          * days of audio on a really big screen, then it's too big.
4455          */
4456
4457         if (spp * lots_of_pixels > three_days) {
4458                 return;
4459         }
4460
4461         samples_per_pixel = spp;
4462
4463         if (tempo_lines) {
4464                 tempo_lines->tempo_map_changed();
4465         }
4466
4467         bool const showing_time_selection = selection->time.length() > 0;
4468
4469         if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4470                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4471                         (*i)->reshow_selection (selection->time);
4472                 }
4473         }
4474
4475         ZoomChanged (); /* EMIT_SIGNAL */
4476
4477         ArdourCanvas::GtkCanvasViewport* c;
4478
4479         c = get_track_canvas();
4480         if (c) {
4481                 c->canvas()->zoomed ();
4482         }
4483
4484         if (playhead_cursor) {
4485                 playhead_cursor->set_position (playhead_cursor->current_frame ());
4486         }
4487
4488         refresh_location_display();
4489         _summary->set_overlays_dirty ();
4490
4491         update_marker_labels ();
4492
4493         instant_save ();
4494 }
4495
4496 void
4497 Editor::queue_visual_videotimeline_update ()
4498 {
4499         /* TODO:
4500          * pending_visual_change.add (VisualChange::VideoTimeline);
4501          * or maybe even more specific: which videotimeline-image
4502          * currently it calls update_video_timeline() to update
4503          * _all outdated_ images on the video-timeline.
4504          * see 'exposeimg()' in video_image_frame.cc
4505          */
4506         ensure_visual_change_idle_handler ();
4507 }
4508
4509 void
4510 Editor::ensure_visual_change_idle_handler ()
4511 {
4512         if (pending_visual_change.idle_handler_id < 0) {
4513                 // see comment in add_to_idle_resize above.
4514                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4515                 pending_visual_change.being_handled = false;
4516         }
4517 }
4518
4519 int
4520 Editor::_idle_visual_changer (void* arg)
4521 {
4522         return static_cast<Editor*>(arg)->idle_visual_changer ();
4523 }
4524
4525 int
4526 Editor::idle_visual_changer ()
4527 {
4528         /* set_horizontal_position() below (and maybe other calls) call
4529            gtk_main_iteration(), so it's possible that a signal will be handled
4530            half-way through this method.  If this signal wants an
4531            idle_visual_changer we must schedule another one after this one, so
4532            mark the idle_handler_id as -1 here to allow that.  Also make a note
4533            that we are doing the visual change, so that changes in response to
4534            super-rapid-screen-update can be dropped if we are still processing
4535            the last one.
4536         */
4537
4538         pending_visual_change.idle_handler_id = -1;
4539         pending_visual_change.being_handled = true;
4540         
4541         VisualChange vc = pending_visual_change;
4542
4543         pending_visual_change.pending = (VisualChange::Type) 0;
4544
4545         visual_changer (vc);
4546
4547         pending_visual_change.being_handled = false;
4548
4549         return 0; /* this is always a one-shot call */
4550 }
4551
4552 void
4553 Editor::visual_changer (const VisualChange& vc)
4554 {
4555         double const last_time_origin = horizontal_position ();
4556
4557         if (vc.pending & VisualChange::ZoomLevel) {
4558                 set_samples_per_pixel (vc.samples_per_pixel);
4559
4560                 compute_fixed_ruler_scale ();
4561
4562                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4563                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4564                 
4565                 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4566                                             current_bbt_points_begin, current_bbt_points_end);
4567                 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4568                                          current_bbt_points_begin, current_bbt_points_end);
4569                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4570
4571                 update_video_timeline();
4572         }
4573
4574         if (vc.pending & VisualChange::TimeOrigin) {
4575                 set_horizontal_position (vc.time_origin / samples_per_pixel);
4576         }
4577
4578         if (vc.pending & VisualChange::YOrigin) {
4579                 vertical_adjustment.set_value (vc.y_origin);
4580         }
4581
4582         if (last_time_origin == horizontal_position ()) {
4583                 /* changed signal not emitted */
4584                 update_fixed_rulers ();
4585                 redisplay_tempo (true);
4586         }
4587
4588         if (!(vc.pending & VisualChange::ZoomLevel)) {
4589                 update_video_timeline();
4590         }
4591
4592         _summary->set_overlays_dirty ();
4593 }
4594
4595 struct EditorOrderTimeAxisSorter {
4596     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4597             return a->order () < b->order ();
4598     }
4599 };
4600
4601 void
4602 Editor::sort_track_selection (TrackViewList& sel)
4603 {
4604         EditorOrderTimeAxisSorter cmp;
4605         sel.sort (cmp);
4606 }
4607
4608 framepos_t
4609 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4610 {
4611         bool ignored;
4612         framepos_t where = 0;
4613         EditPoint ep = _edit_point;
4614
4615         if(Profile->get_mixbus())
4616                 if (ep == EditAtSelectedMarker)
4617                         ep=EditAtPlayhead;
4618                 
4619         if (from_context_menu && (ep == EditAtMouse)) {
4620                 return  canvas_event_sample (&context_click_event, 0, 0);
4621         }
4622
4623         if (entered_marker) {
4624                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4625                 return entered_marker->position();
4626         }
4627
4628         if (ignore_playhead && ep == EditAtPlayhead) {
4629                 ep = EditAtSelectedMarker;
4630         }
4631
4632         switch (ep) {
4633         case EditAtPlayhead:
4634                 where = _session->audible_frame();
4635                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4636                 break;
4637
4638         case EditAtSelectedMarker:
4639                 if (!selection->markers.empty()) {
4640                         bool is_start;
4641                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4642                         if (loc) {
4643                                 if (is_start) {
4644                                         where =  loc->start();
4645                                 } else {
4646                                         where = loc->end();
4647                                 }
4648                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4649                                 break;
4650                         }
4651                 }
4652                 /* fallthru */
4653
4654         default:
4655         case EditAtMouse:
4656                 if (!mouse_frame (where, ignored)) {
4657                         /* XXX not right but what can we do ? */
4658                         return 0;
4659                 }
4660                 snap_to (where);
4661                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4662                 break;
4663         }
4664
4665         return where;
4666 }
4667
4668 void
4669 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4670 {
4671         if (!_session) return;
4672
4673         begin_reversible_command (cmd);
4674
4675         Location* tll;
4676
4677         if ((tll = transport_loop_location()) == 0) {
4678                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4679                 XMLNode &before = _session->locations()->get_state();
4680                 _session->locations()->add (loc, true);
4681                 _session->set_auto_loop_location (loc);
4682                 XMLNode &after = _session->locations()->get_state();
4683                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4684         } else {
4685                 XMLNode &before = tll->get_state();
4686                 tll->set_hidden (false, this);
4687                 tll->set (start, end);
4688                 XMLNode &after = tll->get_state();
4689                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4690         }
4691
4692         commit_reversible_command ();
4693 }
4694
4695 void
4696 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4697 {
4698         if (!_session) return;
4699
4700         begin_reversible_command (cmd);
4701
4702         Location* tpl;
4703
4704         if ((tpl = transport_punch_location()) == 0) {
4705                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
4706                 XMLNode &before = _session->locations()->get_state();
4707                 _session->locations()->add (loc, true);
4708                 _session->set_auto_punch_location (loc);
4709                 XMLNode &after = _session->locations()->get_state();
4710                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4711         } else {
4712                 XMLNode &before = tpl->get_state();
4713                 tpl->set_hidden (false, this);
4714                 tpl->set (start, end);
4715                 XMLNode &after = tpl->get_state();
4716                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4717         }
4718
4719         commit_reversible_command ();
4720 }
4721
4722 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4723  *  @param rs List to which found regions are added.
4724  *  @param where Time to look at.
4725  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4726  */
4727 void
4728 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4729 {
4730         const TrackViewList* tracks;
4731
4732         if (ts.empty()) {
4733                 tracks = &track_views;
4734         } else {
4735                 tracks = &ts;
4736         }
4737
4738         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4739
4740                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4741
4742                 if (rtv) {
4743                         boost::shared_ptr<Track> tr;
4744                         boost::shared_ptr<Playlist> pl;
4745
4746                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4747
4748                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4749                                                 (framepos_t) floor ( (double) where * tr->speed()));
4750
4751                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4752                                         RegionView* rv = rtv->view()->find_view (*i);
4753                                         if (rv) {
4754                                                 rs.add (rv);
4755                                         }
4756                                 }
4757                         }
4758                 }
4759         }
4760 }
4761
4762 void
4763 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4764 {
4765         const TrackViewList* tracks;
4766
4767         if (ts.empty()) {
4768                 tracks = &track_views;
4769         } else {
4770                 tracks = &ts;
4771         }
4772
4773         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4774                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4775                 if (rtv) {
4776                         boost::shared_ptr<Track> tr;
4777                         boost::shared_ptr<Playlist> pl;
4778
4779                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4780
4781                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4782                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4783
4784                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4785
4786                                         RegionView* rv = rtv->view()->find_view (*i);
4787
4788                                         if (rv) {
4789                                                 rs.add (rv);
4790                                         }
4791                                 }
4792                         }
4793                 }
4794         }
4795 }
4796
4797 /** Get regions using the following method:
4798  *
4799  *  Make a region list using:
4800  *   (a) any selected regions
4801  *   (b) the intersection of any selected tracks and the edit point(*)
4802  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4803  *
4804  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4805  *
4806  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4807  */
4808
4809 RegionSelection
4810 Editor::get_regions_from_selection_and_edit_point ()
4811 {
4812         RegionSelection regions;
4813
4814         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4815                 regions.add (entered_regionview);
4816         } else {
4817                 regions = selection->regions;
4818         }
4819
4820         if ( regions.empty() ) {
4821                 TrackViewList tracks = selection->tracks;
4822
4823                 if (!tracks.empty()) {
4824                         /* no region selected or entered, but some selected tracks:
4825                          * act on all regions on the selected tracks at the edit point
4826                          */ 
4827                         framepos_t const where = get_preferred_edit_position ();
4828                         get_regions_at(regions, where, tracks);
4829                 }
4830         }
4831
4832         return regions;
4833 }
4834
4835 /** Get regions using the following method:
4836  *
4837  *  Make a region list using:
4838  *   (a) any selected regions
4839  *   (b) the intersection of any selected tracks and the edit point(*)
4840  *   (c) if neither exists, then whatever region is under the mouse
4841  *
4842  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4843  *
4844  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4845  */
4846 RegionSelection
4847 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4848 {
4849         RegionSelection regions;
4850
4851         if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4852                 regions.add (entered_regionview);
4853         } else {
4854                 regions = selection->regions;
4855         }
4856
4857         if ( regions.empty() ) {
4858                 TrackViewList tracks = selection->tracks;
4859
4860                 if (!tracks.empty()) {
4861                         /* no region selected or entered, but some selected tracks:
4862                          * act on all regions on the selected tracks at the edit point
4863                          */ 
4864                         get_regions_at(regions, pos, tracks);
4865                 }
4866         }
4867
4868         return regions;
4869 }
4870
4871 /** Start with regions that are selected, or the entered regionview if none are selected.
4872  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4873  *  of the regions that we started with.
4874  */
4875
4876 RegionSelection
4877 Editor::get_regions_from_selection_and_entered ()
4878 {
4879         RegionSelection regions = selection->regions;
4880
4881         if (regions.empty() && entered_regionview) {
4882                 regions.add (entered_regionview);
4883         }
4884
4885         return regions;
4886 }
4887
4888 void
4889 Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
4890 {
4891         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4892                 RouteTimeAxisView* tatv;
4893                 
4894                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4895                         boost::shared_ptr<Playlist> pl;
4896                         std::vector<boost::shared_ptr<Region> > results;
4897                         boost::shared_ptr<Track> tr;
4898                         
4899                         if ((tr = tatv->track()) == 0) {
4900                                 /* bus */
4901                                 continue;
4902                         }
4903                         
4904                         if ((pl = (tr->playlist())) != 0) {
4905                                 boost::shared_ptr<Region> r = pl->region_by_id (id);
4906                                 if (r) {
4907                                         RegionView* marv = tatv->view()->find_view (r);
4908                                         if (marv) {
4909                                                 regions.push_back (marv);
4910                                         }
4911                                 }
4912                         }
4913                 }
4914         }
4915 }
4916
4917 void
4918 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4919 {
4920         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4921
4922                 RouteTimeAxisView* tatv;
4923
4924                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4925
4926                         boost::shared_ptr<Playlist> pl;
4927                         vector<boost::shared_ptr<Region> > results;
4928                         RegionView* marv;
4929                         boost::shared_ptr<Track> tr;
4930
4931                         if ((tr = tatv->track()) == 0) {
4932                                 /* bus */
4933                                 continue;
4934                         }
4935
4936                         if ((pl = (tr->playlist())) != 0) {
4937                                 if (src_comparison) {
4938                                         pl->get_source_equivalent_regions (region, results);
4939                                 } else {
4940                                         pl->get_region_list_equivalent_regions (region, results);
4941                                 }
4942                         }
4943
4944                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4945                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4946                                         regions.push_back (marv);
4947                                 }
4948                         }
4949
4950                 }
4951         }
4952 }
4953
4954 void
4955 Editor::show_rhythm_ferret ()
4956 {
4957         if (rhythm_ferret == 0) {
4958                 rhythm_ferret = new RhythmFerret(*this);
4959         }
4960
4961         rhythm_ferret->set_session (_session);
4962         rhythm_ferret->show ();
4963         rhythm_ferret->present ();
4964 }
4965
4966 void
4967 Editor::first_idle ()
4968 {
4969         MessageDialog* dialog = 0;
4970         
4971         if (track_views.size() > 1) {
4972                 dialog = new MessageDialog (
4973                         *this,
4974                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4975                         true
4976                         );
4977                 dialog->present ();
4978                 ARDOUR_UI::instance()->flush_pending ();
4979         }
4980
4981         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4982                 (*t)->first_idle();
4983         }
4984
4985         // first idle adds route children (automation tracks), so we need to redisplay here
4986         _routes->redisplay ();
4987
4988         delete dialog;
4989
4990         if (_session->undo_depth() == 0) {
4991                 undo_action->set_sensitive(false);
4992         }
4993         redo_action->set_sensitive(false);
4994         begin_selection_op_history ();
4995
4996         _have_idled = true;
4997 }
4998
4999 gboolean
5000 Editor::_idle_resize (gpointer arg)
5001 {
5002         return ((Editor*)arg)->idle_resize ();
5003 }
5004
5005 void
5006 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5007 {
5008         if (resize_idle_id < 0) {
5009                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5010                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5011                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5012                  */
5013                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5014                 _pending_resize_amount = 0;
5015         }
5016
5017         /* make a note of the smallest resulting height, so that we can clamp the
5018            lower limit at TimeAxisView::hSmall */
5019
5020         int32_t min_resulting = INT32_MAX;
5021
5022         _pending_resize_amount += h;
5023         _pending_resize_view = view;
5024
5025         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5026
5027         if (selection->tracks.contains (_pending_resize_view)) {
5028                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5029                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5030                 }
5031         }
5032
5033         if (min_resulting < 0) {
5034                 min_resulting = 0;
5035         }
5036
5037         /* clamp */
5038         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5039                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5040         }
5041 }
5042
5043 /** Handle pending resizing of tracks */
5044 bool
5045 Editor::idle_resize ()
5046 {
5047         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5048
5049         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5050             selection->tracks.contains (_pending_resize_view)) {
5051
5052                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5053                         if (*i != _pending_resize_view) {
5054                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5055                         }
5056                 }
5057         }
5058
5059         _pending_resize_amount = 0;
5060         _group_tabs->set_dirty ();
5061         resize_idle_id = -1;
5062
5063         return false;
5064 }
5065
5066 void
5067 Editor::located ()
5068 {
5069         ENSURE_GUI_THREAD (*this, &Editor::located);
5070
5071         if (_session) {
5072                 playhead_cursor->set_position (_session->audible_frame ());
5073                 if (_follow_playhead && !_pending_initial_locate) {
5074                         reset_x_origin_to_follow_playhead ();
5075                 }
5076         }
5077
5078         _pending_locate_request = false;
5079         _pending_initial_locate = false;
5080 }
5081
5082 void
5083 Editor::region_view_added (RegionView * rv)
5084 {
5085         for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5086                 if (rv->region ()->id () == (*pr)) {
5087                         selection->add (rv);
5088                         selection->regions.pending.erase (pr);
5089                         break;
5090                 }
5091         }
5092         _summary->set_background_dirty ();
5093 }
5094
5095 void
5096 Editor::region_view_removed ()
5097 {
5098         _summary->set_background_dirty ();
5099 }
5100
5101 RouteTimeAxisView*
5102 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5103 {
5104         TrackViewList::const_iterator j = track_views.begin ();
5105         while (j != track_views.end()) {
5106                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5107                 if (rtv && rtv->route() == r) {
5108                         return rtv;
5109                 }
5110                 ++j;
5111         }
5112
5113         return 0;
5114 }
5115
5116
5117 TrackViewList
5118 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5119 {
5120         TrackViewList t;
5121
5122         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5123                 TimeAxisView* tv = axis_view_from_route (*i);
5124                 if (tv) {
5125                         t.push_back (tv);
5126                 }
5127         }
5128
5129         return t;
5130 }
5131
5132 void
5133 Editor::suspend_route_redisplay ()
5134 {
5135         if (_routes) {
5136                 _routes->suspend_redisplay();
5137         }
5138 }
5139
5140 void
5141 Editor::resume_route_redisplay ()
5142 {
5143         if (_routes) {
5144                 _routes->resume_redisplay();
5145         }
5146 }
5147
5148 void
5149 Editor::add_routes (RouteList& routes)
5150 {
5151         ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5152
5153         RouteTimeAxisView *rtv;
5154         list<RouteTimeAxisView*> new_views;
5155
5156         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5157                 boost::shared_ptr<Route> route = (*x);
5158
5159                 if (route->is_auditioner() || route->is_monitor()) {
5160                         continue;
5161                 }
5162
5163                 DataType dt = route->input()->default_type();
5164
5165                 if (dt == ARDOUR::DataType::AUDIO) {
5166                         rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5167                         rtv->set_route (route);
5168                 } else if (dt == ARDOUR::DataType::MIDI) {
5169                         rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5170                         rtv->set_route (route);
5171                 } else {
5172                         throw unknown_type();
5173                 }
5174
5175                 new_views.push_back (rtv);
5176                 track_views.push_back (rtv);
5177
5178                 rtv->effective_gain_display ();
5179
5180                 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5181                 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5182         }
5183
5184         if (new_views.size() > 0) {
5185                 _routes->routes_added (new_views);
5186                 _summary->routes_added (new_views);
5187         }
5188
5189         if (show_editor_mixer_when_tracks_arrive) {
5190                 show_editor_mixer (true);
5191         }
5192
5193         editor_list_button.set_sensitive (true);
5194 }
5195
5196 void
5197 Editor::timeaxisview_deleted (TimeAxisView *tv)
5198 {
5199         if (tv == entered_track) {
5200                 entered_track = 0;
5201         }
5202
5203         if (_session && _session->deletion_in_progress()) {
5204                 /* the situation is under control */
5205                 return;
5206         }
5207
5208         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5209
5210         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5211
5212         _routes->route_removed (tv);
5213
5214         TimeAxisView::Children c = tv->get_child_list ();
5215         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5216                 if (entered_track == i->get()) {
5217                         entered_track = 0;
5218                 }
5219         }
5220
5221         /* remove it from the list of track views */
5222
5223         TrackViewList::iterator i;
5224
5225         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5226                 i = track_views.erase (i);
5227         }
5228
5229         /* update whatever the current mixer strip is displaying, if revelant */
5230
5231         boost::shared_ptr<Route> route;
5232
5233         if (rtav) {
5234                 route = rtav->route ();
5235         }
5236
5237         if (current_mixer_strip && current_mixer_strip->route() == route) {
5238
5239                 TimeAxisView* next_tv;
5240
5241                 if (track_views.empty()) {
5242                         next_tv = 0;
5243                 } else if (i == track_views.end()) {
5244                         next_tv = track_views.front();
5245                 } else {
5246                         next_tv = (*i);
5247                 }
5248
5249
5250                 if (next_tv) {
5251                         set_selected_mixer_strip (*next_tv);
5252                 } else {
5253                         /* make the editor mixer strip go away setting the
5254                          * button to inactive (which also unticks the menu option)
5255                          */
5256
5257                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5258                 }
5259         }
5260 }
5261
5262 void
5263 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5264 {
5265         if (apply_to_selection) {
5266                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5267
5268                         TrackSelection::iterator j = i;
5269                         ++j;
5270
5271                         hide_track_in_display (*i, false);
5272
5273                         i = j;
5274                 }
5275         } else {
5276                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5277
5278                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5279                         // this will hide the mixer strip
5280                         set_selected_mixer_strip (*tv);
5281                 }
5282
5283                 _routes->hide_track_in_display (*tv);
5284         }
5285 }
5286
5287 bool
5288 Editor::sync_track_view_list_and_routes ()
5289 {
5290         track_views = TrackViewList (_routes->views ());
5291
5292         _summary->set_dirty ();
5293         _group_tabs->set_dirty ();
5294
5295         return false; // do not call again (until needed)
5296 }
5297
5298 void
5299 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5300 {
5301         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5302                 theslot (**i);
5303         }
5304 }
5305
5306 /** Find a RouteTimeAxisView by the ID of its route */
5307 RouteTimeAxisView*
5308 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5309 {
5310         RouteTimeAxisView* v;
5311
5312         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5313                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5314                         if(v->route()->id() == id) {
5315                                 return v;
5316                         }
5317                 }
5318         }
5319
5320         return 0;
5321 }
5322
5323 void
5324 Editor::fit_route_group (RouteGroup *g)
5325 {
5326         TrackViewList ts = axis_views_from_routes (g->route_list ());
5327         fit_tracks (ts);
5328 }
5329
5330 void
5331 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5332 {
5333         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5334
5335         if (r == 0) {
5336                 _session->cancel_audition ();
5337                 return;
5338         }
5339
5340         if (_session->is_auditioning()) {
5341                 _session->cancel_audition ();
5342                 if (r == last_audition_region) {
5343                         return;
5344                 }
5345         }
5346
5347         _session->audition_region (r);
5348         last_audition_region = r;
5349 }
5350
5351
5352 void
5353 Editor::hide_a_region (boost::shared_ptr<Region> r)
5354 {
5355         r->set_hidden (true);
5356 }
5357
5358 void
5359 Editor::show_a_region (boost::shared_ptr<Region> r)
5360 {
5361         r->set_hidden (false);
5362 }
5363
5364 void
5365 Editor::audition_region_from_region_list ()
5366 {
5367         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5368 }
5369
5370 void
5371 Editor::hide_region_from_region_list ()
5372 {
5373         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5374 }
5375
5376 void
5377 Editor::show_region_in_region_list ()
5378 {
5379         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5380 }
5381
5382 void
5383 Editor::step_edit_status_change (bool yn)
5384 {
5385         if (yn) {
5386                 start_step_editing ();
5387         } else {
5388                 stop_step_editing ();
5389         }
5390 }
5391
5392 void
5393 Editor::start_step_editing ()
5394 {
5395         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5396 }
5397
5398 void
5399 Editor::stop_step_editing ()
5400 {
5401         step_edit_connection.disconnect ();
5402 }
5403
5404 bool
5405 Editor::check_step_edit ()
5406 {
5407         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5408                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5409                 if (mtv) {
5410                         mtv->check_step_edit ();
5411                 }
5412         }
5413
5414         return true; // do it again, till we stop
5415 }
5416
5417 bool
5418 Editor::scroll_press (Direction dir)
5419 {
5420         ++_scroll_callbacks;
5421
5422         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5423                 /* delay the first auto-repeat */
5424                 return true;
5425         }
5426
5427         switch (dir) {
5428         case LEFT:
5429                 scroll_backward (1);
5430                 break;
5431
5432         case RIGHT:
5433                 scroll_forward (1);
5434                 break;
5435
5436         case UP:
5437                 scroll_up_one_track ();
5438                 break;
5439
5440         case DOWN:
5441                 scroll_down_one_track ();
5442                 break;
5443         }
5444
5445         /* do hacky auto-repeat */
5446         if (!_scroll_connection.connected ()) {
5447
5448                 _scroll_connection = Glib::signal_timeout().connect (
5449                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5450                         );
5451
5452                 _scroll_callbacks = 0;
5453         }
5454
5455         return true;
5456 }
5457
5458 void
5459 Editor::scroll_release ()
5460 {
5461         _scroll_connection.disconnect ();
5462 }
5463
5464 /** Queue a change for the Editor viewport x origin to follow the playhead */
5465 void
5466 Editor::reset_x_origin_to_follow_playhead ()
5467 {
5468         framepos_t const frame = playhead_cursor->current_frame ();
5469
5470         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5471
5472                 if (_session->transport_speed() < 0) {
5473
5474                         if (frame > (current_page_samples() / 2)) {
5475                                 center_screen (frame-(current_page_samples()/2));
5476                         } else {
5477                                 center_screen (current_page_samples()/2);
5478                         }
5479
5480                 } else {
5481
5482                         framepos_t l = 0;
5483                         
5484                         if (frame < leftmost_frame) {
5485                                 /* moving left */
5486                                 if (_session->transport_rolling()) {
5487                                         /* rolling; end up with the playhead at the right of the page */
5488                                         l = frame - current_page_samples ();
5489                                 } else {
5490                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5491                                         l = frame - current_page_samples() / 4;
5492                                 }
5493                         } else {
5494                                 /* moving right */
5495                                 if (_session->transport_rolling()) {
5496                                         /* rolling: end up with the playhead on the left of the page */
5497                                         l = frame;
5498                                 } else {
5499                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5500                                         l = frame - 3 * current_page_samples() / 4;
5501                                 }
5502                         }
5503
5504                         if (l < 0) {
5505                                 l = 0;
5506                         }
5507                         
5508                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5509                 }
5510         }
5511 }
5512
5513 void
5514 Editor::super_rapid_screen_update ()
5515 {
5516         if (!_session || !_session->engine().running()) {
5517                 return;
5518         }
5519
5520         /* METERING / MIXER STRIPS */
5521
5522         /* update track meters, if required */
5523         if (is_mapped() && meters_running) {
5524                 RouteTimeAxisView* rtv;
5525                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5526                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5527                                 rtv->fast_update ();
5528                         }
5529                 }
5530         }
5531
5532         /* and any current mixer strip */
5533         if (current_mixer_strip) {
5534                 current_mixer_strip->fast_update ();
5535         }
5536
5537         /* PLAYHEAD AND VIEWPORT */
5538
5539         framepos_t const frame = _session->audible_frame();
5540
5541         /* There are a few reasons why we might not update the playhead / viewport stuff:
5542          *
5543          * 1.  we don't update things when there's a pending locate request, otherwise
5544          *     when the editor requests a locate there is a chance that this method
5545          *     will move the playhead before the locate request is processed, causing
5546          *     a visual glitch.
5547          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5548          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5549          */
5550
5551         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5552
5553                 last_update_frame = frame;
5554
5555                 if (!_dragging_playhead) {
5556                         playhead_cursor->set_position (frame);
5557                 }
5558
5559                 if (!_stationary_playhead) {
5560
5561                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5562                                 /* We only do this if we aren't already
5563                                    handling a visual change (ie if
5564                                    pending_visual_change.being_handled is
5565                                    false) so that these requests don't stack
5566                                    up there are too many of them to handle in
5567                                    time.
5568                                 */
5569                                 reset_x_origin_to_follow_playhead ();
5570                         }
5571
5572                 } else {
5573
5574                         /* don't do continuous scroll till the new position is in the rightmost quarter of the
5575                            editor canvas
5576                         */
5577 #if 0
5578                         // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5579                         double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5580                         if (target <= 0.0) {
5581                                 target = 0.0;
5582                         }
5583                         if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5584                                 target = (target * 0.15) + (current * 0.85);
5585                         } else {
5586                                 /* relax */
5587                         }
5588
5589                         current = target;
5590                         set_horizontal_position (current);
5591 #endif
5592                 }
5593
5594         }
5595 }
5596
5597
5598 void
5599 Editor::session_going_away ()
5600 {
5601         _have_idled = false;
5602
5603         _session_connections.drop_connections ();
5604
5605         super_rapid_screen_update_connection.disconnect ();
5606
5607         selection->clear ();
5608         cut_buffer->clear ();
5609
5610         clicked_regionview = 0;
5611         clicked_axisview = 0;
5612         clicked_routeview = 0;
5613         entered_regionview = 0;
5614         entered_track = 0;
5615         last_update_frame = 0;
5616         _drags->abort ();
5617
5618         playhead_cursor->hide ();
5619
5620         /* rip everything out of the list displays */
5621
5622         _regions->clear ();
5623         _routes->clear ();
5624         _route_groups->clear ();
5625
5626         /* do this first so that deleting a track doesn't reset cms to null
5627            and thus cause a leak.
5628         */
5629
5630         if (current_mixer_strip) {
5631                 if (current_mixer_strip->get_parent() != 0) {
5632                         global_hpacker.remove (*current_mixer_strip);
5633                 }
5634                 delete current_mixer_strip;
5635                 current_mixer_strip = 0;
5636         }
5637
5638         /* delete all trackviews */
5639
5640         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5641                 delete *i;
5642         }
5643         track_views.clear ();
5644
5645         nudge_clock->set_session (0);
5646
5647         editor_list_button.set_active(false);
5648         editor_list_button.set_sensitive(false);
5649
5650         /* clear tempo/meter rulers */
5651         remove_metric_marks ();
5652         hide_measures ();
5653         clear_marker_display ();
5654
5655         stop_step_editing ();
5656         
5657         /* get rid of any existing editor mixer strip */
5658
5659         WindowTitle title(Glib::get_application_name());
5660         title += _("Editor");
5661
5662         set_title (title.get_string());
5663
5664         SessionHandlePtr::session_going_away ();
5665 }
5666
5667
5668 void
5669 Editor::show_editor_list (bool yn)
5670 {
5671         if (yn) {
5672                 _the_notebook.show ();
5673         } else {
5674                 _the_notebook.hide ();
5675         }
5676 }
5677
5678 void
5679 Editor::change_region_layering_order (bool from_context_menu)
5680 {
5681         const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5682
5683         if (!clicked_routeview) {
5684                 if (layering_order_editor) {
5685                         layering_order_editor->hide ();
5686                 }
5687                 return;
5688         }
5689
5690         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5691
5692         if (!track) {
5693                 return;
5694         }
5695
5696         boost::shared_ptr<Playlist> pl = track->playlist();
5697
5698         if (!pl) {
5699                 return;
5700         }
5701
5702         if (layering_order_editor == 0) {
5703                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5704         }
5705
5706         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5707         layering_order_editor->maybe_present ();
5708 }
5709
5710 void
5711 Editor::update_region_layering_order_editor ()
5712 {
5713         if (layering_order_editor && layering_order_editor->is_visible ()) {
5714                 change_region_layering_order (true);
5715         }
5716 }
5717
5718 void
5719 Editor::setup_fade_images ()
5720 {
5721         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5722         _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5723         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5724         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5725         _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5726
5727         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5728         _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5729         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5730         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5731         _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5732         
5733         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5734         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5735         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5736         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5737         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5738
5739         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5740         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5741         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5742         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5743         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5744
5745 }
5746
5747 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5748 Gtk::MenuItem&
5749 Editor::action_menu_item (std::string const & name)
5750 {
5751         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5752         assert (a);
5753
5754         return *manage (a->create_menu_item ());
5755 }
5756
5757 void
5758 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5759 {
5760         EventBox* b = manage (new EventBox);
5761         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5762         Label* l = manage (new Label (name));
5763         l->set_angle (-90);
5764         b->add (*l);
5765         b->show_all ();
5766         _the_notebook.append_page (widget, *b);
5767 }
5768
5769 bool
5770 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5771 {
5772         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5773                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5774         }
5775
5776         if (ev->type == GDK_2BUTTON_PRESS) {
5777
5778                 /* double-click on a notebook tab shrinks or expands the notebook */
5779
5780                 if (_notebook_shrunk) {
5781                         if (pre_notebook_shrink_pane_width) {
5782                                 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5783                         }
5784                         _notebook_shrunk = false;
5785                 } else {
5786                         pre_notebook_shrink_pane_width = edit_pane.get_position();
5787
5788                         /* this expands the LHS of the edit pane to cover the notebook
5789                            PAGE but leaves the tabs visible.
5790                          */
5791                         edit_pane.set_position (edit_pane.get_position() + page->get_width());
5792                         _notebook_shrunk = true;
5793                 }
5794         }
5795
5796         return true;
5797 }
5798
5799 void
5800 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5801 {
5802         using namespace Menu_Helpers;
5803         
5804         MenuList& items = _control_point_context_menu.items ();
5805         items.clear ();
5806         
5807         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5808         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5809         if (!can_remove_control_point (item)) {
5810                 items.back().set_sensitive (false);
5811         }
5812
5813         _control_point_context_menu.popup (event->button.button, event->button.time);
5814 }
5815
5816 void
5817 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5818 {
5819         using namespace Menu_Helpers;
5820
5821         NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5822         if (!note) {
5823                 return;
5824         }
5825
5826         /* We need to get the selection here and pass it to the operations, since
5827            popping up the menu will cause a region leave event which clears
5828            entered_regionview. */
5829
5830         MidiRegionView&       mrv = note->region_view();
5831         const RegionSelection rs  = get_regions_from_selection_and_entered ();
5832
5833         MenuList& items = _note_context_menu.items();
5834         items.clear();
5835
5836         items.push_back(MenuElem(_("Delete"),
5837                                  sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5838         items.push_back(MenuElem(_("Edit..."),
5839                                  sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5840         items.push_back(MenuElem(_("Legatize"),
5841                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5842         items.push_back(MenuElem(_("Quantize..."),
5843                                  sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5844         items.push_back(MenuElem(_("Remove Overlap"),
5845                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5846         items.push_back(MenuElem(_("Transform..."),
5847                                  sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5848
5849         _note_context_menu.popup (event->button.button, event->button.time);
5850 }
5851
5852 void
5853 Editor::zoom_vertical_modifier_released()
5854 {
5855         _stepping_axis_view = 0;
5856 }
5857
5858 void
5859 Editor::ui_parameter_changed (string parameter)
5860 {
5861         if (parameter == "icon-set") {
5862                 while (!_cursor_stack.empty()) {
5863                         _cursor_stack.pop_back();
5864                 }
5865                 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5866                 _cursor_stack.push_back(_cursors->grabber);
5867         } else if (parameter == "draggable-playhead") {
5868                 if (_verbose_cursor) {
5869                         playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());
5870                 }
5871         }
5872 }