AU GUIs basically working, though unfinished; push up dialog for massive split operat...
[ardour.git] / gtk2_ardour / editor.cc
1 /*
2     Copyright (C) 2000-2007 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 #include <sys/time.h>
21 #include <unistd.h>
22 #include <cstdlib>
23 #include <cmath>
24 #include <string>
25 #include <algorithm>
26
27 #include <boost/none.hpp>
28
29 #include <sigc++/bind.h>
30
31 #include <pbd/convert.h>
32 #include <pbd/error.h>
33 #include <pbd/enumwriter.h>
34 #include <pbd/memento_command.h>
35
36 #include <glibmm/miscutils.h>
37 #include <gtkmm/image.h>
38 #include <gdkmm/color.h>
39 #include <gdkmm/bitmap.h>
40
41 #include <gtkmm2ext/grouped_buttons.h>
42 #include <gtkmm2ext/gtk_ui.h>
43 #include <gtkmm2ext/tearoff.h>
44 #include <gtkmm2ext/utils.h>
45 #include <gtkmm2ext/window_title.h>
46 #include <gtkmm2ext/choice.h>
47
48 #include <ardour/audio_track.h>
49 #include <ardour/audio_diskstream.h>
50 #include <ardour/plugin_manager.h>
51 #include <ardour/location.h>
52 #include <ardour/audioplaylist.h>
53 #include <ardour/audioregion.h>
54 #include <ardour/region.h>
55 #include <ardour/session_route.h>
56 #include <ardour/tempo.h>
57 #include <ardour/utils.h>
58 #include <ardour/profile.h>
59
60 #include <control_protocol/control_protocol.h>
61
62 #include "ardour_ui.h"
63 #include "editor.h"
64 #include "keyboard.h"
65 #include "marker.h"
66 #include "playlist_selector.h"
67 #include "audio_region_view.h"
68 #include "rgb_macros.h"
69 #include "selection.h"
70 #include "audio_streamview.h"
71 #include "time_axis_view.h"
72 #include "audio_time_axis.h"
73 #include "utils.h"
74 #include "crossfade_view.h"
75 #include "editing.h"
76 #include "public_editor.h"
77 #include "crossfade_edit.h"
78 #include "canvas_impl.h"
79 #include "actions.h"
80 #include "gui_thread.h"
81 #include "sfdb_ui.h"
82 #include "rhythm_ferret.h"
83
84 #ifdef FFT_ANALYSIS
85 #include "analysis_window.h"
86 #endif
87
88 #include "i18n.h"
89
90 /* <CMT Additions> */
91 #include "imageframe_socket_handler.h"
92 /* </CMT Additions> */
93
94 using namespace std;
95 using namespace sigc;
96 using namespace ARDOUR;
97 using namespace PBD;
98 using namespace Gtk;
99 using namespace Glib;
100 using namespace Gtkmm2ext;
101 using namespace Editing;
102
103 using PBD::atoi;
104
105 const double Editor::timebar_height = 15.0;
106
107 #include "editor_xpms"
108
109 static const gchar *_snap_type_strings[] = {
110         N_("CD Frames"),
111         N_("SMPTE Frames"),
112         N_("SMPTE Seconds"),
113         N_("SMPTE Minutes"),
114         N_("Seconds"),
115         N_("Minutes"),
116         N_("Beats/32"),
117         N_("Beats/16"),
118         N_("Beats/8"),
119         N_("Beats/4"),
120         N_("Beats/3"),
121         N_("Beats"),
122         N_("Bars"),
123         N_("Marks"),
124         N_("Region starts"),
125         N_("Region ends"),
126         N_("Region syncs"),
127         N_("Region bounds"),
128         0
129 };
130
131 static const gchar *_snap_mode_strings[] = {
132         N_("No Grid"),
133         N_("Grid"),
134         N_("Magnetic"),
135         0
136 };
137
138 static const gchar *_edit_point_strings[] = {
139         N_("Playhead"),
140         N_("Marker"),
141         N_("Mouse"),
142         0
143 };
144
145 static const gchar *_zoom_focus_strings[] = {
146         N_("Left"),
147         N_("Right"),
148         N_("Center"),
149         N_("Playhead"),
150         N_("Mouse"),
151         N_("Edit Point"),
152         0
153 };
154
155 #ifdef USE_RUBBERBAND
156 static const gchar *_rb_opt_strings[] = {
157         N_("Mushy"),
158         N_("Smooth"),
159         N_("Balanced multitimbral mixture"),
160         N_("Unpitched percussion with stable notes"),
161         N_("Crisp monophonic instrumental"),
162         N_("Unpitched solo percussion"),
163         0
164 };
165 #endif
166
167 /* Soundfile  drag-n-drop */
168
169 Gdk::Cursor* Editor::cross_hair_cursor = 0;
170 Gdk::Cursor* Editor::selector_cursor = 0;
171 Gdk::Cursor* Editor::trimmer_cursor = 0;
172 Gdk::Cursor* Editor::grabber_cursor = 0;
173 Gdk::Cursor* Editor::zoom_cursor = 0;
174 Gdk::Cursor* Editor::time_fx_cursor = 0;
175 Gdk::Cursor* Editor::fader_cursor = 0;
176 Gdk::Cursor* Editor::speaker_cursor = 0;
177 Gdk::Cursor* Editor::wait_cursor = 0;
178 Gdk::Cursor* Editor::timebar_cursor = 0;
179 Gdk::Cursor* Editor::transparent_cursor = 0;
180
181 void
182 show_me_the_size (Requisition* r, const char* what)
183 {
184         cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
185 }
186
187 Editor::Editor ()
188         : 
189           /* time display buttons */
190           minsec_label (_("Mins:Secs")),
191           bbt_label (_("Bars:Beats")),
192           smpte_label (_("Timecode")),
193           frame_label (_("Samples")),
194           tempo_label (_("Tempo")),
195           meter_label (_("Meter")),
196           mark_label (_("Location Markers")),
197           range_mark_label (_("Range Markers")),
198           transport_mark_label (_("Loop/Punch Ranges")),
199           cd_mark_label (_("CD Markers")),
200
201           edit_packer (3, 3, true),
202
203           /* the values here don't matter: layout widgets
204              reset them as needed.
205           */
206
207           vertical_adjustment (0.0, 0.0, 10.0, 400.0),
208           horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
209
210           /* tool bar related */
211
212           edit_point_clock (X_("editpoint"), false, X_("EditPointClock"), true),
213           zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
214           
215           toolbar_selection_clock_table (2,3),
216           
217           automation_mode_button (_("mode")),
218           global_automation_button (_("automation")),
219
220           /* <CMT Additions> */
221           image_socket_listener(0),
222           /* </CMT Additions> */
223
224           /* nudge */
225
226           nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true),
227           meters_running(false)
228
229 {
230         constructed = false;
231
232         /* we are a singleton */
233
234         PublicEditor::_instance = this;
235
236         session = 0;
237
238         selection = new Selection;
239         cut_buffer = new Selection;
240
241         selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
242         selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
243         selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
244         selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
245         selection->MarkersChanged.connect (mem_fun(*this, &Editor::marker_selection_changed));
246
247         clicked_regionview = 0;
248         clicked_trackview = 0;
249         clicked_audio_trackview = 0;
250         clicked_crossfadeview = 0;
251         clicked_control_point = 0;
252         last_update_frame = 0;
253         drag_info.item = 0;
254         current_mixer_strip = 0;
255         current_bbt_points = 0;
256         
257         snap_type_strings =  I18N (_snap_type_strings);
258         snap_mode_strings =  I18N (_snap_mode_strings);
259         zoom_focus_strings = I18N (_zoom_focus_strings);
260         edit_point_strings = I18N (_edit_point_strings);
261 #ifdef USE_RUBBERBAND
262         rb_opt_strings = I18N (_rb_opt_strings);
263 #endif
264         
265         snap_threshold = 5.0;
266         bbt_beat_subdivision = 4;
267         canvas_width = 0;
268         canvas_height = 0;
269         autoscroll_active = false;
270         autoscroll_timeout_tag = -1;
271         interthread_progress_window = 0;
272         logo_item = 0;
273
274 #ifdef FFT_ANALYSIS
275         analysis_window = 0;
276 #endif
277
278         current_interthread_info = 0;
279         _show_measures = true;
280         _show_waveforms = true;
281         _show_waveforms_recording = true;
282         first_action_message = 0;
283         export_dialog = 0;
284         export_range_markers_dialog = 0;
285         show_gain_after_trim = false;
286         ignore_route_list_reorder = false;
287         no_route_list_redisplay = false;
288         verbose_cursor_on = true;
289         route_removal = false;
290         show_automatic_regions_in_region_list = true;
291         last_item_entered = 0;
292         last_item_entered_n = 0;
293
294         region_list_sort_type = (Editing::RegionListSortType) 0;
295         have_pending_keyboard_selection = false;
296         _follow_playhead = true;
297         _xfade_visibility = true;
298         editor_ruler_menu = 0;
299         no_ruler_shown_update = false;
300         edit_group_list_menu = 0;
301         route_list_menu = 0;
302         region_list_menu = 0;
303         marker_menu = 0;
304         start_end_marker_menu = 0;
305         range_marker_menu = 0;
306         marker_menu_item = 0;
307         tm_marker_menu = 0;
308         transport_marker_menu = 0;
309         new_transport_marker_menu = 0;
310         editor_mixer_strip_width = Wide;
311         show_editor_mixer_when_tracks_arrive = false;
312         region_edit_menu_split_item = 0;
313         temp_location = 0;
314         region_edit_menu_split_multichannel_item = 0;
315         leftmost_frame = 0;
316         ignore_mouse_mode_toggle = false;
317         current_stepping_trackview = 0;
318         entered_track = 0;
319         entered_regionview = 0;
320         entered_marker = 0;
321         clear_entered_track = false;
322         _new_regionviews_show_envelope = false;
323         current_timefx = 0;
324         in_edit_group_row_change = false;
325         last_canvas_frame = 0;
326         playhead_cursor = 0;
327         button_release_can_deselect = true;
328         canvas_idle_queued = false;
329         _dragging_playhead = false;
330         _dragging_edit_point = false;
331         _dragging_hscrollbar = false;
332         select_new_marker = false;
333         zoomed_to_region = false;
334         rhythm_ferret = 0;
335
336         scrubbing_direction = 0;
337
338         sfbrowser = 0;
339         ignore_route_order_sync = false;
340
341         location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
342         location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
343         location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
344         location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
345         location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
346
347         range_marker_drag_rect = 0;
348         marker_drag_line = 0;
349         
350         set_mouse_mode (MouseObject, true);
351
352         last_visual_state.frames_per_unit = 0;
353
354         frames_per_unit = 2048; /* too early to use reset_zoom () */
355         reset_hscrollbar_stepping ();
356         
357         zoom_focus = ZoomFocusLeft;
358         set_zoom_focus (ZoomFocusLeft);
359         zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
360
361         initialize_rulers ();
362         initialize_canvas ();
363
364         edit_controls_vbox.set_spacing (0);
365         horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled), false);
366         vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
367         
368         track_canvas.set_hadjustment (horizontal_adjustment);
369         track_canvas.set_vadjustment (vertical_adjustment);
370         time_canvas.set_hadjustment (horizontal_adjustment);
371
372         track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
373         time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
374         
375         controls_layout.add (edit_controls_vbox);
376         controls_layout.set_name ("EditControlsBase");
377         controls_layout.add_events (Gdk::SCROLL_MASK);
378         controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
379         
380         controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
381         controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
382         controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
383
384         edit_vscrollbar.set_adjustment (vertical_adjustment);
385         edit_hscrollbar.set_adjustment (horizontal_adjustment);
386
387         edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
388         edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
389         edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
390
391         edit_hscrollbar.set_name ("EditorHScrollbar");
392
393         build_cursors ();
394         setup_toolbar ();
395
396         edit_point_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_point_clock_changed));
397         
398         time_canvas_vbox.pack_start (*_ruler_separator, false, false);
399         time_canvas_vbox.pack_start (*minsec_ruler, false, false);
400         time_canvas_vbox.pack_start (*smpte_ruler, false, false);
401         time_canvas_vbox.pack_start (*frames_ruler, false, false);
402         time_canvas_vbox.pack_start (*bbt_ruler, false, false);
403         time_canvas_vbox.pack_start (time_canvas, true, true);
404         time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
405
406         bbt_label.set_name ("EditorTimeButton");
407         bbt_label.set_size_request (-1, (int)timebar_height);
408         bbt_label.set_alignment (1.0, 0.5);
409         bbt_label.set_padding (5,0);
410         minsec_label.set_name ("EditorTimeButton");
411         minsec_label.set_size_request (-1, (int)timebar_height);
412         minsec_label.set_alignment (1.0, 0.5);
413         minsec_label.set_padding (5,0);
414         smpte_label.set_name ("EditorTimeButton");
415         smpte_label.set_size_request (-1, (int)timebar_height);
416         smpte_label.set_alignment (1.0, 0.5);
417         smpte_label.set_padding (5,0);
418         frame_label.set_name ("EditorTimeButton");
419         frame_label.set_size_request (-1, (int)timebar_height);
420         frame_label.set_alignment (1.0, 0.5);
421         frame_label.set_padding (5,0);
422         tempo_label.set_name ("EditorTimeButton");
423         tempo_label.set_size_request (-1, (int)timebar_height);
424         tempo_label.set_alignment (1.0, 0.5);
425         tempo_label.set_padding (5,0);
426         meter_label.set_name ("EditorTimeButton");
427         meter_label.set_size_request (-1, (int)timebar_height);
428         meter_label.set_alignment (1.0, 0.5);
429         meter_label.set_padding (5,0);
430         mark_label.set_name ("EditorTimeButton");
431         mark_label.set_size_request (-1, (int)timebar_height);
432         mark_label.set_alignment (1.0, 0.5);
433         mark_label.set_padding (5,0);
434         cd_mark_label.set_name ("EditorTimeButton");
435         cd_mark_label.set_size_request (-1, (int)timebar_height);
436         cd_mark_label.set_alignment (1.0, 0.5);
437         cd_mark_label.set_padding (5,0);
438         range_mark_label.set_name ("EditorTimeButton");
439         range_mark_label.set_size_request (-1, (int)timebar_height);
440         range_mark_label.set_alignment (1.0, 0.5);
441         range_mark_label.set_padding (5,0);
442         transport_mark_label.set_name ("EditorTimeButton");
443         transport_mark_label.set_size_request (-1, (int)timebar_height);
444         transport_mark_label.set_alignment (1.0, 0.5);
445         transport_mark_label.set_padding (5,0);
446         
447         time_button_vbox.pack_start (minsec_label, false, false);
448         time_button_vbox.pack_start (smpte_label, false, false);
449         time_button_vbox.pack_start (frame_label, false, false);
450         time_button_vbox.pack_start (bbt_label, false, false);
451         time_button_vbox.pack_start (meter_label, false, false);
452         time_button_vbox.pack_start (tempo_label, false, false);
453         time_button_vbox.pack_start (mark_label, false, false);
454
455         time_button_event_box.add (time_button_vbox);
456         
457         time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
458         time_button_event_box.set_name ("TimebarLabelBase");
459         time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
460
461         time_button_frame.add(time_button_event_box);
462         time_button_frame.property_shadow_type() = Gtk::SHADOW_OUT;
463
464         /* these enable us to have a dedicated window (for cursor setting, etc.) 
465            for the canvas areas.
466         */
467
468         track_canvas_event_box.add (track_canvas);
469
470         time_canvas_event_box.add (time_canvas_vbox);
471         time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
472         
473         edit_packer.set_col_spacings (0);
474         edit_packer.set_row_spacings (0);
475         edit_packer.set_homogeneous (false);
476         edit_packer.set_border_width (0);
477         edit_packer.set_name ("EditorWindow");
478         
479         edit_packer.attach (edit_vscrollbar,         0, 1, 1, 3,    FILL,        FILL|EXPAND, 0, 0);
480
481         edit_packer.attach (time_button_frame,       0, 2, 0, 1,    FILL,        FILL, 0, 0);
482         edit_packer.attach (time_canvas_event_box,   2, 3, 0, 1,    FILL|EXPAND, FILL, 0, 0);
483
484         edit_packer.attach (controls_layout,         1, 2, 1, 2,    FILL,        FILL|EXPAND, 0, 0);
485         edit_packer.attach (track_canvas_event_box,  2, 3, 1, 2,    FILL|EXPAND, FILL|EXPAND, 0, 0);
486
487         edit_packer.attach (zoom_box,                1, 2, 2, 3,    FILL,         FILL, 0, 0);
488         edit_packer.attach (edit_hscrollbar,         2, 3, 2, 3,    FILL|EXPAND,  FILL, 0, 0);
489
490         bottom_hbox.set_border_width (2);
491         bottom_hbox.set_spacing (3);
492
493         route_display_model = ListStore::create(route_display_columns);
494         route_list_display.set_model (route_display_model);
495         route_list_display.append_column (_("Show"), route_display_columns.visible);
496         route_list_display.append_column (_("Name"), route_display_columns.text);
497         route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
498         route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
499         route_list_display.set_headers_visible (true);
500         route_list_display.set_name ("TrackListDisplay");
501         route_list_display.get_selection()->set_mode (SELECTION_NONE);
502         route_list_display.set_reorderable (true);
503         route_list_display.set_size_request (100,-1);
504
505         CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
506         route_list_visible_cell->property_activatable() = true;
507         route_list_visible_cell->property_radio() = false;
508
509         route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
510         route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
511         route_display_model->signal_rows_reordered().connect (mem_fun (*this, &Editor::track_list_reorder));
512
513         route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
514
515         route_list_scroller.add (route_list_display);
516         route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
517
518         group_model = ListStore::create(group_columns);
519         edit_group_display.set_model (group_model);
520         edit_group_display.append_column (_("Name"), group_columns.text);
521         edit_group_display.append_column (_("Active"), group_columns.is_active);
522         edit_group_display.append_column (_("Show"), group_columns.is_visible);
523         edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
524         edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
525         edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
526         edit_group_display.get_column (0)->set_expand (true);
527         edit_group_display.get_column (1)->set_expand (false);
528         edit_group_display.get_column (2)->set_expand (false);
529         edit_group_display.set_headers_visible (true);
530
531         /* name is directly editable */
532
533         CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
534         name_cell->property_editable() = true;
535         name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
536
537         /* use checkbox for the active + visible columns */
538
539         CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
540         active_cell->property_activatable() = true;
541         active_cell->property_radio() = false;
542
543         active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
544         active_cell->property_activatable() = true;
545         active_cell->property_radio() = false;
546
547         group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
548
549         edit_group_display.set_name ("EditGroupList");
550         edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
551         edit_group_display.set_headers_visible (true);
552         edit_group_display.set_reorderable (false);
553         edit_group_display.set_rules_hint (true);
554         edit_group_display.set_size_request (75, -1);
555
556         edit_group_display_scroller.add (edit_group_display);
557         edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
558
559         edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
560
561         VBox* edit_group_display_packer = manage (new VBox());
562         HBox* edit_group_display_button_box = manage (new HBox());
563         edit_group_display_button_box->set_homogeneous (true);
564
565         Button* edit_group_add_button = manage (new Button ());
566         Button* edit_group_remove_button = manage (new Button ());
567
568         Widget* w;
569
570         w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
571         w->show();
572         edit_group_add_button->add (*w);
573
574         w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
575         w->show();
576         edit_group_remove_button->add (*w);
577
578         edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
579         edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
580         
581         edit_group_display_button_box->pack_start (*edit_group_add_button);
582         edit_group_display_button_box->pack_start (*edit_group_remove_button);
583
584         edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
585         edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
586
587         region_list_display.set_size_request (100, -1);
588         region_list_display.set_name ("RegionListDisplay");
589
590         region_list_model = TreeStore::create (region_list_columns);
591         region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
592         region_list_model->set_sort_column (0, SORT_ASCENDING);
593
594         region_list_display.set_model (region_list_model);
595         region_list_display.append_column (_("Regions"), region_list_columns.name);
596         region_list_display.set_headers_visible (false);
597
598         CellRendererText* region_name_cell = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
599         region_name_cell->property_editable() = true;
600         region_name_cell->signal_edited().connect (mem_fun (*this, &Editor::region_name_edit));
601
602         region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
603         
604         TreeViewColumn* tv_col = region_list_display.get_column(0);
605         CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
606         tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
607         tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
608         
609         region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
610         region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
611
612         /* setup DnD handling */
613         
614         list<TargetEntry> region_list_target_table;
615         
616         region_list_target_table.push_back (TargetEntry ("text/plain"));
617         region_list_target_table.push_back (TargetEntry ("text/uri-list"));
618         region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
619         
620         region_list_display.add_drop_targets (region_list_target_table);
621         region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
622
623         region_list_scroller.add (region_list_display);
624         region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
625
626         region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
627         region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
628         region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
629         region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
630         region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
631         // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
632         
633         named_selection_scroller.add (named_selection_display);
634         named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
635
636         named_selection_model = TreeStore::create (named_selection_columns);
637         named_selection_display.set_model (named_selection_model);
638         named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
639         named_selection_display.set_headers_visible (false);
640         named_selection_display.set_size_request (100, -1);
641         named_selection_display.set_name ("NamedSelectionDisplay");
642         
643         named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
644         named_selection_display.set_size_request (100, -1);
645         named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
646         named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
647         named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
648
649         /* SNAPSHOTS */
650
651         snapshot_display_model = ListStore::create (snapshot_display_columns);
652         snapshot_display.set_model (snapshot_display_model);
653         snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
654         snapshot_display.set_name ("SnapshotDisplay");
655         snapshot_display.set_size_request (75, -1);
656         snapshot_display.set_headers_visible (false);
657         snapshot_display.set_reorderable (false);
658         snapshot_display_scroller.add (snapshot_display);
659         snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
660
661         snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
662         snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
663
664         Gtk::Label* nlabel;
665
666         nlabel = manage (new Label (_("Regions")));
667         nlabel->set_angle (-90);
668         the_notebook.append_page (region_list_scroller, *nlabel);
669         nlabel = manage (new Label (_("Tracks/Busses")));
670         nlabel->set_angle (-90);
671         the_notebook.append_page (route_list_scroller, *nlabel);
672         nlabel = manage (new Label (_("Snapshots")));
673         nlabel->set_angle (-90);
674         the_notebook.append_page (snapshot_display_scroller, *nlabel);
675         nlabel = manage (new Label (_("Edit Groups")));
676         nlabel->set_angle (-90);
677         the_notebook.append_page (*edit_group_display_packer, *nlabel);
678         
679         if (!Profile->get_sae()) {
680                 nlabel = manage (new Label (_("Chunks")));
681                 nlabel->set_angle (-90);
682                 the_notebook.append_page (named_selection_scroller, *nlabel);
683         }
684
685         the_notebook.set_show_tabs (true);
686         the_notebook.set_scrollable (true);
687         the_notebook.popup_enable ();
688         the_notebook.set_tab_pos (Gtk::POS_RIGHT);
689
690         post_maximal_editor_width = 0;
691         post_maximal_pane_position = 0;
692         edit_pane.pack1 (edit_packer, true, true);
693         edit_pane.pack2 (the_notebook, false, true);
694         
695         edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
696
697         top_hbox.pack_start (toolbar_frame, true, true);
698
699         HBox *hbox = manage (new HBox);
700         hbox->pack_start (edit_pane, true, true);
701
702         global_vpacker.pack_start (top_hbox, false, false);
703         global_vpacker.pack_start (*hbox, true, true);
704
705         global_hpacker.pack_start (global_vpacker, true, true);
706
707         set_name ("EditorWindow");
708         add_accel_group (ActionManager::ui_manager->get_accel_group());
709
710         status_bar_hpacker.show ();
711
712         vpacker.pack_end (status_bar_hpacker, false, false);
713         vpacker.pack_end (global_hpacker, true, true);
714
715         /* register actions now so that set_state() can find them and set toggles/checks etc */
716         
717         register_actions ();
718
719         snap_type = SnapToBeat;
720         set_snap_to (snap_type);
721         snap_mode = SnapOff;
722         set_snap_mode (snap_mode);
723         _edit_point = EditAtMouse;
724         set_edit_point_preference (_edit_point);
725
726         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
727         set_state (*node);
728
729         _playlist_selector = new PlaylistSelector();
730         _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
731
732         RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
733
734         /* nudge stuff */
735
736         nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
737         nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
738
739         ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
740         ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
741
742         nudge_forward_button.set_name ("TransportButton");
743         nudge_backward_button.set_name ("TransportButton");
744
745         fade_context_menu.set_name ("ArdourContextMenu");
746
747         /* icons, titles, WM stuff */
748
749         list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
750         Glib::RefPtr<Gdk::Pixbuf> icon;
751
752         if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
753                 window_icons.push_back (icon);
754         }
755         if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
756                 window_icons.push_back (icon);
757         }
758         if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
759                 window_icons.push_back (icon);
760         }
761         if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
762                 window_icons.push_back (icon);
763         }
764         if (!window_icons.empty()) {
765                 set_icon_list (window_icons);
766                 set_default_icon_list (window_icons);
767         }
768
769         WindowTitle title(Glib::get_application_name());
770         title += _("Editor");
771         set_title (title.get_string());
772         set_wmclass (X_("ardour_editor"), "Ardour");
773
774         add (vpacker);
775         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
776
777         signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
778         signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
779
780         /* allow external control surfaces/protocols to do various things */
781
782         ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
783         ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
784         ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
785         ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
786
787         Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
788         Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
789
790         constructed = true;
791         instant_save ();
792 }
793
794 Editor::~Editor()
795 {
796         /* <CMT Additions> */
797         if(image_socket_listener)
798         {
799                 if(image_socket_listener->is_connected())
800                 {
801                         image_socket_listener->close_connection() ;
802                 }
803                 
804                 delete image_socket_listener ;
805                 image_socket_listener = 0 ;
806         }
807         /* </CMT Additions> */
808 }
809
810 void
811 Editor::add_toplevel_controls (Container& cont)
812 {
813         vpacker.pack_start (cont, false, false);
814         cont.show_all ();
815 }
816
817 void
818 Editor::catch_vanishing_regionview (RegionView *rv)
819 {
820         /* note: the selection will take care of the vanishing
821            audioregionview by itself.
822         */
823
824         if (clicked_regionview == rv) {
825                 clicked_regionview = 0;
826         }
827
828         if (entered_regionview == rv) {
829                 set_entered_regionview (0);
830         }
831 }
832
833 void
834 Editor::set_entered_regionview (RegionView* rv)
835 {
836         if (rv == entered_regionview) {
837                 return;
838         }
839
840         if (entered_regionview) {
841                 entered_regionview->exited ();
842         }
843
844         if ((entered_regionview = rv) != 0) {
845                 entered_regionview->entered ();
846         }
847 }
848
849 void
850 Editor::set_entered_track (TimeAxisView* tav)
851 {
852         if (entered_track) {
853                 entered_track->exited ();
854         }
855
856         if ((entered_track = tav) != 0) {
857                 entered_track->entered ();
858         }
859 }
860
861 void
862 Editor::show_window ()
863 {
864         show_all ();
865         present ();
866
867         /* now reset all audio_time_axis heights, because widgets might need
868            to be re-hidden
869         */
870         
871         TimeAxisView *tv;
872         
873         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
874                 tv = (static_cast<TimeAxisView*>(*i));
875                 tv->reset_height ();
876         }
877 }
878
879 void
880 Editor::instant_save ()
881 {
882         if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
883                 return;
884         }
885
886         if (session) {
887                 session->add_instant_xml(get_state(), session->path());
888         } else {
889                 Config->add_instant_xml(get_state(), get_user_ardour_path());
890         }
891 }
892
893 void
894 Editor::edit_point_clock_changed()
895 {
896         if (_dragging_edit_point) {
897                 return;
898         }
899
900         if (selection->markers.empty()) {
901                 return;
902         }
903
904         bool ignored;
905         Location* loc = find_location_from_marker (selection->markers.front(), ignored);
906
907         if (!loc) {
908                 return;
909         }
910
911         loc->move_to (edit_point_clock.current_time());
912 }
913
914 void
915 Editor::zoom_adjustment_changed ()
916 {
917         if (session == 0) {
918                 return;
919         }
920
921         double fpu = zoom_range_clock.current_duration() / canvas_width;
922
923         if (fpu < 1.0) {
924                 fpu = 1.0;
925                 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
926         } else if (fpu > session->current_end_frame() / canvas_width) {
927                 fpu = session->current_end_frame() / canvas_width;
928                 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
929         }
930         
931         temporal_zoom (fpu);
932 }
933
934 void
935 Editor::control_scroll (float fraction)
936 {
937         ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
938
939         if (!session) {
940                 return;
941         }
942
943         double step = fraction * current_page_frames();
944
945         /*
946                 _control_scroll_target is an optional<T>
947         
948                 it acts like a pointer to an nframes_t, with
949                 a operator conversion to boolean to check
950                 that it has a value could possibly use
951                 playhead_cursor->current_frame to store the
952                 value and a boolean in the class to know
953                 when it's out of date
954         */
955
956         if (!_control_scroll_target) {
957                 _control_scroll_target = session->transport_frame();
958                 _dragging_playhead = true;
959         }
960
961         if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
962                 *_control_scroll_target = 0;
963         } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
964                 *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
965         } else {
966                 *_control_scroll_target += (nframes_t) floor (step);
967         }
968
969         /* move visuals, we'll catch up with it later */
970
971         playhead_cursor->set_position (*_control_scroll_target);
972         UpdateAllTransportClocks (*_control_scroll_target);
973         
974         if (*_control_scroll_target > (current_page_frames() / 2)) {
975                 /* try to center PH in window */
976                 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
977         } else {
978                 reset_x_origin (0);
979         }
980
981         /*
982                 Now we do a timeout to actually bring the session to the right place
983                 according to the playhead. This is to avoid reading disk buffers on every
984                 call to control_scroll, which is driven by ScrollTimeline and therefore
985                 probably by a control surface wheel which can generate lots of events.
986         */
987         /* cancel the existing timeout */
988
989         control_scroll_connection.disconnect ();
990
991         /* add the next timeout */
992
993         control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
994 }
995
996 bool
997 Editor::deferred_control_scroll (nframes_t target)
998 {
999         session->request_locate (*_control_scroll_target, session->transport_rolling());
1000         // reset for next stream
1001         _control_scroll_target = boost::none;
1002         _dragging_playhead = false;
1003         return false;
1004 }
1005
1006 void
1007 Editor::on_realize ()
1008 {
1009         Window::on_realize ();
1010         Realized ();
1011 }
1012
1013 void
1014 Editor::start_scrolling ()
1015 {
1016         scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect 
1017                 (mem_fun(*this, &Editor::update_current_screen));
1018 }
1019
1020 void
1021 Editor::stop_scrolling ()
1022 {
1023         scroll_connection.disconnect ();
1024 }
1025
1026 void
1027 Editor::map_position_change (nframes_t frame)
1028 {
1029         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1030
1031         if (session == 0 || !_follow_playhead) {
1032                 return;
1033         }
1034
1035         center_screen (frame);
1036         playhead_cursor->set_position (frame);
1037 }       
1038
1039 void
1040 Editor::center_screen (nframes_t frame)
1041 {
1042         double page = canvas_width * frames_per_unit;
1043
1044         /* if we're off the page, then scroll.
1045          */
1046         
1047         if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1048                 center_screen_internal (frame, page);
1049         }
1050 }
1051
1052 void
1053 Editor::center_screen_internal (nframes_t frame, float page)
1054 {
1055         page /= 2;
1056                 
1057         if (frame > page) {
1058                 frame -= (nframes_t) page;
1059         } else {
1060                 frame = 0;
1061         }
1062
1063         reset_x_origin (frame);
1064 }
1065
1066 void
1067 Editor::handle_new_duration ()
1068 {
1069         ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1070
1071         nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1072                                   
1073         if (new_end > last_canvas_frame) {
1074                 last_canvas_frame = new_end;
1075                 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1076                 reset_scrolling_region ();
1077         }
1078
1079         horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1080 }
1081
1082 void
1083 Editor::update_title_s (const string & snap_name)
1084 {
1085         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1086         
1087         update_title ();
1088 }
1089
1090 void
1091 Editor::update_title ()
1092 {
1093         ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1094
1095         if (session) {
1096                 bool dirty = session->dirty();
1097
1098                 string session_name;
1099
1100                 if (session->snap_name() != session->name()) {
1101                         session_name = session->snap_name();
1102                 } else {
1103                         session_name = session->name();
1104                 }
1105
1106                 if (dirty) {
1107                         session_name = "*" + session_name;
1108                 }
1109
1110                 WindowTitle title(session_name);
1111                 title += Glib::get_application_name();
1112                 set_title (title.get_string());
1113         }
1114 }
1115
1116 void
1117 Editor::connect_to_session (Session *t)
1118 {
1119         session = t;
1120
1121         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1122         set_state (*node);
1123
1124         /* catch up with the playhead */
1125
1126         session->request_locate (playhead_cursor->current_frame);
1127
1128         if (first_action_message) {
1129                 first_action_message->hide();
1130         }
1131
1132         update_title ();
1133
1134         session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1135         session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1136
1137         /* These signals can all be emitted by a non-GUI thread. Therefore the
1138            handlers for them must not attempt to directly interact with the GUI,
1139            but use Gtkmm2ext::UI::instance()->call_slot();
1140         */
1141
1142         session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1143         session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1144         session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1145         session_connections.push_back (session->AudioRegionsAdded.connect (mem_fun(*this, &Editor::handle_new_audio_regions)));
1146         session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::handle_audio_region_removed)));
1147         session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1148         session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1149         session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1150         session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1151         session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1152         session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1153         session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1154         session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1155         session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1156
1157         session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1158
1159         session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1160
1161         edit_groups_changed ();
1162
1163         edit_point_clock.set_session (session);
1164         zoom_range_clock.set_session (session);
1165         _playlist_selector->set_session (session);
1166         nudge_clock.set_session (session);
1167
1168         if (rhythm_ferret) {
1169                 rhythm_ferret->set_session (session);
1170         }
1171
1172 #ifdef FFT_ANALYSIS
1173         if (analysis_window != 0)
1174                 analysis_window->set_session (session);
1175 #endif
1176
1177         Location* loc = session->locations()->auto_loop_location();
1178         if (loc == 0) {
1179                 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1180                 if (loc->start() == loc->end()) {
1181                         loc->set_end (loc->start() + 1);
1182                 }
1183                 session->locations()->add (loc, false);
1184                 session->set_auto_loop_location (loc);
1185         } else {
1186                 // force name
1187                 loc->set_name (_("Loop"));
1188         }
1189         
1190         loc = session->locations()->auto_punch_location();
1191         if (loc == 0) {
1192                 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1193                 if (loc->start() == loc->end()) {
1194                         loc->set_end (loc->start() + 1);
1195                 }
1196                 session->locations()->add (loc, false);
1197                 session->set_auto_punch_location (loc);
1198         } else {
1199                 // force name
1200                 loc->set_name (_("Punch"));
1201         }
1202
1203         Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1204         
1205         session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1206         
1207         refresh_location_display ();
1208         session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1209         session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1210         session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1211         session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1212         session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1213
1214         if (sfbrowser) {
1215                 sfbrowser->set_session (session);
1216         }
1217
1218         handle_new_duration ();
1219
1220         redisplay_regions ();
1221         redisplay_named_selections ();
1222         redisplay_snapshots ();
1223
1224         initial_route_list_display ();
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         restore_ruler_visibility ();
1231         //tempo_map_changed (Change (0));
1232         session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1233
1234         start_scrolling ();
1235
1236         /* don't show master bus in a new session */
1237
1238         if (ARDOUR_UI::instance()->session_is_new ()) {
1239
1240                 TreeModel::Children rows = route_display_model->children();
1241                 TreeModel::Children::iterator i;
1242         
1243                 no_route_list_redisplay = true;
1244                 
1245                 for (i = rows.begin(); i != rows.end(); ++i) {
1246                         TimeAxisView *tv =  (*i)[route_display_columns.tv];
1247                         AudioTimeAxisView *atv;
1248                         
1249                         if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1250                                 if (atv->route()->master()) {
1251                                         route_list_display.get_selection()->unselect (i);
1252                                 }
1253                         }
1254                 }
1255                 
1256                 no_route_list_redisplay = false;
1257                 redisplay_route_list ();
1258         }
1259
1260         /* register for undo history */
1261
1262         session->register_with_memento_command_factory(_id, this);
1263
1264                 start_updating ();
1265 }
1266
1267 void
1268 Editor::build_cursors ()
1269 {
1270         using namespace Gdk;
1271         
1272         Gdk::Color mbg ("#000000" ); /* Black */
1273         Gdk::Color mfg ("#0000ff" ); /* Blue. */
1274
1275         {
1276                 RefPtr<Bitmap> source, mask;
1277                 source = Bitmap::create (mag_bits, mag_width, mag_height);
1278                 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1279                 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1280         }
1281
1282         Gdk::Color fbg ("#ffffff" );
1283         Gdk::Color ffg  ("#000000" );
1284         
1285         {
1286                 RefPtr<Bitmap> source, mask;
1287                 
1288                 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1289                 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1290                 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1291         }
1292         
1293         { 
1294                 RefPtr<Bitmap> source, mask;
1295                 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1296                 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1297                 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1298         }
1299
1300         { 
1301                 RefPtr<Bitmap> bits;
1302                 char pix[4] = { 0, 0, 0, 0 };
1303                 bits = Bitmap::create (pix, 2, 2);
1304                 Gdk::Color c;
1305                 transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
1306         }
1307
1308         grabber_cursor = new Gdk::Cursor (HAND2);
1309         cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1310         trimmer_cursor =  new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1311         selector_cursor = new Gdk::Cursor (XTERM);
1312         time_fx_cursor = new Gdk::Cursor (SIZING);
1313         wait_cursor = new Gdk::Cursor  (WATCH);
1314         timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1315 }
1316
1317 void
1318 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1319 {
1320         using namespace Menu_Helpers;
1321         AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1322
1323         if (arv == 0) {
1324                 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1325                 /*NOTREACHED*/
1326         }
1327
1328         MenuList& items (fade_context_menu.items());
1329
1330         items.clear ();
1331
1332         switch (item_type) {
1333         case FadeInItem:
1334         case FadeInHandleItem:
1335                 if (arv->audio_region()->fade_in_active()) {
1336                         items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1337                 } else {
1338                         items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1339                 }
1340                 
1341                 items.push_back (SeparatorElem());
1342
1343                 if (Profile->get_sae()) {
1344                         items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1345                         items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1346                 } else {
1347                         items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1348                         items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1349                         items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1350                         items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1351                         items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1352                 }
1353                 break;
1354
1355         case FadeOutItem:
1356         case FadeOutHandleItem:
1357                 if (arv->audio_region()->fade_out_active()) {
1358                         items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1359                 } else {
1360                         items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1361                 }
1362                 
1363                 items.push_back (SeparatorElem());
1364
1365                 if (Profile->get_sae()) {
1366                         items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1367                         items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1368                 } else {
1369                         items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1370                         items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1371                         items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1372                         items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1373                         items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1374                 }
1375                 break;
1376
1377         default:
1378                 fatal << _("programming error: ")
1379                       << X_("non-fade canvas item passed to popup_fade_context_menu()")
1380                       << endmsg;
1381                 /*NOTREACHED*/
1382         }
1383
1384         fade_context_menu.popup (button, time);
1385 }
1386
1387 void
1388 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, nframes_t frame)
1389 {
1390         using namespace Menu_Helpers;
1391         Menu* (Editor::*build_menu_function)(nframes_t);
1392         Menu *menu;
1393
1394         switch (item_type) {
1395         case RegionItem:
1396         case RegionViewName:
1397         case RegionViewNameHighlight:
1398                 if (with_selection) {
1399                         build_menu_function = &Editor::build_track_selection_context_menu;
1400                 } else {
1401                         build_menu_function = &Editor::build_track_region_context_menu;
1402                 }
1403                 break;
1404
1405         case SelectionItem:
1406                 if (with_selection) {
1407                         build_menu_function = &Editor::build_track_selection_context_menu;
1408                 } else {
1409                         build_menu_function = &Editor::build_track_context_menu;
1410                 }
1411                 break;
1412
1413         case CrossfadeViewItem:
1414                 build_menu_function = &Editor::build_track_crossfade_context_menu;
1415                 break;
1416
1417         case StreamItem:
1418                 if (clicked_audio_trackview->get_diskstream()) {
1419                         build_menu_function = &Editor::build_track_context_menu;
1420                 } else {
1421                         build_menu_function = &Editor::build_track_bus_context_menu;
1422                 }
1423                 break;
1424
1425         default:
1426                 /* probably shouldn't happen but if it does, we don't care */
1427                 return;
1428         }
1429
1430         menu = (this->*build_menu_function)(frame);
1431         menu->set_name ("ArdourContextMenu");
1432         
1433         /* now handle specific situations */
1434
1435         switch (item_type) {
1436         case RegionItem:
1437         case RegionViewName:
1438         case RegionViewNameHighlight:
1439                 if (!with_selection) {
1440                         if (region_edit_menu_split_item) {
1441                                 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1442                                         ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1443                                 } else {
1444                                         ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1445                                 }
1446                         }
1447                         /*
1448                         if (region_edit_menu_split_multichannel_item) {
1449                                 if (clicked_regionview && clicked_regionview->region().n_channels() > 1) {
1450                                         // GTK2FIX find the action, change its sensitivity
1451                                         // region_edit_menu_split_multichannel_item->set_sensitive (true);
1452                                 } else {
1453                                         // GTK2FIX see above
1454                                         // region_edit_menu_split_multichannel_item->set_sensitive (false);
1455                                 }
1456                         }*/
1457                 }
1458                 break;
1459
1460         case SelectionItem:
1461                 break;
1462
1463         case CrossfadeViewItem:
1464                 break;
1465
1466         case StreamItem:
1467                 break;
1468
1469         default:
1470                 /* probably shouldn't happen but if it does, we don't care */
1471                 return;
1472         }
1473
1474         if (item_type != SelectionItem && clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1475
1476                 /* Bounce to disk */
1477                 
1478                 using namespace Menu_Helpers;
1479                 MenuList& edit_items  = menu->items();
1480                 
1481                 edit_items.push_back (SeparatorElem());
1482
1483                 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1484                 case AudioTrack::NoFreeze:
1485                         edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1486                         break;
1487
1488                 case AudioTrack::Frozen:
1489                         edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1490                         break;
1491                         
1492                 case AudioTrack::UnFrozen:
1493                         edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1494                         break;
1495                 }
1496
1497         }
1498
1499         menu->popup (button, time);
1500 }
1501
1502 Menu*
1503 Editor::build_track_context_menu (nframes_t ignored)
1504 {
1505         using namespace Menu_Helpers;
1506
1507         MenuList& edit_items = track_context_menu.items();
1508         edit_items.clear();
1509
1510         add_dstream_context_items (edit_items);
1511         return &track_context_menu;
1512 }
1513
1514 Menu*
1515 Editor::build_track_bus_context_menu (nframes_t ignored)
1516 {
1517         using namespace Menu_Helpers;
1518
1519         MenuList& edit_items = track_context_menu.items();
1520         edit_items.clear();
1521
1522         add_bus_context_items (edit_items);
1523         return &track_context_menu;
1524 }
1525
1526 Menu*
1527 Editor::build_track_region_context_menu (nframes_t frame)
1528 {
1529         using namespace Menu_Helpers;
1530         MenuList& edit_items  = track_region_context_menu.items();
1531         edit_items.clear();
1532
1533         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1534
1535         if (atv) {
1536                 boost::shared_ptr<Diskstream> ds;
1537                 boost::shared_ptr<Playlist> pl;
1538                 
1539                 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1540                         Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)frame * ds->speed()));
1541                         for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1542                                 add_region_context_items (atv->audio_view(), (*i), edit_items);
1543                         }
1544                         delete regions;
1545                 }
1546         }
1547
1548         add_dstream_context_items (edit_items);
1549
1550         return &track_region_context_menu;
1551 }
1552
1553 Menu*
1554 Editor::build_track_crossfade_context_menu (nframes_t frame)
1555 {
1556         using namespace Menu_Helpers;
1557         MenuList& edit_items  = track_crossfade_context_menu.items();
1558         edit_items.clear ();
1559
1560         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1561
1562         if (atv) {
1563                 boost::shared_ptr<Diskstream> ds;
1564                 boost::shared_ptr<Playlist> pl;
1565                 boost::shared_ptr<AudioPlaylist> apl;
1566
1567                 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1568
1569                         Playlist::RegionList* regions = pl->regions_at (frame);
1570                         AudioPlaylist::Crossfades xfades;
1571
1572                         apl->crossfades_at (frame, xfades);
1573
1574                         bool many = xfades.size() > 1;
1575
1576                         for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1577                                 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1578                         }
1579
1580                         for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1581                                 add_region_context_items (atv->audio_view(), (*i), edit_items);
1582                         }
1583
1584                         delete regions;
1585                 }
1586         }
1587
1588         add_dstream_context_items (edit_items);
1589
1590         return &track_crossfade_context_menu;
1591 }
1592
1593 #ifdef FFT_ANALYSIS
1594 void
1595 Editor::analyze_region_selection()
1596 {
1597         if (analysis_window == 0) {
1598                 analysis_window = new AnalysisWindow();
1599
1600                 if (session != 0)
1601                         analysis_window->set_session(session);
1602
1603                 analysis_window->show_all();
1604         }
1605
1606         analysis_window->set_regionmode();
1607         analysis_window->analyze();
1608         
1609         analysis_window->present();
1610 }
1611
1612 void
1613 Editor::analyze_range_selection()
1614 {
1615         if (analysis_window == 0) {
1616                 analysis_window = new AnalysisWindow();
1617
1618                 if (session != 0)
1619                         analysis_window->set_session(session);
1620
1621                 analysis_window->show_all();
1622         }
1623
1624         analysis_window->set_rangemode();
1625         analysis_window->analyze();
1626         
1627         analysis_window->present();
1628 }
1629 #endif /* FFT_ANALYSIS */
1630
1631
1632
1633 Menu*
1634 Editor::build_track_selection_context_menu (nframes_t ignored)
1635 {
1636         using namespace Menu_Helpers;
1637         MenuList& edit_items  = track_selection_context_menu.items();
1638         edit_items.clear ();
1639
1640         add_selection_context_items (edit_items);
1641         // edit_items.push_back (SeparatorElem());
1642         // add_dstream_context_items (edit_items);
1643
1644         return &track_selection_context_menu;
1645 }
1646
1647 void
1648 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1649 {
1650         using namespace Menu_Helpers;
1651         Menu     *xfade_menu = manage (new Menu);
1652         MenuList& items       = xfade_menu->items();
1653         xfade_menu->set_name ("ArdourContextMenu");
1654         string str;
1655
1656         if (xfade->active()) {
1657                 str = _("Mute");
1658         } else { 
1659                 str = _("Unmute");
1660         }
1661
1662         items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1663         items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1664
1665         if (xfade->can_follow_overlap()) {
1666
1667                 if (xfade->following_overlap()) {
1668                         str = _("Convert to short");
1669                 } else {
1670                         str = _("Convert to full");
1671                 }
1672
1673                 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1674         }
1675
1676         if (many) {
1677                 str = xfade->out()->name();
1678                 str += "->";
1679                 str += xfade->in()->name();
1680         } else {
1681                 str = _("Crossfade");
1682         }
1683
1684         edit_items.push_back (MenuElem (str, *xfade_menu));
1685         edit_items.push_back (SeparatorElem());
1686 }
1687
1688 void
1689 Editor::xfade_edit_left_region ()
1690 {
1691         if (clicked_crossfadeview) {
1692                 clicked_crossfadeview->left_view.show_region_editor ();
1693         }
1694 }
1695
1696 void
1697 Editor::xfade_edit_right_region ()
1698 {
1699         if (clicked_crossfadeview) {
1700                 clicked_crossfadeview->right_view.show_region_editor ();
1701         }
1702 }
1703
1704 void
1705 Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr<Region> region, Menu_Helpers::MenuList& edit_items)
1706 {
1707         using namespace Menu_Helpers;
1708         Menu     *region_menu = manage (new Menu);
1709         MenuList& items       = region_menu->items();
1710         region_menu->set_name ("ArdourContextMenu");
1711         
1712         boost::shared_ptr<AudioRegion> ar;
1713
1714         if (region) {
1715                 ar = boost::dynamic_pointer_cast<AudioRegion> (region);
1716         }
1717
1718         /* when this particular menu pops up, make the relevant region 
1719            become selected.
1720         */
1721
1722         region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr<Region>(region)));
1723
1724         items.push_back (MenuElem (_("Rename"), mem_fun(*this, &Editor::rename_region)));
1725         items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1726         items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1727         items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun  (*this, &Editor::lower_region_to_bottom)));
1728         items.push_back (SeparatorElem());
1729         items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_point)));
1730         items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1731         items.push_back (SeparatorElem());
1732
1733         items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::play_selected_region)));
1734         items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1735         items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1736
1737 #ifdef FFT_ANALYSIS
1738         items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1739 #endif
1740
1741         items.push_back (SeparatorElem());
1742
1743         sigc::connection fooc;
1744
1745         items.push_back (CheckMenuElem (_("Lock")));
1746         CheckMenuItem* region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1747         if (region->locked()) {
1748                 region_lock_item->set_active();
1749         }
1750         region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1751
1752         items.push_back (CheckMenuElem (_("Glue to Bars&Beats")));
1753         CheckMenuItem* bbt_glue_item = static_cast<CheckMenuItem*>(&items.back());
1754
1755         switch (region->positional_lock_style()) {
1756         case Region::MusicTime:
1757                 bbt_glue_item->set_active (true);
1758                 break;
1759         default:
1760                 bbt_glue_item->set_active (false);
1761                 break;
1762         }
1763
1764         bbt_glue_item->signal_activate().connect (bind (mem_fun (*this, &Editor::set_region_lock_style), Region::MusicTime));
1765
1766         items.push_back (CheckMenuElem (_("Mute")));
1767         CheckMenuItem* region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1768         fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1769         if (region->muted()) {
1770                 fooc.block (true);
1771                 region_mute_item->set_active();
1772                 fooc.block (false);
1773         }
1774         
1775         if (!Profile->get_sae()) {
1776                 items.push_back (CheckMenuElem (_("Opaque")));
1777                 CheckMenuItem* region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1778                 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1779                 if (region->opaque()) {
1780                         fooc.block (true);
1781                         region_opaque_item->set_active();
1782                         fooc.block (false);
1783                 }
1784         }
1785
1786         items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1787         if (region->at_natural_position()) {
1788                 items.back().set_sensitive (false);
1789         }
1790         
1791         items.push_back (SeparatorElem());
1792         
1793         if (ar) {
1794                 
1795                 RegionView* rv = sv->find_view (ar);
1796                 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1797                 
1798                 if (!Profile->get_sae()) {
1799                         items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1800
1801                         items.push_back (CheckMenuElem (_("Envelope Visible")));
1802                         CheckMenuItem* region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1803                         fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1804                         if (arv->envelope_visible()) {
1805                                 fooc.block (true);
1806                                 region_envelope_visible_item->set_active (true);
1807                                 fooc.block (false);
1808                         }
1809                 
1810                         items.push_back (CheckMenuElem (_("Envelope Active")));
1811                         CheckMenuItem* region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1812                         fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1813                         
1814                         if (ar->envelope_active()) {
1815                                 fooc.block (true);
1816                                 region_envelope_active_item->set_active (true);
1817                                 fooc.block (false);
1818                         }
1819
1820                         items.push_back (SeparatorElem());
1821                 }
1822
1823                 if (ar->scale_amplitude() != 1.0f) {
1824                         items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1825                 } else {
1826                         items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1827                 }
1828         }
1829
1830         items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1831         items.push_back (SeparatorElem());
1832
1833         /* range related stuff */
1834
1835         items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region)));
1836         items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)));
1837         items.push_back (SeparatorElem());
1838                          
1839         /* Nudge region */
1840
1841         Menu *nudge_menu = manage (new Menu());
1842         MenuList& nudge_items = nudge_menu->items();
1843         nudge_menu->set_name ("ArdourContextMenu");
1844         
1845         nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false, false))));
1846         nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false, false))));
1847         nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1848         nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1849
1850         items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1851         items.push_back (SeparatorElem());
1852
1853         Menu *trim_menu = manage (new Menu);
1854         MenuList& trim_items = trim_menu->items();
1855         trim_menu->set_name ("ArdourContextMenu");
1856         
1857         trim_items.push_back (MenuElem (_("Start to edit point"), mem_fun(*this, &Editor::trim_region_from_edit_point)));
1858         trim_items.push_back (MenuElem (_("Edit point to end"), mem_fun(*this, &Editor::trim_region_to_edit_point)));
1859         trim_items.push_back (MenuElem (_("Trim To Loop"), mem_fun(*this, &Editor::trim_region_to_loop)));
1860         trim_items.push_back (MenuElem (_("Trim To Punch"), mem_fun(*this, &Editor::trim_region_to_punch)));
1861                              
1862         items.push_back (MenuElem (_("Trim"), *trim_menu));
1863         items.push_back (SeparatorElem());
1864
1865         items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1866         region_edit_menu_split_item = &items.back();
1867
1868         items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1869         region_edit_menu_split_multichannel_item = &items.back();
1870
1871         items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), false))));
1872         items.push_back (MenuElem (_("Multi-Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1873         items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1874         items.push_back (SeparatorElem());
1875         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1876
1877         /* OK, stick the region submenu at the top of the list, and then add
1878            the standard items.
1879         */
1880
1881         /* we have to hack up the region name because "_" has a special
1882            meaning for menu titles.
1883         */
1884
1885         string::size_type pos = 0;
1886         string menu_item_name = region->name();
1887
1888         while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1889                 menu_item_name.replace (pos, 1, "__");
1890                 pos += 2;
1891         }
1892         
1893         edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1894         edit_items.push_back (SeparatorElem());
1895 }
1896
1897 void
1898 Editor::add_selection_context_items (Menu_Helpers::MenuList& items)
1899 {
1900         using namespace Menu_Helpers;
1901
1902         items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1903         items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1904
1905 #ifdef FFT_ANALYSIS
1906         items.push_back (SeparatorElem());
1907         items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1908 #endif
1909         
1910         items.push_back (SeparatorElem());
1911         items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1912         items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1913
1914         items.push_back (SeparatorElem());
1915         items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1916         items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1917         
1918         items.push_back (SeparatorElem());
1919         items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1920
1921         items.push_back (SeparatorElem());
1922         items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1923         items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1924         
1925         items.push_back (SeparatorElem());
1926         items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1927         items.push_back (SeparatorElem());
1928         items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1929         items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1930         items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1931         items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1932         items.push_back (SeparatorElem());
1933         items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1934         items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1935 }
1936
1937 void
1938 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1939 {
1940         using namespace Menu_Helpers;
1941
1942         /* Playback */
1943
1944         Menu *play_menu = manage (new Menu);
1945         MenuList& play_items = play_menu->items();
1946         play_menu->set_name ("ArdourContextMenu");
1947         
1948         play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
1949         play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1950         play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1951         play_items.push_back (SeparatorElem());
1952         play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1953         
1954         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1955
1956         /* Selection */
1957
1958         Menu *select_menu = manage (new Menu);
1959         MenuList& select_items = select_menu->items();
1960         select_menu->set_name ("ArdourContextMenu");
1961         
1962         select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1963         select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1964         select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1965         select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1966         select_items.push_back (SeparatorElem());
1967         select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1968         select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1969         select_items.push_back (SeparatorElem());
1970         select_items.push_back (MenuElem (_("Select All After Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1971         select_items.push_back (MenuElem (_("Select All Before Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1972         select_items.push_back (MenuElem (_("Select All After Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1973         select_items.push_back (MenuElem (_("Select All Before Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1974         select_items.push_back (MenuElem (_("Select All Between Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), false)));
1975         select_items.push_back (MenuElem (_("Select All Within Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), true)));
1976         select_items.push_back (MenuElem (_("Select Range Between Playhead & Edit Point"), mem_fun(*this, &Editor::select_range_between)));
1977
1978         select_items.push_back (SeparatorElem());
1979
1980         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1981
1982         /* Cut-n-Paste */
1983
1984         Menu *cutnpaste_menu = manage (new Menu);
1985         MenuList& cutnpaste_items = cutnpaste_menu->items();
1986         cutnpaste_menu->set_name ("ArdourContextMenu");
1987         
1988         cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1989         cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1990         cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1991
1992         cutnpaste_items.push_back (SeparatorElem());
1993
1994         cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1995         cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1996
1997         cutnpaste_items.push_back (SeparatorElem());
1998
1999         cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
2000
2001         edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2002
2003         /* Adding new material */
2004         
2005         edit_items.push_back (SeparatorElem());
2006         edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2007         edit_items.push_back (MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2008
2009         /* Nudge track */
2010
2011         Menu *nudge_menu = manage (new Menu());
2012         MenuList& nudge_items = nudge_menu->items();
2013         nudge_menu->set_name ("ArdourContextMenu");
2014         
2015         edit_items.push_back (SeparatorElem());
2016         nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2017         nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2018         nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2019         nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2020
2021         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2022 }
2023
2024 void
2025 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2026 {
2027         using namespace Menu_Helpers;
2028
2029         /* Playback */
2030
2031         Menu *play_menu = manage (new Menu);
2032         MenuList& play_items = play_menu->items();
2033         play_menu->set_name ("ArdourContextMenu");
2034         
2035         play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
2036         play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
2037         edit_items.push_back (MenuElem (_("Play"), *play_menu));
2038
2039         /* Selection */
2040
2041         Menu *select_menu = manage (new Menu);
2042         MenuList& select_items = select_menu->items();
2043         select_menu->set_name ("ArdourContextMenu");
2044         
2045         select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2046         select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
2047         select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2048         select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
2049         select_items.push_back (SeparatorElem());
2050         select_items.push_back (MenuElem (_("Select all after edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2051         select_items.push_back (MenuElem (_("Select all before edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2052         select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2053         select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2054
2055         edit_items.push_back (MenuElem (_("Select"), *select_menu));
2056
2057         /* Cut-n-Paste */
2058
2059         Menu *cutnpaste_menu = manage (new Menu);
2060         MenuList& cutnpaste_items = cutnpaste_menu->items();
2061         cutnpaste_menu->set_name ("ArdourContextMenu");
2062         
2063         cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2064         cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2065         cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2066
2067         Menu *nudge_menu = manage (new Menu());
2068         MenuList& nudge_items = nudge_menu->items();
2069         nudge_menu->set_name ("ArdourContextMenu");
2070         
2071         edit_items.push_back (SeparatorElem());
2072         nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2073         nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2074         nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2075         nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2076
2077         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2078 }
2079
2080 /* CURSOR SETTING AND MARKS AND STUFF */
2081
2082 void
2083 Editor::set_snap_to (SnapType st)
2084 {
2085    unsigned int snap_ind = (unsigned int)st;
2086         snap_type = st;
2087
2088    if ( snap_ind > snap_type_strings.size() - 1 ) {
2089       snap_ind = 0;
2090       snap_type = (SnapType)snap_ind;
2091    }
2092
2093         string str = snap_type_strings[snap_ind];
2094
2095         if (str != snap_type_selector.get_active_text()) {
2096                 snap_type_selector.set_active_text (str);
2097         }
2098
2099         instant_save ();
2100
2101         switch (snap_type) {
2102         case SnapToAThirtysecondBeat:
2103         case SnapToASixteenthBeat:
2104         case SnapToAEighthBeat:
2105         case SnapToAQuarterBeat:
2106         case SnapToAThirdBeat:
2107                 update_tempo_based_rulers ();
2108         default:
2109                 /* relax */
2110                 break;
2111     }
2112 }
2113
2114 void
2115 Editor::set_snap_mode (SnapMode mode)
2116 {
2117         snap_mode = mode;
2118         string str = snap_mode_strings[(int)mode];
2119
2120         if (str != snap_mode_selector.get_active_text ()) {
2121                 snap_mode_selector.set_active_text (str);
2122         }
2123
2124         instant_save ();
2125 }
2126 void
2127 Editor::set_edit_point_preference (EditPoint ep)
2128 {
2129         bool changed = _edit_point != ep;
2130
2131         _edit_point = ep;
2132         string str = edit_point_strings[(int)ep];
2133
2134         if (str != edit_point_selector.get_active_text ()) {
2135                 edit_point_selector.set_active_text (str);
2136         }
2137
2138         if (!changed) {
2139                 return;
2140         }
2141
2142         if (Profile->get_sae()) {
2143
2144                 switch (zoom_focus) {
2145                 case ZoomFocusMouse:
2146                 case ZoomFocusPlayhead:
2147                 case ZoomFocusEdit:
2148                         switch (_edit_point) {
2149                         case EditAtMouse:
2150                                 set_zoom_focus (ZoomFocusMouse);
2151                                 break;
2152                         case EditAtPlayhead:
2153                                 set_zoom_focus (ZoomFocusPlayhead);
2154                                 break;
2155                         case EditAtSelectedMarker:
2156                                 set_zoom_focus (ZoomFocusEdit);
2157                                 break;
2158                         }
2159                         break;
2160                 default:
2161                         break;
2162                 }
2163         } 
2164                                                 
2165         instant_save ();
2166 }
2167
2168 int
2169 Editor::set_state (const XMLNode& node)
2170 {
2171         const XMLProperty* prop;
2172         XMLNode* geometry;
2173         int x, y, xoff, yoff;
2174         Gdk::Geometry g;
2175
2176         if ((prop = node.property ("id")) != 0) {
2177                 _id = prop->value ();
2178         }
2179
2180         if ((geometry = find_named_node (node, "geometry")) == 0) {
2181
2182                 g.base_width = default_width;
2183                 g.base_height = default_height;
2184                 x = 1;
2185                 y = 1;
2186                 xoff = 0;
2187                 yoff = 21;
2188
2189         } else {
2190
2191                 g.base_width = atoi(geometry->property("x_size")->value());
2192                 g.base_height = atoi(geometry->property("y_size")->value());
2193                 x = atoi(geometry->property("x_pos")->value());
2194                 y = atoi(geometry->property("y_pos")->value());
2195                 xoff = atoi(geometry->property("x_off")->value());
2196                 yoff = atoi(geometry->property("y_off")->value());
2197         }
2198
2199         set_default_size (g.base_width, g.base_height);
2200         move (x, y);
2201
2202         if (session && (prop = node.property ("playhead"))) {
2203                 nframes_t pos = atol (prop->value().c_str());
2204                 playhead_cursor->set_position (pos);
2205         } else {
2206                 playhead_cursor->set_position (0);
2207
2208                 /* reset_x_origin() doesn't work right here, since the old
2209                    position may be zero already, and it does nothing in such
2210                    circumstances.
2211                 */
2212                 
2213                 leftmost_frame = 0;
2214                 horizontal_adjustment.set_value (0);
2215         }
2216
2217         if ((prop = node.property ("mixer-width"))) {
2218                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2219         }
2220
2221         if ((prop = node.property ("zoom-focus"))) {
2222                 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2223         }
2224
2225         if ((prop = node.property ("zoom"))) {
2226                 reset_zoom (PBD::atof (prop->value()));
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 ("edit-point"))) {
2238                 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point));
2239         }
2240
2241         if ((prop = node.property ("mouse-mode"))) {
2242                 MouseMode m = str2mousemode(prop->value());
2243                 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2244                 set_mouse_mode (m, true);
2245         } else {
2246                 mouse_mode = MouseGain; /* lie, to force the mode switch */
2247                 set_mouse_mode (MouseObject, true);
2248         }
2249
2250         if ((prop = node.property ("show-waveforms"))) {
2251                 bool yn = (prop->value() == "yes");
2252                 _show_waveforms = !yn;
2253                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2254                 if (act) {
2255                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2256                         /* do it twice to force the change */
2257                         tact->set_active (!yn);
2258                         tact->set_active (yn);
2259                 }
2260         }
2261
2262         if ((prop = node.property ("show-waveforms-recording"))) {
2263                 bool yn = (prop->value() == "yes");
2264                 _show_waveforms_recording = !yn;
2265                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2266                 if (act) {
2267                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2268                         /* do it twice to force the change */
2269                         tact->set_active (!yn);
2270                         tact->set_active (yn);
2271                 }
2272         }
2273         
2274         if ((prop = node.property ("show-measures"))) {
2275                 bool yn = (prop->value() == "yes");
2276                 _show_measures = !yn;
2277                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2278                 if (act) {
2279                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2280                         /* do it twice to force the change */
2281                         tact->set_active (!yn);
2282                         tact->set_active (yn);
2283                 }
2284         }
2285
2286         if ((prop = node.property ("follow-playhead"))) {
2287                 bool yn = (prop->value() == "yes");
2288                 set_follow_playhead (yn);
2289                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2290                 if (act) {
2291                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2292                         if (tact->get_active() != yn) {
2293                                 tact->set_active (yn);
2294                         }
2295                 }
2296         }
2297
2298         if ((prop = node.property ("region-list-sort-type"))) {
2299                 region_list_sort_type = (Editing::RegionListSortType) -1; // force change 
2300                 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2301         }
2302
2303         if ((prop = node.property ("xfades-visible"))) {
2304                 bool yn = (prop->value() == "yes");
2305                 _xfade_visibility = !yn;
2306                 // set_xfade_visibility (yn);
2307         }
2308
2309         if ((prop = node.property ("show-editor-mixer"))) {
2310
2311                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2312                 if (act) {
2313
2314                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2315                         bool yn = (prop->value() == X_("yes"));
2316
2317                         /* do it twice to force the change */
2318                         
2319                         tact->set_active (!yn);
2320                         tact->set_active (yn);
2321                 }
2322         }
2323
2324
2325         return 0;
2326 }
2327
2328 XMLNode&
2329 Editor::get_state ()
2330 {
2331         XMLNode* node = new XMLNode ("Editor");
2332         char buf[32];
2333
2334         _id.print (buf, sizeof (buf));
2335         node->add_property ("id", buf);
2336         
2337         if (is_realized()) {
2338                 Glib::RefPtr<Gdk::Window> win = get_window();
2339                 
2340                 int x, y, xoff, yoff, width, height;
2341                 win->get_root_origin(x, y);
2342                 win->get_position(xoff, yoff);
2343                 win->get_size(width, height);
2344                 
2345                 XMLNode* geometry = new XMLNode ("geometry");
2346
2347                 snprintf(buf, sizeof(buf), "%d", width);
2348                 geometry->add_property("x_size", string(buf));
2349                 snprintf(buf, sizeof(buf), "%d", height);
2350                 geometry->add_property("y_size", string(buf));
2351                 snprintf(buf, sizeof(buf), "%d", x);
2352                 geometry->add_property("x_pos", string(buf));
2353                 snprintf(buf, sizeof(buf), "%d", y);
2354                 geometry->add_property("y_pos", string(buf));
2355                 snprintf(buf, sizeof(buf), "%d", xoff);
2356                 geometry->add_property("x_off", string(buf));
2357                 snprintf(buf, sizeof(buf), "%d", yoff);
2358                 geometry->add_property("y_off", string(buf));
2359                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2360                 geometry->add_property("edit_pane_pos", string(buf));
2361
2362                 node->add_child_nocopy (*geometry);
2363         }
2364
2365         maybe_add_mixer_strip_width (*node);
2366         
2367         snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2368         node->add_property ("zoom-focus", buf);
2369         snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2370         node->add_property ("zoom", buf);
2371         snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2372         node->add_property ("snap-to", buf);
2373         snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2374         node->add_property ("snap-mode", buf);
2375
2376         node->add_property ("edit-point", enum_2_string (_edit_point));
2377
2378         snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2379         node->add_property ("playhead", buf);
2380
2381         node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2382         node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2383         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2384         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2385         node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2386         node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2387         node->add_property ("mouse-mode", enum2str(mouse_mode));
2388         
2389         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2390         if (act) {
2391                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2392                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2393         }
2394
2395         return *node;
2396 }
2397
2398
2399
2400 TimeAxisView *
2401 Editor::trackview_by_y_position (double y)
2402 {
2403         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2404
2405                 TimeAxisView *tv;
2406
2407                 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2408                         return tv;
2409                 }
2410         }
2411
2412         return 0;
2413 }
2414
2415 void
2416 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2417 {
2418         Location* before = 0;
2419         Location* after = 0;
2420
2421         if (!session || snap_mode == SnapOff) {
2422                 return;
2423         }
2424
2425         const nframes64_t one_second = session->frame_rate();
2426         const nframes64_t one_minute = session->frame_rate() * 60;
2427         const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2428         nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2429         nframes64_t presnap = start;
2430
2431         switch (snap_type) {
2432         case SnapToCDFrame:
2433                 if (direction) {
2434                         start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2435                 } else {
2436                         start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2437                 }
2438                 break;
2439
2440         case SnapToSMPTEFrame:
2441                 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2442                         start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2443                 } else {
2444                         start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) *  session->frames_per_smpte_frame());
2445                 }
2446                 break;
2447
2448         case SnapToSMPTESeconds:
2449                 if (session->smpte_offset_negative())
2450                 {
2451                         start += session->smpte_offset ();
2452                 } else {
2453                         start -= session->smpte_offset ();
2454                 }    
2455                 if (start % one_smpte_second > one_smpte_second / 2) {
2456                         start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2457                 } else {
2458                         start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2459                 }
2460                 
2461                 if (session->smpte_offset_negative())
2462                 {
2463                         start -= session->smpte_offset ();
2464                 } else {
2465                         start += session->smpte_offset ();
2466                 }
2467                 break;
2468                 
2469         case SnapToSMPTEMinutes:
2470                 if (session->smpte_offset_negative())
2471                 {
2472                         start += session->smpte_offset ();
2473                 } else {
2474                         start -= session->smpte_offset ();
2475                 }
2476                 if (start % one_smpte_minute > one_smpte_minute / 2) {
2477                         start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2478                 } else {
2479                         start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2480                 }
2481                 if (session->smpte_offset_negative())
2482                 {
2483                         start -= session->smpte_offset ();
2484                 } else {
2485                         start += session->smpte_offset ();
2486                 }
2487                 break;
2488                 
2489         case SnapToSeconds:
2490                 if (start % one_second > one_second / 2) {
2491                         start = (nframes_t) ceil ((double) start / one_second) * one_second;
2492                 } else {
2493                         start = (nframes_t) floor ((double) start / one_second) * one_second;
2494                 }
2495                 break;
2496                 
2497         case SnapToMinutes:
2498                 if (start % one_minute > one_minute / 2) {
2499                         start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2500                 } else {
2501                         start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2502                 }
2503                 break;
2504
2505         case SnapToBar:
2506                 start = session->tempo_map().round_to_bar (start, direction);
2507                 break;
2508
2509         case SnapToBeat:
2510                 start = session->tempo_map().round_to_beat (start, direction);
2511                 break;
2512
2513         case SnapToAThirtysecondBeat:
2514                 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2515                 break;
2516
2517         case SnapToASixteenthBeat:
2518                 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2519                 break;
2520
2521         case SnapToAEighthBeat:
2522                 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2523                 break;
2524
2525         case SnapToAQuarterBeat:
2526                 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2527                 break;
2528
2529         case SnapToAThirdBeat:
2530                 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2531                 break;
2532
2533         case SnapToMark:
2534                 if (for_mark) {
2535                         return;
2536                 }
2537
2538                 before = session->locations()->first_location_before (start);
2539                 after = session->locations()->first_location_after (start);
2540
2541                 if (direction < 0) {
2542                         if (before) {
2543                                 start = before->start();
2544                         } else {
2545                                 start = 0;
2546                         }
2547                 } else if (direction > 0) {
2548                         if (after) {
2549                                 start = after->start();
2550                         } else {
2551                                 start = session->current_end_frame();
2552                         }
2553                 } else {
2554                         if (before) {
2555                                 if (after) {
2556                                         /* find nearest of the two */
2557                                         if ((start - before->start()) < (after->start() - start)) {
2558                                                 start = before->start();
2559                                         } else {
2560                                                 start = after->start();
2561                                         }
2562                                 } else {
2563                                         start = before->start();
2564                                 }
2565                         } else if (after) {
2566                                 start = after->start();
2567                         } else {
2568                                 /* relax */
2569                         }
2570                 }
2571                 break;
2572
2573         case SnapToRegionStart:
2574         case SnapToRegionEnd:
2575         case SnapToRegionSync:
2576         case SnapToRegionBoundary:
2577                 if (!region_boundary_cache.empty()) {
2578                         vector<nframes_t>::iterator i;
2579
2580                         if (direction > 0) {
2581                                 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2582                         } else {
2583                                 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2584                         }
2585                         
2586                         if (i != region_boundary_cache.end()) {
2587                                 start = *i;
2588                         } else {
2589                                 start = region_boundary_cache.back();
2590                         }
2591                 }
2592                 break;
2593         }
2594
2595         switch (snap_mode) {
2596         case SnapNormal:
2597                 return;                 
2598                 
2599         case SnapMagnetic:
2600                 
2601                 if (presnap > start) {
2602                         if (presnap > (start + unit_to_frame(snap_threshold))) {
2603                                 start = presnap;
2604                         }
2605                         
2606                 } else if (presnap < start) {
2607                         if (presnap < (start - unit_to_frame(snap_threshold))) {
2608                                 start = presnap;
2609                         }
2610                 }
2611                 
2612         default:
2613                 /* handled at entry */
2614                 return;
2615                 
2616         }
2617 }
2618
2619 void
2620 Editor::setup_toolbar ()
2621 {
2622         string pixmap_path;
2623
2624 #ifdef GTKOSX
2625         const guint32 FUDGE = 38; // Combo's are stupid - they steal space from the entry for the button
2626 #else
2627         const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2628 #endif
2629
2630         /* Mode Buttons (tool selection) */
2631
2632         vector<ToggleButton *> mouse_mode_buttons;
2633
2634         mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2635         mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2636         mouse_mode_buttons.push_back (&mouse_move_button);
2637
2638         if (!Profile->get_sae()) {
2639                 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2640                 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2641                 mouse_mode_buttons.push_back (&mouse_select_button);
2642
2643                 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2644                 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2645                 mouse_mode_buttons.push_back (&mouse_gain_button);
2646         }
2647
2648         mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2649         mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2650         mouse_mode_buttons.push_back (&mouse_zoom_button);
2651         mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2652         mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2653         mouse_mode_buttons.push_back (&mouse_timefx_button);
2654         mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2655         mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2656         mouse_mode_buttons.push_back (&mouse_audition_button);
2657         
2658         mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2659
2660         HBox* mode_box = manage(new HBox);
2661         mode_box->set_border_width (2);
2662         mode_box->set_spacing(4);
2663         mouse_mode_button_box.set_spacing(1);
2664         mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2665         if (!Profile->get_sae()) {
2666                 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2667         }
2668         mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2669         if (!Profile->get_sae()) {
2670                 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2671         }
2672         mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2673         mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2674         mouse_mode_button_box.set_homogeneous(true);
2675
2676         vector<string> edit_mode_strings;
2677         edit_mode_strings.push_back (edit_mode_to_string (Splice));
2678         edit_mode_strings.push_back (edit_mode_to_string (Slide));
2679
2680         edit_mode_selector.set_name ("EditModeSelector");
2681         Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2682         set_popdown_strings (edit_mode_selector, edit_mode_strings);
2683         edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2684
2685         mode_box->pack_start(edit_mode_selector);
2686         mode_box->pack_start(mouse_mode_button_box);
2687         
2688         mouse_mode_tearoff = manage (new TearOff (*mode_box));
2689         mouse_mode_tearoff->set_name ("MouseModeBase");
2690
2691         mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2692                                                   &mouse_mode_tearoff->tearoff_window()));
2693         mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2694                                                   &mouse_mode_tearoff->tearoff_window(), 1));
2695         mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2696                                                   &mouse_mode_tearoff->tearoff_window()));
2697         mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2698                                                    &mouse_mode_tearoff->tearoff_window(), 1));
2699
2700         mouse_move_button.set_name ("MouseModeButton");
2701         mouse_select_button.set_name ("MouseModeButton");
2702         mouse_gain_button.set_name ("MouseModeButton");
2703         mouse_zoom_button.set_name ("MouseModeButton");
2704         mouse_timefx_button.set_name ("MouseModeButton");
2705         mouse_audition_button.set_name ("MouseModeButton");
2706
2707         ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2708         ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2709         ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2710         ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2711         ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2712         ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2713
2714         mouse_move_button.unset_flags (CAN_FOCUS);
2715         mouse_select_button.unset_flags (CAN_FOCUS);
2716         mouse_gain_button.unset_flags (CAN_FOCUS);
2717         mouse_zoom_button.unset_flags (CAN_FOCUS);
2718         mouse_timefx_button.unset_flags (CAN_FOCUS);
2719         mouse_audition_button.unset_flags (CAN_FOCUS);
2720
2721         mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2722         mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2723
2724         mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2725         mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2726         mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2727         mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2728         mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2729
2730         // mouse_move_button.set_active (true);
2731         
2732
2733         /* Zoom */
2734         
2735         zoom_box.set_spacing (1);
2736         zoom_box.set_border_width (2);
2737
2738         zoom_in_button.set_name ("EditorTimeButton");
2739         zoom_in_button.set_size_request(-1,16);
2740         zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2741         zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2742         ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2743         
2744         zoom_out_button.set_name ("EditorTimeButton");
2745         zoom_out_button.set_size_request(-1,16);
2746         zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2747         zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2748         ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2749
2750         zoom_out_full_button.set_name ("EditorTimeButton");
2751         zoom_out_full_button.set_size_request(-1,16);
2752         zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2753         zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2754         ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2755
2756         zoom_focus_selector.set_name ("ZoomFocusSelector");
2757         Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, _("Playhead"), FUDGE, 0);
2758         set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2759         zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2760         ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2761
2762         zoom_box.pack_start (zoom_focus_selector, true, true);
2763         zoom_box.pack_start (zoom_out_button, false, false);
2764         zoom_box.pack_start (zoom_in_button, false, false);
2765         zoom_box.pack_start (zoom_out_full_button, false, false);
2766
2767         snap_box.set_spacing (1);
2768         snap_box.set_border_width (2);
2769
2770         snap_type_selector.set_name ("SnapTypeSelector");
2771         Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, _("SMPTE Seconds"), 2+FUDGE, 10);
2772         set_popdown_strings (snap_type_selector, snap_type_strings);
2773         snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2774         ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units"));
2775
2776         snap_mode_selector.set_name ("SnapModeSelector");
2777         Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, _("Magnetic Snap"), 2+FUDGE, 10);
2778         set_popdown_strings (snap_mode_selector, snap_mode_strings);
2779         snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2780         ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2781
2782         edit_point_selector.set_name ("SnapModeSelector");
2783         Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, _("Playhead"), 2+FUDGE, 10);
2784         set_popdown_strings (edit_point_selector, edit_point_strings);
2785         edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
2786         ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
2787
2788         snap_box.pack_start (edit_point_clock, false, false);
2789         snap_box.pack_start (snap_mode_selector, false, false);
2790         snap_box.pack_start (snap_type_selector, false, false);
2791         snap_box.pack_start (edit_point_selector, false, false);
2792
2793         /* Nudge */
2794
2795         HBox *nudge_box = manage (new HBox);
2796         nudge_box->set_spacing(1);
2797         nudge_box->set_border_width (2);
2798
2799         nudge_forward_button.signal_button_release_event().connect (mem_fun(*this, &Editor::nudge_forward_release), false);
2800         nudge_backward_button.signal_button_release_event().connect (mem_fun(*this, &Editor::nudge_backward_release), false);
2801
2802         nudge_box->pack_start (nudge_backward_button, false, false);
2803         nudge_box->pack_start (nudge_forward_button, false, false);
2804         nudge_box->pack_start (nudge_clock, false, false);
2805
2806
2807         /* Pack everything in... */
2808
2809         HBox* hbox = new HBox;
2810         hbox->set_spacing(10);
2811
2812         tools_tearoff = new TearOff (*hbox);
2813         tools_tearoff->set_name ("MouseModeBase");
2814
2815         tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2816                                              &tools_tearoff->tearoff_window()));
2817         tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2818                                              &tools_tearoff->tearoff_window(), 0));
2819         tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2820                                              &tools_tearoff->tearoff_window()));
2821         tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2822                                               &tools_tearoff->tearoff_window(), 0));
2823
2824         toolbar_hbox.set_spacing (10);
2825         toolbar_hbox.set_border_width (1);
2826
2827         toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2828         toolbar_hbox.pack_start (*tools_tearoff, false, false);
2829
2830         
2831         hbox->pack_start (snap_box, false, false);
2832         // hbox->pack_start (zoom_box, false, false); 
2833         hbox->pack_start (*nudge_box, false, false);
2834
2835         hbox->show_all ();
2836         
2837         toolbar_base.set_name ("ToolBarBase");
2838         toolbar_base.add (toolbar_hbox);
2839
2840         toolbar_frame.set_shadow_type (SHADOW_OUT);
2841         toolbar_frame.set_name ("BaseFrame");
2842         toolbar_frame.add (toolbar_base);
2843 }
2844
2845 int
2846 Editor::convert_drop_to_paths (vector<ustring>& paths, 
2847                                const RefPtr<Gdk::DragContext>& context,
2848                                gint                x,
2849                                gint                y,
2850                                const SelectionData& data,
2851                                guint               info,
2852                                guint               time)                               
2853
2854 {       
2855         if (session == 0) {
2856                 return -1;
2857         }
2858
2859         vector<ustring> uris = data.get_uris();
2860
2861         if (uris.empty()) {
2862
2863                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2864                    are actually URI lists. So do it by hand.
2865                 */
2866
2867                 if (data.get_target() != "text/plain") {
2868                         return -1;
2869                 }
2870   
2871                 /* Parse the "uri-list" format that Nautilus provides, 
2872                    where each pathname is delimited by \r\n
2873                 */
2874         
2875                 const char* p = data.get_text().c_str();
2876                 const char* q;
2877
2878                 while (p)
2879                 {
2880                         if (*p != '#')
2881                         {
2882                                 while (g_ascii_isspace (*p))
2883                                         p++;
2884                                 
2885                                 q = p;
2886                                 while (*q && (*q != '\n') && (*q != '\r'))
2887                                         q++;
2888                                 
2889                                 if (q > p)
2890                                 {
2891                                         q--;
2892                                         while (q > p && g_ascii_isspace (*q))
2893                                                 q--;
2894                                         
2895                                         if (q > p)
2896                                         {
2897                                                 uris.push_back (ustring (p, q - p + 1));
2898                                         }
2899                                 }
2900                         }
2901                         p = strchr (p, '\n');
2902                         if (p)
2903                                 p++;
2904                 }
2905
2906                 if (uris.empty()) {
2907                         return -1;
2908                 }
2909         }
2910         
2911         for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2912
2913                 if ((*i).substr (0,7) == "file://") {
2914
2915                         
2916                         ustring p = *i;
2917                         PBD::url_decode (p);
2918
2919                         // scan forward past three slashes
2920                         
2921                         ustring::size_type slashcnt = 0;
2922                         ustring::size_type n = 0;
2923                         ustring::iterator x = p.begin();
2924
2925                         while (slashcnt < 3 && x != p.end()) {
2926                                 if ((*x) == '/') {
2927                                         slashcnt++;
2928                                 } else if (slashcnt == 3) {
2929                                         break;
2930                                 }
2931                                 ++n;
2932                                 ++x;
2933                         }
2934
2935                         if (slashcnt != 3 || x == p.end()) {
2936                                 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2937                                 continue;
2938                         }
2939
2940                         paths.push_back (p.substr (n - 1));
2941                 }
2942         }
2943
2944         return 0;
2945 }
2946
2947 void
2948 Editor::new_tempo_section ()
2949
2950 {
2951 }
2952
2953 void
2954 Editor::map_transport_state ()
2955 {
2956         ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2957
2958         if (session->transport_stopped()) {
2959                 have_pending_keyboard_selection = false;
2960         }
2961
2962         update_loop_range_view (true);
2963 }
2964
2965 /* UNDO/REDO */
2966
2967 Editor::State::State ()
2968 {
2969         selection = new Selection;
2970 }
2971
2972 Editor::State::~State ()
2973 {
2974         delete selection;
2975 }
2976
2977 UndoAction
2978 Editor::get_memento () const
2979 {
2980         State *state = new State;
2981
2982         store_state (*state);
2983         return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2984 }
2985
2986 void
2987 Editor::store_state (State& state) const
2988 {
2989         *state.selection = *selection;
2990 }
2991
2992 void
2993 Editor::restore_state (State *state)
2994 {
2995         if (*selection == *state->selection) {
2996                 return;
2997         }
2998
2999         *selection = *state->selection;
3000         time_selection_changed ();
3001         region_selection_changed ();   
3002
3003         /* XXX other selection change handlers? */
3004 }
3005
3006 void
3007 Editor::begin_reversible_command (string name)
3008 {
3009         if (session) {
3010                 // before = &get_state();
3011                 session->begin_reversible_command (name);
3012         }
3013 }
3014
3015 void
3016 Editor::commit_reversible_command ()
3017 {
3018         if (session) {
3019                 // session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
3020                 session->commit_reversible_command ();
3021         }
3022 }
3023
3024 void
3025 Editor::set_edit_group_solo (Route& route, bool yn)
3026 {
3027         RouteGroup *edit_group;
3028
3029         if ((edit_group = route.edit_group()) != 0) {
3030                 edit_group->apply (&Route::set_solo, yn, this);
3031         } else {
3032                 route.set_solo (yn, this);
3033         }
3034 }
3035
3036 void
3037 Editor::set_edit_group_mute (Route& route, bool yn)
3038 {
3039         RouteGroup *edit_group = 0;
3040
3041         if ((edit_group == route.edit_group()) != 0) {
3042                 edit_group->apply (&Route::set_mute, yn, this);
3043         } else {
3044                 route.set_mute (yn, this);
3045         }
3046 }
3047                 
3048 void
3049 Editor::history_changed ()
3050 {
3051         string label;
3052
3053         if (undo_action && session) {
3054                 if (session->undo_depth() == 0) {
3055                         label = _("Undo");
3056                 } else {
3057                         label = string_compose(_("Undo (%1)"), session->next_undo());
3058                 }
3059                 undo_action->property_label() = label;
3060         }
3061
3062         if (redo_action && session) {
3063                 if (session->redo_depth() == 0) {
3064                         label = _("Redo");
3065                 } else {
3066                         label = string_compose(_("Redo (%1)"), session->next_redo());
3067                 }
3068                 redo_action->property_label() = label;
3069         }
3070 }
3071
3072 void
3073 Editor::duplicate_dialog (bool with_dialog)
3074 {
3075         float times = 1.0f;
3076
3077         if (mouse_mode == MouseRange) {
3078                 if (selection->time.length() == 0) {
3079                         return;
3080                 }
3081         }
3082
3083         RegionSelection rs;
3084         get_regions_for_action (rs);
3085         
3086         if (mouse_mode != MouseRange) {
3087
3088                 if (rs.empty()) {
3089                         return;
3090                 }
3091         }
3092
3093         if (with_dialog) {
3094
3095                 ArdourDialog win ("Duplication Dialog");
3096                 Label  label (_("Number of Duplications:"));
3097                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3098                 SpinButton spinner (adjustment, 0.0, 1);
3099                 HBox hbox;
3100                 
3101                 win.get_vbox()->set_spacing (12);
3102                 win.get_vbox()->pack_start (hbox);
3103                 hbox.set_border_width (6);
3104                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3105                 
3106                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3107                    place, visually. so do this by hand.
3108                 */
3109                 
3110                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3111                 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3112                 spinner.grab_focus();
3113
3114                 hbox.show ();
3115                 label.show ();
3116                 spinner.show ();
3117                 
3118                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3119                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3120                 win.set_default_response (RESPONSE_ACCEPT);
3121                 
3122                 win.set_position (WIN_POS_MOUSE);
3123                 
3124                 spinner.grab_focus ();
3125                 
3126                 switch (win.run ()) {
3127                 case RESPONSE_ACCEPT:
3128                         break;
3129                 default:
3130                         return;
3131                 }
3132                 
3133                 times = adjustment.get_value();
3134         }
3135
3136         if (mouse_mode == MouseRange) {
3137                 duplicate_selection (times);
3138         } else {
3139                 duplicate_some_regions (rs, times);
3140         }
3141 }
3142
3143 void
3144 Editor::show_verbose_canvas_cursor ()
3145 {
3146         verbose_canvas_cursor->raise_to_top();
3147         verbose_canvas_cursor->show();
3148         verbose_cursor_visible = true;
3149 }
3150
3151 void
3152 Editor::hide_verbose_canvas_cursor ()
3153 {
3154         verbose_canvas_cursor->hide();
3155         verbose_cursor_visible = false;
3156 }
3157
3158 double
3159 Editor::clamp_verbose_cursor_x (double x)
3160 {
3161         return min (horizontal_adjustment.get_value() + canvas_width - 75.0, x);
3162 }
3163
3164 double
3165 Editor::clamp_verbose_cursor_y (double y)
3166 {
3167         return min (vertical_adjustment.get_value() + canvas_height - 50.0, y);
3168 }
3169
3170 void
3171 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3172 {
3173         verbose_canvas_cursor->property_text() = txt.c_str();
3174         /* don't get too close to the edge */
3175         verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (x);
3176         verbose_canvas_cursor->property_y() = clamp_verbose_cursor_x (y);
3177 }
3178
3179 void
3180 Editor::set_verbose_canvas_cursor_text (const string & txt)
3181 {
3182         verbose_canvas_cursor->property_text() = txt.c_str();
3183 }
3184
3185 void
3186 Editor::set_edit_mode (EditMode m)
3187 {
3188         Config->set_edit_mode (m);
3189 }
3190
3191 void
3192 Editor::cycle_edit_mode ()
3193 {
3194         switch (Config->get_edit_mode()) {
3195         case Slide:
3196                 Config->set_edit_mode (Splice);
3197                 break;
3198         case Splice:
3199                 Config->set_edit_mode (Slide);
3200                 break;
3201         }
3202 }
3203
3204 void
3205 Editor::edit_mode_selection_done ()
3206 {
3207         if (session == 0) {
3208                 return;
3209         }
3210
3211         string choice = edit_mode_selector.get_active_text();
3212         EditMode mode = Slide;
3213
3214         if (choice == _("Splice Edit")) {
3215                 mode = Splice;
3216         } else if (choice == _("Slide Edit")) {
3217                 mode = Slide;
3218         }
3219
3220         Config->set_edit_mode (mode);
3221 }       
3222
3223 void
3224 Editor::snap_type_selection_done ()
3225 {
3226         string choice = snap_type_selector.get_active_text();
3227         SnapType snaptype = SnapToBeat;
3228
3229         if (choice == _("Beats/3")) {
3230                 snaptype = SnapToAThirdBeat;
3231         } else if (choice == _("Beats/4")) {
3232                 snaptype = SnapToAQuarterBeat;
3233         } else if (choice == _("Beats/8")) {
3234                 snaptype = SnapToAEighthBeat;
3235         } else if (choice == _("Beats/16")) {
3236                 snaptype = SnapToASixteenthBeat;
3237         } else if (choice == _("Beats/32")) {
3238                 snaptype = SnapToAThirtysecondBeat;
3239         } else if (choice == _("Beats")) {
3240                 snaptype = SnapToBeat;
3241         } else if (choice == _("Bars")) {
3242                 snaptype = SnapToBar;
3243         } else if (choice == _("Marks")) {
3244                 snaptype = SnapToMark;
3245         } else if (choice == _("Region starts")) {
3246                 snaptype = SnapToRegionStart;
3247         } else if (choice == _("Region ends")) {
3248                 snaptype = SnapToRegionEnd;
3249         } else if (choice == _("Region bounds")) {
3250                 snaptype = SnapToRegionBoundary;
3251         } else if (choice == _("Region syncs")) {
3252                 snaptype = SnapToRegionSync;
3253         } else if (choice == _("CD Frames")) {
3254                 snaptype = SnapToCDFrame;
3255         } else if (choice == _("SMPTE Frames")) {
3256                 snaptype = SnapToSMPTEFrame;
3257         } else if (choice == _("SMPTE Seconds")) {
3258                 snaptype = SnapToSMPTESeconds;
3259         } else if (choice == _("SMPTE Minutes")) {
3260                 snaptype = SnapToSMPTEMinutes;
3261         } else if (choice == _("Seconds")) {
3262                 snaptype = SnapToSeconds;
3263         } else if (choice == _("Minutes")) {
3264                 snaptype = SnapToMinutes;
3265         }
3266
3267         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3268         if (ract) {
3269                 ract->set_active ();
3270         }
3271 }       
3272
3273 void
3274 Editor::snap_mode_selection_done ()
3275 {
3276         string choice = snap_mode_selector.get_active_text();
3277         SnapMode mode = SnapNormal;
3278
3279         if (choice == _("No Grid")) {
3280                 mode = SnapOff;
3281         } else if (choice == _("Grid")) {
3282                 mode = SnapNormal;
3283         } else if (choice == _("Magnetic")) {
3284                 mode = SnapMagnetic;
3285         }
3286
3287         RefPtr<RadioAction> ract = snap_mode_action (mode);
3288
3289         if (ract) {
3290                 ract->set_active (true);
3291         }
3292 }
3293
3294 void
3295 Editor::cycle_edit_point (bool with_marker)
3296 {
3297         switch (_edit_point) {
3298         case EditAtMouse:
3299                 set_edit_point_preference (EditAtPlayhead);
3300                 break;
3301         case EditAtPlayhead:
3302                 if (with_marker) {
3303                         set_edit_point_preference (EditAtSelectedMarker);
3304                 } else {
3305                         set_edit_point_preference (EditAtMouse);
3306                 }
3307                 break;
3308         case EditAtSelectedMarker:
3309                 set_edit_point_preference (EditAtMouse);
3310                 break;
3311         }
3312 }
3313
3314 void
3315 Editor::edit_point_selection_done ()
3316 {
3317         string choice = edit_point_selector.get_active_text();
3318         EditPoint ep = EditAtSelectedMarker;
3319
3320         if (choice == _("Marker")) {
3321                 set_edit_point_preference (EditAtSelectedMarker);
3322         } else if (choice == _("Playhead")) {
3323                 set_edit_point_preference (EditAtPlayhead);
3324         } else {
3325                 set_edit_point_preference (EditAtMouse);
3326         }
3327
3328         RefPtr<RadioAction> ract = edit_point_action (ep);
3329
3330         if (ract) {
3331                 ract->set_active (true);
3332         }
3333 }
3334
3335 void
3336 Editor::zoom_focus_selection_done ()
3337 {
3338         string choice = zoom_focus_selector.get_active_text();
3339         ZoomFocus focus_type = ZoomFocusLeft;
3340
3341         if (choice == _("Left")) {
3342                 focus_type = ZoomFocusLeft;
3343         } else if (choice == _("Right")) {
3344                 focus_type = ZoomFocusRight;
3345         } else if (choice == _("Center")) {
3346                 focus_type = ZoomFocusCenter;
3347         } else if (choice == _("Playhead")) {
3348                 focus_type = ZoomFocusPlayhead;
3349         } else if (choice == _("Mouse")) {
3350                 focus_type = ZoomFocusMouse;
3351         } else if (choice == _("Edit Point")) {
3352                 focus_type = ZoomFocusEdit;
3353         } 
3354         
3355         RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3356
3357         if (ract) {
3358                 ract->set_active ();
3359         }
3360 }       
3361
3362 gint
3363 Editor::edit_controls_button_release (GdkEventButton* ev)
3364 {
3365         if (Keyboard::is_context_menu_event (ev)) {
3366                 ARDOUR_UI::instance()->add_route (this);
3367         }
3368         return TRUE;
3369 }
3370
3371 gint
3372 Editor::mouse_select_button_release (GdkEventButton* ev)
3373 {
3374         /* this handles just right-clicks */
3375
3376         if (ev->button != 3) {
3377                 return false;
3378         }
3379
3380         return true;
3381 }
3382
3383 Editor::TrackViewList *
3384 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3385 {
3386         TrackViewList *v;
3387         TrackViewList::iterator i;
3388
3389         v = new TrackViewList;
3390
3391         if (track == 0 && group == 0) {
3392
3393                 /* all views */
3394
3395                 for (i = track_views.begin(); i != track_views.end (); ++i) {
3396                         v->push_back (*i);
3397                 }
3398
3399         } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3400                 
3401                 /* just the view for this track
3402                  */
3403
3404                 v->push_back (track);
3405
3406         } else {
3407                 
3408                 /* views for all tracks in the edit group */
3409                 
3410                 for (i  = track_views.begin(); i != track_views.end (); ++i) {
3411
3412                         if (group == 0 || (*i)->edit_group() == group) {
3413                                 v->push_back (*i);
3414                         }
3415                 }
3416         }
3417         
3418         return v;
3419 }
3420
3421 void
3422 Editor::set_zoom_focus (ZoomFocus f)
3423 {
3424         string str = zoom_focus_strings[(int)f];
3425
3426         if (str != zoom_focus_selector.get_active_text()) {
3427                 zoom_focus_selector.set_active_text (str);
3428         }
3429         
3430         if (zoom_focus != f) {
3431                 zoom_focus = f;
3432
3433                 ZoomFocusChanged (); /* EMIT_SIGNAL */
3434
3435                 instant_save ();
3436         }
3437 }
3438
3439 void
3440 Editor::ensure_float (Window& win)
3441 {
3442         win.set_transient_for (*this);
3443 }
3444
3445 void 
3446 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3447 {
3448         /* recover or initialize pane positions. do this here rather than earlier because
3449            we don't want the positions to change the child allocations, which they seem to do.
3450          */
3451
3452         int pos;
3453         XMLProperty* prop;
3454         char buf[32];
3455         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3456         int width, height;
3457         static int32_t done;
3458         XMLNode* geometry;
3459
3460         if ((geometry = find_named_node (*node, "geometry")) == 0) {
3461                 width = default_width;
3462                 height = default_height;
3463         } else {
3464                 width = atoi(geometry->property("x_size")->value());
3465                 height = atoi(geometry->property("y_size")->value());
3466         }
3467
3468         if (which == static_cast<Paned*> (&edit_pane)) {
3469
3470                 if (done) {
3471                         return;
3472                 }
3473
3474                 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3475                         /* initial allocation is 90% to canvas, 10% to notebook */
3476                         pos = (int) floor (alloc.get_width() * 0.90f);
3477                         snprintf (buf, sizeof(buf), "%d", pos);
3478                 } else {
3479                         pos = atoi (prop->value());
3480                 }
3481                 
3482                 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3483                         edit_pane.set_position (pos);
3484                         pre_maximal_pane_position = pos;
3485                 }
3486         }
3487 }
3488
3489 void
3490 Editor::detach_tearoff (Box* b, Window* w)
3491 {
3492         if (tools_tearoff->torn_off() && 
3493             mouse_mode_tearoff->torn_off()) {
3494                 top_hbox.remove (toolbar_frame);
3495         }
3496 }
3497
3498 void
3499 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3500 {
3501         if (toolbar_frame.get_parent() == 0) {
3502                 top_hbox.pack_end (toolbar_frame);
3503         }
3504 }
3505
3506 void
3507 Editor::set_show_measures (bool yn)
3508 {
3509         if (_show_measures != yn) {
3510                 hide_measures ();
3511
3512                 if ((_show_measures = yn) == true) {
3513                         draw_measures ();
3514                 }
3515                 instant_save ();
3516         }
3517 }
3518
3519 void
3520 Editor::toggle_follow_playhead ()
3521 {
3522         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3523         if (act) {
3524                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3525                 set_follow_playhead (tact->get_active());
3526         }
3527 }
3528
3529 void
3530 Editor::set_follow_playhead (bool yn)
3531 {
3532         if (_follow_playhead != yn) {
3533                 if ((_follow_playhead = yn) == true) {
3534                         /* catch up */
3535                         update_current_screen ();
3536                 }
3537                 instant_save ();
3538         }
3539 }
3540
3541 void
3542 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3543 {
3544         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3545         if (xfade) {
3546                 xfade->set_active (!xfade->active());
3547         }
3548 }
3549
3550 void
3551 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3552 {
3553         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3554         if (xfade) {
3555                 xfade->set_follow_overlap (!xfade->following_overlap());
3556         }
3557 }
3558
3559 void
3560 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3561 {
3562         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3563
3564         if (!xfade) {
3565                 return;
3566         }
3567
3568         CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3569                 
3570         ensure_float (cew);
3571         
3572         switch (cew.run ()) {
3573         case RESPONSE_ACCEPT:
3574                 break;
3575         default:
3576                 return;
3577         }
3578         
3579         cew.apply ();
3580         xfade->StateChanged (Change (~0));
3581 }
3582
3583 PlaylistSelector&
3584 Editor::playlist_selector () const
3585 {
3586         return *_playlist_selector;
3587 }
3588
3589 nframes_t
3590 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3591 {
3592         nframes_t ret;
3593
3594         ret = nudge_clock.current_duration (pos);
3595         next = ret + 1; /* XXXX fix me */
3596
3597         return ret;
3598 }
3599
3600 void
3601 Editor::end_location_changed (Location* location)
3602 {
3603         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3604         reset_scrolling_region ();
3605 }
3606
3607 int
3608 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3609 {
3610         ArdourDialog dialog ("playlist deletion dialog");
3611         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
3612                                         "If left alone, no audio files used by it will be cleaned.\n"
3613                                         "If deleted, audio files used by it alone by will cleaned."),
3614                                       pl->name()));
3615         
3616         dialog.set_position (WIN_POS_CENTER);
3617         dialog.get_vbox()->pack_start (label);
3618
3619         label.show ();
3620
3621         dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3622         dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3623         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3624
3625         switch (dialog.run ()) {
3626         case RESPONSE_ACCEPT:
3627                 /* delete the playlist */
3628                 return 0;
3629                 break;
3630
3631         case RESPONSE_REJECT:
3632                 /* keep the playlist */
3633                 return 1;
3634                 break;
3635
3636         default:
3637                 break;
3638         }
3639
3640         return -1;
3641 }
3642
3643 bool
3644 Editor::audio_region_selection_covers (nframes_t where)
3645 {
3646         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3647                 if ((*a)->region()->covers (where)) {
3648                         return true;
3649                 }
3650         }
3651
3652         return false;
3653 }
3654
3655 void
3656 Editor::prepare_for_cleanup ()
3657 {
3658         cut_buffer->clear_regions ();
3659         cut_buffer->clear_playlists ();
3660
3661         selection->clear_regions ();
3662         selection->clear_playlists ();
3663 }
3664
3665 Location*
3666 Editor::transport_loop_location()
3667 {
3668         if (session) {
3669                 return session->locations()->auto_loop_location();
3670         } else {
3671                 return 0;
3672         }
3673 }
3674
3675 Location*
3676 Editor::transport_punch_location()
3677 {
3678         if (session) {
3679                 return session->locations()->auto_punch_location();
3680         } else {
3681                 return 0;
3682         }
3683 }
3684
3685 bool
3686 Editor::control_layout_scroll (GdkEventScroll* ev)
3687 {
3688         switch (ev->direction) {
3689         case GDK_SCROLL_UP:
3690                 scroll_tracks_up_line ();
3691                 return true;
3692                 break;
3693
3694         case GDK_SCROLL_DOWN:
3695                 scroll_tracks_down_line ();
3696                 return true;
3697                 
3698         default:
3699                 /* no left/right handling yet */
3700                 break;
3701         }
3702
3703         return false;
3704 }
3705
3706
3707 /** A new snapshot has been selected.
3708  */
3709 void
3710 Editor::snapshot_display_selection_changed ()
3711 {
3712         if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3713
3714                 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3715                 
3716                 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3717
3718                 if (snap_name.length() == 0) {
3719                         return;
3720                 }
3721                 
3722                 if (session->snap_name() == snap_name) {
3723                         return;
3724                 }
3725                 
3726                 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3727         }
3728 }
3729
3730 bool
3731 Editor::snapshot_display_button_press (GdkEventButton* ev)
3732 {
3733         if (ev->button == 3) {
3734                 /* Right-click on the snapshot list. Work out which snapshot it
3735                    was over. */
3736                 Gtk::TreeModel::Path path;
3737                 Gtk::TreeViewColumn* col;
3738                 int cx;
3739                 int cy;
3740                 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3741                 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3742                 if (iter) {
3743                         Gtk::TreeModel::Row row = *iter;
3744                         popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3745                 }
3746                 return true;
3747         }
3748
3749         return false;
3750 }
3751
3752
3753 /** Pop up the snapshot display context menu.
3754  * @param button Button used to open the menu.
3755  * @param time Menu open time.
3756  * @snapshot_name Name of the snapshot that the menu click was over.
3757  */
3758
3759 void
3760 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3761 {
3762         using namespace Menu_Helpers;
3763
3764         MenuList& items (snapshot_context_menu.items());
3765         items.clear ();
3766
3767         const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3768
3769         items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)));
3770         if (!modification_allowed) {
3771                 items.back().set_sensitive (false);
3772         }
3773
3774         items.push_back (MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)));
3775         if (!modification_allowed) {
3776                 items.back().set_sensitive (false);
3777         }
3778
3779         snapshot_context_menu.popup (button, time);
3780 }
3781
3782 void
3783 Editor::rename_snapshot (Glib::ustring old_name)
3784 {
3785         ArdourPrompter prompter(true);
3786
3787         string new_name;
3788
3789         prompter.set_name ("Prompter");
3790         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3791         prompter.set_prompt (_("New name of snapshot"));
3792         prompter.set_initial_text (old_name);
3793         
3794         if (prompter.run() == RESPONSE_ACCEPT) {
3795                 prompter.get_result (new_name);
3796                 if (new_name.length()) {
3797                         session->rename_state (old_name, new_name);
3798                         redisplay_snapshots ();
3799                 }
3800         }
3801 }
3802
3803
3804 void
3805 Editor::remove_snapshot (Glib::ustring name)
3806 {
3807         vector<string> choices;
3808
3809         std::string prompt  = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3810
3811         choices.push_back (_("No, do nothing."));
3812         choices.push_back (_("Yes, remove it."));
3813
3814         Gtkmm2ext::Choice prompter (prompt, choices);
3815
3816         if (prompter.run () == 1) {
3817                 session->remove_state (name);
3818                 redisplay_snapshots ();
3819         }
3820 }
3821
3822 void
3823 Editor::redisplay_snapshots ()
3824 {
3825         if (session == 0) {
3826                 return;
3827         }
3828
3829         vector<string*>* states;
3830
3831         if ((states = session->possible_states()) == 0) {
3832                 return;
3833         }
3834
3835         snapshot_display_model->clear ();
3836
3837         for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3838                 string statename = *(*i);
3839                 TreeModel::Row row = *(snapshot_display_model->append());
3840                 
3841                 /* this lingers on in case we ever want to change the visible
3842                    name of the snapshot.
3843                 */
3844                 
3845                 string display_name;
3846                 display_name = statename;
3847
3848                 if (statename == session->snap_name()) {
3849                         snapshot_display.get_selection()->select(row);
3850                 } 
3851                 
3852                 row[snapshot_display_columns.visible_name] = display_name;
3853                 row[snapshot_display_columns.real_name] = statename;
3854         }
3855
3856         delete states;
3857 }
3858
3859 void
3860 Editor::session_state_saved (string snap_name)
3861 {
3862         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3863         redisplay_snapshots ();
3864 }
3865
3866 void
3867 Editor::maximise_editing_space ()
3868 {
3869         initial_ruler_update_required = true;
3870
3871         mouse_mode_tearoff->set_visible (false);
3872         tools_tearoff->set_visible (false);
3873
3874         pre_maximal_pane_position = edit_pane.get_position();
3875         pre_maximal_editor_width = this->get_width();
3876
3877         if(post_maximal_pane_position == 0) {
3878                 post_maximal_pane_position = edit_pane.get_width();
3879         }
3880
3881
3882         fullscreen();
3883         if(post_maximal_editor_width) {
3884                 edit_pane.set_position (post_maximal_pane_position - 
3885                         abs(post_maximal_editor_width - pre_maximal_editor_width));
3886         } else {
3887                 edit_pane.set_position (post_maximal_pane_position);
3888         }
3889 }
3890
3891 void
3892 Editor::restore_editing_space ()
3893 {
3894         initial_ruler_update_required = true;
3895
3896         // user changed width of pane during fullscreen
3897         if(post_maximal_pane_position != edit_pane.get_position()) {
3898                 post_maximal_pane_position = edit_pane.get_position();
3899         }
3900
3901         unfullscreen();
3902
3903         mouse_mode_tearoff->set_visible (true);
3904         tools_tearoff->set_visible (true);
3905         post_maximal_editor_width = this->get_width();
3906
3907
3908         edit_pane.set_position (
3909                 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3910         );
3911 }
3912
3913 /**
3914  *  Make new playlists for a given track and also any others that belong
3915  *  to the same active edit group.
3916  *  @param v Track.
3917  */
3918
3919 void 
3920 Editor::new_playlists (TimeAxisView* v)
3921 {
3922         begin_reversible_command (_("new playlists"));
3923         mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3924         commit_reversible_command ();
3925 }
3926
3927
3928 /**
3929  *  Use a copy of the current playlist for a given track and also any others that belong
3930  *  to the same active edit group.
3931  *  @param v Track.
3932  */
3933
3934 void
3935 Editor::copy_playlists (TimeAxisView* v)
3936 {
3937         begin_reversible_command (_("copy playlists"));
3938         mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3939         commit_reversible_command ();
3940 }
3941
3942
3943 /**
3944  *  Clear the current playlist for a given track and also any others that belong
3945  *  to the same active edit group.
3946  *  @param v Track.
3947  */
3948
3949 void 
3950 Editor::clear_playlists (TimeAxisView* v)
3951 {
3952         begin_reversible_command (_("clear playlists"));
3953         mapover_audio_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3954         commit_reversible_command ();
3955 }
3956
3957 void 
3958 Editor::mapped_use_new_playlist (AudioTimeAxisView& atv, uint32_t sz)
3959 {
3960         atv.use_new_playlist (sz > 1 ? false : true);
3961 }
3962
3963 void
3964 Editor::mapped_use_copy_playlist (AudioTimeAxisView& atv, uint32_t sz)
3965 {
3966         atv.use_copy_playlist (sz > 1 ? false : true);
3967 }
3968
3969 void 
3970 Editor::mapped_clear_playlist (AudioTimeAxisView& atv, uint32_t sz)
3971 {
3972         atv.clear_playlist ();
3973 }
3974
3975 bool
3976 Editor::on_key_press_event (GdkEventKey* ev)
3977 {
3978         return key_press_focus_accelerator_handler (*this, ev);
3979 }
3980
3981 bool
3982 Editor::on_key_release_event (GdkEventKey* ev)
3983 {
3984         return Gtk::Window::on_key_release_event (ev);
3985         // return key_press_focus_accelerator_handler (*this, ev);
3986 }
3987
3988 void
3989 Editor::reset_x_origin (nframes_t frame)
3990 {
3991         queue_visual_change (frame);
3992 }
3993
3994 void
3995 Editor::reset_zoom (double fpu)
3996 {
3997         queue_visual_change (fpu);
3998 }
3999
4000 void
4001 Editor::reposition_and_zoom (nframes_t frame, double fpu)
4002 {
4003         reset_x_origin (frame);
4004         reset_zoom (fpu);
4005 }
4006
4007 void
4008 Editor::swap_visual_state ()
4009 {
4010         if (last_visual_state.frames_per_unit == 0) {
4011                 // never set
4012                 return;
4013         }
4014
4015         /* note: the correct functionality here is very dependent on the ordering of 
4016            setting zoom focus, horizontal position and finally zoom. this is because
4017            it is set_frames_per_unit() that overwrites last_visual_state.
4018         */
4019
4020         set_zoom_focus (last_visual_state.zoom_focus);
4021         reposition_and_zoom (last_visual_state.leftmost_frame, last_visual_state.frames_per_unit);
4022         zoomed_to_region = false;
4023 }
4024
4025 void
4026 Editor::set_frames_per_unit (double fpu)
4027 {
4028         /* this is the core function that controls the zoom level of the canvas. it is called
4029            whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4030         */
4031
4032         if (fpu == frames_per_unit) {
4033                 return;
4034         }
4035
4036         if (fpu < 2.0) {
4037                 fpu = 2.0;
4038         }
4039
4040         
4041         /* don't allow zooms that fit more than the maximum number
4042            of frames into an 800 pixel wide space.
4043         */
4044
4045         if (max_frames / fpu < 800.0) {
4046                 return;
4047         }
4048
4049         if (fpu == frames_per_unit) {
4050                 return;
4051         }
4052         
4053         last_visual_state.frames_per_unit = frames_per_unit;
4054         last_visual_state.leftmost_frame = leftmost_frame;
4055         last_visual_state.zoom_focus = zoom_focus;
4056
4057         frames_per_unit = fpu;
4058         post_zoom ();
4059 }
4060
4061 void
4062 Editor::post_zoom ()
4063 {
4064         // convert fpu to frame count
4065
4066         nframes_t frames = (nframes_t) floor (frames_per_unit * canvas_width);
4067
4068         if (frames_per_unit != zoom_range_clock.current_duration()) {
4069                 zoom_range_clock.set (frames);
4070         }
4071
4072         if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4073                 if (!selection->tracks.empty()) {
4074                         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4075                                 (*i)->reshow_selection (selection->time);
4076                         }
4077                 } else {
4078                         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4079                                 (*i)->reshow_selection (selection->time);
4080                         }
4081                 }
4082         }
4083
4084         ZoomChanged (); /* EMIT_SIGNAL */
4085
4086         reset_hscrollbar_stepping ();
4087         reset_scrolling_region ();
4088
4089         if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
4090
4091         instant_save ();
4092 }
4093
4094 void
4095 Editor::queue_visual_change (nframes_t where)
4096 {
4097         pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
4098         pending_visual_change.time_origin = where;
4099         
4100         if (pending_visual_change.idle_handler_id < 0) {
4101                 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4102         }
4103 }
4104
4105 void
4106 Editor::queue_visual_change (double fpu)
4107 {
4108         pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
4109         pending_visual_change.frames_per_unit = fpu;
4110
4111         if (pending_visual_change.idle_handler_id < 0) {
4112                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
4113         }
4114 }
4115
4116 int
4117 Editor::_idle_visual_changer (void* arg)
4118 {
4119         return static_cast<Editor*>(arg)->idle_visual_changer ();
4120 }
4121
4122 int
4123 Editor::idle_visual_changer ()
4124 {
4125         VisualChange::Type p = pending_visual_change.pending;
4126
4127         pending_visual_change.pending = (VisualChange::Type) 0;
4128         pending_visual_change.idle_handler_id = -1;
4129
4130         if (p & VisualChange::ZoomLevel) {
4131                 set_frames_per_unit (pending_visual_change.frames_per_unit);
4132         }
4133
4134         if (p & VisualChange::TimeOrigin) {
4135                 
4136                 nframes_t time_origin = (nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit);
4137
4138                 if (time_origin != pending_visual_change.time_origin) {
4139                         horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
4140                 } else {
4141                         update_fixed_rulers();
4142                         redisplay_tempo (true);
4143                 }
4144         }
4145
4146         return 0; /* this is always a one-shot call */
4147 }
4148
4149 struct EditorOrderTimeAxisSorter {
4150     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4151             return a->order < b->order;
4152     }
4153 };
4154         
4155 void
4156 Editor::sort_track_selection (TrackSelection* sel)
4157 {
4158         EditorOrderTimeAxisSorter cmp;
4159
4160         if (sel) {
4161                 sel->sort (cmp);
4162         } else {
4163                 selection->tracks.sort (cmp);
4164         }
4165 }
4166
4167 nframes64_t
4168 Editor::get_preferred_edit_position (bool ignore_playhead)
4169 {
4170         bool ignored;
4171         nframes64_t where = 0;
4172         EditPoint ep = _edit_point;
4173
4174         if (entered_marker) {
4175                 return entered_marker->position();
4176         }
4177
4178         if (ignore_playhead && ep == EditAtPlayhead) {
4179                 ep = EditAtSelectedMarker;
4180         }
4181
4182         switch (ep) {
4183         case EditAtPlayhead:
4184                 where = session->audible_frame();
4185                 break;
4186                 
4187         case EditAtSelectedMarker:
4188                 if (!selection->markers.empty()) {
4189                         bool is_start;
4190                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4191                         if (loc) {
4192                                 if (is_start) {
4193                                         where =  loc->start();
4194                                 } else {
4195                                         where = loc->end();
4196                                 }
4197                                 break;
4198                         }
4199                 } 
4200                 /* fallthru */
4201                 
4202         default:
4203         case EditAtMouse:
4204                 if (!mouse_frame (where, ignored)) {
4205                         /* XXX not right but what can we do ? */
4206                         return 0;
4207                 }
4208                 snap_to (where);
4209                 break;
4210         }
4211
4212         return where;
4213 }
4214
4215 void
4216 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4217 {
4218         if (!session) return;
4219
4220         begin_reversible_command (cmd);
4221         
4222         Location* tll;
4223
4224         if ((tll = transport_loop_location()) == 0) {
4225                 Location* loc = new Location (start, end, _("Loop"),  Location::IsAutoLoop);
4226                 XMLNode &before = session->locations()->get_state();
4227                 session->locations()->add (loc, true);
4228                 session->set_auto_loop_location (loc);
4229                 XMLNode &after = session->locations()->get_state();
4230                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4231         }
4232         else {
4233                 XMLNode &before = tll->get_state();
4234                 tll->set_hidden (false, this);
4235                 tll->set (start, end);
4236                 XMLNode &after = tll->get_state();
4237                 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4238         }
4239         
4240         commit_reversible_command ();
4241 }
4242
4243 void
4244 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4245 {
4246         if (!session) return;
4247
4248         begin_reversible_command (cmd);
4249         
4250         Location* tpl;
4251
4252         if ((tpl = transport_punch_location()) == 0) {
4253                 Location* loc = new Location (start, end, _("Loop"),  Location::IsAutoPunch);
4254                 XMLNode &before = session->locations()->get_state();
4255                 session->locations()->add (loc, true);
4256                 session->set_auto_loop_location (loc);
4257                 XMLNode &after = session->locations()->get_state();
4258                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4259         }
4260         else {
4261                 XMLNode &before = tpl->get_state();
4262                 tpl->set_hidden (false, this);
4263                 tpl->set (start, end);
4264                 XMLNode &after = tpl->get_state();
4265                 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4266         }
4267         
4268         commit_reversible_command ();
4269 }
4270
4271 void
4272 Editor::get_regions_at (RegionSelection& rs, nframes64_t where, const TrackSelection& ts) const
4273 {
4274         const TrackSelection* tracks;
4275
4276         if (ts.empty()) {
4277                 tracks = &track_views;
4278         } else {
4279                 tracks = &ts;
4280         }
4281
4282         for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4283         
4284                 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*t);
4285
4286                 if (atv) {
4287                         boost::shared_ptr<Diskstream> ds;
4288                         boost::shared_ptr<Playlist> pl;
4289                         
4290                         if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
4291
4292                                 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)where * ds->speed()));
4293
4294                                 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4295
4296                                         RegionView* rv = atv->audio_view()->find_view (*i);
4297
4298                                         if (rv) {
4299                                                 rs.push_back (rv);
4300                                         }
4301                                 }
4302
4303                                 delete regions;
4304                         }
4305                 }
4306         }
4307 }
4308
4309 void
4310 Editor::get_regions_after (RegionSelection& rs, nframes64_t where, const TrackSelection& ts) const
4311 {
4312         const TrackSelection* tracks;
4313
4314         if (ts.empty()) {
4315                 tracks = &track_views;
4316         } else {
4317                 tracks = &ts;
4318         }
4319
4320         for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4321         
4322                 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*t);
4323
4324                 if (atv) {
4325                         boost::shared_ptr<Diskstream> ds;
4326                         boost::shared_ptr<Playlist> pl;
4327                         
4328                         if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
4329
4330                                 Playlist::RegionList* regions = pl->regions_touched ((nframes_t) floor ( (double)where * ds->speed()), max_frames);
4331
4332                                 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4333
4334                                         RegionView* rv = atv->audio_view()->find_view (*i);
4335
4336                                         if (rv) {
4337                                                 rs.push_back (rv);
4338                                         }
4339                                 }
4340
4341                                 delete regions;
4342                         }
4343                 }
4344         }
4345 }
4346
4347 void
4348 Editor::get_regions_for_action (RegionSelection& rs, bool allow_entered)
4349 {
4350         bool use_regions_at = true;
4351
4352         if (selection->regions.empty()) {
4353
4354                 if (selection->tracks.empty()) {
4355
4356                         /* no regions or tracks selected, but entered regionview is valid
4357                            and we're in object mode - just use entered regionview
4358                         */
4359                         
4360                         if (entered_regionview && (mouse_mode == Editing::MouseObject)) {
4361                                 rs.add (entered_regionview);
4362                                 return;
4363                         }
4364                 }
4365         } else {
4366                 use_regions_at = false;
4367         }
4368
4369         rs = selection->regions;
4370
4371         /* consider adding the entered regionview */
4372
4373         if (allow_entered && entered_regionview && (mouse_mode == Editing::MouseObject)) {
4374                 
4375                 /* only add the entered regionview if its not selected OR
4376                    (we're not going to use regions at edit point OR its track is not selected)
4377
4378                    this avoids duplicate regions ending up in "rs"
4379                 */
4380
4381                 if (!selection->selected (entered_regionview) && 
4382                     (!use_regions_at || !selection->selected (&entered_regionview->get_time_axis_view()))) {
4383                         rs.add (entered_regionview);
4384                 }
4385         }
4386
4387         if (use_regions_at) {
4388
4389                 /* nothing selected, so get all regions at the edit point across
4390                    all selected tracks
4391                 */
4392                 
4393                 if (!selection->tracks.empty()) {
4394                         nframes64_t where = get_preferred_edit_position();
4395                         get_regions_at (rs, where, selection->tracks);
4396                 }
4397         }
4398 }
4399
4400 void
4401 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4402 {
4403
4404         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4405                 
4406                 RouteTimeAxisView* tatv;
4407                 
4408                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4409                         
4410                         boost::shared_ptr<Playlist> pl;
4411                         vector<boost::shared_ptr<Region> > results;
4412                         RegionView* marv;
4413                         boost::shared_ptr<Diskstream> ds;
4414                         
4415                         if ((ds = tatv->get_diskstream()) == 0) {
4416                                 /* bus */
4417                                 continue;
4418                         }
4419                         
4420                         if ((pl = (ds->playlist())) != 0) {
4421                                 pl->get_region_list_equivalent_regions (region, results);
4422                         }
4423                         
4424                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4425                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4426                                         regions.push_back (marv);
4427                                 }
4428                         }
4429                         
4430                 }
4431         }
4432 }       
4433
4434 void
4435 Editor::show_rhythm_ferret ()
4436 {
4437         if (rhythm_ferret == 0) {
4438                 rhythm_ferret = new RhythmFerret(*this);
4439         }
4440
4441         rhythm_ferret->set_session (session);
4442         rhythm_ferret->show ();
4443         rhythm_ferret->present ();
4444 }