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