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