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