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