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