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