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