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