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