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