e43af5f7ccc80e30551227fe1f11872ca09164e9
[ardour.git] / gtk2_ardour / editor.cc
1 /*
2     Copyright (C) 2000 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <unistd.h>
22 #include <cstdlib>
23 #include <cmath>
24 #include <string>
25 #include <algorithm>
26
27 #include <sigc++/bind.h>
28
29 #include <libgnomecanvas/libgnomecanvas.h>
30 #include <pbd/error.h>
31
32 #include <gtkmm2ext/gtk_ui.h>
33 #include <gtkmm2ext/tearoff.h>
34 #include <gtkmm2ext/utils.h>
35
36 #include <ardour/audio_track.h>
37 #include <ardour/diskstream.h>
38 #include <ardour/plugin_manager.h>
39 #include <ardour/location.h>
40 #include <ardour/audioplaylist.h>
41 #include <ardour/audioregion.h>
42 #include <ardour/session.h>
43 #include <ardour/session_route.h>
44 #include <ardour/tempo.h>
45 #include <ardour/utils.h>
46
47 #include "ardour_ui.h"
48 #include "canvas-ruler.h"
49 #include "canvas-simpleline.h"
50 #include "canvas-simplerect.h"
51 #include "canvas-waveview.h"
52 #include "check_mark.h"
53 #include "editor.h"
54 #include "grouped_buttons.h"
55 #include "keyboard.h"
56 #include "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.signal_button_press_event().connect (mem_fun(*this, &Editor::hscroll_slider_button_press));
391         edit_hscrollbar.signal_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->signal_add_event()s (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK);
410         viewport->signal_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.signal_set_event()s (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
475         time_button_event_box.set_name ("TimebarLabelBase");
476         time_button_event_box.signal_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.signal_set_event()s (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.signal_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.signal_add_event()s (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.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
638         region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
639         region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press));
640         region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
641         region_list_display.signal_motion_notify_event().connect (mem_fun(*this, &Editor::region_list_display_motion));
642         region_list_display.signal_enter_notify_event().connect (mem_fun(*this, &Editor::region_list_display_enter_notify));
643         region_list_display.signal_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.signal_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.signal_button_release_event().connect (bind (ptr_fun (pane_handler), static_cast<Paned*> (&route_group_vpane)));
690         region_selection_vpane.signal_button_release_event().connect (bind (ptr_fun (pane_handler), static_cast<Paned*> (&region_selection_vpane)));
691         canvas_region_list_pane.signal_button_release_event().connect (bind (ptr_fun (pane_handler), static_cast<Paned*> (&canvas_region_list_pane)));
692         track_list_canvas_pane.signal_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->signal_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         gnome_canvas_init ();
821
822         track_gnome_canvas = gnome_canvas_new_aa ();
823
824         /* adjust sensitivity for "picking" items */
825
826         // GNOME_CANVAS(track_gnome_canvas)->close_enough = 2;
827
828         gtk_signal_connect (GTK_OBJECT(gnome_canvas_root (GNOME_CANVAS(track_gnome_canvas))), "event",
829                             (GtkSignalFunc) Editor::_track_canvas_event, this);
830         track_canvas = wrap (track_gnome_canvas);
831         track_canvas->set_name ("EditorMainCanvas");
832
833         track_canvas->signal_add_event()s (Gdk::POINTER_MOTION_HINT_MASK);
834
835         track_canvas->signal_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 = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
849                                                      gnome_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 = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
859                                                   gnome_canvas_group_get_type(),
860                                                   "x", 0.0,
861                                                   "y", 0.0,
862                                                   NULL);
863
864         cursor_group = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
865                                                   gnome_canvas_group_get_type(),
866                                                   "x", 0.0,
867                                                   "y", 0.0,
868                                                   NULL);
869         
870         time_gnome_canvas = gnome_canvas_new_aa ();
871         time_canvas = wrap (time_gnome_canvas);
872         time_canvas->set_name ("EditorTimeCanvas");
873
874         time_canvas->signal_add_event()s (Gdk::POINTER_MOTION_HINT_MASK);
875
876         meter_group = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(time_gnome_canvas)),
877                                             gnome_canvas_group_get_type(),
878                                             "x", 0.0,
879                                             "y", 0.0,
880                                             NULL);
881         tempo_group = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(time_gnome_canvas)),
882                                             gnome_canvas_group_get_type(),
883                                             "x", 0.0,
884                                             "y", timebar_height,
885                                             NULL);
886         marker_group = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(time_gnome_canvas)),
887                                             gnome_canvas_group_get_type(),
888                                             "x", 0.0,
889                                             "y", timebar_height * 2.0,
890                                             NULL);
891         range_marker_group = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(time_gnome_canvas)),
892                                             gnome_canvas_group_get_type(),
893                                             "x", 0.0,
894                                             "y", timebar_height * 3.0,
895                                             NULL);
896         transport_marker_group = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(time_gnome_canvas)),
897                                             gnome_canvas_group_get_type(),
898                                             "x", 0.0,
899                                             "y", timebar_height * 4.0,
900                                             NULL);
901         
902         tempo_bar = gnome_canvas_item_new (GNOME_CANVAS_GROUP(tempo_group),
903                                          gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(meter_group),
912                                          gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(marker_group),
921                                           gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(range_marker_group),
930                                                 gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(transport_marker_group),
939                                                     gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(range_marker_group),
949                                                    gnome_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         gnome_canvas_item_hide (range_bar_drag_rect);
958
959         transport_bar_drag_rect = gnome_canvas_item_new (GNOME_CANVAS_GROUP(transport_marker_group),
960                                                        gnome_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         gnome_canvas_item_hide (transport_bar_drag_rect);
969
970         
971         marker_drag_line_points = gnome_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 = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
980                                                 gnome_canvas_line_get_type(),
981                                                 "width_pixels", 1,
982                                                 "fill_color_rgba", color_map[cMarkerDragLine],
983                                                 "points", marker_drag_line_points,
984                                                 NULL);
985         gnome_canvas_item_hide (marker_drag_line);
986
987         range_marker_drag_rect = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
988                                                gnome_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         gnome_canvas_item_hide (range_marker_drag_rect);
997         
998
999         transport_loop_range_rect = gnome_canvas_item_new ((GNOME_CANVAS_GROUP(time_line_group)),
1000                                                gnome_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         gnome_canvas_item_hide (transport_loop_range_rect);
1010
1011         transport_punch_range_rect = gnome_canvas_item_new ((GNOME_CANVAS_GROUP(time_line_group)),
1012                                                gnome_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         gnome_canvas_item_lower_to_bottom (transport_punch_range_rect);
1022         gnome_canvas_item_lower_to_bottom (transport_loop_range_rect); // loop on the bottom
1023         gnome_canvas_item_hide (transport_punch_range_rect);
1024
1025         transport_punchin_line = gnome_canvas_item_new ((GNOME_CANVAS_GROUP(time_line_group)),
1026                                                gnome_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         gnome_canvas_item_hide (transport_punchin_line);
1035
1036         transport_punchout_line  = gnome_canvas_item_new ((GNOME_CANVAS_GROUP(time_line_group)),
1037                                                gnome_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         gnome_canvas_item_hide (transport_punchout_line);
1046
1047
1048
1049         
1050         // used to show zoom mode active zooming
1051         zoom_rect = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
1052                                          gnome_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         gnome_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 = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
1068                                                gnome_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         gnome_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 = gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(tempo_group),
1110                                           gnome_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 = gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(meter_group),
1125                                           gnome_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 = gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(marker_group),
1140                                            gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(range_marker_group),
1147                                            gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(transport_marker_group),
1154                                            gnome_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         gnome_canvas_set_scroll_region (GNOME_CANVAS(time_gnome_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::on_realize ()
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::on_realize ();
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::on_map ()
1390 {
1391         Window::on_map ();
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 = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
1448                                                                     gnome_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                         gnome_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_gnome_canvas->allocation.height;
1524                 canvas_alloc_width = track_gnome_canvas->allocation.width;
1525         }
1526
1527         canvas_height = max (canvas_height, canvas_alloc_height);
1528
1529         gnome_canvas_set_scroll_region (GNOME_CANVAS(track_gnome_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                 gnome_canvas_item_set (marker_drag_line, "points", marker_drag_line_points, NULL);
1540         }
1541         if (range_marker_drag_rect) {
1542                 gnome_canvas_item_set (range_marker_drag_rect, "y1", 0.0, "y2", (double) canvas_height, NULL);
1543         }
1544         if (transport_loop_range_rect) {
1545                 gnome_canvas_item_set (transport_loop_range_rect, "y1", 0.0, "y2", (double) canvas_height, NULL);
1546         }
1547         if (transport_punch_range_rect) {
1548                 gnome_canvas_item_set (transport_punch_range_rect, "y1", 0.0, "y2", (double) canvas_height, NULL);
1549         }
1550         if (transport_punchin_line) {
1551                 gnome_canvas_item_set (transport_punchin_line, "y1", 0.0, "y2", (double) canvas_height, NULL);
1552         }
1553         if (transport_punchout_line) {
1554                 gnome_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                 gnome_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, GnomeCanvasItem* 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->signal_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.signal_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         set_popdown_string (edit_mode_selector, internationalize (edit_mode_strings));
3134
3135         edit_mode_box.pack_start (edit_mode_label, false, false);
3136         edit_mode_box.pack_start (edit_mode_selector, false, false);
3137
3138         edit_mode_selector.get_popwin()->signal_unmap_event().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
3139
3140         /* Snap Type */
3141
3142         snap_type_label.set_name ("ToolBarLabel");
3143
3144         snap_type_selector.set_name ("SnapTypeSelector");
3145         snap_type_selector.get_entry()->set_name ("SnapTypeSelector");
3146         snap_type_selector.get_popwin()->set_name ("SnapTypeSelector");
3147
3148         snap_type_box.set_spacing (3);
3149         snap_type_box.set_border_width (3);
3150
3151         /* XXX another disgusting hack because of the way combo boxes size themselves */
3152
3153         const guint32 FUDGE = 10; // Combo's are stupid - they steal space from the entry for the button
3154         Gtkmm2ext::set_size_request_to_display_given_text (*snap_type_selector.get_entry(), "Region bounds", 2+FUDGE, 10);
3155         set_popdown_strings (snap_type_selector, internationalize (snap_type_strings));
3156
3157         snap_type_box.pack_start (snap_type_label, false, false);
3158         snap_type_box.pack_start (snap_type_selector, false, false);
3159
3160         snap_type_selector.get_popwin()->signal_unmap_event().connect (mem_fun(*this, &Editor::snap_type_selection_done));
3161
3162         /* Snap mode, not snap type */
3163
3164         snap_mode_label.set_name ("ToolBarLabel");
3165
3166         snap_mode_selector.set_name ("SnapModeSelector");
3167         snap_mode_selector.get_entry()->set_name ("SnapModeSelector");
3168         snap_mode_selector.get_popwin()->set_name ("SnapModeSelector");
3169         
3170         snap_mode_box.set_spacing (3);
3171         snap_mode_box.set_border_width (3);
3172
3173         Gtkmm2ext::set_size_request_to_display_given_text (*snap_mode_selector.get_entry(), "SngpMode", 2, 10);
3174         set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings));
3175
3176         snap_mode_box.pack_start (snap_mode_label, false, false);
3177         snap_mode_box.pack_start (snap_mode_selector, false, false);
3178
3179         snap_mode_selector.get_popwin()->signal_unmap_event().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
3180
3181         /* Zoom focus mode */
3182
3183         zoom_focus_label.set_name ("ToolBarLabel");
3184
3185         zoom_focus_selector.set_name ("ZoomFocusSelector");
3186         zoom_focus_selector.get_entry()->set_name ("ZoomFocusSelector");
3187         zoom_focus_selector.get_popwin()->set_name ("ZoomFocusSelector");
3188
3189         zoom_focus_box.set_spacing (3);
3190         zoom_focus_box.set_border_width (3);
3191
3192         /* XXX another disgusting hack because of the way combo boxes size themselves */
3193
3194         Gtkmm2ext::set_size_request_to_display_given_text (*zoom_focus_selector.get_entry(), "Edgt Cursor", 2, 10);
3195         set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings));
3196
3197         zoom_focus_box.pack_start (zoom_focus_label, false, false);
3198         zoom_focus_box.pack_start (zoom_focus_selector, false, false);
3199
3200         zoom_focus_selector.get_popwin()->signal_unmap_event().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
3201
3202         /* selection/cursor clocks */
3203
3204         toolbar_selection_cursor_label.set_name ("ToolBarLabel");
3205         selection_start_clock_label.set_name ("ToolBarLabel");
3206         selection_end_clock_label.set_name ("ToolBarLabel");
3207         edit_cursor_clock_label.set_name ("ToolBarLabel");
3208
3209         selection_start_clock_label.set_text (_("Start:"));
3210         selection_end_clock_label.set_text (_("End:"));
3211         edit_cursor_clock_label.set_text (_("Edit:"));
3212
3213         toolbar_selection_clock_table.set_border_width (5);
3214         toolbar_selection_clock_table.set_col_spacings (2);
3215         toolbar_selection_clock_table.set_homogeneous (false);
3216
3217 //      toolbar_selection_clock_table.attach (selection_start_clock_label, 0, 1, 0, 1, 0, 0, 0, 0);
3218 //      toolbar_selection_clock_table.attach (selection_end_clock_label, 1, 2, 0, 1, 0, 0, 0, 0);
3219         toolbar_selection_clock_table.attach (edit_cursor_clock_label, 2, 3, 0, 1, 0, 0, 0, 0);
3220
3221 //      toolbar_selection_clock_table.attach (selection_start_clock, 0, 1, 1, 2, 0, 0);
3222 //      toolbar_selection_clock_table.attach (selection_end_clock, 1, 2, 1, 2, 0, 0);
3223         toolbar_selection_clock_table.attach (edit_cursor_clock, 2, 3, 1, 2, 0, 0);
3224
3225
3226 //      toolbar_clock_vbox.set_spacing (2);
3227 //      toolbar_clock_vbox.set_border_width (10);
3228         /* the editor/mixer button will be enabled at session connect */
3229
3230         editor_mixer_button.set_active(false);
3231         editor_mixer_button.set_sensitive(false);
3232
3233         HBox* hbox = new HBox;
3234
3235         hbox->pack_start (editor_mixer_button, false, false);
3236         hbox->pack_start (toolbar_selection_clock_table, false, false);
3237         hbox->pack_start (zoom_indicator_vbox, false, false); 
3238         hbox->pack_start (zoom_focus_box, false, false);
3239         hbox->pack_start (snap_type_box, false, false);
3240         hbox->pack_start (snap_mode_box, false, false);
3241         hbox->pack_start (edit_mode_box, false, false);
3242
3243         VBox *vbox = manage (new VBox);
3244
3245         vbox->set_spacing (3);
3246         vbox->set_border_width (3);
3247
3248         HBox *nbox = manage (new HBox);
3249         
3250         nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
3251         nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
3252
3253         nbox->pack_start (nudge_backward_button, false, false);
3254         nbox->pack_start (nudge_forward_button, false, false);
3255         nbox->pack_start (nudge_clock, false, false, 5);
3256
3257         nudge_label.set_name ("ToolBarLabel");
3258
3259         vbox->pack_start (nudge_label, false, false);
3260         vbox->pack_start (*nbox, false, false);
3261
3262         hbox->pack_start (*vbox, false, false);
3263
3264         hbox->show_all ();
3265
3266         tools_tearoff = new TearOff (*hbox);
3267         tools_tearoff->set_name ("MouseModeBase");
3268
3269         tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox), 
3270                                              static_cast<Gtk::Widget*>(hbox)));
3271         tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox), 
3272                                              static_cast<Gtk::Widget*> (hbox), 0));
3273
3274         toolbar_hbox.set_spacing (8);
3275         toolbar_hbox.set_border_width (2);
3276
3277         toolbar_hbox.pack_start (*tools_tearoff, false, false);
3278         toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
3279         
3280         toolbar_base.set_name ("ToolBarBase");
3281         toolbar_base.add (toolbar_hbox);
3282
3283         toolbar_frame.set_shadow_type (Gtk::SHADOW_OUT);
3284         toolbar_frame.set_name ("BaseFrame");
3285         toolbar_frame.add (toolbar_base);
3286 }
3287
3288 gint
3289 Editor::_autoscroll_canvas (void *arg)
3290 {
3291         return ((Editor *) arg)->autoscroll_canvas ();
3292 }
3293
3294 gint
3295 Editor::autoscroll_canvas ()
3296 {
3297         jack_nframes_t new_frame;
3298         bool keep_calling = true;
3299
3300         if (autoscroll_direction < 0) {
3301                 if (leftmost_frame < autoscroll_distance) {
3302                         new_frame = 0;
3303                 } else {
3304                         new_frame = leftmost_frame - autoscroll_distance;
3305                 }
3306         } else {
3307                 if (leftmost_frame > max_frames - autoscroll_distance) {
3308                         new_frame = max_frames;
3309                 } else {
3310                         new_frame = leftmost_frame + autoscroll_distance;
3311                 }
3312         }
3313
3314         if (new_frame != leftmost_frame) {
3315                 reposition_x_origin (new_frame);
3316         }
3317
3318         if (new_frame == 0 || new_frame == max_frames) {
3319                 /* we are done */
3320                 return FALSE;
3321         }
3322
3323         autoscroll_cnt++;
3324
3325         if (autoscroll_cnt == 1) {
3326
3327                 /* connect the timeout so that we get called repeatedly */
3328                 
3329                 autoscroll_timeout_tag = gtk_timeout_add (100, _autoscroll_canvas, this);
3330                 keep_calling = false;
3331
3332         } else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) {
3333                 
3334                 /* after about a while, speed up a bit by changing the timeout interval */
3335
3336                 autoscroll_timeout_tag = gtk_timeout_add (50, _autoscroll_canvas, this);
3337                 keep_calling = false;
3338                 
3339         } else if (autoscroll_cnt >= 20 && autoscroll_cnt < 30) {
3340
3341                 /* after about another while, speed up some more */
3342
3343                 autoscroll_timeout_tag = gtk_timeout_add (25, _autoscroll_canvas, this);
3344                 keep_calling = false;
3345
3346         } else if (autoscroll_cnt >= 30) {
3347
3348                 /* we've been scrolling for a while ... crank it up */
3349
3350                 autoscroll_distance = 10 * (jack_nframes_t) floor (canvas_width * frames_per_unit);
3351         }
3352
3353         return keep_calling;
3354 }
3355
3356 void
3357 Editor::start_canvas_autoscroll (int dir)
3358 {
3359         if (!session) {
3360                 return;
3361         }
3362
3363         stop_canvas_autoscroll ();
3364
3365         autoscroll_direction = dir;
3366         autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/10.0);
3367         autoscroll_cnt = 0;
3368         
3369         /* do it right now, which will start the repeated callbacks */
3370         
3371         autoscroll_canvas ();
3372 }
3373
3374 void
3375 Editor::stop_canvas_autoscroll ()
3376 {
3377         if (autoscroll_timeout_tag >= 0) {
3378                 gtk_timeout_remove (autoscroll_timeout_tag);
3379                 autoscroll_timeout_tag = -1;
3380         }
3381 }
3382
3383 int
3384 Editor::convert_drop_to_paths (vector<string>& paths, 
3385                                GdkDragContext     *context,
3386                                gint                x,
3387                                gint                y,
3388                                GtkSelectionData   *data,
3389                                guint               info,
3390                                guint               time)                               
3391
3392 {       
3393         string spath;
3394         char *path;
3395         int state;
3396         gchar *tname = gdk_atom_name (data->type);
3397
3398         if (session == 0 || strcmp (tname, "text/plain") != 0) {
3399                 return -1;
3400         }
3401
3402         /* Parse the "uri-list" format that Nautilus provides, 
3403            where each pathname is delimited by \r\n
3404         */
3405
3406         path = (char *) data->data;
3407         state = 0;
3408
3409         for (int n = 0; n < data->length; ++n) {
3410
3411                 switch (state) {
3412                 case 0:
3413                         if (path[n] == '\r') {
3414                                 state = 1;
3415                         } else {
3416                                 spath += path[n];
3417                         }
3418                         break;
3419                 case 1:
3420                         if (path[n] == '\n') {
3421                                 paths.push_back (spath);
3422                                 spath = "";
3423                                 state = 0;
3424                         } else {
3425                                 warning << _("incorrectly formatted URI list, ignored")
3426                                         << endmsg;
3427                                 return -1;
3428                         }
3429                         break;
3430                 }
3431         }
3432
3433         /* nautilus and presumably some other file managers prefix even text/plain with file:// */
3434                 
3435         for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
3436
3437                 // cerr << "dropped text was " << *p << endl;
3438
3439                 url_decode (*p);
3440
3441                 // cerr << "decoded was " << *p << endl;
3442
3443                 if ((*p).substr (0,7) == "file://") {
3444                         (*p) = (*p).substr (7);
3445                 }
3446         }
3447         
3448         return 0;
3449 }
3450
3451 void  
3452 Editor::track_canvas_drag_data_received  (GdkDragContext     *context,
3453                                           gint                x,
3454                                           gint                y,
3455                                           GtkSelectionData   *data,
3456                                           guint               info,
3457                                           guint               time)
3458 {
3459         TimeAxisView* tvp;
3460         AudioTimeAxisView* tv;
3461         double cy;
3462         vector<string> paths;
3463         string spath;
3464         GdkEvent ev;
3465         jack_nframes_t frame;
3466
3467         if (convert_drop_to_paths (paths, context, x, y, data, info, time)) {
3468                 goto out;
3469         }
3470
3471         /* D-n-D coordinates are window-relative, so convert to "world" coordinates
3472          */
3473
3474         double wx;
3475         double wy;
3476
3477         gnome_canvas_window_to_world (GNOME_CANVAS(track_gnome_canvas), (double) x, (double) y, &wx, &wy);
3478
3479         ev.type = GDK_BUTTON_RELEASE;
3480         ev.button.x = wx;
3481         ev.button.y = wy;
3482
3483         frame = event_frame (&ev, 0, &cy);
3484
3485         snap_to (frame);
3486
3487         if ((tvp = trackview_by_y_position (cy)) == 0) {
3488
3489                 /* drop onto canvas background: create a new track */
3490
3491                 insert_paths_as_new_tracks (paths, false);
3492
3493                 
3494         } else if ((tv = dynamic_cast<AudioTimeAxisView*>(tvp)) != 0) {
3495
3496                 /* check that its an audio track, not a bus */
3497
3498                 if (tv->get_diskstream()) {
3499
3500                         for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
3501                                 insert_sndfile_into (*p, true, tv, frame);
3502                         }
3503                 }
3504
3505         }
3506
3507   out:
3508         gtk_drag_finish (context, TRUE, FALSE, time);
3509 }
3510
3511 void
3512 Editor::new_tempo_section ()
3513
3514 {
3515 }
3516
3517 void
3518 Editor::map_transport_state ()
3519 {
3520         ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
3521
3522         if (session->transport_stopped()) {
3523                 have_pending_keyboard_selection = false;
3524         }
3525 }
3526
3527 /* UNDO/REDO */
3528
3529 Editor::State::State ()
3530 {
3531         selection = new Selection;
3532 }
3533
3534 Editor::State::~State ()
3535 {
3536         delete selection;
3537 }
3538
3539 UndoAction
3540 Editor::get_memento () const
3541 {
3542         State *state = new State;
3543
3544         store_state (*state);
3545         return bind (slot (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
3546 }
3547
3548 void
3549 Editor::store_state (State& state) const
3550 {
3551         *state.selection = *selection;
3552 }
3553
3554 void
3555 Editor::restore_state (State *state)
3556 {
3557         if (*selection == *state->selection) {
3558                 return;
3559         }
3560
3561         *selection = *state->selection;
3562         time_selection_changed ();
3563         region_selection_changed ();
3564
3565         /* XXX other selection change handlers? */
3566 }
3567
3568 void
3569 Editor::begin_reversible_command (string name)
3570 {
3571         if (session) {
3572                 UndoAction ua = get_memento();
3573                 session->begin_reversible_command (name, &ua);
3574         }
3575 }
3576
3577 void
3578 Editor::commit_reversible_command ()
3579 {
3580         if (session) {
3581                 UndoAction ua = get_memento();
3582                 session->commit_reversible_command (&ua);
3583         }
3584 }
3585
3586 void
3587 Editor::flush_track_canvas ()
3588 {
3589         /* I don't think this is necessary, and only causes more problems.
3590            I'm commenting it out
3591            and if the imageframe folks don't have any issues, we can take
3592            out this method entirely
3593         */
3594         
3595         //gnome_canvas_update_now (GNOME_CANVAS(track_gnome_canvas));
3596         //gtk_main_iteration ();
3597 }
3598
3599 void
3600 Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove)
3601 {
3602         if (!clicked_trackview) {
3603                 return;
3604         }
3605
3606         if (with_undo) {
3607                 begin_reversible_command (_("set selected trackview"));
3608         }
3609
3610         if (add) {
3611                 
3612                 if (selection->selected (clicked_trackview)) {
3613                         if (!no_remove) {
3614                                 selection->remove (clicked_trackview);
3615                         }
3616                 } else {
3617                         selection->add (clicked_trackview);
3618                 }
3619                 
3620         } else {
3621
3622                 if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) {
3623                         /* no commit necessary */
3624                         return;
3625                 } 
3626
3627                 selection->set (clicked_trackview);
3628         }
3629         
3630         if (with_undo) {
3631                 commit_reversible_command ();
3632         }
3633 }
3634
3635 void
3636 Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no_remove)
3637 {
3638         if (!clicked_control_point) {
3639                 return;
3640         }
3641
3642         if (with_undo) {
3643                 begin_reversible_command (_("set selected control point"));
3644         }
3645
3646         if (add) {
3647                 
3648         } else {
3649
3650         }
3651         
3652         if (with_undo) {
3653                 commit_reversible_command ();
3654         }
3655 }
3656
3657 void
3658 Editor::set_selected_regionview_from_click (bool add, bool no_track_remove)
3659 {
3660         if (!clicked_regionview) {
3661                 return;
3662         }
3663
3664         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&clicked_regionview->get_time_axis_view());
3665
3666         if (!atv) {
3667                 return;
3668         }
3669
3670         RouteGroup* group = atv->route().edit_group();
3671         vector<AudioRegionView*> all_equivalent_regions;
3672         
3673         if (group && group->is_active()) {
3674
3675                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3676
3677                         AudioTimeAxisView* tatv;
3678
3679                         if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3680
3681                                 if (tatv->route().edit_group() != group) {
3682                                         continue;
3683                                 }
3684                         
3685                                 AudioPlaylist* pl;
3686                                 vector<AudioRegion*> results;
3687                                 AudioRegionView* marv;
3688                                 DiskStream* ds;
3689                                 
3690                                 if ((ds = tatv->get_diskstream()) == 0) {
3691                                         /* bus */
3692                                         continue;
3693                                 }
3694                                 
3695                                 if ((pl = ds->playlist()) != 0) {
3696                                         pl->get_equivalent_regions (clicked_regionview->region, 
3697                                                                     results);
3698                                 }
3699                                 
3700                                 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3701                                         if ((marv = tatv->view->find_view (**ir)) != 0) {
3702                                                 all_equivalent_regions.push_back (marv);
3703                                         }
3704                                 }
3705                                 
3706                         }
3707                 }
3708
3709         } else {
3710
3711                 all_equivalent_regions.push_back (clicked_regionview);
3712
3713         }
3714         
3715         begin_reversible_command (_("set selected regionview"));
3716         
3717         if (add) {
3718
3719                 if (clicked_regionview->get_selected()) {
3720                         if (group && group->is_active() && selection->audio_regions.size() > 1) {
3721                                 /* reduce selection down to just the one clicked */
3722                                 selection->set (clicked_regionview);
3723                         } else {
3724                                 selection->remove (clicked_regionview);
3725                         }
3726                 } else {
3727                         selection->add (all_equivalent_regions);
3728                 }
3729
3730                 set_selected_track_from_click (add, false, no_track_remove);
3731                 
3732         } else {
3733
3734                 // karsten wiese suggested these two lines to make
3735                 // a selected region rise to the top. but this
3736                 // leads to a mismatch between actual layering
3737                 // and visual layering. resolution required ....
3738                 //
3739                 // gnome_canvas_item_raise_to_top (clicked_regionview->get_canvas_group());
3740                 // gnome_canvas_item_raise_to_top (clicked_regionview->get_time_axis_view().canvas_display);
3741
3742                 if (clicked_regionview->get_selected()) {
3743                         /* no commit necessary: we are the one selected. */
3744                         return;
3745
3746                 } else {
3747                         
3748                         selection->set (all_equivalent_regions);
3749                         set_selected_track_from_click (add, false, false);
3750                 }
3751         }
3752
3753         commit_reversible_command () ;
3754 }
3755
3756 void
3757 Editor::set_selected_regionview_from_region_list (Region& r, bool add)
3758 {
3759         vector<AudioRegionView*> all_equivalent_regions;
3760         AudioRegion* region;
3761
3762         if ((region = dynamic_cast<AudioRegion*>(&r)) == 0) {
3763                 return;
3764         }
3765
3766         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3767                 
3768                 AudioTimeAxisView* tatv;
3769                 
3770                 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3771                         
3772                         AudioPlaylist* pl;
3773                         vector<AudioRegion*> results;
3774                         AudioRegionView* marv;
3775                         DiskStream* ds;
3776                         
3777                         if ((ds = tatv->get_diskstream()) == 0) {
3778                                 /* bus */
3779                                 continue;
3780                         }
3781
3782                         if ((pl = ds->playlist()) != 0) {
3783                                 pl->get_region_list_equivalent_regions (*region, results);
3784                         }
3785                         
3786                         for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3787                                 if ((marv = tatv->view->find_view (**ir)) != 0) {
3788                                         all_equivalent_regions.push_back (marv);
3789                                 }
3790                         }
3791                         
3792                 }
3793         }
3794         
3795         begin_reversible_command (_("set selected regions"));
3796         
3797         if (add) {
3798
3799                 selection->add (all_equivalent_regions);
3800                 
3801         } else {
3802
3803                 selection->set (all_equivalent_regions);
3804         }
3805
3806         commit_reversible_command () ;
3807 }
3808
3809 gint
3810 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r)
3811 {
3812         AudioRegionView* rv;
3813         AudioRegion* ar;
3814
3815         if ((ar = dynamic_cast<AudioRegion*> (r)) == 0) {
3816                 return TRUE;
3817         }
3818
3819         if ((rv = sv->find_view (*ar)) == 0) {
3820                 return TRUE;
3821         }
3822
3823         /* don't reset the selection if its something other than 
3824            a single other region.
3825         */
3826
3827         if (selection->audio_regions.size() > 1) {
3828                 return TRUE;
3829         }
3830         
3831         begin_reversible_command (_("set selected regions"));
3832         
3833         selection->set (rv);
3834
3835         commit_reversible_command () ;
3836
3837         return TRUE;
3838 }
3839
3840 void
3841 Editor::set_edit_group_solo (Route& route, bool yn)
3842 {
3843         RouteGroup *edit_group;
3844
3845         if ((edit_group = route.edit_group()) != 0) {
3846                 edit_group->apply (&Route::set_solo, yn, this);
3847         } else {
3848                 route.set_solo (yn, this);
3849         }
3850 }
3851
3852 void
3853 Editor::set_edit_group_mute (Route& route, bool yn)
3854 {
3855         RouteGroup *edit_group = 0;
3856
3857         if ((edit_group == route.edit_group()) != 0) {
3858                 edit_group->apply (&Route::set_mute, yn, this);
3859         } else {
3860                 route.set_mute (yn, this);
3861         }
3862 }
3863                 
3864 void
3865 Editor::set_edit_menu (Menu& menu)
3866 {
3867         edit_menu = &menu;
3868         edit_menu->map_.connect (mem_fun(*this, &Editor::edit_menu_map_handler));
3869 }
3870
3871 void
3872 Editor::edit_menu_map_handler ()
3873 {
3874         using namespace Menu_Helpers;
3875         MenuList& edit_items = edit_menu->items();
3876         string label;
3877
3878         /* Nuke all the old items */
3879                 
3880         edit_items.clear ();
3881
3882         if (session == 0) {
3883                 return;
3884         }
3885
3886         if (session->undo_depth() == 0) {
3887                 label = _("Undo");
3888         } else {
3889                 label = string_compose(_("Undo (%1)"), session->next_undo());
3890         }
3891         
3892         edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::undo), 1U)));
3893         
3894         if (session->undo_depth() == 0) {
3895                 edit_items.back()->set_sensitive (false);
3896         }
3897         
3898         if (session->redo_depth() == 0) {
3899                 label = _("Redo");
3900         } else {
3901                 label = string_compose(_("Redo (%1)"), session->next_redo());
3902         }
3903         
3904         edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::redo), 1U)));
3905         if (session->redo_depth() == 0) {
3906                 edit_items.back()->set_sensitive (false);
3907         }
3908
3909         vector<MenuItem*> mitems;
3910
3911         edit_items.push_back (SeparatorElem());
3912         edit_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
3913         mitems.push_back (edit_items.back());
3914         edit_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
3915         mitems.push_back (edit_items.back());
3916         edit_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
3917         mitems.push_back (edit_items.back());
3918         edit_items.push_back (SeparatorElem());
3919         edit_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
3920         mitems.push_back (edit_items.back());
3921         edit_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
3922         mitems.push_back (edit_items.back());
3923         edit_items.push_back (SeparatorElem());
3924
3925         if (selection->empty()) {
3926                 for (vector<MenuItem*>::iterator i = mitems.begin(); i != mitems.end(); ++i) {
3927                         (*i)->set_sensitive (false);
3928                 }
3929         }
3930
3931         Menu* import_menu = manage (new Menu());
3932         import_menu->set_name ("ArdourContextMenu");
3933         MenuList& import_items = import_menu->items();
3934         
3935         import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::import_audio), true)));
3936         import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::import_audio), false)));
3937
3938         Menu* embed_menu = manage (new Menu());
3939         embed_menu->set_name ("ArdourContextMenu");
3940         MenuList& embed_items = embed_menu->items();
3941
3942         embed_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::insert_sndfile), true)));
3943         embed_items.push_back (MenuElem (_("... as new region"), mem_fun(*this, &Editor::embed_audio)));
3944
3945         edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu));
3946         edit_items.push_back (MenuElem (_("Embed audio (link)"), *embed_menu));
3947         edit_items.push_back (SeparatorElem());
3948
3949         edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture)));
3950         if (!session->have_captured()) {
3951                 edit_items.back()->set_sensitive (false);
3952         }
3953 }
3954
3955 void
3956 Editor::duplicate_dialog (bool dup_region)
3957 {
3958         if (dup_region) {
3959                 if (clicked_regionview == 0) {
3960                         return;
3961                 }
3962         } else {
3963                 if (selection->time.length() == 0) {
3964                         return;
3965                 }
3966         }
3967
3968         ArdourDialog win ("duplicate dialog");
3969         Entry  entry;
3970         Label  label (_("Duplicate how many times?"));
3971         HBox   hbox;
3972         HBox   button_box;
3973         Button ok_button (_("OK"));
3974         Button cancel_button (_("Cancel"));
3975         VBox   vbox;
3976
3977         button_box.set_spacing (7);
3978         set_size_request_to_display_given_text (ok_button, _("Cancel"), 20, 15); // this is cancel on purpose
3979         set_size_request_to_display_given_text (cancel_button, _("Cancel"), 20, 15);
3980         button_box.pack_end (ok_button, false, false);
3981         button_box.pack_end (cancel_button, false, false);
3982         
3983         hbox.set_spacing (5);
3984         hbox.pack_start (label);
3985         hbox.pack_start (entry, true, true);
3986         
3987         vbox.set_spacing (5);
3988         vbox.set_border_width (5);
3989         vbox.pack_start (hbox);
3990         vbox.pack_start (button_box);
3991
3992         win.add (vbox);
3993         win.set_position (Gtk::WIN_POS_MOUSE);
3994         win.show_all ();
3995
3996         ok_button.signal_clicked().connect (bind (slot (win, &ArdourDialog::stop), 0));
3997         entry.activate.connect (bind (slot (win, &ArdourDialog::stop), 0));
3998         cancel_button.signal_clicked().connect (bind (slot (win, &ArdourDialog::stop), 1));
3999
4000         entry.signal_focus_in_event()().connect (slot (ARDOUR_UI::generic_focus_in_event));
4001         entry.signal_focus_out_event()().connect (slot (ARDOUR_UI::generic_focus_out_event));
4002         
4003         entry.set_text ("1");
4004         set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15);
4005         entry.select_region (0, entry.get_text_length());
4006
4007         win.set_position (Gtk::WIN_POS_MOUSE);
4008         win.realize ();
4009         win.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
4010
4011         entry.grab_focus ();
4012
4013         win.run ();
4014
4015         if (win.run_status() != 0) {
4016                 return;
4017         }
4018
4019         string text = entry.get_text();
4020         float times;
4021
4022         if (sscanf (text.c_str(), "%f", &times) == 1) {
4023                 if (dup_region) {
4024                         AudioRegionSelection regions;
4025                         regions.add (clicked_regionview);
4026                         duplicate_some_regions (regions, times);
4027                 } else {
4028                         duplicate_selection (times);
4029                 }
4030         }
4031 }
4032
4033 void
4034 Editor::show_verbose_canvas_cursor ()
4035 {
4036         gnome_canvas_item_raise_to_top (verbose_canvas_cursor);
4037         gnome_canvas_item_show (verbose_canvas_cursor);
4038         verbose_cursor_visible = true;
4039 }
4040
4041 void
4042 Editor::hide_verbose_canvas_cursor ()
4043 {
4044         gnome_canvas_item_hide (verbose_canvas_cursor);
4045         verbose_cursor_visible = false;
4046 }
4047
4048 void
4049 Editor::set_verbose_canvas_cursor (string txt, double x, double y)
4050 {
4051         /* XXX get origin of canvas relative to root window,
4052            add x and y and check compared to gdk_screen_{width,height}
4053         */
4054         gnome_canvas_item_set (verbose_canvas_cursor, "text", txt.c_str(), "x", x, "y", y, NULL);       
4055 }
4056
4057 void
4058 Editor::set_verbose_canvas_cursor_text (string txt)
4059 {
4060         gnome_canvas_item_set (verbose_canvas_cursor, "text", txt.c_str(), NULL);
4061 }
4062
4063 gint
4064 Editor::edit_mode_selection_done (GdkEventAny *ev)
4065 {
4066         if (session == 0) {
4067                 return FALSE;
4068         }
4069
4070         string choice = edit_mode_selector.get_entry()->get_text();
4071         EditMode mode = Slide;
4072
4073         if (choice == _("Splice")) {
4074                 mode = Splice;
4075         } else if (choice == _("Slide")) {
4076                 mode = Slide;
4077         }
4078
4079         session->set_edit_mode (mode);
4080
4081         return FALSE;
4082 }       
4083
4084 gint
4085 Editor::snap_type_selection_done (GdkEventAny *ev)
4086 {
4087         if (session == 0) {
4088                 return FALSE;
4089         }
4090
4091         string choice = snap_type_selector.get_entry()->get_text();
4092         SnapType snaptype = SnapToFrame;
4093         
4094         if (choice == _("Beats/3")) {
4095                 snaptype = SnapToAThirdBeat;
4096         } else if (choice == _("Beats/4")) {
4097                 snaptype = SnapToAQuarterBeat;
4098         } else if (choice == _("Beats/8")) {
4099                 snaptype = SnapToAEighthBeat;
4100         } else if (choice == _("Beats/16")) {
4101                 snaptype = SnapToASixteenthBeat;
4102         } else if (choice == _("Beats/32")) {
4103                 snaptype = SnapToAThirtysecondBeat;
4104         } else if (choice == _("Beats")) {
4105                 snaptype = SnapToBeat;
4106         } else if (choice == _("Bars")) {
4107                 snaptype = SnapToBar;
4108         } else if (choice == _("Marks")) {
4109                 snaptype = SnapToMark;
4110         } else if (choice == _("Edit Cursor")) {
4111                 snaptype = SnapToEditCursor;
4112         } else if (choice == _("Region starts")) {
4113                 snaptype = SnapToRegionStart;
4114         } else if (choice == _("Region ends")) {
4115                 snaptype = SnapToRegionEnd;
4116         } else if (choice == _("Region bounds")) {
4117                 snaptype = SnapToRegionBoundary;
4118         } else if (choice == _("Region syncs")) {
4119                 snaptype = SnapToRegionSync;
4120         } else if (choice == _("CD Frames")) {
4121                 snaptype = SnapToCDFrame;
4122         } else if (choice == _("SMPTE Frames")) {
4123                 snaptype = SnapToSMPTEFrame;
4124         } else if (choice == _("SMPTE Seconds")) {
4125                 snaptype = SnapToSMPTESeconds;
4126         } else if (choice == _("SMPTE Minutes")) {
4127                 snaptype = SnapToSMPTEMinutes;
4128         } else if (choice == _("Seconds")) {
4129                 snaptype = SnapToSeconds;
4130         } else if (choice == _("Minutes")) {
4131                 snaptype = SnapToMinutes;
4132         } else if (choice == _("None")) {
4133                 snaptype = SnapToFrame;
4134         }
4135         
4136         set_snap_to (snaptype);
4137
4138         return FALSE;
4139 }       
4140
4141 gint
4142 Editor::snap_mode_selection_done (GdkEventAny *ev)
4143 {
4144         if(session == 0) return FALSE;
4145
4146         string choice = snap_mode_selector.get_entry()->get_text();
4147         SnapMode mode = SnapNormal;
4148
4149         if (choice == _("Normal")) {
4150                 mode = SnapNormal;
4151         } else if (choice == _("Magnetic")) {
4152                 mode = SnapMagnetic;
4153         }
4154
4155         set_snap_mode (mode);
4156
4157         return FALSE;
4158 }
4159
4160 gint
4161 Editor::zoom_focus_selection_done (GdkEventAny *ev)
4162 {
4163         if (session == 0) {
4164                 return FALSE;
4165         }
4166
4167         string choice = zoom_focus_selector.get_entry()->get_text();
4168         ZoomFocus focus_type = ZoomFocusLeft;
4169
4170         if (choice == _("Left")) {
4171                 focus_type = ZoomFocusLeft;
4172         } else if (choice == _("Right")) {
4173                 focus_type = ZoomFocusRight;
4174         } else if (choice == _("Center")) {
4175                 focus_type = ZoomFocusCenter;
4176         } else if (choice == _("Playhead")) {
4177                 focus_type = ZoomFocusPlayhead;
4178         } else if (choice == _("Edit Cursor")) {
4179                 focus_type = ZoomFocusEdit;
4180         } 
4181
4182         set_zoom_focus (focus_type);
4183
4184         return FALSE;
4185 }       
4186
4187 gint
4188 Editor::edit_controls_button_release (GdkEventButton* ev)
4189 {
4190         if (Keyboard::is_context_menu_event (ev)) {
4191                 ARDOUR_UI::instance()->add_route ();
4192         }
4193         return TRUE;
4194 }
4195
4196 void
4197 Editor::track_selection_changed ()
4198 {
4199         switch (selection->tracks.size()){
4200         case 0:
4201                 break;
4202         default:
4203                 set_selected_mixer_strip (*(selection->tracks.front()));
4204                 break;
4205         }
4206
4207         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4208                 (*i)->set_selected (false);
4209                 if (mouse_mode == MouseRange) {
4210                         (*i)->hide_selection ();
4211                 }
4212         }
4213
4214         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4215                 (*i)->set_selected (true);
4216                 if (mouse_mode == MouseRange) {
4217                         (*i)->show_selection (selection->time);
4218                 }
4219         }
4220 }
4221
4222 void
4223 Editor::time_selection_changed ()
4224 {
4225         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4226                 (*i)->hide_selection ();
4227         }
4228
4229         if (selection->tracks.empty()) {
4230                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4231                         (*i)->show_selection (selection->time);
4232                 }
4233         } else {
4234                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4235                         (*i)->show_selection (selection->time);
4236                 }
4237         }
4238 }
4239
4240 void
4241 Editor::region_selection_changed ()
4242 {
4243         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4244                 (*i)->set_selected_regionviews (selection->audio_regions);
4245         }
4246 }
4247
4248 void
4249 Editor::point_selection_changed ()
4250 {
4251         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4252                 (*i)->set_selected_points (selection->points);
4253         }
4254 }
4255
4256 void
4257 Editor::run_sub_event_loop ()
4258 {
4259         Keyboard::the_keyboard().allow_focus (true);
4260         sub_event_loop_status = 0;
4261         Main::run ();
4262 }
4263
4264 void
4265 Editor::finish_sub_event_loop (int status)
4266 {
4267         Main::quit ();
4268         Keyboard::the_keyboard().allow_focus (false);
4269         sub_event_loop_status = status;
4270 }
4271
4272 gint
4273 Editor::finish_sub_event_loop_on_delete (GdkEventAny *ignored, int32_t status)
4274 {
4275         finish_sub_event_loop (status);
4276         return TRUE;
4277 }
4278
4279 gint
4280 Editor::mouse_select_button_release (GdkEventButton* ev)
4281 {
4282         /* this handles just right-clicks */
4283
4284         if (ev->button != 3) {
4285                 return FALSE;
4286         }
4287
4288         return TRUE;
4289 }
4290
4291 Editor::TrackViewList *
4292 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
4293 {
4294         TrackViewList *v;
4295         TrackViewList::iterator i;
4296
4297         v = new TrackViewList;
4298
4299         if (track == 0 && group == 0) {
4300
4301                 /* all views */
4302
4303                 for (i = track_views.begin(); i != track_views.end (); ++i) {
4304                         v->push_back (*i);
4305                 }
4306
4307         } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
4308                 
4309                 /* just the view for this track
4310                  */
4311
4312                 v->push_back (track);
4313
4314         } else {
4315                 
4316                 /* views for all tracks in the edit group */
4317                 
4318                 for (i  = track_views.begin(); i != track_views.end (); ++i) {
4319
4320                         if (group == 0 || (*i)->edit_group() == group) {
4321                                 v->push_back (*i);
4322                         }
4323                 }
4324         }
4325         
4326         return v;
4327 }
4328
4329 void
4330 Editor::set_zoom_focus (ZoomFocus f)
4331 {
4332         if (zoom_focus != f) {
4333                 zoom_focus = f;
4334                 vector<string> txt = internationalize (zoom_focus_strings);
4335                 zoom_focus_selector.get_entry()->set_text (txt[(int)f]);
4336                 ZoomFocusChanged (); /* EMIT_SIGNAL */
4337
4338                 instant_save ();
4339         }
4340 }
4341
4342 void
4343 Editor::ensure_float (Window& win)
4344 {
4345         win.set_transient_for (*this);
4346 }
4347
4348 void 
4349 Editor::pane_allocation_handler (GtkAllocation *alloc, Gtk::Paned* which)
4350 {
4351         /* recover or initialize pane positions. do this here rather than earlier because
4352            we don't want the positions to change the child allocations, which they seem to do.
4353          */
4354
4355         int pos;
4356         XMLProperty* prop;
4357         char buf[32];
4358         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
4359         int width, height;
4360         static int32_t done[4] = { 0, 0, 0, 0 };
4361         XMLNode* geometry;
4362
4363         if ((geometry = find_named_node (*node, "geometry")) == 0) {
4364                 width = default_width;
4365                 height = default_height;
4366         } else {
4367                 width = atoi(geometry->property("x_size")->value());
4368                 height = atoi(geometry->property("y_size")->value());
4369         }
4370
4371         if (which == static_cast<Gtk::Paned*> (&track_list_canvas_pane)) {
4372
4373                 if (done[0]) {
4374                         return;
4375                 }
4376
4377                 if (!geometry || (prop = geometry->property("track_list_canvas_pane_pos")) == 0) {
4378                         pos = 75;
4379                         snprintf (buf, sizeof(buf), "%d", pos);
4380                 } else {
4381                         pos = atoi (prop->value());
4382                 }
4383
4384                 if ((done[0] = GTK_WIDGET(track_list_canvas_pane.gobj())->allocation.width > pos)) {
4385                         track_list_canvas_pane.set_position (pos);
4386                 }
4387
4388         } else if (which == static_cast<Gtk::Paned*> (&canvas_region_list_pane)) {
4389
4390                 if (done[1]) {
4391                         return;
4392                 }
4393
4394                 if (!geometry || (prop = geometry->property("canvas_region_list_pane_pos")) == 0) {
4395                         pos = width - (95 * 2);
4396                         snprintf (buf, sizeof(buf), "%d", pos);
4397                 } else {
4398                         pos = atoi (prop->value());
4399                 }
4400
4401                 if ((done[1] = GTK_WIDGET(canvas_region_list_pane.gobj())->allocation.width > pos)) {
4402                         canvas_region_list_pane.set_position (pos);
4403                 }
4404
4405         } else if (which == static_cast<Gtk::Paned*> (&route_group_vpane)) {
4406
4407                 if (done[2]) {
4408                         return;
4409                 }
4410
4411                 if (!geometry || (prop = geometry->property("route_group_pane_pos")) == 0) {
4412                         pos = width - (95 * 2);
4413                         snprintf (buf, sizeof(buf), "%d", pos);
4414                 } else {
4415                         pos = atoi (prop->value());
4416                 }
4417
4418                 if ((done[2] = GTK_WIDGET(route_group_vpane.gobj())->allocation.height > pos)) {
4419                         route_group_vpane.set_position (pos);
4420                 }
4421
4422         } else if (which == static_cast<Gtk::Paned*> (&region_selection_vpane)) {
4423
4424                 if (done[3]) {
4425                         return;
4426                 }
4427
4428                 if (!geometry || (prop = geometry->property("region_selection_pane_pos")) == 0) {
4429                         pos = width - (95 * 2);
4430                         snprintf (buf, sizeof(buf), "%d", pos);
4431                 } else {
4432                         pos = atoi (prop->value());
4433                 }
4434
4435                 if ((done[3] = GTK_WIDGET(region_selection_vpane.gobj())->allocation.height > pos)) { 
4436                         region_selection_vpane.set_position (pos);
4437                 }
4438         }
4439 }
4440
4441 void
4442 Editor::detach_tearoff (Gtk::Box* b, Gtk::Widget* w)
4443 {
4444         if (tools_tearoff->torn_off() && 
4445             mouse_mode_tearoff->torn_off()) {
4446                 top_hbox.remove (toolbar_frame);
4447         }
4448         
4449         ensure_float (*w->get_toplevel());
4450 }
4451
4452 void
4453 Editor::reattach_tearoff (Gtk::Box* b, Gtk::Widget* w, int32_t n)
4454 {
4455         if (toolbar_frame.get_parent() == 0) {
4456                 top_hbox.pack_end (toolbar_frame);
4457         }
4458 }
4459
4460 void
4461 Editor::set_show_measures (bool yn)
4462 {
4463         if (_show_measures != yn) {
4464                 hide_measures ();
4465
4466                 if ((_show_measures = yn) == true) {
4467                         draw_measures ();
4468                 }
4469                 DisplayControlChanged (ShowMeasures);
4470                 instant_save ();
4471         }
4472 }
4473
4474 void
4475 Editor::set_follow_playhead (bool yn)
4476 {
4477         if (_follow_playhead != yn) {
4478                 if ((_follow_playhead = yn) == true) {
4479                         /* catch up */
4480                         update_current_screen ();
4481                 }
4482                 DisplayControlChanged (FollowPlayhead);
4483                 instant_save ();
4484         }
4485 }
4486
4487 void
4488 Editor::toggle_xfade_active (Crossfade* xfade)
4489 {
4490         xfade->set_active (!xfade->active());
4491 }
4492
4493 void
4494 Editor::toggle_xfade_length (Crossfade* xfade)
4495 {
4496         xfade->set_follow_overlap (!xfade->following_overlap());
4497 }
4498
4499 void
4500 Editor::edit_xfade (Crossfade* xfade)
4501 {
4502         CrossfadeEditor cew (*session, *xfade, xfade->fade_in().get_min_y(), 1.0);
4503                 
4504         ensure_float (cew);
4505         
4506         cew.ok_button.signal_clicked().connect (bind (slot (cew, &ArdourDialog::stop), 1));
4507         cew.cancel_button.signal_clicked().connect (bind (slot (cew, &ArdourDialog::stop), 0));
4508         cew.signal_delete_event().connect (slot (cew, &ArdourDialog::wm_doi_event_stop));
4509
4510         cew.run ();
4511         
4512         if (cew.run_status() == 1) {
4513                 cew.apply ();
4514                 xfade->StateChanged (Change (~0));
4515         }
4516 }
4517
4518 PlaylistSelector&
4519 Editor::playlist_selector () const
4520 {
4521         return *_playlist_selector;
4522 }
4523
4524 jack_nframes_t
4525 Editor::get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next)
4526 {
4527         jack_nframes_t ret;
4528
4529         ret = nudge_clock.current_duration (pos);
4530         next = ret + 1; /* XXXX fix me */
4531
4532         return ret;
4533 }
4534
4535 void
4536 Editor::end_location_changed (Location* location)
4537 {
4538         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
4539         track_canvas_scroller.get_hadjustment()->set_upper (location->end() / frames_per_unit);
4540 }
4541
4542 int
4543 Editor::playlist_deletion_dialog (Playlist* pl)
4544 {
4545         ArdourDialog dialog ("playlist deletion dialog");
4546         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
4547                                  "If left alone, no audio files used by it will be cleaned.\n"
4548                                  "If deleted, audio files used by it alone by will cleaned."),
4549                                pl->name()));
4550         HBox   button_box;
4551         Button del_button (_("Delete playlist"));
4552         Button keep_button (_("Keep playlist"));
4553         Button abort_button (_("Cancel cleanup"));
4554         VBox   vbox;
4555
4556         button_box.set_spacing (7);
4557         button_box.set_homogeneous (true);
4558         button_box.pack_end (del_button, false, false);
4559         button_box.pack_end (keep_button, false, false);
4560         button_box.pack_end (abort_button, false, false);
4561         
4562         vbox.set_spacing (5);
4563         vbox.set_border_width (5);
4564         vbox.pack_start (label);
4565         vbox.pack_start (button_box);
4566
4567         dialog.add (vbox);
4568         dialog.set_position (GTK_WIN_POS_CENTER);
4569         dialog.show_all ();
4570
4571         del_button.signal_clicked().connect (bind (slot (dialog, &ArdourDialog::stop), 0));
4572         keep_button.signal_clicked().connect (bind (slot (dialog, &ArdourDialog::stop), 1));
4573         abort_button.signal_clicked().connect (bind (slot (dialog, &ArdourDialog::stop), 2));
4574
4575         dialog.realize ();
4576         dialog.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
4577
4578         dialog.run ();
4579
4580         switch (dialog.run_status()) {
4581         case 1:
4582                 /* keep the playlist */
4583                 return 1;
4584                 break;
4585         case 0:
4586                 /* delete the playlist */
4587                 return 0;
4588                 break;
4589         case 2:
4590                 /* abort cleanup */
4591                 return -1;
4592                 break;
4593         default:
4594                 /* keep the playlist */
4595                 return 1;
4596         }
4597 }
4598
4599 bool
4600 Editor::audio_region_selection_covers (jack_nframes_t where)
4601 {
4602         for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) {
4603                 if ((*a)->region.covers (where)) {
4604                         return true;
4605                 }
4606         }
4607
4608         return false;
4609 }
4610
4611 void
4612 Editor::prepare_for_cleanup ()
4613 {
4614         cut_buffer->clear_audio_regions ();
4615         cut_buffer->clear_playlists ();
4616
4617         selection->clear_audio_regions ();
4618         selection->clear_playlists ();
4619 }
4620
4621 void
4622 Editor::init_colormap ()
4623 {
4624         for (size_t x = 0; x < sizeof (color_id_strs) / sizeof (color_id_strs[0]); ++x) {
4625                 pair<ColorID,int> newpair;
4626                 
4627                 newpair.first = (ColorID) x;
4628                 newpair.second = rgba_from_style (enum2str (newpair.first), 0, 0, 0, 255);
4629                 color_map.insert (newpair);
4630         }
4631 }
4632
4633 Location*
4634 Editor::transport_loop_location()
4635 {
4636         if (session) {
4637                 return session->locations()->auto_loop_location();
4638         } else {
4639                 return 0;
4640         }
4641 }
4642
4643 Location*
4644 Editor::transport_punch_location()
4645 {
4646         if (session) {
4647                 return session->locations()->auto_punch_location();
4648         } else {
4649                 return 0;
4650         }
4651 }