3e8402bbca1534f21590944f1db93d7b4458bfc8
[ardour.git] / gtk2_ardour / editor.cc
1 /*
2     Copyright (C) 2000 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     $Id$
19 */
20
21 #include <unistd.h>
22 #include <cstdlib>
23 #include <cmath>
24 #include <string>
25 #include <algorithm>
26
27 #include <sigc++/bind.h>
28
29 #include <pbd/error.h>
30
31 #include <gtkmm/image.h>
32 #include <gdkmm/color.h>
33 #include <gdkmm/bitmap.h>
34
35 #include <gtkmm2ext/gtk_ui.h>
36 #include <gtkmm2ext/tearoff.h>
37 #include <gtkmm2ext/utils.h>
38
39 #include <ardour/audio_track.h>
40 #include <ardour/diskstream.h>
41 #include <ardour/plugin_manager.h>
42 #include <ardour/location.h>
43 #include <ardour/audioplaylist.h>
44 #include <ardour/audioregion.h>
45 #include <ardour/region.h>
46 #include <ardour/session_route.h>
47 #include <ardour/tempo.h>
48 #include <ardour/utils.h>
49
50 #include "ardour_ui.h"
51 #include "editor.h"
52 #include "grouped_buttons.h"
53 #include "keyboard.h"
54 #include "marker.h"
55 #include "playlist_selector.h"
56 #include "regionview.h"
57 #include "rgb_macros.h"
58 #include "selection.h"
59 #include "streamview.h"
60 #include "time_axis_view.h"
61 #include "utils.h"
62 #include "crossfade_view.h"
63 #include "editing.h"
64 #include "public_editor.h"
65 #include "crossfade_edit.h"
66 #include "audio_time_axis.h"
67 #include "canvas_impl.h"
68 #include "actions.h"
69 #include "gui_thread.h"
70
71 #include "i18n.h"
72
73 /* <CMT Additions> */
74 #include "imageframe_socket_handler.h"
75 /* </CMT Additions> */
76
77 using namespace std;
78 using namespace sigc;
79 using namespace ARDOUR;
80 using namespace Gtk;
81 using namespace Glib;
82 using namespace Gtkmm2ext;
83 using namespace Editing;
84
85 const double Editor::timebar_height = 15.0;
86
87 #include "editor_xpms"
88
89 static const int32_t slide_index = 0;
90 static const int32_t splice_index = 1;
91
92 static const gchar *edit_mode_strings[] = {
93         N_("Slide"),
94         N_("Splice"),
95         0
96 };
97
98 static const gchar *snap_type_strings[] = {
99         N_("None"),
100         N_("CD Frames"),
101         N_("SMPTE Frames"),
102         N_("SMPTE Seconds"),
103         N_("SMPTE Minutes"),
104         N_("Seconds"),
105         N_("Minutes"),
106         N_("Beats/32"),
107         N_("Beats/16"),
108         N_("Beats/8"),
109         N_("Beats/4"),
110         N_("Beats/3"),
111         N_("Beats"),
112         N_("Bars"),
113         N_("Marks"),
114         N_("Edit Cursor"),
115         N_("Region starts"),
116         N_("Region ends"),
117         N_("Region syncs"),
118         N_("Region bounds"),
119         0
120 };
121
122 static const gchar *snap_mode_strings[] = {
123         N_("Normal"),
124         N_("Magnetic"),
125         0
126 };
127
128 static const gchar *zoom_focus_strings[] = {
129         N_("Left"),
130         N_("Right"),
131         N_("Center"),
132         N_("Playhead"),
133         N_("Edit Cursor"),
134         0
135 };
136
137 /* Soundfile  drag-n-drop */
138
139 Gdk::Cursor* Editor::cross_hair_cursor = 0;
140 Gdk::Cursor* Editor::selector_cursor = 0;
141 Gdk::Cursor* Editor::trimmer_cursor = 0;
142 Gdk::Cursor* Editor::grabber_cursor = 0;
143 Gdk::Cursor* Editor::zoom_cursor = 0;
144 Gdk::Cursor* Editor::time_fx_cursor = 0;
145 Gdk::Cursor* Editor::fader_cursor = 0;
146 Gdk::Cursor* Editor::speaker_cursor = 0;
147 Gdk::Cursor* Editor::wait_cursor = 0;
148 Gdk::Cursor* Editor::timebar_cursor = 0;
149
150 Editor::Editor (AudioEngine& eng) 
151         : engine (eng),
152
153           /* time display buttons */
154
155           minsec_label (_("Mins:Secs")),
156           bbt_label (_("Bars:Beats")),
157           smpte_label (_("SMPTE")),
158           frame_label (_("Frames")),
159           tempo_label (_("Tempo")),
160           meter_label (_("Meter")),
161           mark_label (_("Location Markers")),
162           range_mark_label (_("Range Markers")),
163           transport_mark_label (_("Loop/Punch Ranges")),
164
165           edit_packer (3, 3, false),
166           edit_hscroll_left_arrow (Gtk::ARROW_LEFT, Gtk::SHADOW_OUT),
167           edit_hscroll_right_arrow (Gtk::ARROW_RIGHT, Gtk::SHADOW_OUT),
168
169           /* tool bar related */
170
171           editor_mixer_button (_("editor\nmixer")),
172
173           selection_start_clock (X_("SelectionStartClock"), true),
174           selection_end_clock (X_("SelectionEndClock"), true),
175           edit_cursor_clock (X_("EditCursorClock"), true),
176           zoom_range_clock (X_("ZoomRangeClock"), true, true),
177           
178           toolbar_selection_clock_table (2,3),
179           
180           mouse_mode_button_table (2, 3),
181
182           mouse_select_button (_("range")),
183           mouse_move_button (_("object")),
184           mouse_gain_button (_("gain")),
185           mouse_zoom_button (_("zoom")),
186           mouse_timefx_button (_("timefx")),
187           mouse_audition_button (_("listen")),
188
189           automation_mode_button (_("mode")),
190           global_automation_button (_("automation")),
191
192           edit_mode_label (_("Edit Mode")),
193           snap_type_label (_("Snap To")),
194           snap_mode_label(_("Snap Mode")),
195           zoom_focus_label (_("Zoom Focus")),
196
197           /* <CMT Additions> */
198           image_socket_listener(0),
199           /* </CMT Additions> */
200
201           /* nudge */
202
203           nudge_label (_("Nudge")),
204           nudge_clock (X_("NudgeClock"), true, true)
205
206 {
207         constructed = false;
208
209         /* we are a singleton */
210
211         PublicEditor::_instance = this;
212
213         init_colormap ();
214
215         session = 0;
216
217         selection = new Selection;
218         cut_buffer = new Selection;
219
220         selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
221         selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
222         selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
223         selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
224
225         clicked_regionview = 0;
226         clicked_trackview = 0;
227         clicked_audio_trackview = 0;
228         clicked_crossfadeview = 0;
229         clicked_control_point = 0;
230         latest_regionview = 0;
231         last_update_frame = 0;
232         drag_info.item = 0;
233         last_audition_region = 0;
234         current_mixer_strip = 0;
235         current_bbt_points = 0;
236
237         snap_type = SnapToFrame;
238         set_snap_to (snap_type);
239         snap_mode = SnapNormal;
240         set_snap_mode (snap_mode);
241         snap_threshold = 5.0;
242         bbt_beat_subdivision = 4;
243         canvas_width = 0;
244         canvas_height = 0;
245         autoscroll_timeout_tag = -1;
246         interthread_progress_window = 0;
247         current_interthread_info = 0;
248         _show_measures = true;
249         _show_waveforms = true;
250         _show_waveforms_recording = true;
251         first_action_message = 0;
252         export_dialog = 0;
253         show_gain_after_trim = false;
254         no_zoom_repos_update = false;
255         ignore_route_list_reorder = false;
256         verbose_cursor_on = true;
257         route_removal = false;
258         track_spacing = 0;
259         show_automatic_regions_in_region_list = true;
260         have_pending_keyboard_selection = false;
261         _follow_playhead = true;
262         _xfade_visibility = true;
263         editor_ruler_menu = 0;
264         no_ruler_shown_update = false;
265         edit_group_list_menu = 0;
266         route_list_menu = 0;
267         region_list_menu = 0;
268         marker_menu = 0;
269         marker_menu_item = 0;
270         tm_marker_menu = 0;
271         transport_marker_menu = 0;
272         new_transport_marker_menu = 0;
273         editor_mixer_strip_width = Wide;
274         repos_zoom_queued = false;
275         import_audio_item = 0;
276         embed_audio_item = 0;
277         region_edit_menu_split_item = 0;
278         temp_location = 0;
279         region_edit_menu_split_multichannel_item = 0;
280         edit_hscroll_dragging = false;
281         leftmost_frame = 0;
282         ignore_mouse_mode_toggle = false;
283         current_stepping_trackview = 0;
284         entered_track = 0;
285         entered_regionview = 0;
286         clear_entered_track = false;
287         _new_regionviews_show_envelope = false;
288         current_timestretch = 0;
289
290         edit_cursor = 0;
291         playhead_cursor = 0;
292
293         location_marker_color = color_map[cLocationMarker];
294         location_range_color = color_map[cLocationRange];
295         location_cd_marker_color = color_map[cLocationCDMarker];
296         location_loop_color = color_map[cLocationLoop];
297         location_punch_color = color_map[cLocationPunch];
298
299         range_marker_drag_rect = 0;
300         marker_drag_line = 0;
301         
302         mouse_mode = MouseZoom; /* force change in next call */
303         set_mouse_mode (MouseObject, true);
304
305         frames_per_unit = 2048; /* too early to use set_frames_per_unit */
306         zoom_focus = ZoomFocusLeft;
307         zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
308
309         initialize_rulers ();
310         initialize_canvas ();
311
312         track_canvas_scroller.add (track_canvas);
313         track_canvas_scroller.set_policy (POLICY_NEVER, POLICY_NEVER);
314         track_canvas_scroller.set_name ("TrackCanvasScroller");
315
316         track_canvas_scroller.get_vadjustment()->signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
317         track_canvas_scroller.get_vadjustment()->set_step_increment (10.0);
318
319         track_canvas_scroller.get_hadjustment()->set_lower (0.0);
320         track_canvas_scroller.get_hadjustment()->set_upper (1200.0);
321         track_canvas_scroller.get_hadjustment()->set_step_increment (20.0);
322         track_canvas_scroller.get_hadjustment()->signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
323
324         edit_vscrollbar.set_adjustment(*track_canvas_scroller.get_vadjustment());
325         edit_hscrollbar.set_adjustment(*track_canvas_scroller.get_hadjustment());
326
327         edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscroll_slider_button_press));
328         edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscroll_slider_button_release));
329         edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscroll_slider_allocate));
330         
331         time_canvas_scroller.add (time_canvas);
332         time_canvas_scroller.set_policy (POLICY_NEVER, POLICY_NEVER);
333         time_canvas_scroller.set_hadjustment (*track_canvas_scroller.get_hadjustment());
334         time_canvas_scroller.set_name ("TimeCanvasScroller");
335
336         track_canvas_scroller.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
337         time_canvas_scroller.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
338         
339         edit_controls_vbox.set_spacing (track_spacing);
340         edit_controls_hbox.pack_start (edit_controls_vbox, true, true);
341         edit_controls_scroller.add (edit_controls_hbox);
342         edit_controls_scroller.set_name ("EditControlsBase");
343         edit_controls_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
344
345         Viewport* viewport = static_cast<Viewport*> (edit_controls_scroller.get_child());
346
347         viewport->set_shadow_type (Gtk::SHADOW_NONE);
348         viewport->set_name ("EditControlsBase");
349         viewport->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
350         viewport->signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
351
352         build_cursors ();
353         setup_toolbar ();
354
355         edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
356         
357         time_canvas_vbox.pack_start (*minsec_ruler, false, false);
358         time_canvas_vbox.pack_start (*smpte_ruler, false, false);
359         time_canvas_vbox.pack_start (*frames_ruler, false, false);
360         time_canvas_vbox.pack_start (*bbt_ruler, false, false);
361         time_canvas_vbox.pack_start (time_canvas_scroller, true, true);
362         time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars));
363
364         bbt_label.set_name ("EditorTimeButton");
365         bbt_label.set_size_request (-1, (int)timebar_height);
366         bbt_label.set_alignment (1.0, 0.5);
367         bbt_label.set_padding (5,0);
368         minsec_label.set_name ("EditorTimeButton");
369         minsec_label.set_size_request (-1, (int)timebar_height);
370         minsec_label.set_alignment (1.0, 0.5);
371         minsec_label.set_padding (5,0);
372         smpte_label.set_name ("EditorTimeButton");
373         smpte_label.set_size_request (-1, (int)timebar_height);
374         smpte_label.set_alignment (1.0, 0.5);
375         smpte_label.set_padding (5,0);
376         frame_label.set_name ("EditorTimeButton");
377         frame_label.set_size_request (-1, (int)timebar_height);
378         frame_label.set_alignment (1.0, 0.5);
379         frame_label.set_padding (5,0);
380         tempo_label.set_name ("EditorTimeButton");
381         tempo_label.set_size_request (-1, (int)timebar_height);
382         tempo_label.set_alignment (1.0, 0.5);
383         tempo_label.set_padding (5,0);
384         meter_label.set_name ("EditorTimeButton");
385         meter_label.set_size_request (-1, (int)timebar_height);
386         meter_label.set_alignment (1.0, 0.5);
387         meter_label.set_padding (5,0);
388         mark_label.set_name ("EditorTimeButton");
389         mark_label.set_size_request (-1, (int)timebar_height);
390         mark_label.set_alignment (1.0, 0.5);
391         mark_label.set_padding (5,0);
392         range_mark_label.set_name ("EditorTimeButton");
393         range_mark_label.set_size_request (-1, (int)timebar_height);
394         range_mark_label.set_alignment (1.0, 0.5);
395         range_mark_label.set_padding (5,0);
396         transport_mark_label.set_name ("EditorTimeButton");
397         transport_mark_label.set_size_request (-1, (int)timebar_height);
398         transport_mark_label.set_alignment (1.0, 0.5);
399         transport_mark_label.set_padding (5,0);
400         
401         time_button_vbox.pack_start (minsec_label, false, false);
402         time_button_vbox.pack_start (smpte_label, false, false);
403         time_button_vbox.pack_start (frame_label, false, false);
404         time_button_vbox.pack_start (bbt_label, false, false);
405         time_button_vbox.pack_start (meter_label, false, false);
406         time_button_vbox.pack_start (tempo_label, false, false);
407         time_button_vbox.pack_start (mark_label, false, false);
408
409         time_button_event_box.add (time_button_vbox);
410         
411         time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
412         time_button_event_box.set_name ("TimebarLabelBase");
413         time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
414
415         /* these enable us to have a dedicated window (for cursor setting, etc.) 
416            for the canvas areas.
417         */
418
419         track_canvas_event_box.add (track_canvas_scroller);
420
421         time_canvas_event_box.add (time_canvas_vbox);
422         time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
423
424         
425         edit_packer.set_col_spacings (0);
426         edit_packer.set_row_spacings (0);
427         edit_packer.set_homogeneous (false);
428         edit_packer.set_name ("EditorWindow");
429
430         edit_packer.attach (edit_hscrollbar,            1, 2, 0, 1,    FILL|EXPAND,  FILL, 0, 0);
431
432         edit_packer.attach (time_button_event_box,          0, 1, 1, 2,    FILL, FILL, 0, 0);
433         edit_packer.attach (time_canvas_event_box,          1, 2, 1, 2,    FILL|EXPAND, FILL, 0, 0);
434
435         edit_packer.attach (edit_controls_scroller,         0, 1, 2, 3,    FILL,FILL, 0, 0);
436         edit_packer.attach (track_canvas_event_box,         1, 2, 2, 3,    FILL|EXPAND, FILL|EXPAND, 0, 0);
437         edit_packer.attach (edit_vscrollbar,                2, 3, 2, 3,    FILL,        FILL|EXPAND, 0, 0);
438
439         edit_frame.set_name ("BaseFrame");
440         edit_frame.set_shadow_type (SHADOW_IN);
441         edit_frame.add (edit_packer);
442
443         zoom_in_button.set_name ("EditorTimeButton");
444         zoom_out_button.set_name ("EditorTimeButton");
445         ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom in"));
446         ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom out"));
447
448         zoom_out_full_button.set_name ("EditorTimeButton");
449         ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to session"));
450
451         zoom_in_button.add (*(manage (new Gtk::Image (Stock::ZOOM_IN, ICON_SIZE_BUTTON))));
452         zoom_out_button.add (*(manage (new Gtk::Image (Stock::ZOOM_OUT, ICON_SIZE_BUTTON))));
453         zoom_out_full_button.add (*(manage (new Gtk::Image (Stock::ZOOM_FIT, ICON_SIZE_BUTTON))));
454         
455         zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
456         zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
457         zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
458         
459         zoom_indicator_box.pack_start (zoom_out_button, false, false);
460         zoom_indicator_box.pack_start (zoom_in_button, false, false);
461         zoom_indicator_box.pack_start (zoom_range_clock, false, false); 
462         zoom_indicator_box.pack_start (zoom_out_full_button, false, false);
463         
464         zoom_indicator_label.set_text (_("Zoom Span"));
465         zoom_indicator_label.set_name ("ToolBarLabel");
466
467         zoom_indicator_vbox.set_spacing (3);
468         zoom_indicator_vbox.set_border_width (3);
469         zoom_indicator_vbox.pack_start (zoom_indicator_label, false, false);
470         zoom_indicator_vbox.pack_start (zoom_indicator_box, false, false);
471
472         bottom_hbox.set_border_width (3);
473         bottom_hbox.set_spacing (3);
474
475         route_display_model = ListStore::create(route_display_columns);
476         route_list.set_model (route_display_model);
477         route_list.append_column (_("Tracks"), route_display_columns.text);
478         route_list.set_name ("TrackListDisplay");
479         route_list.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
480         route_list.set_reorderable (true);
481         
482         route_list.set_size_request (75,-1);
483         route_list.set_headers_visible (true);
484         route_list.set_headers_clickable (true);
485
486         // GTK2FIX
487         // route_list.signal_rows_reordered().connect (mem_fun (*this, &Editor::queue_route_list_reordered));
488
489         // GTK2FIX
490         // route_display_model->set_sort_func (0, mem_fun (*this, &Editor::route_list_compare_func));
491
492         // GTK2FIX
493         //route_list.set_shadow_type (Gtk::SHADOW_IN);
494
495         route_list_scroller.add (route_list);
496         route_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
497
498         route_list.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::route_display_selection_changed));
499         route_list.signal_columns_changed().connect (mem_fun(*this, &Editor::route_list_column_click));
500
501         edit_group_list_button_label.set_text (_("Edit Groups"));
502         edit_group_list_button_label.set_name ("EditGroupTitleButton");
503         edit_group_list_button.add (edit_group_list_button_label);
504         edit_group_list_button.set_name ("EditGroupTitleButton");
505
506         group_model = ListStore::create(group_columns);
507         edit_group_list.set_model (group_model);
508         edit_group_list.append_column (_("active"), group_columns.is_active);
509         edit_group_list.append_column (_("groupname"), group_columns.text);
510         edit_group_list.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
511         edit_group_list.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
512
513         /* use checkbox for the active column */
514
515         CellRendererToggle *active_cell = dynamic_cast<CellRendererToggle*>(edit_group_list.get_column_cell_renderer (0));
516         active_cell->property_activatable() = true;
517         active_cell->property_radio() = false;
518
519         edit_group_list.set_name ("MixerGroupList");
520         //edit_group_list.set_shadow_type (Gtk::SHADOW_IN);
521
522         edit_group_list.columns_autosize ();
523         edit_group_list.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
524         edit_group_list.set_reorderable (false);
525
526         edit_group_list.set_size_request (75, -1);
527         edit_group_list.set_headers_visible (true);
528
529         edit_group_list_scroller.add (edit_group_list);
530         edit_group_list_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
531
532         edit_group_list_button.signal_clicked().connect (mem_fun(*this, &Editor::edit_group_list_button_clicked));
533         edit_group_list.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event));
534         edit_group_list.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::edit_group_selection_changed));
535         
536         TreeModel::Row row = *(group_model->append());
537         row[group_columns.is_active] = false;
538         row[group_columns.text] = (_("-all-"));
539         edit_group_list.get_selection()->select (row);
540 /* GTK2FIX is set_data(0) setting the is_active to false here?
541         list<string> stupid_list;
542
543         stupid_list.push_back ("*");
544         stupid_list.push_back (_("-all-"));
545
546         edit_group_list.rows().push_back (stupid_list);
547         edit_group_list.rows().back().set_data (0);
548         edit_group_list.rows().back().select();
549         
550 */
551         edit_group_vbox.pack_start (edit_group_list_button, false, false);
552         edit_group_vbox.pack_start (edit_group_list_scroller, true, true);
553         
554         region_list_model = TreeStore::create (region_list_columns);
555         region_list_sort_model = TreeModelSort::create (region_list_model);
556         region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
557
558         region_list_display.set_model (region_list_sort_model);
559         region_list_display.append_column (_("Regions"), region_list_columns.name);
560         region_list_display.set_reorderable (true);
561         region_list_display.set_size_request (100, -1);
562         region_list_display.set_data ("editor", this);
563         region_list_display.set_flags (Gtk::CAN_FOCUS);
564         region_list_display.set_name ("RegionListDisplay");
565
566         region_list_scroller.add (region_list_display);
567         region_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
568
569         list<Gtk::TargetEntry> region_list_target_table;
570         
571         region_list_target_table.push_back (TargetEntry ("STRING"));
572         region_list_target_table.push_back (TargetEntry ("text/plain"));
573         region_list_target_table.push_back (TargetEntry ("text/uri-list"));
574         region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
575
576         // GTK2FIX
577         // region_list_display.drag_dest_set (region_list_target_table, DEST_DEFAULT_ALL, GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE));
578         // region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
579
580         region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
581         region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
582         region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press));
583         region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
584         region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
585         // GTK2FIX
586         //region_list_display.unselect_row.connect (mem_fun(*this, &Editor::region_list_display_unselected));
587         //region_list_display.signal_columns_changed().connect (mem_fun(*this, &Editor::region_list_column_click));
588         
589         named_selection_scroller.add (named_selection_display);
590         named_selection_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
591
592         named_selection_model = TreeStore::create (named_selection_columns);
593         named_selection_display.set_model (named_selection_model);
594         named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
595         named_selection_display.set_size_request (100, -1);
596         named_selection_display.set_name ("RegionListDisplay");
597         
598         named_selection_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
599         named_selection_display.set_size_request (100, -1);
600         named_selection_display.set_headers_visible (true);
601         named_selection_display.set_headers_clickable (true);
602         named_selection_display.signal_button_press_event().connect (mem_fun(*this, &Editor::named_selection_display_button_press));
603         named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
604
605         the_notebook.append_page (route_list_scroller, _("Tracks/Busses"));
606         the_notebook.append_page (edit_group_vbox, _("Edit Groups"));
607         the_notebook.append_page (region_list_scroller, _("Regions"));
608         the_notebook.append_page (named_selection_scroller, _("Chunks"));
609         the_notebook.set_show_tabs (true);
610
611         TearOff *notebook_tearoff = manage (new TearOff (the_notebook));
612
613         edit_pane.pack1 (edit_frame, true, true);
614         edit_pane.pack2 (*notebook_tearoff, true, true);
615
616         edit_pane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Gtk::Paned*> (&edit_pane)));
617
618         top_hbox.pack_start (toolbar_frame, true, true);
619
620         HBox *hbox = manage (new HBox);
621         hbox->pack_start (edit_pane, true, true);
622
623         global_vpacker.pack_start (top_hbox, false, false);
624         global_vpacker.pack_start (*hbox, true, true);
625
626         global_hpacker.pack_start (global_vpacker, true, true);
627
628         set_name ("EditorWindow");
629         add_accel_group (ActionManager::ui_manager->get_accel_group());
630
631         vpacker.pack_end (global_hpacker, true, true);
632         
633         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
634         set_state (*node);
635
636         _playlist_selector = new PlaylistSelector();
637         _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
638
639         AudioRegionView::AudioRegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_audio_regionview));
640
641         /* nudge stuff */
642
643         nudge_forward_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(right_arrow_xpm)))));
644         nudge_backward_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(left_arrow_xpm)))));
645
646         ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge region/selection forwards"));
647         ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge region/selection backwards"));
648
649         nudge_forward_button.set_name ("TransportButton");
650         nudge_backward_button.set_name ("TransportButton");
651
652         fade_context_menu.set_name ("ArdourContextMenu");
653
654         set_title (_("ardour: editor"));
655         set_wmclass (_("ardour_editor"), "Ardour");
656
657         add (vpacker);
658         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
659
660         signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
661         signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
662
663         constructed = true;
664         instant_save ();
665 }
666
667 Editor::~Editor()
668 {
669         /* <CMT Additions> */
670         if(image_socket_listener)
671         {
672                 if(image_socket_listener->is_connected())
673                 {
674                         image_socket_listener->close_connection() ;
675                 }
676                 
677                 delete image_socket_listener ;
678                 image_socket_listener = 0 ;
679         }
680         /* </CMT Additions> */
681 }
682
683 void
684 Editor::add_toplevel_controls (Container& cont)
685 {
686         vpacker.pack_start (cont, false, false);
687         cont.show_all ();
688 }
689
690 void
691 Editor::catch_vanishing_audio_regionview (AudioRegionView *rv)
692 {
693         /* note: the selection will take care of the vanishing
694            audioregionview by itself.
695         */
696
697         if (clicked_regionview == rv) {
698                 clicked_regionview = 0;
699         }
700
701         if (entered_regionview == rv) {
702                 set_entered_regionview (0);
703         }
704 }
705
706 void
707 Editor::set_entered_regionview (AudioRegionView* rv)
708 {
709         if (rv == entered_regionview) {
710                 return;
711         }
712
713         if (entered_regionview) {
714                 entered_regionview->exited ();
715         }
716
717         if ((entered_regionview = rv) != 0) {
718                 entered_regionview->entered ();
719         }
720 }
721
722 void
723 Editor::set_entered_track (TimeAxisView* tav)
724 {
725         if (entered_track) {
726                 entered_track->exited ();
727         }
728
729         if ((entered_track = tav) != 0) {
730                 entered_track->entered ();
731         }
732 }
733
734 gint
735 Editor::left_track_canvas (GdkEventCrossing *ev)
736 {
737         set_entered_track (0);
738         set_entered_regionview (0);
739         return FALSE;
740 }
741
742
743 void
744 Editor::show_window ()
745 {
746         show_all ();
747         present ();
748
749         /* now reset all audio_time_axis heights, because widgets might need
750            to be re-hidden
751         */
752         
753         TimeAxisView *tv;
754         
755         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
756                 tv = (static_cast<TimeAxisView*>(*i));
757                 tv->reset_height ();
758         }
759 }
760
761 void
762 Editor::tie_vertical_scrolling ()
763 {
764         edit_controls_scroller.get_vadjustment()->set_value (track_canvas_scroller.get_vadjustment()->get_value());
765
766         float y1 = track_canvas_scroller.get_vadjustment()->get_value();
767         playhead_cursor->set_y_axis(y1);
768         edit_cursor->set_y_axis(y1);
769 }
770
771 void
772 Editor::set_frames_per_unit (double fpu)
773 {
774         jack_nframes_t frames;
775
776         if (fpu == frames_per_unit) {
777                 return;
778         }
779
780         if (fpu < 1.0) {
781                 fpu = 1.0;
782         }
783
784         // convert fpu to frame count
785
786         frames = (jack_nframes_t) floor (fpu * canvas_width);
787         
788         /* don't allow zooms that fit more than the maximum number
789            of frames into an 800 pixel wide space.
790         */
791
792         if (max_frames / fpu < 800.0) {
793                 return;
794         }
795
796         frames_per_unit = fpu;
797
798         if (frames != zoom_range_clock.current_duration()) {
799                 zoom_range_clock.set (frames);
800         }
801
802         /* only update these if we not about to call reposition_x_origin,
803            which will do the same updates.
804         */
805         
806         if (session) {
807                 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
808         }
809         
810         if (!no_zoom_repos_update) {
811                 track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit);
812                 update_hscroller ();
813                 update_fixed_rulers ();
814                 tempo_map_changed (Change (0));
815         }
816
817         if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
818                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
819                         (*i)->reshow_selection (selection->time);
820                 }
821         }
822
823         ZoomChanged (); /* EMIT_SIGNAL */
824
825         if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
826         if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
827
828         instant_save ();
829
830 }
831
832 void
833 Editor::instant_save ()
834 {
835         if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
836                 return;
837         }
838
839         if (session) {
840                 session->add_instant_xml(get_state(), session->path());
841         } else {
842                 Config->add_instant_xml(get_state(), Config->get_user_ardour_path());
843         }
844 }
845
846 void
847 Editor::reposition_x_origin (jack_nframes_t frame)
848 {
849         if (frame != leftmost_frame) {
850                 leftmost_frame = frame;
851                 double pixel = frame_to_pixel (frame);
852                 if (pixel >= track_canvas_scroller.get_hadjustment()->get_upper()) {
853                         track_canvas_scroller.get_hadjustment()->set_upper (frame_to_pixel (frame + (current_page_frames())));
854                 }
855                 track_canvas_scroller.get_hadjustment()->set_value (frame/frames_per_unit);
856                 XOriginChanged (); /* EMIT_SIGNAL */
857         }
858 }
859
860 void
861 Editor::edit_cursor_clock_changed()
862 {
863         if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
864                 edit_cursor->set_position (edit_cursor_clock.current_time());
865         }
866 }
867
868
869 void
870 Editor::zoom_adjustment_changed ()
871 {
872         if (session == 0 || no_zoom_repos_update) {
873                 return;
874         }
875
876         double fpu = zoom_range_clock.current_duration() / canvas_width;
877
878         if (fpu < 1.0) {
879                 fpu = 1.0;
880                 zoom_range_clock.set ((jack_nframes_t) floor (fpu * canvas_width));
881         } else if (fpu > session->current_end_frame() / canvas_width) {
882                 fpu = session->current_end_frame() / canvas_width;
883                 zoom_range_clock.set ((jack_nframes_t) floor (fpu * canvas_width));
884         }
885         
886         temporal_zoom (fpu);
887 }
888
889 void 
890 Editor::canvas_horizontally_scrolled ()
891 {
892         /* XXX note the potential loss of accuracy here caused by
893            adjustments being 32bit floats with only a 24 bit mantissa,
894            whereas jack_nframes_t is at least a 32 bit uint32_teger.
895         */
896         
897         leftmost_frame = (jack_nframes_t) floor (track_canvas_scroller.get_hadjustment()->get_value() * frames_per_unit);
898         
899         update_hscroller ();
900         update_fixed_rulers ();
901         
902         if (!edit_hscroll_dragging) {
903                 tempo_map_changed (Change (0));
904         } else {
905                 update_tempo_based_rulers();
906         }
907 }
908
909 void
910 Editor::reposition_and_zoom (jack_nframes_t frame, double nfpu)
911 {
912         if (!repos_zoom_queued) {
913           Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu));
914                 repos_zoom_queued = true;
915         }
916 }
917
918 gint
919 Editor::deferred_reposition_and_zoom (jack_nframes_t frame, double nfpu)
920 {
921         /* if we need to force an update to the hscroller stuff,
922            don't set no_zoom_repos_update.
923         */
924
925         no_zoom_repos_update = (frame != leftmost_frame);
926         
927         set_frames_per_unit (nfpu);
928         if (no_zoom_repos_update) {
929                 reposition_x_origin  (frame);
930         }
931         no_zoom_repos_update = false;
932         repos_zoom_queued = false;
933         
934         return FALSE;
935 }
936
937 void
938 Editor::on_realize ()
939 {
940         Window::on_realize ();
941
942         /* Even though we're not using acceleration, we want the
943            labels to show up.
944         */
945
946         track_context_menu.accelerate (*this->get_toplevel());
947         track_region_context_menu.accelerate (*this->get_toplevel());
948 }
949
950
951 void
952 Editor::queue_session_control_changed (Session::ControlType t)
953 {
954         Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::session_control_changed), t));
955 }
956
957 void
958 Editor::session_control_changed (Session::ControlType t)
959 {
960         // right now we're only tracking the loop and punch state
961
962         switch (t) {
963         case Session::AutoLoop:
964                 update_loop_range_view (true);
965                 break;
966         case Session::PunchIn:
967         case Session::PunchOut:
968                 update_punch_range_view (true);
969                 break;
970
971         default:
972                 break;
973         }
974 }
975
976 void
977 Editor::fake_add_edit_group (RouteGroup *group)
978 {
979         Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::add_edit_group), group));
980 }
981
982 void
983 Editor::fake_handle_new_audio_region (AudioRegion *region)
984 {
985         Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_new_audio_region), region));
986 }
987
988 void
989 Editor::fake_handle_audio_region_removed (AudioRegion *region)
990 {
991         Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_audio_region_removed), region));
992 }
993
994 void
995 Editor::fake_handle_new_duration ()
996 {
997         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &Editor::handle_new_duration));
998 }
999
1000 void
1001 Editor::start_scrolling ()
1002 {
1003         scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect 
1004                 (mem_fun(*this, &Editor::update_current_screen));
1005
1006         slower_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect 
1007                 (mem_fun(*this, &Editor::update_slower));
1008 }
1009
1010 void
1011 Editor::stop_scrolling ()
1012 {
1013         scroll_connection.disconnect ();
1014         slower_update_connection.disconnect ();
1015 }
1016
1017 void
1018 Editor::map_position_change (jack_nframes_t frame)
1019 {
1020         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1021
1022         if (session == 0 || !_follow_playhead) {
1023                 return;
1024         }
1025
1026         center_screen (frame);
1027         playhead_cursor->set_position (frame);
1028 }       
1029
1030 void
1031 Editor::center_screen (jack_nframes_t frame)
1032 {
1033         double page = canvas_width * frames_per_unit;
1034
1035         /* if we're off the page, then scroll.
1036          */
1037         
1038         if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1039                 center_screen_internal (frame, page);
1040         }
1041 }
1042
1043 void
1044 Editor::center_screen_internal (jack_nframes_t frame, float page)
1045 {
1046         page /= 2;
1047                 
1048         if (frame > page) {
1049                 frame -= (jack_nframes_t) page;
1050         } else {
1051                 frame = 0;
1052         }
1053
1054     reposition_x_origin (frame);
1055 }
1056
1057 void
1058 Editor::handle_new_duration ()
1059 {
1060         reset_scrolling_region ();
1061
1062         if (session) {
1063                 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1064                 track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit);
1065         }
1066         
1067         update_hscroller ();
1068 }
1069
1070 void
1071 Editor::update_title_s (string snap_name)
1072 {
1073         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1074         
1075         update_title ();
1076 }
1077
1078 void
1079 Editor::update_title ()
1080 {
1081         ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1082
1083         if (session) {
1084                 bool dirty = session->dirty();
1085
1086                 string wintitle = _("ardour: editor: ");
1087
1088                 if (dirty) {
1089                         wintitle += '[';
1090                 }
1091
1092                 wintitle += session->name();
1093
1094                 if (session->snap_name() != session->name()) {
1095                         wintitle += ':';
1096                         wintitle += session->snap_name();
1097                 }
1098
1099                 if (dirty) {
1100                         wintitle += ']';
1101                 }
1102
1103                 set_title (wintitle);
1104         }
1105 }
1106
1107 void
1108 Editor::connect_to_session (Session *t)
1109 {
1110         session = t;
1111
1112         if (first_action_message) {
1113                 first_action_message->hide();
1114         }
1115
1116         flush_track_canvas();
1117
1118         update_title ();
1119
1120         session->going_away.connect (mem_fun(*this, &Editor::session_going_away));
1121
1122         /* These signals can all be emitted by a non-GUI thread. Therefore the
1123            handlers for them must not attempt to directly interact with the GUI,
1124            but use Gtkmm2ext::UI::instance()->call_slot();
1125         */
1126
1127         session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1128         session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1129         session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route_p)));
1130         session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::fake_handle_new_audio_region)));
1131         session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::fake_handle_audio_region_removed)));
1132         session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::fake_handle_new_duration)));
1133         session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::fake_add_edit_group)));
1134         session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1135         session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1136         session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1137         session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1138         session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1139         session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1140
1141         session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1142         session_connections.push_back (session->SMPTETypeChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1143
1144         session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1145
1146         session->foreach_edit_group(this, &Editor::add_edit_group);
1147
1148         editor_mixer_button.signal_toggled().connect (mem_fun(*this, &Editor::editor_mixer_button_toggled));
1149         editor_mixer_button.set_name (X_("EditorMixerButton"));
1150
1151         edit_cursor_clock.set_session (session);
1152         selection_start_clock.set_session (session);
1153         selection_end_clock.set_session (session);
1154         zoom_range_clock.set_session (session);
1155         _playlist_selector->set_session (session);
1156         nudge_clock.set_session (session);
1157
1158         switch (session->get_edit_mode()) {
1159         case Splice:
1160                 edit_mode_selector.set_active_text (edit_mode_strings[splice_index]);
1161                 break;
1162
1163         case Slide:
1164                 edit_mode_selector.set_active_text (edit_mode_strings[slide_index]);
1165                 break;
1166         }
1167
1168         Location* loc = session->locations()->auto_loop_location();
1169         if (loc == 0) {
1170                 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1171                 if (loc->start() == loc->end()) {
1172                         loc->set_end (loc->start() + 1);
1173                 }
1174                 session->locations()->add (loc, false);
1175                 session->set_auto_loop_location (loc);
1176         }
1177         else {
1178                 // force name
1179                 loc->set_name (_("Loop"));
1180         }
1181         
1182         loc = session->locations()->auto_punch_location();
1183         if (loc == 0) {
1184                 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1185                 if (loc->start() == loc->end()) {
1186                         loc->set_end (loc->start() + 1);
1187                 }
1188                 session->locations()->add (loc, false);
1189                 session->set_auto_punch_location (loc);
1190         }
1191         else {
1192                 // force name
1193                 loc->set_name (_("Punch"));
1194         }
1195
1196         update_loop_range_view (true);
1197         update_punch_range_view (true);
1198         
1199         session->ControlChanged.connect (mem_fun(*this, &Editor::queue_session_control_changed));
1200
1201         
1202         refresh_location_display ();
1203         session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1204         session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1205         session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1206         session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1207         session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1208
1209         reset_scrolling_region ();
1210
1211         redisplay_regions ();
1212         redisplay_named_selections ();
1213
1214         //route_list.freeze (); GTK2FIX
1215         route_display_model->clear ();
1216         session->foreach_route (this, &Editor::handle_new_route);
1217         // route_list.select_all ();
1218         // GTK2FIX
1219         //route_list.sort ();
1220         route_list_reordered ();
1221         //route_list.thaw ();
1222
1223         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1224                 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1225         }
1226
1227         /* ::reposition_x_origin() doesn't work right here, since the old
1228            position may be zero already, and it does nothing in such
1229            circumstances.
1230         */
1231
1232         leftmost_frame = 0;
1233         
1234         track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1235         track_canvas_scroller.get_hadjustment()->set_value (0);
1236
1237         update_hscroller ();
1238         restore_ruler_visibility ();
1239         tempo_map_changed (Change (0));
1240
1241         edit_cursor->set_position (0);
1242         playhead_cursor->set_position (0);
1243
1244         start_scrolling ();
1245
1246         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1247         set_state (*node);
1248
1249         /* don't show master bus in a new session */
1250
1251         if (ARDOUR_UI::instance()->session_is_new ()) {
1252
1253                 TreeModel::Children rows = route_display_model->children();
1254                 TreeModel::Children::iterator i;
1255         
1256                 //route_list.freeze ();
1257                 
1258                 for (i = rows.begin(); i != rows.end(); ++i) {
1259                   TimeAxisView *tv =  (*i)[route_display_columns.tv];
1260                         AudioTimeAxisView *atv;
1261
1262                         if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1263                                 if (atv->route().master()) {
1264                                         route_list.get_selection()->unselect (i);
1265                                         //(*i)->unselect ();
1266                                 }
1267                         }
1268                 }
1269
1270                 //route_list.thaw ();
1271         }
1272 }
1273
1274 void
1275 Editor::build_cursors ()
1276 {
1277         using namespace Gdk;
1278         
1279         Gdk::Color mbg ("#000000" ); /* Black */
1280         Gdk::Color mfg ("#0000ff" ); /* Blue. */
1281
1282         {
1283                 RefPtr<Bitmap> source, mask;
1284                 source = Bitmap::create (mag_bits, mag_width, mag_height);
1285                 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1286                 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1287         }
1288
1289         Gdk::Color fbg ("#ffffff" );
1290         Gdk::Color ffg  ("#000000" );
1291         
1292         {
1293                 RefPtr<Bitmap> source, mask;
1294                 
1295                 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1296                 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1297                 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1298         }
1299         
1300         { 
1301                 RefPtr<Bitmap> source, mask;
1302                 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1303                 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1304                 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1305         }
1306
1307         grabber_cursor = new Gdk::Cursor (HAND2);
1308         cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1309         trimmer_cursor =  new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1310         selector_cursor = new Gdk::Cursor (XTERM);
1311         time_fx_cursor = new Gdk::Cursor (SIZING);
1312         wait_cursor = new Gdk::Cursor  (WATCH);
1313         timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1314 }
1315
1316 void
1317 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1318 {
1319         using namespace Menu_Helpers;
1320         AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1321
1322         if (arv == 0) {
1323                 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1324                 /*NOTREACHED*/
1325         }
1326
1327         MenuList& items (fade_context_menu.items());
1328
1329         items.clear ();
1330
1331         switch (item_type) {
1332         case FadeInItem:
1333         case FadeInHandleItem:
1334                 if (arv->region.fade_in_active()) {
1335                         items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), false)));
1336                 } else {
1337                         items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), true)));
1338                 }
1339                 
1340                 items.push_back (SeparatorElem());
1341                 
1342                 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Linear)));
1343                 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogB)));
1344                 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Fast)));
1345                 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogA)));
1346                 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Slow)));
1347                 break;
1348
1349         case FadeOutItem:
1350         case FadeOutHandleItem:
1351                 if (arv->region.fade_out_active()) {
1352                         items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), false)));
1353                 } else {
1354                         items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), true)));
1355                 }
1356                 
1357                 items.push_back (SeparatorElem());
1358                 
1359                 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Linear)));
1360                 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Fast)));
1361                 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogB)));
1362                 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogA)));
1363                 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Slow)));
1364
1365                 break;
1366         default:
1367                 fatal << _("programming error: ")
1368                       << X_("non-fade canvas item passed to popup_fade_context_menu()")
1369                       << endmsg;
1370                 /*NOTREACHED*/
1371         }
1372
1373         fade_context_menu.popup (button, time);
1374 }
1375
1376 void
1377 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, jack_nframes_t frame)
1378 {
1379         using namespace Menu_Helpers;
1380         Menu* (Editor::*build_menu_function)(jack_nframes_t);
1381         Menu *menu;
1382
1383         switch (item_type) {
1384         case RegionItem:
1385         case AudioRegionViewName:
1386         case AudioRegionViewNameHighlight:
1387                 if (with_selection) {
1388                         build_menu_function = &Editor::build_track_selection_context_menu;
1389                 } else {
1390                         build_menu_function = &Editor::build_track_region_context_menu;
1391                 }
1392                 break;
1393
1394         case SelectionItem:
1395                 if (with_selection) {
1396                         build_menu_function = &Editor::build_track_selection_context_menu;
1397                 } else {
1398                         build_menu_function = &Editor::build_track_context_menu;
1399                 }
1400                 break;
1401
1402         case CrossfadeViewItem:
1403                 build_menu_function = &Editor::build_track_crossfade_context_menu;
1404                 break;
1405
1406         case StreamItem:
1407                 if (clicked_audio_trackview->get_diskstream()) {
1408                         build_menu_function = &Editor::build_track_context_menu;
1409                 } else {
1410                         build_menu_function = &Editor::build_track_bus_context_menu;
1411                 }
1412                 break;
1413
1414         default:
1415                 /* probably shouldn't happen but if it does, we don't care */
1416                 return;
1417         }
1418
1419         menu = (this->*build_menu_function)(frame);
1420         menu->set_name ("ArdourContextMenu");
1421         
1422         /* now handle specific situations */
1423
1424         switch (item_type) {
1425         case RegionItem:
1426         case AudioRegionViewName:
1427         case AudioRegionViewNameHighlight:
1428                 if (!with_selection) {
1429                         if (region_edit_menu_split_item) {
1430                                 if (clicked_regionview && clicked_regionview->region.covers (edit_cursor->current_frame)) {
1431                                         // GTK2FIX find the action, change its sensitivity
1432                                         // region_edit_menu_split_item->set_sensitive (true);
1433                                 } else {
1434                                         // GTK2FIX see above
1435                                         // region_edit_menu_split_item->set_sensitive (false);
1436                                 }
1437                         }
1438                         if (region_edit_menu_split_multichannel_item) {
1439                                 if (clicked_regionview && clicked_regionview->region.n_channels() > 1) {
1440                                         // GTK2FIX find the action, change its sensitivity
1441                                         // region_edit_menu_split_multichannel_item->set_sensitive (true);
1442                                 } else {
1443                                         // GTK2FIX see above
1444                                         // region_edit_menu_split_multichannel_item->set_sensitive (false);
1445                                 }
1446                         }
1447                 }
1448                 break;
1449
1450         case SelectionItem:
1451                 break;
1452
1453         case CrossfadeViewItem:
1454                 break;
1455
1456         case StreamItem:
1457                 break;
1458
1459         default:
1460                 /* probably shouldn't happen but if it does, we don't care */
1461                 return;
1462         }
1463
1464         if (clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1465
1466                 /* Bounce to disk */
1467                 
1468                 using namespace Menu_Helpers;
1469                 MenuList& edit_items  = menu->items();
1470                 
1471                 edit_items.push_back (SeparatorElem());
1472
1473                 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1474                 case AudioTrack::NoFreeze:
1475                         edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1476                         break;
1477
1478                 case AudioTrack::Frozen:
1479                         edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1480                         break;
1481                         
1482                 case AudioTrack::UnFrozen:
1483                         edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1484                         break;
1485                 }
1486
1487         }
1488
1489         menu->popup (button, time);
1490 }
1491
1492 Menu*
1493 Editor::build_track_context_menu (jack_nframes_t ignored)
1494 {
1495         using namespace Menu_Helpers;
1496
1497         MenuList& edit_items = track_context_menu.items();
1498         edit_items.clear();
1499
1500         add_dstream_context_items (edit_items);
1501         return &track_context_menu;
1502 }
1503
1504 Menu*
1505 Editor::build_track_bus_context_menu (jack_nframes_t ignored)
1506 {
1507         using namespace Menu_Helpers;
1508
1509         MenuList& edit_items = track_context_menu.items();
1510         edit_items.clear();
1511
1512         add_bus_context_items (edit_items);
1513         return &track_context_menu;
1514 }
1515
1516 Menu*
1517 Editor::build_track_region_context_menu (jack_nframes_t frame)
1518 {
1519         using namespace Menu_Helpers;
1520         MenuList& edit_items  = track_region_context_menu.items();
1521         edit_items.clear();
1522
1523         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1524
1525         if (atv) {
1526                 DiskStream* ds;
1527                 Playlist* pl;
1528                 
1529                 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1530                         Playlist::RegionList* regions = pl->regions_at ((jack_nframes_t) floor ( (double)frame * ds->speed()));
1531                         for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1532                                 add_region_context_items (atv->view, (*i), edit_items);
1533                         }
1534                         delete regions;
1535                 }
1536         }
1537
1538         add_dstream_context_items (edit_items);
1539
1540         return &track_region_context_menu;
1541 }
1542
1543 Menu*
1544 Editor::build_track_crossfade_context_menu (jack_nframes_t frame)
1545 {
1546         using namespace Menu_Helpers;
1547         MenuList& edit_items  = track_crossfade_context_menu.items();
1548         edit_items.clear ();
1549
1550         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1551
1552         if (atv) {
1553                 DiskStream* ds;
1554                 Playlist* pl;
1555                 AudioPlaylist* apl;
1556
1557                 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = dynamic_cast<AudioPlaylist*> (pl)) != 0)) {
1558
1559                         Playlist::RegionList* regions = pl->regions_at (frame);
1560                         AudioPlaylist::Crossfades xfades;
1561
1562                         apl->crossfades_at (frame, xfades);
1563
1564                         bool many = xfades.size() > 1;
1565
1566                         for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1567                                 add_crossfade_context_items (atv->view, (*i), edit_items, many);
1568                         }
1569
1570                         for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1571                                 add_region_context_items (atv->view, (*i), edit_items);
1572                         }
1573
1574                         delete regions;
1575                 }
1576         }
1577
1578         add_dstream_context_items (edit_items);
1579
1580         return &track_crossfade_context_menu;
1581 }
1582
1583 Menu*
1584 Editor::build_track_selection_context_menu (jack_nframes_t ignored)
1585 {
1586         using namespace Menu_Helpers;
1587         MenuList& edit_items  = track_selection_context_menu.items();
1588         edit_items.clear ();
1589
1590         add_selection_context_items (edit_items);
1591         add_dstream_context_items (edit_items);
1592
1593         return &track_selection_context_menu;
1594 }
1595
1596 void
1597 Editor::add_crossfade_context_items (StreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many)
1598 {
1599         using namespace Menu_Helpers;
1600         Menu     *xfade_menu = manage (new Menu);
1601         MenuList& items       = xfade_menu->items();
1602         xfade_menu->set_name ("ArdourContextMenu");
1603         string str;
1604
1605         if (xfade->active()) {
1606                 str = _("Mute");
1607         } else { 
1608                 str = _("Unmute");
1609         }
1610
1611         items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), xfade)));
1612         items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), xfade)));
1613
1614         if (xfade->can_follow_overlap()) {
1615
1616                 if (xfade->following_overlap()) {
1617                         str = _("Convert to short");
1618                 } else {
1619                         str = _("Convert to full");
1620                 }
1621
1622                 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1623         }
1624
1625         if (many) {
1626                 str = xfade->out().name();
1627                 str += "->";
1628                 str += xfade->in().name();
1629         } else {
1630                 str = _("Crossfade");
1631         }
1632
1633         edit_items.push_back (MenuElem (str, *xfade_menu));
1634         edit_items.push_back (SeparatorElem());
1635 }
1636
1637 void
1638 Editor::xfade_edit_left_region ()
1639 {
1640         if (clicked_crossfadeview) {
1641                 clicked_crossfadeview->left_view.show_region_editor ();
1642         }
1643 }
1644
1645 void
1646 Editor::xfade_edit_right_region ()
1647 {
1648         if (clicked_crossfadeview) {
1649                 clicked_crossfadeview->right_view.show_region_editor ();
1650         }
1651 }
1652
1653 void
1654 Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items)
1655 {
1656         using namespace Menu_Helpers;
1657         Menu     *region_menu = manage (new Menu);
1658         MenuList& items       = region_menu->items();
1659         region_menu->set_name ("ArdourContextMenu");
1660         
1661         AudioRegion* ar = 0;
1662
1663         if (region) {
1664                 ar = dynamic_cast<AudioRegion*> (region);
1665         }
1666
1667         /* when this particular menu pops up, make the relevant region 
1668            become selected.
1669         */
1670
1671         region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, region));
1672
1673         items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1674         items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1675         items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun  (*this, &Editor::lower_region_to_bottom)));
1676         items.push_back (SeparatorElem());
1677         items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1678         items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1679         items.push_back (SeparatorElem());
1680
1681         items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
1682         items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1683         items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1684         items.push_back (SeparatorElem());
1685
1686         /* XXX hopefully this nonsense will go away with SigC++ 2.X, where the compiler
1687            might be able to figure out which overloaded member function to use in
1688            a bind() call ...
1689         */
1690
1691         void (Editor::*type_A_pmf)(void (Region::*pmf)(bool), bool) = &Editor::region_selection_op;
1692
1693         items.push_back (MenuElem (_("Lock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, true)));
1694         items.push_back (MenuElem (_("Unlock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, false)));
1695         items.push_back (SeparatorElem());
1696
1697         if (region->muted()) {
1698                 items.push_back (MenuElem (_("Unmute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, false)));
1699         } else {
1700                 items.push_back (MenuElem (_("Mute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, true)));
1701         }
1702         items.push_back (SeparatorElem());
1703
1704         items.push_back (MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1705         items.push_back (SeparatorElem());
1706
1707
1708         if (ar) {
1709
1710                 items.push_back (MenuElem (_("Toggle envelope visibility"), mem_fun(*this, &Editor::toggle_gain_envelope_visibility)));
1711                 items.push_back (MenuElem (_("Toggle envelope active"), mem_fun(*this, &Editor::toggle_gain_envelope_active)));
1712                 items.push_back (SeparatorElem());
1713
1714                 if (ar->scale_amplitude() != 1.0f) {
1715                         items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1716                 } else {
1717                         items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1718                 }
1719         }
1720         items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1721         items.push_back (SeparatorElem());
1722
1723         /* Nudge region */
1724
1725         Menu *nudge_menu = manage (new Menu());
1726         MenuList& nudge_items = nudge_menu->items();
1727         nudge_menu->set_name ("ArdourContextMenu");
1728         
1729         nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1730         nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1731         nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1732         nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1733
1734         items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1735         items.push_back (SeparatorElem());
1736
1737         Menu *trim_menu = manage (new Menu);
1738         MenuList& trim_items = trim_menu->items();
1739         trim_menu->set_name ("ArdourContextMenu");
1740         
1741         trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1742         trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1743                              
1744         items.push_back (MenuElem (_("Trim"), *trim_menu));
1745         items.push_back (SeparatorElem());
1746
1747         items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1748         region_edit_menu_split_item = &items.back();
1749
1750         items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1751         region_edit_menu_split_multichannel_item = &items.back();
1752
1753         items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1754         items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1755         items.push_back (SeparatorElem());
1756         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1757         items.push_back (SeparatorElem());
1758         items.push_back (MenuElem (_("Destroy"), mem_fun(*this, &Editor::destroy_clicked_region)));
1759
1760         /* OK, stick the region submenu at the top of the list, and then add
1761            the standard items.
1762         */
1763
1764         /* we have to hack up the region name because "_" has a special
1765            meaning for menu titles.
1766         */
1767
1768         string::size_type pos = 0;
1769         string menu_item_name = region->name();
1770
1771         while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1772                 menu_item_name.replace (pos, 1, "__");
1773                 pos += 2;
1774         }
1775         
1776         edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1777         edit_items.push_back (SeparatorElem());
1778 }
1779
1780 void
1781 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1782 {
1783         using namespace Menu_Helpers;
1784         Menu     *selection_menu = manage (new Menu);
1785         MenuList& items       = selection_menu->items();
1786         selection_menu->set_name ("ArdourContextMenu");
1787
1788         items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1789         items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
1790         items.push_back (SeparatorElem());
1791         items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::name_selection)));
1792         items.push_back (SeparatorElem());
1793         items.push_back (MenuElem (_("Create Region"), mem_fun(*this, &Editor::new_region_from_selection)));
1794         items.push_back (MenuElem (_("Separate Region"), mem_fun(*this, &Editor::separate_region_from_selection)));
1795         items.push_back (MenuElem (_("Crop Region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1796         items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1797         items.push_back (SeparatorElem());
1798         items.push_back (MenuElem (_("Duplicate"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1799         items.push_back (SeparatorElem());
1800         items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_selection)));
1801         items.push_back (SeparatorElem());
1802         items.push_back (MenuElem (_("Fill range w/Region"), mem_fun(*this, &Editor::region_fill_selection)));
1803         
1804         edit_items.push_back (MenuElem (_("Range"), *selection_menu));
1805         edit_items.push_back (SeparatorElem());
1806 }
1807
1808 void
1809 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1810 {
1811         using namespace Menu_Helpers;
1812
1813         /* Playback */
1814
1815         Menu *play_menu = manage (new Menu);
1816         MenuList& play_items = play_menu->items();
1817         play_menu->set_name ("ArdourContextMenu");
1818         
1819         play_items.push_back (MenuElem (_("Play from edit cursor")));
1820         play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1821         play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1822         play_items.push_back (SeparatorElem());
1823         play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1824         
1825         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1826
1827         /* Selection */
1828
1829         Menu *select_menu = manage (new Menu);
1830         MenuList& select_items = select_menu->items();
1831         select_menu->set_name ("ArdourContextMenu");
1832         
1833         select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
1834         select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
1835         select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1836         select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
1837         select_items.push_back (SeparatorElem());
1838         select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1839         select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1840         select_items.push_back (SeparatorElem());
1841
1842         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1843
1844         /* Cut-n-Paste */
1845
1846         Menu *cutnpaste_menu = manage (new Menu);
1847         MenuList& cutnpaste_items = cutnpaste_menu->items();
1848         cutnpaste_menu->set_name ("ArdourContextMenu");
1849         
1850         cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1851         cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1852         cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1853         cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1854
1855         cutnpaste_items.push_back (SeparatorElem());
1856
1857         cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1858         cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1859
1860         cutnpaste_items.push_back (SeparatorElem());
1861
1862         cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1863
1864         cutnpaste_items.push_back (SeparatorElem());
1865
1866         cutnpaste_items.push_back (MenuElem (_("New Region from range"), mem_fun(*this, &Editor::new_region_from_selection)));
1867         cutnpaste_items.push_back (MenuElem (_("Separate Range"), mem_fun(*this, &Editor::separate_region_from_selection)));
1868
1869         edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1870
1871         /* Adding new material */
1872         
1873         Menu *import_menu = manage (new Menu());
1874         MenuList& import_items = import_menu->items();
1875         import_menu->set_name ("ArdourContextMenu");
1876         
1877         import_items.push_back (MenuElem (_("Insert Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1878         import_items.push_back (MenuElem (_("Insert external sndfile"), bind (mem_fun(*this, &Editor::insert_sndfile), false)));
1879
1880         edit_items.push_back (MenuElem (_("Import"), *import_menu));
1881
1882         /* Nudge track */
1883
1884         Menu *nudge_menu = manage (new Menu());
1885         MenuList& nudge_items = nudge_menu->items();
1886         nudge_menu->set_name ("ArdourContextMenu");
1887         
1888         edit_items.push_back (SeparatorElem());
1889         nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1890         nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1891         nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1892         nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1893
1894         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1895 }
1896
1897 void
1898 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1899 {
1900         using namespace Menu_Helpers;
1901
1902         /* Playback */
1903
1904         Menu *play_menu = manage (new Menu);
1905         MenuList& play_items = play_menu->items();
1906         play_menu->set_name ("ArdourContextMenu");
1907         
1908         play_items.push_back (MenuElem (_("Play from edit cursor")));
1909         play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1910         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1911
1912         /* Selection */
1913
1914         Menu *select_menu = manage (new Menu);
1915         MenuList& select_items = select_menu->items();
1916         select_menu->set_name ("ArdourContextMenu");
1917         
1918         select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
1919         select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
1920         select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1921         select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
1922         select_items.push_back (SeparatorElem());
1923         select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1924         select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1925         select_items.push_back (SeparatorElem());
1926
1927         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1928
1929         /* Cut-n-Paste */
1930
1931         Menu *cutnpaste_menu = manage (new Menu);
1932         MenuList& cutnpaste_items = cutnpaste_menu->items();
1933         cutnpaste_menu->set_name ("ArdourContextMenu");
1934         
1935         cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1936         cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1937         cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1938
1939         Menu *nudge_menu = manage (new Menu());
1940         MenuList& nudge_items = nudge_menu->items();
1941         nudge_menu->set_name ("ArdourContextMenu");
1942         
1943         edit_items.push_back (SeparatorElem());
1944         nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1945         nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1946         nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1947         nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1948
1949         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1950 }
1951
1952 /* CURSOR SETTING AND MARKS AND STUFF */
1953
1954 void
1955 Editor::set_snap_to (SnapType st)
1956 {
1957         snap_type = st;
1958         vector<string> txt = internationalize (snap_type_strings);
1959         snap_type_selector.set_active_text (txt[(int)st]);
1960
1961         instant_save ();
1962
1963         switch (snap_type) {
1964         case SnapToAThirtysecondBeat:
1965         case SnapToASixteenthBeat:
1966         case SnapToAEighthBeat:
1967         case SnapToAQuarterBeat:
1968         case SnapToAThirdBeat:
1969                 update_tempo_based_rulers ();
1970         default:
1971                 /* relax */
1972                 break;
1973     }
1974 }
1975
1976 void
1977 Editor::set_snap_mode (SnapMode mode)
1978 {
1979         snap_mode = mode;
1980         vector<string> txt = internationalize (snap_mode_strings);
1981         snap_mode_selector.set_active_text (txt[(int)mode]);
1982
1983         instant_save ();
1984 }
1985
1986 void
1987 Editor::add_location_from_selection ()
1988 {
1989         if (selection->time.empty()) {
1990                 return;
1991         }
1992
1993         if (session == 0 || clicked_trackview == 0) {
1994                 return;
1995         }
1996
1997         jack_nframes_t start = selection->time[clicked_selection].start;
1998         jack_nframes_t end = selection->time[clicked_selection].end;
1999
2000         Location *location = new Location (start, end, "selection");
2001
2002         session->begin_reversible_command (_("add marker"));
2003         session->add_undo (session->locations()->get_memento());
2004         session->locations()->add (location, true);
2005         session->add_redo_no_execute (session->locations()->get_memento());
2006         session->commit_reversible_command ();
2007 }
2008
2009 void
2010 Editor::add_location_from_playhead_cursor ()
2011 {
2012         jack_nframes_t where = session->audible_frame();
2013         
2014         Location *location = new Location (where, where, "mark", Location::IsMark);
2015         session->begin_reversible_command (_("add marker"));
2016         session->add_undo (session->locations()->get_memento());
2017         session->locations()->add (location, true);
2018         session->add_redo_no_execute (session->locations()->get_memento());
2019         session->commit_reversible_command ();
2020 }
2021
2022
2023 int
2024 Editor::set_state (const XMLNode& node)
2025 {
2026         const XMLProperty* prop;
2027         XMLNode* geometry;
2028         int x, y, width, height, xoff, yoff;
2029
2030         if ((geometry = find_named_node (node, "geometry")) == 0) {
2031
2032                 width = default_width;
2033                 height = default_height;
2034                 x = 1;
2035                 y = 1;
2036                 xoff = 0;
2037                 yoff = 21;
2038
2039         } else {
2040
2041                 width = atoi(geometry->property("x_size")->value());
2042                 height = atoi(geometry->property("y_size")->value());
2043                 x = atoi(geometry->property("x_pos")->value());
2044                 y = atoi(geometry->property("y_pos")->value());
2045                 xoff = atoi(geometry->property("x_off")->value());
2046                 yoff = atoi(geometry->property("y_off")->value());
2047         }
2048
2049         set_default_size(width, height);
2050         // GTK2FIX
2051         // set_position(x, y-yoff);
2052
2053         if ((prop = node.property ("zoom-focus"))) {
2054                 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2055         }
2056
2057         if ((prop = node.property ("zoom"))) {
2058                 set_frames_per_unit (atof (prop->value()));
2059         }
2060
2061         if ((prop = node.property ("snap-to"))) {
2062                 set_snap_to ((SnapType) atoi (prop->value()));
2063         }
2064
2065         if ((prop = node.property ("snap-mode"))) {
2066                 set_snap_mode ((SnapMode) atoi (prop->value()));
2067         }
2068
2069         if ((prop = node.property ("show-waveforms"))) {
2070                 bool yn = (prop->value() == "yes");
2071                 _show_waveforms = !yn;
2072                 set_show_waveforms (yn);
2073         }
2074
2075         if ((prop = node.property ("show-waveforms-recording"))) {
2076                 bool yn = (prop->value() == "yes");
2077                 _show_waveforms_recording = !yn;
2078                 set_show_waveforms_recording (yn);
2079         }
2080         
2081         if ((prop = node.property ("show-measures"))) {
2082                 bool yn = (prop->value() == "yes");
2083                 _show_measures = !yn;
2084                 set_show_measures (yn);
2085         }
2086
2087         if ((prop = node.property ("follow-playhead"))) {
2088                 bool yn = (prop->value() == "yes");
2089                 _follow_playhead = !yn;
2090                 set_follow_playhead (yn);
2091         }
2092
2093         if ((prop = node.property ("xfades-visible"))) {
2094                 bool yn = (prop->value() == "yes");
2095                 _xfade_visibility = !yn;
2096                 set_xfade_visibility (yn);
2097         }
2098
2099         if ((prop = node.property ("region-list-sort-type"))) {
2100                 region_list_sort_type = (Editing::RegionListSortType) -1; /* force change */
2101                 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2102         }
2103
2104         if ((prop = node.property ("mouse-mode"))) {
2105                 MouseMode m = str2mousemode(prop->value());
2106                 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2107                 set_mouse_mode (m, true);
2108         } else {
2109                 mouse_mode = MouseGain; /* lie, to force the mode switch */
2110                 set_mouse_mode (MouseObject, true);
2111         }
2112
2113         if ((prop = node.property ("editor-mixer-button"))) {
2114                 editor_mixer_button.set_active(prop->value() == "yes");
2115         }
2116
2117         return 0;
2118 }
2119
2120 XMLNode&
2121 Editor::get_state ()
2122 {
2123         XMLNode* node = new XMLNode ("Editor");
2124         char buf[32];
2125
2126         if (is_realized()) {
2127                 Glib::RefPtr<Gdk::Window> win = get_window();
2128                 
2129                 int x, y, xoff, yoff, width, height;
2130                 win->get_root_origin(x, y);
2131                 win->get_position(xoff, yoff);
2132                 win->get_size(width, height);
2133                 
2134                 XMLNode* geometry = new XMLNode ("geometry");
2135                 char buf[32];
2136                 snprintf(buf, sizeof(buf), "%d", width);
2137                 geometry->add_property("x_size", string(buf));
2138                 snprintf(buf, sizeof(buf), "%d", height);
2139                 geometry->add_property("y_size", string(buf));
2140                 snprintf(buf, sizeof(buf), "%d", x);
2141                 geometry->add_property("x_pos", string(buf));
2142                 snprintf(buf, sizeof(buf), "%d", y);
2143                 geometry->add_property("y_pos", string(buf));
2144                 snprintf(buf, sizeof(buf), "%d", xoff);
2145                 geometry->add_property("x_off", string(buf));
2146                 snprintf(buf, sizeof(buf), "%d", yoff);
2147                 geometry->add_property("y_off", string(buf));
2148                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2149                 geometry->add_property("edit_pane_pos", string(buf));
2150
2151                 node->add_child_nocopy (*geometry);
2152         }
2153
2154         snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2155         node->add_property ("zoom-focus", buf);
2156         snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2157         node->add_property ("zoom", buf);
2158         snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2159         node->add_property ("snap-to", buf);
2160         snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2161         node->add_property ("snap-mode", buf);
2162
2163         node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2164         node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2165         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2166         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2167         node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2168         node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2169         node->add_property ("mouse-mode", enum2str(mouse_mode));
2170         node->add_property ("editor-mixer-button", editor_mixer_button.get_active() ? "yes" : "no");
2171         
2172         return *node;
2173 }
2174
2175
2176
2177 TimeAxisView *
2178 Editor::trackview_by_y_position (double y)
2179 {
2180         TrackViewList::iterator iter;
2181         TimeAxisView *tv;
2182
2183         for (iter = track_views.begin(); iter != track_views.end(); ++iter) {
2184
2185                 tv = *iter;
2186
2187                 if (tv->hidden()) {
2188                         continue;
2189                 }
2190
2191                 if (tv->y_position <= y && y < ((tv->y_position + tv->height + track_spacing))) {
2192                         return tv;
2193                 }
2194         }
2195
2196         return 0;
2197 }
2198
2199 void
2200 Editor::snap_to (jack_nframes_t& start, int32_t direction, bool for_mark)
2201 {
2202         Location* before = 0;
2203         Location* after = 0;
2204
2205         if (!session) {
2206                 return;
2207         }
2208
2209         const jack_nframes_t one_second = session->frame_rate();
2210         const jack_nframes_t one_minute = session->frame_rate() * 60;
2211
2212         jack_nframes_t presnap = start;
2213
2214         switch (snap_type) {
2215         case SnapToFrame:
2216                 break;
2217
2218         case SnapToCDFrame:
2219                 if (direction) {
2220                         start = (jack_nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2221                 } else {
2222                         start = (jack_nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2223                 }
2224                 break;
2225         case SnapToSMPTEFrame:
2226                 if (direction) {
2227                         start = (jack_nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2228                 } else {
2229                         start = (jack_nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) *  session->frames_per_smpte_frame());
2230                 }
2231                 break;
2232
2233         case SnapToSMPTESeconds:
2234                 if (session->smpte_offset_negative())
2235                 {
2236                         start += session->smpte_offset ();
2237                 } else {
2238                         start -= session->smpte_offset ();
2239                 }    
2240                 if (direction > 0) {
2241                         start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2242                 } else {
2243                         start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2244                 }
2245                 
2246                 if (session->smpte_offset_negative())
2247                 {
2248                         start -= session->smpte_offset ();
2249                 } else {
2250                         start += session->smpte_offset ();
2251                 }
2252                 break;
2253                 
2254         case SnapToSMPTEMinutes:
2255                 if (session->smpte_offset_negative())
2256                 {
2257                         start += session->smpte_offset ();
2258                 } else {
2259                         start -= session->smpte_offset ();
2260                 }
2261                 if (direction) {
2262                         start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2263                 } else {
2264                         start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2265                 }
2266                 if (session->smpte_offset_negative())
2267                 {
2268                         start -= session->smpte_offset ();
2269                 } else {
2270                         start += session->smpte_offset ();
2271                 }
2272                 break;
2273                 
2274         case SnapToSeconds:
2275                 if (direction) {
2276                         start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2277                 } else {
2278                         start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2279                 }
2280                 break;
2281                 
2282         case SnapToMinutes:
2283                 if (direction) {
2284                         start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2285                 } else {
2286                         start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2287                 }
2288                 break;
2289
2290         case SnapToBar:
2291                 start = session->tempo_map().round_to_bar (start, direction);
2292                 break;
2293
2294         case SnapToBeat:
2295                 start = session->tempo_map().round_to_beat (start, direction);
2296                 break;
2297
2298         case SnapToAThirtysecondBeat:
2299                 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2300                 break;
2301
2302         case SnapToASixteenthBeat:
2303                 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2304                 break;
2305
2306         case SnapToAEighthBeat:
2307                 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2308                 break;
2309
2310         case SnapToAQuarterBeat:
2311                 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2312                 break;
2313
2314         case SnapToAThirdBeat:
2315                 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2316                 break;
2317
2318         case SnapToEditCursor:
2319                 start = edit_cursor->current_frame;
2320                 break;
2321
2322         case SnapToMark:
2323                 if (for_mark) {
2324                         return;
2325                 }
2326
2327                 before = session->locations()->first_location_before (start);
2328                 after = session->locations()->first_location_after (start);
2329
2330                 if (direction < 0) {
2331                         if (before) {
2332                                 start = before->start();
2333                         } else {
2334                                 start = 0;
2335                         }
2336                 } else if (direction > 0) {
2337                         if (after) {
2338                                 start = after->start();
2339                         } else {
2340                                 start = session->current_end_frame();
2341                         }
2342                 } else {
2343                         if (before) {
2344                                 if (after) {
2345                                         /* find nearest of the two */
2346                                         if ((start - before->start()) < (after->start() - start)) {
2347                                                 start = before->start();
2348                                         } else {
2349                                                 start = after->start();
2350                                         }
2351                                 } else {
2352                                         start = before->start();
2353                                 }
2354                         } else if (after) {
2355                                 start = after->start();
2356                         } else {
2357                                 /* relax */
2358                         }
2359                 }
2360                 break;
2361
2362         case SnapToRegionStart:
2363         case SnapToRegionEnd:
2364         case SnapToRegionSync:
2365         case SnapToRegionBoundary:
2366                 if (!region_boundary_cache.empty()) {
2367                         vector<jack_nframes_t>::iterator i;
2368
2369                         if (direction > 0) {
2370                                 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2371                         } else {
2372                                 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2373                         }
2374                         
2375                         if (i != region_boundary_cache.end()) {
2376                                 start = *i;
2377                         } else {
2378                                 start = region_boundary_cache.back();
2379                         }
2380                 }
2381                 break;
2382         }
2383
2384         switch (snap_mode) {
2385         case SnapNormal:
2386                 return;                 
2387                 
2388         case SnapMagnetic:
2389                 
2390                 if (presnap > start) {
2391                         if (presnap > (start + unit_to_frame(snap_threshold))) {
2392                                 start = presnap;
2393                         }
2394                         
2395                 } else if (presnap < start) {
2396                         if (presnap < (start - unit_to_frame(snap_threshold))) {
2397                                 start = presnap;
2398                         }
2399                 }
2400                 
2401         default:
2402                 return;
2403                 
2404         }
2405 }
2406
2407 void
2408 Editor::setup_toolbar ()
2409 {
2410         string pixmap_path;
2411         vector<ToggleButton *> mouse_mode_buttons;
2412
2413         mouse_mode_buttons.push_back (&mouse_move_button);
2414         mouse_mode_buttons.push_back (&mouse_select_button);
2415         mouse_mode_buttons.push_back (&mouse_gain_button);
2416         mouse_mode_buttons.push_back (&mouse_zoom_button);
2417         mouse_mode_buttons.push_back (&mouse_timefx_button);
2418         mouse_mode_buttons.push_back (&mouse_audition_button);
2419         mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2420
2421         mouse_mode_button_table.set_homogeneous (true);
2422         mouse_mode_button_table.set_col_spacings (2);
2423         mouse_mode_button_table.set_row_spacings (2);
2424         mouse_mode_button_table.set_border_width (5);
2425
2426         mouse_mode_button_table.attach (mouse_move_button, 0, 1, 0, 1);
2427         mouse_mode_button_table.attach (mouse_select_button, 1, 2, 0, 1);
2428         mouse_mode_button_table.attach (mouse_zoom_button, 2, 3, 0, 1);
2429  
2430         mouse_mode_button_table.attach (mouse_gain_button, 0, 1, 1, 2);
2431         mouse_mode_button_table.attach (mouse_timefx_button, 1, 2, 1, 2);
2432         mouse_mode_button_table.attach (mouse_audition_button, 2, 3, 1, 2);
2433
2434         mouse_mode_tearoff = manage (new TearOff (mouse_mode_button_table));
2435         mouse_mode_tearoff->set_name ("MouseModeBase");
2436
2437         mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox), 
2438                                                   mouse_mode_tearoff->tearoff_window()));
2439         mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox), 
2440                                                   mouse_mode_tearoff->tearoff_window(), 1));
2441
2442         mouse_move_button.set_name ("MouseModeButton");
2443         mouse_select_button.set_name ("MouseModeButton");
2444         mouse_gain_button.set_name ("MouseModeButton");
2445         mouse_zoom_button.set_name ("MouseModeButton");
2446         mouse_timefx_button.set_name ("MouseModeButton");
2447         mouse_audition_button.set_name ("MouseModeButton");
2448
2449         ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("select/move objects"));
2450         ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("select/move ranges"));
2451         ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("draw gain automation"));
2452         ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("select zoom range"));
2453         ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("stretch/shrink regions"));
2454         ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("listen to specific regions"));
2455
2456         mouse_move_button.unset_flags (Gtk::CAN_FOCUS);
2457         mouse_select_button.unset_flags (Gtk::CAN_FOCUS);
2458         mouse_gain_button.unset_flags (Gtk::CAN_FOCUS);
2459         mouse_zoom_button.unset_flags (Gtk::CAN_FOCUS);
2460         mouse_timefx_button.unset_flags (Gtk::CAN_FOCUS);
2461         mouse_audition_button.unset_flags (Gtk::CAN_FOCUS);
2462
2463         mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2464         mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2465
2466         mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2467         mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2468         mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2469         mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2470         mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2471
2472         // mouse_move_button.set_active (true);
2473
2474         /* automation control */
2475
2476         global_automation_button.set_name ("MouseModeButton");
2477         automation_mode_button.set_name ("MouseModeButton");
2478
2479         automation_box.set_spacing (2);
2480         automation_box.set_border_width (2);
2481         automation_box.pack_start (global_automation_button, false, false);
2482         automation_box.pack_start (automation_mode_button, false, false);
2483
2484         /* Edit mode */
2485
2486         edit_mode_label.set_name ("ToolBarLabel");
2487
2488         edit_mode_selector.set_name ("EditModeSelector");
2489
2490         edit_mode_box.set_spacing (3);
2491         edit_mode_box.set_border_width (3);
2492
2493         /* XXX another disgusting hack because of the way combo boxes size themselves */
2494
2495         Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "EdgtMode", 2, 10);
2496         set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings));
2497         edit_mode_box.pack_start (edit_mode_label, false, false);
2498         edit_mode_box.pack_start (edit_mode_selector, false, false);
2499
2500         edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2501
2502         /* Snap Type */
2503
2504         snap_type_label.set_name ("ToolBarLabel");
2505
2506         snap_type_selector.set_name ("SnapTypeSelector");
2507
2508         snap_type_box.set_spacing (3);
2509         snap_type_box.set_border_width (3);
2510
2511         /* XXX another disgusting hack because of the way combo boxes size themselves */
2512
2513         const guint32 FUDGE = 10; // Combo's are stupid - they steal space from the entry for the button
2514         Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "Region bounds", 2+FUDGE, 10);
2515         set_popdown_strings (snap_type_selector, internationalize (snap_type_strings));
2516
2517         snap_type_box.pack_start (snap_type_label, false, false);
2518         snap_type_box.pack_start (snap_type_selector, false, false);
2519
2520         snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2521
2522         /* Snap mode, not snap type */
2523
2524         snap_mode_label.set_name ("ToolBarLabel");
2525
2526         snap_mode_selector.set_name ("SnapModeSelector");
2527         
2528         snap_mode_box.set_spacing (3);
2529         snap_mode_box.set_border_width (3);
2530
2531         Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "SngpMode", 2, 10);
2532         set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings));
2533
2534         snap_mode_box.pack_start (snap_mode_label, false, false);
2535         snap_mode_box.pack_start (snap_mode_selector, false, false);
2536
2537         snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2538
2539         /* Zoom focus mode */
2540
2541         zoom_focus_label.set_name ("ToolBarLabel");
2542
2543         zoom_focus_selector.set_name ("ZoomFocusSelector");
2544
2545         zoom_focus_box.set_spacing (3);
2546         zoom_focus_box.set_border_width (3);
2547
2548         /* XXX another disgusting hack because of the way combo boxes size themselves */
2549
2550         Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edgt Cursor", 2, 10);
2551         set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings));
2552
2553         zoom_focus_box.pack_start (zoom_focus_label, false, false);
2554         zoom_focus_box.pack_start (zoom_focus_selector, false, false);
2555
2556         zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2557
2558         /* selection/cursor clocks */
2559
2560         toolbar_selection_cursor_label.set_name ("ToolBarLabel");
2561         selection_start_clock_label.set_name ("ToolBarLabel");
2562         selection_end_clock_label.set_name ("ToolBarLabel");
2563         edit_cursor_clock_label.set_name ("ToolBarLabel");
2564
2565         selection_start_clock_label.set_text (_("Start:"));
2566         selection_end_clock_label.set_text (_("End:"));
2567         edit_cursor_clock_label.set_text (_("Edit:"));
2568
2569         toolbar_selection_clock_table.set_border_width (5);
2570         toolbar_selection_clock_table.set_col_spacings (2);
2571         toolbar_selection_clock_table.set_homogeneous (false);
2572
2573 //      toolbar_selection_clock_table.attach (selection_start_clock_label, 0, 1, 0, 1, 0, 0, 0, 0);
2574 //      toolbar_selection_clock_table.attach (selection_end_clock_label, 1, 2, 0, 1, 0, 0, 0, 0);
2575         toolbar_selection_clock_table.attach (edit_cursor_clock_label, 2, 3, 0, 1, FILL, FILL, 0, 0);
2576
2577 //      toolbar_selection_clock_table.attach (selection_start_clock, 0, 1, 1, 2, 0, 0);
2578 //      toolbar_selection_clock_table.attach (selection_end_clock, 1, 2, 1, 2, 0, 0);
2579         toolbar_selection_clock_table.attach (edit_cursor_clock, 2, 3, 1, 2, FILL, FILL);
2580
2581
2582 //      toolbar_clock_vbox.set_spacing (2);
2583 //      toolbar_clock_vbox.set_border_width (10);
2584         /* the editor/mixer button will be enabled at session connect */
2585
2586         editor_mixer_button.set_active(false);
2587         editor_mixer_button.set_sensitive(false);
2588
2589         HBox* hbox = new HBox;
2590
2591         hbox->pack_start (editor_mixer_button, false, false);
2592         hbox->pack_start (toolbar_selection_clock_table, false, false);
2593         hbox->pack_start (zoom_indicator_vbox, false, false); 
2594         hbox->pack_start (zoom_focus_box, false, false);
2595         hbox->pack_start (snap_type_box, false, false);
2596         hbox->pack_start (snap_mode_box, false, false);
2597         hbox->pack_start (edit_mode_box, false, false);
2598
2599         VBox *vbox = manage (new VBox);
2600
2601         vbox->set_spacing (3);
2602         vbox->set_border_width (3);
2603
2604         HBox *nbox = manage (new HBox);
2605         
2606         nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2607         nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2608
2609         nbox->pack_start (nudge_backward_button, false, false);
2610         nbox->pack_start (nudge_forward_button, false, false);
2611         nbox->pack_start (nudge_clock, false, false, 5);
2612
2613         nudge_label.set_name ("ToolBarLabel");
2614
2615         vbox->pack_start (nudge_label, false, false);
2616         vbox->pack_start (*nbox, false, false);
2617
2618         hbox->pack_start (*vbox, false, false);
2619
2620         hbox->show_all ();
2621
2622         tools_tearoff = new TearOff (*hbox);
2623         tools_tearoff->set_name ("MouseModeBase");
2624
2625         tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox), 
2626                                              tools_tearoff->tearoff_window()));
2627         tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox), 
2628                                              tools_tearoff->tearoff_window(), 0));
2629
2630
2631         toolbar_hbox.set_spacing (8);
2632         toolbar_hbox.set_border_width (2);
2633
2634         toolbar_hbox.pack_start (*tools_tearoff, false, false);
2635         toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2636         
2637         toolbar_base.set_name ("ToolBarBase");
2638         toolbar_base.add (toolbar_hbox);
2639
2640         toolbar_frame.set_shadow_type (Gtk::SHADOW_OUT);
2641         toolbar_frame.set_name ("BaseFrame");
2642         toolbar_frame.add (toolbar_base);
2643 }
2644
2645 gint
2646 Editor::_autoscroll_canvas (void *arg)
2647 {
2648         return ((Editor *) arg)->autoscroll_canvas ();
2649 }
2650
2651 gint
2652 Editor::autoscroll_canvas ()
2653 {
2654         jack_nframes_t new_frame;
2655         bool keep_calling = true;
2656
2657         if (autoscroll_direction < 0) {
2658                 if (leftmost_frame < autoscroll_distance) {
2659                         new_frame = 0;
2660                 } else {
2661                         new_frame = leftmost_frame - autoscroll_distance;
2662                 }
2663         } else {
2664                 if (leftmost_frame > max_frames - autoscroll_distance) {
2665                         new_frame = max_frames;
2666                 } else {
2667                         new_frame = leftmost_frame + autoscroll_distance;
2668                 }
2669         }
2670
2671         if (new_frame != leftmost_frame) {
2672                 reposition_x_origin (new_frame);
2673         }
2674
2675         if (new_frame == 0 || new_frame == max_frames) {
2676                 /* we are done */
2677                 return FALSE;
2678         }
2679
2680         autoscroll_cnt++;
2681
2682         if (autoscroll_cnt == 1) {
2683
2684                 /* connect the timeout so that we get called repeatedly */
2685                 
2686                 autoscroll_timeout_tag = gtk_timeout_add (100, _autoscroll_canvas, this);
2687                 keep_calling = false;
2688
2689         } else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) {
2690                 
2691                 /* after about a while, speed up a bit by changing the timeout interval */
2692
2693                 autoscroll_timeout_tag = gtk_timeout_add (50, _autoscroll_canvas, this);
2694                 keep_calling = false;
2695                 
2696         } else if (autoscroll_cnt >= 20 && autoscroll_cnt < 30) {
2697
2698                 /* after about another while, speed up some more */
2699
2700                 autoscroll_timeout_tag = gtk_timeout_add (25, _autoscroll_canvas, this);
2701                 keep_calling = false;
2702
2703         } else if (autoscroll_cnt >= 30) {
2704
2705                 /* we've been scrolling for a while ... crank it up */
2706
2707                 autoscroll_distance = 10 * (jack_nframes_t) floor (canvas_width * frames_per_unit);
2708         }
2709
2710         return keep_calling;
2711 }
2712
2713 void
2714 Editor::start_canvas_autoscroll (int dir)
2715 {
2716         if (!session) {
2717                 return;
2718         }
2719
2720         stop_canvas_autoscroll ();
2721
2722         autoscroll_direction = dir;
2723         autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/10.0);
2724         autoscroll_cnt = 0;
2725         
2726         /* do it right now, which will start the repeated callbacks */
2727         
2728         autoscroll_canvas ();
2729 }
2730
2731 void
2732 Editor::stop_canvas_autoscroll ()
2733 {
2734         if (autoscroll_timeout_tag >= 0) {
2735                 gtk_timeout_remove (autoscroll_timeout_tag);
2736                 autoscroll_timeout_tag = -1;
2737         }
2738 }
2739
2740 int
2741 Editor::convert_drop_to_paths (vector<string>& paths, 
2742                                GdkDragContext     *context,
2743                                gint                x,
2744                                gint                y,
2745                                GtkSelectionData   *data,
2746                                guint               info,
2747                                guint               time)                               
2748
2749 {       
2750         string spath;
2751         char *path;
2752         int state;
2753         gchar *tname = gdk_atom_name (data->type);
2754
2755         if (session == 0 || strcmp (tname, "text/plain") != 0) {
2756                 return -1;
2757         }
2758
2759         /* Parse the "uri-list" format that Nautilus provides, 
2760            where each pathname is delimited by \r\n
2761         */
2762
2763         path = (char *) data->data;
2764         state = 0;
2765
2766         for (int n = 0; n < data->length; ++n) {
2767
2768                 switch (state) {
2769                 case 0:
2770                         if (path[n] == '\r') {
2771                                 state = 1;
2772                         } else {
2773                                 spath += path[n];
2774                         }
2775                         break;
2776                 case 1:
2777                         if (path[n] == '\n') {
2778                                 paths.push_back (spath);
2779                                 spath = "";
2780                                 state = 0;
2781                         } else {
2782                                 warning << _("incorrectly formatted URI list, ignored")
2783                                         << endmsg;
2784                                 return -1;
2785                         }
2786                         break;
2787                 }
2788         }
2789
2790         /* nautilus and presumably some other file managers prefix even text/plain with file:// */
2791                 
2792         for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
2793
2794                 // cerr << "dropped text was " << *p << endl;
2795
2796                 url_decode (*p);
2797
2798                 // cerr << "decoded was " << *p << endl;
2799
2800                 if ((*p).substr (0,7) == "file://") {
2801                         (*p) = (*p).substr (7);
2802                 }
2803         }
2804         
2805         return 0;
2806 }
2807
2808 void  
2809 Editor::track_canvas_drag_data_received  (GdkDragContext     *context,
2810                                           gint                x,
2811                                           gint                y,
2812                                           GtkSelectionData   *data,
2813                                           guint               info,
2814                                           guint               time)
2815 {
2816         TimeAxisView* tvp;
2817         AudioTimeAxisView* tv;
2818         double cy;
2819         vector<string> paths;
2820         string spath;
2821         GdkEvent ev;
2822         jack_nframes_t frame;
2823
2824         if (convert_drop_to_paths (paths, context, x, y, data, info, time)) {
2825                 goto out;
2826         }
2827
2828         /* D-n-D coordinates are window-relative, so convert to "world" coordinates
2829          */
2830
2831         double wx;
2832         double wy;
2833
2834         track_canvas.c2w( x, y, wx, wy);
2835
2836         ev.type = GDK_BUTTON_RELEASE;
2837         ev.button.x = wx;
2838         ev.button.y = wy;
2839
2840         frame = event_frame (&ev, 0, &cy);
2841
2842         snap_to (frame);
2843
2844         if ((tvp = trackview_by_y_position (cy)) == 0) {
2845
2846                 /* drop onto canvas background: create a new track */
2847
2848                 insert_paths_as_new_tracks (paths, false);
2849
2850                 
2851         } else if ((tv = dynamic_cast<AudioTimeAxisView*>(tvp)) != 0) {
2852
2853                 /* check that its an audio track, not a bus */
2854
2855                 if (tv->get_diskstream()) {
2856
2857                         for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
2858                                 insert_sndfile_into (*p, true, tv, frame);
2859                         }
2860                 }
2861
2862         }
2863
2864   out:
2865         gtk_drag_finish (context, TRUE, FALSE, time);
2866 }
2867
2868 void
2869 Editor::new_tempo_section ()
2870
2871 {
2872 }
2873
2874 void
2875 Editor::map_transport_state ()
2876 {
2877         ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2878
2879         if (session->transport_stopped()) {
2880                 have_pending_keyboard_selection = false;
2881         }
2882 }
2883
2884 /* UNDO/REDO */
2885
2886 Editor::State::State ()
2887 {
2888         selection = new Selection;
2889 }
2890
2891 Editor::State::~State ()
2892 {
2893         delete selection;
2894 }
2895
2896 UndoAction
2897 Editor::get_memento () const
2898 {
2899         State *state = new State;
2900
2901         store_state (*state);
2902         return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2903 }
2904
2905 void
2906 Editor::store_state (State& state) const
2907 {
2908         *state.selection = *selection;
2909 }
2910
2911 void
2912 Editor::restore_state (State *state)
2913 {
2914         if (*selection == *state->selection) {
2915                 return;
2916         }
2917
2918         *selection = *state->selection;
2919         time_selection_changed ();
2920         region_selection_changed ();
2921
2922         /* XXX other selection change handlers? */
2923 }
2924
2925 void
2926 Editor::begin_reversible_command (string name)
2927 {
2928         if (session) {
2929                 UndoAction ua = get_memento();
2930                 session->begin_reversible_command (name, &ua);
2931         }
2932 }
2933
2934 void
2935 Editor::commit_reversible_command ()
2936 {
2937         if (session) {
2938                 UndoAction ua = get_memento();
2939                 session->commit_reversible_command (&ua);
2940         }
2941 }
2942
2943 void
2944 Editor::flush_track_canvas ()
2945 {
2946         /* I don't think this is necessary, and only causes more problems.
2947            I'm commenting it out
2948            and if the imageframe folks don't have any issues, we can take
2949            out this method entirely
2950         */
2951         
2952         //gnome_canvas_update_now (GNOME_CANVAS(track_canvas));
2953         //gtk_main_iteration ();
2954 }
2955
2956 void
2957 Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove)
2958 {
2959         if (!clicked_trackview) {
2960                 return;
2961         }
2962
2963         if (with_undo) {
2964                 begin_reversible_command (_("set selected trackview"));
2965         }
2966
2967         if (add) {
2968                 
2969                 if (selection->selected (clicked_trackview)) {
2970                         if (!no_remove) {
2971                                 selection->remove (clicked_trackview);
2972                         }
2973                 } else {
2974                         selection->add (clicked_trackview);
2975                 }
2976                 
2977         } else {
2978
2979                 if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) {
2980                         /* no commit necessary */
2981                         return;
2982                 } 
2983
2984                 selection->set (clicked_trackview);
2985         }
2986         
2987         if (with_undo) {
2988                 commit_reversible_command ();
2989         }
2990 }
2991
2992 void
2993 Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no_remove)
2994 {
2995         if (!clicked_control_point) {
2996                 return;
2997         }
2998
2999         if (with_undo) {
3000                 begin_reversible_command (_("set selected control point"));
3001         }
3002
3003         if (add) {
3004                 
3005         } else {
3006
3007         }
3008         
3009         if (with_undo) {
3010                 commit_reversible_command ();
3011         }
3012 }
3013
3014 void
3015 Editor::set_selected_regionview_from_click (bool add, bool no_track_remove)
3016 {
3017         if (!clicked_regionview) {
3018                 return;
3019         }
3020
3021         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&clicked_regionview->get_time_axis_view());
3022
3023         if (!atv) {
3024                 return;
3025         }
3026
3027         RouteGroup* group = atv->route().edit_group();
3028         vector<AudioRegionView*> all_equivalent_regions;
3029         
3030         if (group && group->is_active()) {
3031
3032                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3033
3034                         AudioTimeAxisView* tatv;
3035
3036                         if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3037
3038                                 if (tatv->route().edit_group() != group) {
3039                                         continue;
3040                                 }
3041                         
3042                                 AudioPlaylist* pl;
3043                                 vector<AudioRegion*> results;
3044                                 AudioRegionView* marv;
3045                                 DiskStream* ds;
3046                                 
3047                                 if ((ds = tatv->get_diskstream()) == 0) {
3048                                         /* bus */
3049                                         continue;
3050                                 }
3051                                 
3052                                 if ((pl = ds->playlist()) != 0) {
3053                                         pl->get_equivalent_regions (clicked_regionview->region, 
3054                                                                     results);
3055                                 }
3056                                 
3057                                 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3058                                         if ((marv = tatv->view->find_view (**ir)) != 0) {
3059                                                 all_equivalent_regions.push_back (marv);
3060                                         }
3061                                 }
3062                                 
3063                         }
3064                 }
3065
3066         } else {
3067
3068                 all_equivalent_regions.push_back (clicked_regionview);
3069
3070         }
3071         
3072         begin_reversible_command (_("set selected regionview"));
3073         
3074         if (add) {
3075
3076                 if (clicked_regionview->get_selected()) {
3077                         if (group && group->is_active() && selection->audio_regions.size() > 1) {
3078                                 /* reduce selection down to just the one clicked */
3079                                 selection->set (clicked_regionview);
3080                         } else {
3081                                 selection->remove (clicked_regionview);
3082                         }
3083                 } else {
3084                         selection->add (all_equivalent_regions);
3085                 }
3086
3087                 set_selected_track_from_click (add, false, no_track_remove);
3088                 
3089         } else {
3090
3091                 // karsten wiese suggested these two lines to make
3092                 // a selected region rise to the top. but this
3093                 // leads to a mismatch between actual layering
3094                 // and visual layering. resolution required ....
3095                 //
3096                 // gnome_canvas_item_raise_to_top (clicked_regionview->get_canvas_group());
3097                 // gnome_canvas_item_raise_to_top (clicked_regionview->get_time_axis_view().canvas_display);
3098
3099                 if (clicked_regionview->get_selected()) {
3100                         /* no commit necessary: we are the one selected. */
3101                         return;
3102
3103                 } else {
3104                         
3105                         selection->set (all_equivalent_regions);
3106                         set_selected_track_from_click (add, false, false);
3107                 }
3108         }
3109
3110         commit_reversible_command () ;
3111 }
3112
3113 void
3114 Editor::set_selected_regionview_from_region_list (Region& r, bool add)
3115 {
3116         vector<AudioRegionView*> all_equivalent_regions;
3117         AudioRegion* region;
3118
3119         if ((region = dynamic_cast<AudioRegion*>(&r)) == 0) {
3120                 return;
3121         }
3122
3123         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3124                 
3125                 AudioTimeAxisView* tatv;
3126                 
3127                 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3128                         
3129                         AudioPlaylist* pl;
3130                         vector<AudioRegion*> results;
3131                         AudioRegionView* marv;
3132                         DiskStream* ds;
3133                         
3134                         if ((ds = tatv->get_diskstream()) == 0) {
3135                                 /* bus */
3136                                 continue;
3137                         }
3138
3139                         if ((pl = ds->playlist()) != 0) {
3140                                 pl->get_region_list_equivalent_regions (*region, results);
3141                         }
3142                         
3143                         for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3144                                 if ((marv = tatv->view->find_view (**ir)) != 0) {
3145                                         all_equivalent_regions.push_back (marv);
3146                                 }
3147                         }
3148                         
3149                 }
3150         }
3151         
3152         begin_reversible_command (_("set selected regions"));
3153         
3154         if (add) {
3155
3156                 selection->add (all_equivalent_regions);
3157                 
3158         } else {
3159
3160                 selection->set (all_equivalent_regions);
3161         }
3162
3163         commit_reversible_command () ;
3164 }
3165
3166 bool
3167 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r)
3168 {
3169         AudioRegionView* rv;
3170         AudioRegion* ar;
3171
3172         if ((ar = dynamic_cast<AudioRegion*> (r)) == 0) {
3173                 return TRUE;
3174         }
3175
3176         if ((rv = sv->find_view (*ar)) == 0) {
3177                 return TRUE;
3178         }
3179
3180         /* don't reset the selection if its something other than 
3181            a single other region.
3182         */
3183
3184         if (selection->audio_regions.size() > 1) {
3185                 return TRUE;
3186         }
3187         
3188         begin_reversible_command (_("set selected regions"));
3189         
3190         selection->set (rv);
3191
3192         commit_reversible_command () ;
3193
3194         return TRUE;
3195 }
3196
3197 void
3198 Editor::set_edit_group_solo (Route& route, bool yn)
3199 {
3200         RouteGroup *edit_group;
3201
3202         if ((edit_group = route.edit_group()) != 0) {
3203                 edit_group->apply (&Route::set_solo, yn, this);
3204         } else {
3205                 route.set_solo (yn, this);
3206         }
3207 }
3208
3209 void
3210 Editor::set_edit_group_mute (Route& route, bool yn)
3211 {
3212         RouteGroup *edit_group = 0;
3213
3214         if ((edit_group == route.edit_group()) != 0) {
3215                 edit_group->apply (&Route::set_mute, yn, this);
3216         } else {
3217                 route.set_mute (yn, this);
3218         }
3219 }
3220                 
3221 void
3222 Editor::set_edit_menu (Menu& menu)
3223 {
3224         edit_menu = &menu;
3225         edit_menu->signal_map_event().connect (mem_fun(*this, &Editor::edit_menu_map_handler));
3226 }
3227
3228 bool
3229 Editor::edit_menu_map_handler (GdkEventAny* ev)
3230 {
3231         using namespace Menu_Helpers;
3232         MenuList& edit_items = edit_menu->items();
3233         string label;
3234
3235         /* Nuke all the old items */
3236                 
3237         edit_items.clear ();
3238
3239         if (session == 0) {
3240                 return false;
3241         }
3242
3243         if (session->undo_depth() == 0) {
3244                 label = _("Undo");
3245         } else {
3246                 label = string_compose(_("Undo (%1)"), session->next_undo());
3247         }
3248         
3249         edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::undo), 1U)));
3250         
3251         if (session->undo_depth() == 0) {
3252                 edit_items.back().set_sensitive (false);
3253         }
3254         
3255         if (session->redo_depth() == 0) {
3256                 label = _("Redo");
3257         } else {
3258                 label = string_compose(_("Redo (%1)"), session->next_redo());
3259         }
3260         
3261         edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::redo), 1U)));
3262         if (session->redo_depth() == 0) {
3263                 edit_items.back().set_sensitive (false);
3264         }
3265
3266         vector<MenuItem*> mitems;
3267
3268         edit_items.push_back (SeparatorElem());
3269         edit_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
3270         mitems.push_back (&edit_items.back());
3271         edit_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
3272         mitems.push_back (&edit_items.back());
3273         edit_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
3274         mitems.push_back (&edit_items.back());
3275         edit_items.push_back (SeparatorElem());
3276         edit_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
3277         mitems.push_back (&edit_items.back());
3278         edit_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
3279         mitems.push_back (&edit_items.back());
3280         edit_items.push_back (SeparatorElem());
3281
3282         if (selection->empty()) {
3283                 for (vector<MenuItem*>::iterator i = mitems.begin(); i != mitems.end(); ++i) {
3284                         (*i)->set_sensitive (false);
3285                 }
3286         }
3287
3288         Menu* import_menu = manage (new Menu());
3289         import_menu->set_name ("ArdourContextMenu");
3290         MenuList& import_items = import_menu->items();
3291         
3292         import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::import_audio), true)));
3293         import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::import_audio), false)));
3294
3295         Menu* embed_menu = manage (new Menu());
3296         embed_menu->set_name ("ArdourContextMenu");
3297         MenuList& embed_items = embed_menu->items();
3298
3299         embed_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::insert_sndfile), true)));
3300         embed_items.push_back (MenuElem (_("... as new region"), mem_fun(*this, &Editor::embed_audio)));
3301
3302         edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu));
3303         edit_items.push_back (MenuElem (_("Embed audio (link)"), *embed_menu));
3304         edit_items.push_back (SeparatorElem());
3305
3306         edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture)));
3307         if (!session->have_captured()) {
3308                 edit_items.back().set_sensitive (false);
3309         }
3310
3311         return false;
3312 }
3313
3314 void
3315 Editor::duplicate_dialog (bool dup_region)
3316 {
3317         if (dup_region) {
3318                 if (clicked_regionview == 0) {
3319                         return;
3320                 }
3321         } else {
3322                 if (selection->time.length() == 0) {
3323                         return;
3324                 }
3325         }
3326
3327         ArdourDialog win ("duplicate dialog");
3328         Entry  entry;
3329         Label  label (_("Duplicate how many times?"));
3330
3331         win.get_vbox()->pack_start (label);
3332         win.add_action_widget (entry, RESPONSE_ACCEPT);
3333         win.add_button (Stock::OK, RESPONSE_ACCEPT);
3334         win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3335
3336         win.set_position (Gtk::WIN_POS_MOUSE);
3337
3338         entry.set_text ("1");
3339         set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15);
3340         entry.select_region (0, entry.get_text_length());
3341         entry.grab_focus ();
3342
3343         // GTK2FIX
3344         // win.get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
3345
3346
3347         switch (win.run ()) {
3348         case RESPONSE_ACCEPT:
3349                 break;
3350         default:
3351                 return;
3352         }
3353
3354         string text = entry.get_text();
3355         float times;
3356
3357         if (sscanf (text.c_str(), "%f", &times) == 1) {
3358                 if (dup_region) {
3359                         AudioRegionSelection regions;
3360                         regions.add (clicked_regionview);
3361                         duplicate_some_regions (regions, times);
3362                 } else {
3363                         duplicate_selection (times);
3364                 }
3365         }
3366 }
3367
3368 void
3369 Editor::show_verbose_canvas_cursor ()
3370 {
3371         verbose_canvas_cursor->raise_to_top();
3372         verbose_canvas_cursor->show();
3373         verbose_cursor_visible = true;
3374 }
3375
3376 void
3377 Editor::hide_verbose_canvas_cursor ()
3378 {
3379         verbose_canvas_cursor->hide();
3380         verbose_cursor_visible = false;
3381 }
3382
3383 void
3384 Editor::set_verbose_canvas_cursor (string txt, double x, double y)
3385 {
3386         /* XXX get origin of canvas relative to root window,
3387            add x and y and check compared to gdk_screen_{width,height}
3388         */
3389         verbose_canvas_cursor->property_text() = txt.c_str();
3390         verbose_canvas_cursor->property_x() = x;
3391         verbose_canvas_cursor->property_y() = y;
3392 }
3393
3394 void
3395 Editor::set_verbose_canvas_cursor_text (string txt)
3396 {
3397         verbose_canvas_cursor->property_text() = txt.c_str();
3398 }
3399
3400 void
3401 Editor::edit_mode_selection_done ()
3402 {
3403         if (session == 0) {
3404                 return;
3405         }
3406
3407         string choice = edit_mode_selector.get_active_text();
3408         EditMode mode = Slide;
3409
3410         if (choice == _("Splice")) {
3411                 mode = Splice;
3412         } else if (choice == _("Slide")) {
3413                 mode = Slide;
3414         }
3415
3416         session->set_edit_mode (mode);
3417 }       
3418
3419 void
3420 Editor::snap_type_selection_done ()
3421 {
3422         if (session == 0) {
3423                 return;
3424         }
3425
3426         string choice = snap_type_selector.get_active_text();
3427         SnapType snaptype = SnapToFrame;
3428         
3429         if (choice == _("Beats/3")) {
3430                 snaptype = SnapToAThirdBeat;
3431         } else if (choice == _("Beats/4")) {
3432                 snaptype = SnapToAQuarterBeat;
3433         } else if (choice == _("Beats/8")) {
3434                 snaptype = SnapToAEighthBeat;
3435         } else if (choice == _("Beats/16")) {
3436                 snaptype = SnapToASixteenthBeat;
3437         } else if (choice == _("Beats/32")) {
3438                 snaptype = SnapToAThirtysecondBeat;
3439         } else if (choice == _("Beats")) {
3440                 snaptype = SnapToBeat;
3441         } else if (choice == _("Bars")) {
3442                 snaptype = SnapToBar;
3443         } else if (choice == _("Marks")) {
3444                 snaptype = SnapToMark;
3445         } else if (choice == _("Edit Cursor")) {
3446                 snaptype = SnapToEditCursor;
3447         } else if (choice == _("Region starts")) {
3448                 snaptype = SnapToRegionStart;
3449         } else if (choice == _("Region ends")) {
3450                 snaptype = SnapToRegionEnd;
3451         } else if (choice == _("Region bounds")) {
3452                 snaptype = SnapToRegionBoundary;
3453         } else if (choice == _("Region syncs")) {
3454                 snaptype = SnapToRegionSync;
3455         } else if (choice == _("CD Frames")) {
3456                 snaptype = SnapToCDFrame;
3457         } else if (choice == _("SMPTE Frames")) {
3458                 snaptype = SnapToSMPTEFrame;
3459         } else if (choice == _("SMPTE Seconds")) {
3460                 snaptype = SnapToSMPTESeconds;
3461         } else if (choice == _("SMPTE Minutes")) {
3462                 snaptype = SnapToSMPTEMinutes;
3463         } else if (choice == _("Seconds")) {
3464                 snaptype = SnapToSeconds;
3465         } else if (choice == _("Minutes")) {
3466                 snaptype = SnapToMinutes;
3467         } else if (choice == _("None")) {
3468                 snaptype = SnapToFrame;
3469         }
3470         
3471         set_snap_to (snaptype);
3472 }       
3473
3474 void
3475 Editor::snap_mode_selection_done ()
3476 {
3477         if(session == 0) {
3478                 return;
3479         }
3480
3481         string choice = snap_mode_selector.get_active_text();
3482         SnapMode mode = SnapNormal;
3483
3484         if (choice == _("Normal")) {
3485                 mode = SnapNormal;
3486         } else if (choice == _("Magnetic")) {
3487                 mode = SnapMagnetic;
3488         }
3489
3490         set_snap_mode (mode);
3491 }
3492
3493 void
3494 Editor::zoom_focus_selection_done ()
3495 {
3496         if (session == 0) {
3497                 return;
3498         }
3499
3500         string choice = zoom_focus_selector.get_active_text();
3501         ZoomFocus focus_type = ZoomFocusLeft;
3502
3503         if (choice == _("Left")) {
3504                 focus_type = ZoomFocusLeft;
3505         } else if (choice == _("Right")) {
3506                 focus_type = ZoomFocusRight;
3507         } else if (choice == _("Center")) {
3508                 focus_type = ZoomFocusCenter;
3509         } else if (choice == _("Playhead")) {
3510                 focus_type = ZoomFocusPlayhead;
3511         } else if (choice == _("Edit Cursor")) {
3512                 focus_type = ZoomFocusEdit;
3513         } 
3514
3515         set_zoom_focus (focus_type);
3516 }       
3517
3518 gint
3519 Editor::edit_controls_button_release (GdkEventButton* ev)
3520 {
3521         if (Keyboard::is_context_menu_event (ev)) {
3522                 ARDOUR_UI::instance()->add_route ();
3523         }
3524         return TRUE;
3525 }
3526
3527 void
3528 Editor::track_selection_changed ()
3529 {
3530         switch (selection->tracks.size()){
3531         case 0:
3532                 break;
3533         default:
3534                 set_selected_mixer_strip (*(selection->tracks.front()));
3535                 break;
3536         }
3537
3538         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3539                 (*i)->set_selected (false);
3540                 if (mouse_mode == MouseRange) {
3541                         (*i)->hide_selection ();
3542                 }
3543         }
3544
3545         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3546                 (*i)->set_selected (true);
3547                 if (mouse_mode == MouseRange) {
3548                         (*i)->show_selection (selection->time);
3549                 }
3550         }
3551 }
3552
3553 void
3554 Editor::time_selection_changed ()
3555 {
3556         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3557                 (*i)->hide_selection ();
3558         }
3559
3560         if (selection->tracks.empty()) {
3561                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3562                         (*i)->show_selection (selection->time);
3563                 }
3564         } else {
3565                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3566                         (*i)->show_selection (selection->time);
3567                 }
3568         }
3569 }
3570
3571 void
3572 Editor::region_selection_changed ()
3573 {
3574         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3575                 (*i)->set_selected_regionviews (selection->audio_regions);
3576         }
3577 }
3578
3579 void
3580 Editor::point_selection_changed ()
3581 {
3582         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3583                 (*i)->set_selected_points (selection->points);
3584         }
3585 }
3586
3587 void
3588 Editor::run_sub_event_loop ()
3589 {
3590         sub_event_loop_status = 0;
3591         Main::run ();
3592 }
3593
3594 void
3595 Editor::finish_sub_event_loop (int status)
3596 {
3597         Main::quit ();
3598         sub_event_loop_status = status;
3599 }
3600
3601 gint
3602 Editor::finish_sub_event_loop_on_delete (GdkEventAny *ignored, int32_t status)
3603 {
3604         finish_sub_event_loop (status);
3605         return TRUE;
3606 }
3607
3608 gint
3609 Editor::mouse_select_button_release (GdkEventButton* ev)
3610 {
3611         /* this handles just right-clicks */
3612
3613         if (ev->button != 3) {
3614                 return FALSE;
3615         }
3616
3617         return TRUE;
3618 }
3619
3620 Editor::TrackViewList *
3621 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3622 {
3623         TrackViewList *v;
3624         TrackViewList::iterator i;
3625
3626         v = new TrackViewList;
3627
3628         if (track == 0 && group == 0) {
3629
3630                 /* all views */
3631
3632                 for (i = track_views.begin(); i != track_views.end (); ++i) {
3633                         v->push_back (*i);
3634                 }
3635
3636         } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3637                 
3638                 /* just the view for this track
3639                  */
3640
3641                 v->push_back (track);
3642
3643         } else {
3644                 
3645                 /* views for all tracks in the edit group */
3646                 
3647                 for (i  = track_views.begin(); i != track_views.end (); ++i) {
3648
3649                         if (group == 0 || (*i)->edit_group() == group) {
3650                                 v->push_back (*i);
3651                         }
3652                 }
3653         }
3654         
3655         return v;
3656 }
3657
3658 void
3659 Editor::set_zoom_focus (ZoomFocus f)
3660 {
3661         if (zoom_focus != f) {
3662                 zoom_focus = f;
3663                 vector<string> txt = internationalize (zoom_focus_strings);
3664                 zoom_focus_selector.set_active_text (txt[(int)f]);
3665                 ZoomFocusChanged (); /* EMIT_SIGNAL */
3666
3667                 instant_save ();
3668         }
3669 }
3670
3671 void
3672 Editor::ensure_float (Window& win)
3673 {
3674         win.set_transient_for (*this);
3675 }
3676
3677 void 
3678 Editor::pane_allocation_handler (Gtk::Allocation &alloc, Gtk::Paned* which)
3679 {
3680         /* recover or initialize pane positions. do this here rather than earlier because
3681            we don't want the positions to change the child allocations, which they seem to do.
3682          */
3683
3684         int pos;
3685         XMLProperty* prop;
3686         char buf[32];
3687         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3688         int width, height;
3689         static int32_t done[4] = { 0, 0, 0, 0 };
3690         XMLNode* geometry;
3691
3692         if ((geometry = find_named_node (*node, "geometry")) == 0) {
3693                 width = default_width;
3694                 height = default_height;
3695         } else {
3696                 width = atoi(geometry->property("x_size")->value());
3697                 height = atoi(geometry->property("y_size")->value());
3698         }
3699
3700         if (which == static_cast<Gtk::Paned*> (&edit_pane)) {
3701
3702                 if (done[0]) {
3703                         return;
3704                 }
3705
3706                 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3707                         pos = 75;
3708                         snprintf (buf, sizeof(buf), "%d", pos);
3709                 } else {
3710                         pos = atoi (prop->value());
3711                 }
3712
3713                 if ((done[0] = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3714                         edit_pane.set_position (pos);
3715                 }
3716         }
3717 }
3718
3719 void
3720 Editor::detach_tearoff (Gtk::Box* b, Gtk::Window* w)
3721 {
3722         if (tools_tearoff->torn_off() && 
3723             mouse_mode_tearoff->torn_off()) {
3724                 top_hbox.remove (toolbar_frame);
3725         }
3726         
3727         ensure_float (*w);
3728 }
3729
3730 void
3731 Editor::reattach_tearoff (Gtk::Box* b, Gtk::Window* w, int32_t n)
3732 {
3733         if (toolbar_frame.get_parent() == 0) {
3734                 top_hbox.pack_end (toolbar_frame);
3735         }
3736 }
3737
3738 void
3739 Editor::set_show_measures (bool yn)
3740 {
3741         if (_show_measures != yn) {
3742                 hide_measures ();
3743
3744                 if ((_show_measures = yn) == true) {
3745                         draw_measures ();
3746                 }
3747                 DisplayControlChanged (ShowMeasures);
3748                 instant_save ();
3749         }
3750 }
3751
3752 void
3753 Editor::set_follow_playhead (bool yn)
3754 {
3755         if (_follow_playhead != yn) {
3756                 if ((_follow_playhead = yn) == true) {
3757                         /* catch up */
3758                         update_current_screen ();
3759                 }
3760                 DisplayControlChanged (FollowPlayhead);
3761                 instant_save ();
3762         }
3763 }
3764
3765 void
3766 Editor::toggle_xfade_active (Crossfade* xfade)
3767 {
3768         xfade->set_active (!xfade->active());
3769 }
3770
3771 void
3772 Editor::toggle_xfade_length (Crossfade* xfade)
3773 {
3774         xfade->set_follow_overlap (!xfade->following_overlap());
3775 }
3776
3777 void
3778 Editor::edit_xfade (Crossfade* xfade)
3779 {
3780         CrossfadeEditor cew (*session, *xfade, xfade->fade_in().get_min_y(), 1.0);
3781                 
3782         ensure_float (cew);
3783         
3784         // GTK2FIX
3785         // cew.signal_delete_event().connect (mem_fun (cew, &ArdourDialog::wm_doi_event_stop));
3786
3787         switch (cew.run ()) {
3788         case RESPONSE_ACCEPT:
3789                 break;
3790         default:
3791                 return;
3792         }
3793         
3794         cew.apply ();
3795         xfade->StateChanged (Change (~0));
3796 }
3797
3798 PlaylistSelector&
3799 Editor::playlist_selector () const
3800 {
3801         return *_playlist_selector;
3802 }
3803
3804 jack_nframes_t
3805 Editor::get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next)
3806 {
3807         jack_nframes_t ret;
3808
3809         ret = nudge_clock.current_duration (pos);
3810         next = ret + 1; /* XXXX fix me */
3811
3812         return ret;
3813 }
3814
3815 void
3816 Editor::end_location_changed (Location* location)
3817 {
3818         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3819         track_canvas_scroller.get_hadjustment()->set_upper (location->end() / frames_per_unit);
3820 }
3821
3822 int
3823 Editor::playlist_deletion_dialog (Playlist* pl)
3824 {
3825         ArdourDialog dialog ("playlist deletion dialog");
3826         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
3827                                  "If left alone, no audio files used by it will be cleaned.\n"
3828                                  "If deleted, audio files used by it alone by will cleaned."),
3829                                pl->name()));
3830
3831         dialog.set_position (Gtk::WIN_POS_CENTER);
3832         dialog.get_vbox()->pack_start (label);
3833
3834         dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3835         dialog.add_button (_("Keep playlist"), RESPONSE_CANCEL);
3836         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3837
3838         switch (dialog.run ()) {
3839         case RESPONSE_ACCEPT:
3840                 /* delete the playlist */
3841                 return 0;
3842                 break;
3843
3844         case RESPONSE_REJECT:
3845                 /* keep the playlist */
3846                 return 1;
3847                 break;
3848
3849         default:
3850                 break;
3851         }
3852
3853         return -1;
3854 }
3855
3856 bool
3857 Editor::audio_region_selection_covers (jack_nframes_t where)
3858 {
3859         for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) {
3860                 if ((*a)->region.covers (where)) {
3861                         return true;
3862                 }
3863         }
3864
3865         return false;
3866 }
3867
3868 void
3869 Editor::prepare_for_cleanup ()
3870 {
3871         cut_buffer->clear_audio_regions ();
3872         cut_buffer->clear_playlists ();
3873
3874         selection->clear_audio_regions ();
3875         selection->clear_playlists ();
3876 }
3877
3878 void
3879 Editor::init_colormap ()
3880 {
3881         for (size_t x = 0; x < sizeof (color_id_strs) / sizeof (color_id_strs[0]); ++x) {
3882                 pair<ColorID,int> newpair;
3883                 
3884                 newpair.first = (ColorID) x;
3885                 newpair.second = rgba_from_style (enum2str (newpair.first), 0, 0, 0, 255);
3886                 color_map.insert (newpair);
3887         }
3888 }
3889
3890 Location*
3891 Editor::transport_loop_location()
3892 {
3893         if (session) {
3894                 return session->locations()->auto_loop_location();
3895         } else {
3896                 return 0;
3897         }
3898 }
3899
3900 Location*
3901 Editor::transport_punch_location()
3902 {
3903         if (session) {
3904                 return session->locations()->auto_punch_location();
3905         } else {
3906                 return 0;
3907         }
3908 }