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