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