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