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