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