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