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