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