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