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