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