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