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