1be409f4a1d6673adc146fe42ef291a5023abf2c
[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->property_activatable() = true;
544         active_cell->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->property_font_desc() = font;
830         // GTK2FIX
831         // verbose_canvas_cursor->property_anchor() = GTK_ANCHOR_NW;
832         verbose_canvas_cursor->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->property_fill_color_rgba() = color_map[cTempoBar];
852         tempo_bar->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->property_fill_color_rgba() = color_map[cMeterBar];
856         meter_bar->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->property_fill_color_rgba() = color_map[cMarkerBar];
860         marker_bar->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->property_fill_color_rgba() = color_map[cRangeMarkerBar];
864         range_marker_bar->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->property_fill_color_rgba() = color_map[cTransportMarkerBar];
868         transport_marker_bar->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->property_fill_color_rgba() = color_map[cRangeDragBarRectFill];
872         range_bar_drag_rect->property_outline_color_rgba() = color_map[cRangeDragBarRect];
873         range_bar_drag_rect->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 ->property_fill_color_rgba() = color_map[cTransportDragRectFill];
878         transport_bar_drag_rect->property_outline_color_rgba() = color_map[cTransportDragRect];
879         transport_bar_drag_rect->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->property_width_pixels() = 1;
887         marker_drag_line->property_fill_color_rgba() = color_map[cMarkerDragLine];
888         marker_drag_line->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->property_fill_color_rgba() = color_map[cRangeDragRectFill];
893         range_marker_drag_rect->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->property_fill_color_rgba() = color_map[cTransportLoopRectFill];
898         transport_loop_range_rect->property_outline_color_rgba() = color_map[cTransportLoopRect];
899         transport_loop_range_rect->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->property_fill_color_rgba() = color_map[cTransportPunchRectFill];
904         transport_punch_range_rect->property_outline_color_rgba() = color_map[cTransportPunchRect];
905         transport_punch_range_rect->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->property_x1() = 0.0;
912         transport_punchin_line->property_y1() = 0.0;
913         transport_punchin_line->property_x2() = 0.0;
914         transport_punchin_line->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->property_x1() = 0.0;
920         transport_punchout_line->property_y1() = 0.0;
921         transport_punchout_line->property_x2() = 0.0;
922         transport_punchout_line->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->property_fill_color_rgba() = color_map[cZoomRectFill];
929         zoom_rect->property_outline_color_rgba() = color_map[cZoomRect];
930         zoom_rect->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->property_outline_color_rgba() = color_map[cRubberBandRect];
938         rubberband_rect->property_fill_color_rgba() = (guint32) color_map[cRubberBandRectFill];
939         rubberband_rect->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->property_font_desc() = font;
1246                         first_action_message->property_fill_color_rgba() = color_map[cFirstActionMessage];
1247                         first_action_message->property_x() = (gdouble) (canvas_width - pixel_width) / 2.0;
1248                         first_action_message->property_y() = (gdouble) (canvas_height/2.0) - (2.0 * (pixel_height));
1249                         first_action_message->property_anchor() = ANCHOR_NORTH_WEST;
1250                         first_action_message->property_text() = ustring (txt);
1251                         
1252                 } else {
1253
1254                         /* center it */
1255                         first_action_message->property_x() = (gdouble) (canvas_width - pixel_width) / 2.0;
1256                         first_action_message->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->property_points() = marker_drag_line_points;
1329         }
1330         if (range_marker_drag_rect) {
1331                 range_marker_drag_rect->property_y1() = 0.0;
1332                 range_marker_drag_rect->property_y2() = (double) canvas_height;
1333         }
1334
1335         if (transport_loop_range_rect) {
1336                 transport_loop_range_rect->property_y1() = 0.0;
1337                 transport_loop_range_rect->property_y2() = (double) canvas_height;
1338         }
1339
1340         if (transport_punch_range_rect) {
1341                 transport_punch_range_rect->property_y1() = 0.0;
1342                 transport_punch_range_rect->property_y2() = (double) canvas_height;
1343         }
1344
1345         if (transport_punchin_line) {
1346                 transport_punchin_line->property_y1() = 0.0;
1347                 transport_punchin_line->property_y2() = (double) canvas_height;
1348         }
1349
1350         if (transport_punchout_line) {
1351                 transport_punchout_line->property_y1() = 0.0;
1352                 transport_punchout_line->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         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1638                 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1639         }
1640
1641         /* ::reposition_x_origin() doesn't work right here, since the old
1642            position may be zero already, and it does nothing in such
1643            circumstances.
1644         */
1645
1646         leftmost_frame = 0;
1647         
1648         track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1649         track_canvas_scroller.get_hadjustment()->set_value (0);
1650
1651         update_hscroller ();
1652         restore_ruler_visibility ();
1653         tempo_map_changed (Change (0));
1654
1655         edit_cursor->set_position (0);
1656         playhead_cursor->set_position (0);
1657
1658         start_scrolling ();
1659
1660         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1661         set_state (*node);
1662
1663         /* don't show master bus in a new session */
1664
1665         if (ARDOUR_UI::instance()->session_is_new ()) {
1666
1667                 TreeModel::Children rows = route_display_model->children();
1668                 TreeModel::Children::iterator i;
1669         
1670                 //route_list.freeze ();
1671                 
1672                 for (i = rows.begin(); i != rows.end(); ++i) {
1673                   TimeAxisView *tv =  (*i)[route_display_columns.tv];
1674                         AudioTimeAxisView *atv;
1675
1676                         if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1677                                 if (atv->route().master()) {
1678                                         route_list.get_selection()->unselect (i);
1679                                         //(*i)->unselect ();
1680                                 }
1681                         }
1682                 }
1683
1684                 //route_list.thaw ();
1685         }
1686 }
1687
1688 void
1689 Editor::build_cursors ()
1690 {
1691         using namespace Gdk;
1692
1693         Gdk::Color fg ("#ff0000"); /* Red. */
1694         Gdk::Color bg ("#0000ff"); /* Blue. */
1695
1696         {
1697                 RefPtr<Bitmap> source, mask;
1698                 source = Bitmap::create (hand_bits, hand_width, hand_height);
1699                 mask = Bitmap::create (handmask_bits, handmask_width, handmask_height);
1700                 grabber_cursor = new Gdk::Cursor (source, mask, fg, bg, hand_x_hot, hand_y_hot);
1701         }
1702         
1703         Gdk::Color mbg ("#000000" ); /* Black */
1704         Gdk::Color mfg ("#0000ff" ); /* Blue. */
1705
1706         {
1707                 RefPtr<Bitmap> source, mask;
1708                 source = Bitmap::create (mag_bits, mag_width, mag_height);
1709                 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1710                 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1711         }
1712
1713         Gdk::Color fbg ("#ffffff" );
1714         Gdk::Color ffg  ("#000000" );
1715         
1716         {
1717                 RefPtr<Bitmap> source, mask;
1718                 
1719                 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1720                 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1721                 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1722         }
1723         
1724         { 
1725                 RefPtr<Bitmap> source, mask;
1726                 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1727                 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1728                 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1729         }
1730
1731         cross_hair_cursor = new Gdk::Cursor (Gdk::CROSSHAIR);
1732         trimmer_cursor =  new Gdk::Cursor (Gdk::SB_H_DOUBLE_ARROW);
1733         selector_cursor = new Gdk::Cursor (Gdk::XTERM);
1734         time_fx_cursor = new Gdk::Cursor (Gdk::SIZING);
1735         wait_cursor = new Gdk::Cursor  (Gdk::WATCH);
1736         timebar_cursor = new Gdk::Cursor(Gdk::LEFT_PTR);
1737 }
1738
1739 void
1740 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1741 {
1742         using namespace Menu_Helpers;
1743         AudioRegionView* arv = static_cast<AudioRegionView*> (gtk_object_get_data (GTK_OBJECT(item), "regionview"));
1744
1745         if (arv == 0) {
1746                 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1747                 /*NOTREACHED*/
1748         }
1749
1750         MenuList& items (fade_context_menu.items());
1751
1752         items.clear ();
1753
1754         switch (item_type) {
1755         case FadeInItem:
1756         case FadeInHandleItem:
1757                 if (arv->region.fade_in_active()) {
1758                         items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), false)));
1759                 } else {
1760                         items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), true)));
1761                 }
1762                 
1763                 items.push_back (SeparatorElem());
1764                 
1765                 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Linear)));
1766                 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogB)));
1767                 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Fast)));
1768                 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogA)));
1769                 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Slow)));
1770                 break;
1771
1772         case FadeOutItem:
1773         case FadeOutHandleItem:
1774                 if (arv->region.fade_out_active()) {
1775                         items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), false)));
1776                 } else {
1777                         items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), true)));
1778                 }
1779                 
1780                 items.push_back (SeparatorElem());
1781                 
1782                 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Linear)));
1783                 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Fast)));
1784                 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogB)));
1785                 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogA)));
1786                 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Slow)));
1787
1788                 break;
1789         default:
1790                 fatal << _("programming error: ")
1791                       << X_("non-fade canvas item passed to popup_fade_context_menu()")
1792                       << endmsg;
1793                 /*NOTREACHED*/
1794         }
1795
1796         fade_context_menu.popup (button, time);
1797 }
1798
1799 void
1800 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, jack_nframes_t frame)
1801 {
1802         using namespace Menu_Helpers;
1803         Menu* (Editor::*build_menu_function)(jack_nframes_t);
1804         Menu *menu;
1805
1806         switch (item_type) {
1807         case RegionItem:
1808         case AudioRegionViewName:
1809         case AudioRegionViewNameHighlight:
1810                 if (with_selection) {
1811                         build_menu_function = &Editor::build_track_selection_context_menu;
1812                 } else {
1813                         build_menu_function = &Editor::build_track_region_context_menu;
1814                 }
1815                 break;
1816
1817         case SelectionItem:
1818                 if (with_selection) {
1819                         build_menu_function = &Editor::build_track_selection_context_menu;
1820                 } else {
1821                         build_menu_function = &Editor::build_track_context_menu;
1822                 }
1823                 break;
1824
1825         case CrossfadeViewItem:
1826                 build_menu_function = &Editor::build_track_crossfade_context_menu;
1827                 break;
1828
1829         case StreamItem:
1830                 if (clicked_audio_trackview->get_diskstream()) {
1831                         build_menu_function = &Editor::build_track_context_menu;
1832                 } else {
1833                         build_menu_function = &Editor::build_track_bus_context_menu;
1834                 }
1835                 break;
1836
1837         default:
1838                 /* probably shouldn't happen but if it does, we don't care */
1839                 return;
1840         }
1841
1842         menu = (this->*build_menu_function)(frame);
1843         menu->set_name ("ArdourContextMenu");
1844         
1845         /* now handle specific situations */
1846
1847         switch (item_type) {
1848         case RegionItem:
1849         case AudioRegionViewName:
1850         case AudioRegionViewNameHighlight:
1851                 if (!with_selection) {
1852                         if (region_edit_menu_split_item) {
1853                                 if (clicked_regionview && clicked_regionview->region.covers (edit_cursor->current_frame)) {
1854                                         // GTK2FIX find the action, change its sensitivity
1855                                         // region_edit_menu_split_item->set_sensitive (true);
1856                                 } else {
1857                                         // GTK2FIX see above
1858                                         // region_edit_menu_split_item->set_sensitive (false);
1859                                 }
1860                         }
1861                         if (region_edit_menu_split_multichannel_item) {
1862                                 if (clicked_regionview && clicked_regionview->region.n_channels() > 1) {
1863                                         // GTK2FIX find the action, change its sensitivity
1864                                         // region_edit_menu_split_multichannel_item->set_sensitive (true);
1865                                 } else {
1866                                         // GTK2FIX see above
1867                                         // region_edit_menu_split_multichannel_item->set_sensitive (false);
1868                                 }
1869                         }
1870                 }
1871                 break;
1872
1873         case SelectionItem:
1874                 break;
1875
1876         case CrossfadeViewItem:
1877                 break;
1878
1879         case StreamItem:
1880                 break;
1881
1882         default:
1883                 /* probably shouldn't happen but if it does, we don't care */
1884                 return;
1885         }
1886
1887         if (clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1888
1889                 /* Bounce to disk */
1890                 
1891                 using namespace Menu_Helpers;
1892                 MenuList& edit_items  = menu->items();
1893                 
1894                 edit_items.push_back (SeparatorElem());
1895
1896                 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1897                 case AudioTrack::NoFreeze:
1898                         edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1899                         break;
1900
1901                 case AudioTrack::Frozen:
1902                         edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1903                         break;
1904                         
1905                 case AudioTrack::UnFrozen:
1906                         edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1907                         break;
1908                 }
1909
1910         }
1911
1912         menu->popup (button, time);
1913 }
1914
1915 Menu*
1916 Editor::build_track_context_menu (jack_nframes_t ignored)
1917 {
1918         using namespace Menu_Helpers;
1919
1920         MenuList& edit_items = track_context_menu.items();
1921         edit_items.clear();
1922
1923         add_dstream_context_items (edit_items);
1924         return &track_context_menu;
1925 }
1926
1927 Menu*
1928 Editor::build_track_bus_context_menu (jack_nframes_t ignored)
1929 {
1930         using namespace Menu_Helpers;
1931
1932         MenuList& edit_items = track_context_menu.items();
1933         edit_items.clear();
1934
1935         add_bus_context_items (edit_items);
1936         return &track_context_menu;
1937 }
1938
1939 Menu*
1940 Editor::build_track_region_context_menu (jack_nframes_t frame)
1941 {
1942         using namespace Menu_Helpers;
1943         MenuList& edit_items  = track_region_context_menu.items();
1944         edit_items.clear();
1945
1946         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1947
1948         if (atv) {
1949                 DiskStream* ds;
1950                 Playlist* pl;
1951                 
1952                 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1953                         Playlist::RegionList* regions = pl->regions_at ((jack_nframes_t) floor ( (double)frame * ds->speed()));
1954                         for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1955                                 add_region_context_items (atv->view, (*i), edit_items);
1956                         }
1957                         delete regions;
1958                 }
1959         }
1960
1961         add_dstream_context_items (edit_items);
1962
1963         return &track_region_context_menu;
1964 }
1965
1966 Menu*
1967 Editor::build_track_crossfade_context_menu (jack_nframes_t frame)
1968 {
1969         using namespace Menu_Helpers;
1970         MenuList& edit_items  = track_crossfade_context_menu.items();
1971         edit_items.clear ();
1972
1973         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1974
1975         if (atv) {
1976                 DiskStream* ds;
1977                 Playlist* pl;
1978                 AudioPlaylist* apl;
1979
1980                 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = dynamic_cast<AudioPlaylist*> (pl)) != 0)) {
1981
1982                         Playlist::RegionList* regions = pl->regions_at (frame);
1983                         AudioPlaylist::Crossfades xfades;
1984
1985                         apl->crossfades_at (frame, xfades);
1986
1987                         bool many = xfades.size() > 1;
1988
1989                         for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1990                                 add_crossfade_context_items (atv->view, (*i), edit_items, many);
1991                         }
1992
1993                         for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1994                                 add_region_context_items (atv->view, (*i), edit_items);
1995                         }
1996
1997                         delete regions;
1998                 }
1999         }
2000
2001         add_dstream_context_items (edit_items);
2002
2003         return &track_crossfade_context_menu;
2004 }
2005
2006 Menu*
2007 Editor::build_track_selection_context_menu (jack_nframes_t ignored)
2008 {
2009         using namespace Menu_Helpers;
2010         MenuList& edit_items  = track_selection_context_menu.items();
2011         edit_items.clear ();
2012
2013         add_selection_context_items (edit_items);
2014         add_dstream_context_items (edit_items);
2015
2016         return &track_selection_context_menu;
2017 }
2018
2019 void
2020 Editor::add_crossfade_context_items (StreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many)
2021 {
2022         using namespace Menu_Helpers;
2023         Menu     *xfade_menu = manage (new Menu);
2024         MenuList& items       = xfade_menu->items();
2025         xfade_menu->set_name ("ArdourContextMenu");
2026         string str;
2027
2028         if (xfade->active()) {
2029                 str = _("Mute");
2030         } else { 
2031                 str = _("Unmute");
2032         }
2033
2034         items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), xfade)));
2035         items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), xfade)));
2036
2037         if (xfade->can_follow_overlap()) {
2038
2039                 if (xfade->following_overlap()) {
2040                         str = _("Convert to short");
2041                 } else {
2042                         str = _("Convert to full");
2043                 }
2044
2045                 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
2046         }
2047
2048         if (many) {
2049                 str = xfade->out().name();
2050                 str += "->";
2051                 str += xfade->in().name();
2052         } else {
2053                 str = _("Crossfade");
2054         }
2055
2056         edit_items.push_back (MenuElem (str, *xfade_menu));
2057         edit_items.push_back (SeparatorElem());
2058 }
2059
2060 void
2061 Editor::xfade_edit_left_region ()
2062 {
2063         if (clicked_crossfadeview) {
2064                 clicked_crossfadeview->left_view.show_region_editor ();
2065         }
2066 }
2067
2068 void
2069 Editor::xfade_edit_right_region ()
2070 {
2071         if (clicked_crossfadeview) {
2072                 clicked_crossfadeview->right_view.show_region_editor ();
2073         }
2074 }
2075
2076 void
2077 Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items)
2078 {
2079         using namespace Menu_Helpers;
2080         Menu     *region_menu = manage (new Menu);
2081         MenuList& items       = region_menu->items();
2082         region_menu->set_name ("ArdourContextMenu");
2083         
2084         AudioRegion* ar = 0;
2085
2086         if (region) {
2087                 ar = dynamic_cast<AudioRegion*> (region);
2088         }
2089
2090         /* when this particular menu pops up, make the relevant region 
2091            become selected.
2092         */
2093
2094         region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, region));
2095
2096         items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
2097         items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
2098         items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun  (*this, &Editor::lower_region_to_bottom)));
2099         items.push_back (SeparatorElem());
2100         items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
2101         items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
2102         items.push_back (SeparatorElem());
2103
2104         items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
2105         items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
2106         items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
2107         items.push_back (SeparatorElem());
2108
2109         /* XXX hopefully this nonsense will go away with SigC++ 2.X, where the compiler
2110            might be able to figure out which overloaded member function to use in
2111            a bind() call ...
2112         */
2113
2114         void (Editor::*type_A_pmf)(void (Region::*pmf)(bool), bool) = &Editor::region_selection_op;
2115
2116         items.push_back (MenuElem (_("Lock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, true)));
2117         items.push_back (MenuElem (_("Unlock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, false)));
2118         items.push_back (SeparatorElem());
2119
2120         if (region->muted()) {
2121                 items.push_back (MenuElem (_("Unmute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, false)));
2122         } else {
2123                 items.push_back (MenuElem (_("Mute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, true)));
2124         }
2125         items.push_back (SeparatorElem());
2126
2127         items.push_back (MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
2128         items.push_back (SeparatorElem());
2129
2130
2131         if (ar) {
2132
2133                 items.push_back (MenuElem (_("Toggle envelope visibility"), mem_fun(*this, &Editor::toggle_gain_envelope_visibility)));
2134                 items.push_back (MenuElem (_("Toggle envelope active"), mem_fun(*this, &Editor::toggle_gain_envelope_active)));
2135                 items.push_back (SeparatorElem());
2136
2137                 if (ar->scale_amplitude() != 1.0f) {
2138                         items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
2139                 } else {
2140                         items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
2141                 }
2142         }
2143         items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
2144         items.push_back (SeparatorElem());
2145
2146         /* Nudge region */
2147
2148         Menu *nudge_menu = manage (new Menu());
2149         MenuList& nudge_items = nudge_menu->items();
2150         nudge_menu->set_name ("ArdourContextMenu");
2151         
2152         nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
2153         nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
2154         nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
2155         nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
2156
2157         items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2158         items.push_back (SeparatorElem());
2159
2160         Menu *trim_menu = manage (new Menu);
2161         MenuList& trim_items = trim_menu->items();
2162         trim_menu->set_name ("ArdourContextMenu");
2163         
2164         trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
2165         trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
2166                              
2167         items.push_back (MenuElem (_("Trim"), *trim_menu));
2168         items.push_back (SeparatorElem());
2169
2170         items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
2171         region_edit_menu_split_item = &items.back();
2172
2173         items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
2174         region_edit_menu_split_multichannel_item = &items.back();
2175
2176         items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
2177         items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
2178         items.push_back (SeparatorElem());
2179         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
2180         items.push_back (SeparatorElem());
2181         items.push_back (MenuElem (_("Destroy"), mem_fun(*this, &Editor::destroy_clicked_region)));
2182
2183         /* OK, stick the region submenu at the top of the list, and then add
2184            the standard items.
2185         */
2186
2187         /* we have to hack up the region name because "_" has a special
2188            meaning for menu titles.
2189         */
2190
2191         string::size_type pos = 0;
2192         string menu_item_name = region->name();
2193
2194         while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
2195                 menu_item_name.replace (pos, 1, "__");
2196                 pos += 2;
2197         }
2198         
2199         edit_items.push_back (MenuElem (menu_item_name, *region_menu));
2200         edit_items.push_back (SeparatorElem());
2201 }
2202
2203 void
2204 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
2205 {
2206         using namespace Menu_Helpers;
2207         Menu     *selection_menu = manage (new Menu);
2208         MenuList& items       = selection_menu->items();
2209         selection_menu->set_name ("ArdourContextMenu");
2210
2211         items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
2212         items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
2213         items.push_back (SeparatorElem());
2214         items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::name_selection)));
2215         items.push_back (SeparatorElem());
2216         items.push_back (MenuElem (_("Create Region"), mem_fun(*this, &Editor::new_region_from_selection)));
2217         items.push_back (MenuElem (_("Separate Region"), mem_fun(*this, &Editor::separate_region_from_selection)));
2218         items.push_back (MenuElem (_("Crop Region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
2219         items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
2220         items.push_back (SeparatorElem());
2221         items.push_back (MenuElem (_("Duplicate"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
2222         items.push_back (SeparatorElem());
2223         items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_selection)));
2224         items.push_back (SeparatorElem());
2225         items.push_back (MenuElem (_("Fill range w/Region"), mem_fun(*this, &Editor::region_fill_selection)));
2226         
2227         edit_items.push_back (MenuElem (_("Range"), *selection_menu));
2228         edit_items.push_back (SeparatorElem());
2229 }
2230
2231 void
2232 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2233 {
2234         using namespace Menu_Helpers;
2235
2236         /* Playback */
2237
2238         Menu *play_menu = manage (new Menu);
2239         MenuList& play_items = play_menu->items();
2240         play_menu->set_name ("ArdourContextMenu");
2241         
2242         play_items.push_back (MenuElem (_("Play from edit cursor")));
2243         play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
2244         play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
2245         play_items.push_back (SeparatorElem());
2246         play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
2247         
2248         edit_items.push_back (MenuElem (_("Play"), *play_menu));
2249
2250         /* Selection */
2251
2252         Menu *select_menu = manage (new Menu);
2253         MenuList& select_items = select_menu->items();
2254         select_menu->set_name ("ArdourContextMenu");
2255         
2256         select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
2257         select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
2258         select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2259         select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
2260         select_items.push_back (SeparatorElem());
2261         select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
2262         select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
2263         select_items.push_back (SeparatorElem());
2264
2265         edit_items.push_back (MenuElem (_("Select"), *select_menu));
2266
2267         /* Cut-n-Paste */
2268
2269         Menu *cutnpaste_menu = manage (new Menu);
2270         MenuList& cutnpaste_items = cutnpaste_menu->items();
2271         cutnpaste_menu->set_name ("ArdourContextMenu");
2272         
2273         cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2274         cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2275         cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2276         cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
2277
2278         cutnpaste_items.push_back (SeparatorElem());
2279
2280         cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
2281         cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
2282
2283         cutnpaste_items.push_back (SeparatorElem());
2284
2285         cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
2286
2287         cutnpaste_items.push_back (SeparatorElem());
2288
2289         cutnpaste_items.push_back (MenuElem (_("New Region from range"), mem_fun(*this, &Editor::new_region_from_selection)));
2290         cutnpaste_items.push_back (MenuElem (_("Separate Range"), mem_fun(*this, &Editor::separate_region_from_selection)));
2291
2292         edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2293
2294         /* Adding new material */
2295         
2296         Menu *import_menu = manage (new Menu());
2297         MenuList& import_items = import_menu->items();
2298         import_menu->set_name ("ArdourContextMenu");
2299         
2300         import_items.push_back (MenuElem (_("Insert Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2301         import_items.push_back (MenuElem (_("Insert external sndfile"), bind (mem_fun(*this, &Editor::insert_sndfile), false)));
2302
2303         edit_items.push_back (MenuElem (_("Import"), *import_menu));
2304
2305         /* Nudge track */
2306
2307         Menu *nudge_menu = manage (new Menu());
2308         MenuList& nudge_items = nudge_menu->items();
2309         nudge_menu->set_name ("ArdourContextMenu");
2310         
2311         edit_items.push_back (SeparatorElem());
2312         nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2313         nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2314         nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2315         nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2316
2317         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2318 }
2319
2320 void
2321 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2322 {
2323         using namespace Menu_Helpers;
2324
2325         /* Playback */
2326
2327         Menu *play_menu = manage (new Menu);
2328         MenuList& play_items = play_menu->items();
2329         play_menu->set_name ("ArdourContextMenu");
2330         
2331         play_items.push_back (MenuElem (_("Play from edit cursor")));
2332         play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
2333         edit_items.push_back (MenuElem (_("Play"), *play_menu));
2334
2335         /* Selection */
2336
2337         Menu *select_menu = manage (new Menu);
2338         MenuList& select_items = select_menu->items();
2339         select_menu->set_name ("ArdourContextMenu");
2340         
2341         select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
2342         select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
2343         select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2344         select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
2345         select_items.push_back (SeparatorElem());
2346         select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
2347         select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
2348         select_items.push_back (SeparatorElem());
2349
2350         edit_items.push_back (MenuElem (_("Select"), *select_menu));
2351
2352         /* Cut-n-Paste */
2353
2354         Menu *cutnpaste_menu = manage (new Menu);
2355         MenuList& cutnpaste_items = cutnpaste_menu->items();
2356         cutnpaste_menu->set_name ("ArdourContextMenu");
2357         
2358         cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2359         cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2360         cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2361
2362         Menu *nudge_menu = manage (new Menu());
2363         MenuList& nudge_items = nudge_menu->items();
2364         nudge_menu->set_name ("ArdourContextMenu");
2365         
2366         edit_items.push_back (SeparatorElem());
2367         nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2368         nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2369         nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2370         nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2371
2372         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2373 }
2374
2375 /* CURSOR SETTING AND MARKS AND STUFF */
2376
2377 void
2378 Editor::set_snap_to (SnapType st)
2379 {
2380         snap_type = st;
2381         vector<string> txt = internationalize (snap_type_strings);
2382         snap_type_selector.set_active_text (txt[(int)st]);
2383
2384         instant_save ();
2385
2386         switch (snap_type) {
2387         case SnapToAThirtysecondBeat:
2388         case SnapToASixteenthBeat:
2389         case SnapToAEighthBeat:
2390         case SnapToAQuarterBeat:
2391         case SnapToAThirdBeat:
2392                 update_tempo_based_rulers ();
2393         default:
2394                 /* relax */
2395                 break;
2396     }
2397 }
2398
2399 void
2400 Editor::set_snap_mode (SnapMode mode)
2401 {
2402         snap_mode = mode;
2403         vector<string> txt = internationalize (snap_mode_strings);
2404         snap_mode_selector.set_active_text (txt[(int)mode]);
2405
2406         instant_save ();
2407 }
2408
2409 void
2410 Editor::add_location_from_selection ()
2411 {
2412         if (selection->time.empty()) {
2413                 return;
2414         }
2415
2416         if (session == 0 || clicked_trackview == 0) {
2417                 return;
2418         }
2419
2420         jack_nframes_t start = selection->time[clicked_selection].start;
2421         jack_nframes_t end = selection->time[clicked_selection].end;
2422
2423         Location *location = new Location (start, end, "selection");
2424
2425         session->begin_reversible_command (_("add marker"));
2426         session->add_undo (session->locations()->get_memento());
2427         session->locations()->add (location, true);
2428         session->add_redo_no_execute (session->locations()->get_memento());
2429         session->commit_reversible_command ();
2430 }
2431
2432 void
2433 Editor::add_location_from_playhead_cursor ()
2434 {
2435         jack_nframes_t where = session->audible_frame();
2436         
2437         Location *location = new Location (where, where, "mark", Location::IsMark);
2438         session->begin_reversible_command (_("add marker"));
2439         session->add_undo (session->locations()->get_memento());
2440         session->locations()->add (location, true);
2441         session->add_redo_no_execute (session->locations()->get_memento());
2442         session->commit_reversible_command ();
2443 }
2444
2445
2446 int
2447 Editor::set_state (const XMLNode& node)
2448 {
2449         const XMLProperty* prop;
2450         XMLNode* geometry;
2451         int x, y, width, height, xoff, yoff;
2452
2453         if ((geometry = find_named_node (node, "geometry")) == 0) {
2454
2455                 width = default_width;
2456                 height = default_height;
2457                 x = 1;
2458                 y = 1;
2459                 xoff = 0;
2460                 yoff = 21;
2461
2462         } else {
2463
2464                 width = atoi(geometry->property("x_size")->value());
2465                 height = atoi(geometry->property("y_size")->value());
2466                 x = atoi(geometry->property("x_pos")->value());
2467                 y = atoi(geometry->property("y_pos")->value());
2468                 xoff = atoi(geometry->property("x_off")->value());
2469                 yoff = atoi(geometry->property("y_off")->value());
2470         }
2471
2472         set_default_size(width, height);
2473         // GTK2FIX
2474         // set_position(x, y-yoff);
2475
2476         if ((prop = node.property ("zoom-focus"))) {
2477                 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2478         }
2479
2480         if ((prop = node.property ("zoom"))) {
2481                 set_frames_per_unit (atof (prop->value()));
2482         }
2483
2484         if ((prop = node.property ("snap-to"))) {
2485                 set_snap_to ((SnapType) atoi (prop->value()));
2486         }
2487
2488         if ((prop = node.property ("snap-mode"))) {
2489                 set_snap_mode ((SnapMode) atoi (prop->value()));
2490         }
2491
2492         if ((prop = node.property ("show-waveforms"))) {
2493                 bool yn = (prop->value() == "yes");
2494                 _show_waveforms = !yn;
2495                 set_show_waveforms (yn);
2496         }
2497
2498         if ((prop = node.property ("show-waveforms-recording"))) {
2499                 bool yn = (prop->value() == "yes");
2500                 _show_waveforms_recording = !yn;
2501                 set_show_waveforms_recording (yn);
2502         }
2503         
2504         if ((prop = node.property ("show-measures"))) {
2505                 bool yn = (prop->value() == "yes");
2506                 _show_measures = !yn;
2507                 set_show_measures (yn);
2508         }
2509
2510         if ((prop = node.property ("follow-playhead"))) {
2511                 bool yn = (prop->value() == "yes");
2512                 _follow_playhead = !yn;
2513                 set_follow_playhead (yn);
2514         }
2515
2516         if ((prop = node.property ("xfades-visible"))) {
2517                 bool yn = (prop->value() == "yes");
2518                 _xfade_visibility = !yn;
2519                 set_xfade_visibility (yn);
2520         }
2521
2522         if ((prop = node.property ("region-list-sort-type"))) {
2523                 region_list_sort_type = (Editing::RegionListSortType) -1; /* force change */
2524                 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2525         }
2526
2527         if ((prop = node.property ("mouse-mode"))) {
2528                 MouseMode m = str2mousemode(prop->value());
2529                 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2530                 set_mouse_mode (m, true);
2531         } else {
2532                 mouse_mode = MouseGain; /* lie, to force the mode switch */
2533                 set_mouse_mode (MouseObject, true);
2534         }
2535
2536         if ((prop = node.property ("editor-mixer-button"))) {
2537                 editor_mixer_button.set_active(prop->value() == "yes");
2538         }
2539
2540         return 0;
2541 }
2542
2543 XMLNode&
2544 Editor::get_state ()
2545 {
2546         XMLNode* node = new XMLNode ("Editor");
2547         char buf[32];
2548
2549         if (is_realized()) {
2550                 Glib::RefPtr<Gdk::Window> win = get_window();
2551                 
2552                 int x, y, xoff, yoff, width, height;
2553                 win->get_root_origin(x, y);
2554                 win->get_position(xoff, yoff);
2555                 win->get_size(width, height);
2556                 
2557                 XMLNode* geometry = new XMLNode ("geometry");
2558                 char buf[32];
2559                 snprintf(buf, sizeof(buf), "%d", width);
2560                 geometry->add_property("x_size", string(buf));
2561                 snprintf(buf, sizeof(buf), "%d", height);
2562                 geometry->add_property("y_size", string(buf));
2563                 snprintf(buf, sizeof(buf), "%d", x);
2564                 geometry->add_property("x_pos", string(buf));
2565                 snprintf(buf, sizeof(buf), "%d", y);
2566                 geometry->add_property("y_pos", string(buf));
2567                 snprintf(buf, sizeof(buf), "%d", xoff);
2568                 geometry->add_property("x_off", string(buf));
2569                 snprintf(buf, sizeof(buf), "%d", yoff);
2570                 geometry->add_property("y_off", string(buf));
2571                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&canvas_region_list_pane)->gobj()));
2572                 geometry->add_property("canvas_region_list_pane_pos", string(buf));
2573                 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(&track_list_canvas_pane)->gobj()));
2574                 geometry->add_property("track_list_canvas_pane_pos", string(buf));
2575                 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(&region_selection_vpane)->gobj()));
2576                 geometry->add_property("region_selection_pane_pos", string(buf));
2577                 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(&route_group_vpane)->gobj()));
2578                 geometry->add_property("route_group_pane_pos", string(buf));
2579
2580                 node->add_child_nocopy (*geometry);
2581         }
2582
2583         snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2584         node->add_property ("zoom-focus", buf);
2585         snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2586         node->add_property ("zoom", buf);
2587         snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2588         node->add_property ("snap-to", buf);
2589         snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2590         node->add_property ("snap-mode", buf);
2591
2592         node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2593         node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2594         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2595         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2596         node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2597         node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2598         node->add_property ("mouse-mode", enum2str(mouse_mode));
2599         node->add_property ("editor-mixer-button", editor_mixer_button.get_active() ? "yes" : "no");
2600         
2601         return *node;
2602 }
2603
2604
2605
2606 TimeAxisView *
2607 Editor::trackview_by_y_position (double y)
2608 {
2609         TrackViewList::iterator iter;
2610         TimeAxisView *tv;
2611
2612         for (iter = track_views.begin(); iter != track_views.end(); ++iter) {
2613
2614                 tv = *iter;
2615
2616                 if (tv->hidden()) {
2617                         continue;
2618                 }
2619
2620                 if (tv->y_position <= y && y < ((tv->y_position + tv->height + track_spacing))) {
2621                         return tv;
2622                 }
2623         }
2624
2625         return 0;
2626 }
2627
2628 void
2629 Editor::snap_to (jack_nframes_t& start, int32_t direction, bool for_mark)
2630 {
2631         Location* before = 0;
2632         Location* after = 0;
2633
2634         if (!session) {
2635                 return;
2636         }
2637
2638         const jack_nframes_t one_second = session->frame_rate();
2639         const jack_nframes_t one_minute = session->frame_rate() * 60;
2640
2641         jack_nframes_t presnap = start;
2642
2643         switch (snap_type) {
2644         case SnapToFrame:
2645                 break;
2646
2647         case SnapToCDFrame:
2648                 if (direction) {
2649                         start = (jack_nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2650                 } else {
2651                         start = (jack_nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2652                 }
2653                 break;
2654         case SnapToSMPTEFrame:
2655                 if (direction) {
2656                         start = (jack_nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2657                 } else {
2658                         start = (jack_nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) *  session->frames_per_smpte_frame());
2659                 }
2660                 break;
2661
2662         case SnapToSMPTESeconds:
2663                 if (session->smpte_offset_negative())
2664                 {
2665                         start += session->smpte_offset ();
2666                 } else {
2667                         start -= session->smpte_offset ();
2668                 }    
2669                 if (direction > 0) {
2670                         start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2671                 } else {
2672                         start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2673                 }
2674                 
2675                 if (session->smpte_offset_negative())
2676                 {
2677                         start -= session->smpte_offset ();
2678                 } else {
2679                         start += session->smpte_offset ();
2680                 }
2681                 break;
2682                 
2683         case SnapToSMPTEMinutes:
2684                 if (session->smpte_offset_negative())
2685                 {
2686                         start += session->smpte_offset ();
2687                 } else {
2688                         start -= session->smpte_offset ();
2689                 }
2690                 if (direction) {
2691                         start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2692                 } else {
2693                         start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2694                 }
2695                 if (session->smpte_offset_negative())
2696                 {
2697                         start -= session->smpte_offset ();
2698                 } else {
2699                         start += session->smpte_offset ();
2700                 }
2701                 break;
2702                 
2703         case SnapToSeconds:
2704                 if (direction) {
2705                         start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2706                 } else {
2707                         start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2708                 }
2709                 break;
2710                 
2711         case SnapToMinutes:
2712                 if (direction) {
2713                         start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2714                 } else {
2715                         start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2716                 }
2717                 break;
2718
2719         case SnapToBar:
2720                 start = session->tempo_map().round_to_bar (start, direction);
2721                 break;
2722
2723         case SnapToBeat:
2724                 start = session->tempo_map().round_to_beat (start, direction);
2725                 break;
2726
2727         case SnapToAThirtysecondBeat:
2728                 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2729                 break;
2730
2731         case SnapToASixteenthBeat:
2732                 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2733                 break;
2734
2735         case SnapToAEighthBeat:
2736                 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2737                 break;
2738
2739         case SnapToAQuarterBeat:
2740                 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2741                 break;
2742
2743         case SnapToAThirdBeat:
2744                 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2745                 break;
2746
2747         case SnapToEditCursor:
2748                 start = edit_cursor->current_frame;
2749                 break;
2750
2751         case SnapToMark:
2752                 if (for_mark) {
2753                         return;
2754                 }
2755
2756                 before = session->locations()->first_location_before (start);
2757                 after = session->locations()->first_location_after (start);
2758
2759                 if (direction < 0) {
2760                         if (before) {
2761                                 start = before->start();
2762                         } else {
2763                                 start = 0;
2764                         }
2765                 } else if (direction > 0) {
2766                         if (after) {
2767                                 start = after->start();
2768                         } else {
2769                                 start = session->current_end_frame();
2770                         }
2771                 } else {
2772                         if (before) {
2773                                 if (after) {
2774                                         /* find nearest of the two */
2775                                         if ((start - before->start()) < (after->start() - start)) {
2776                                                 start = before->start();
2777                                         } else {
2778                                                 start = after->start();
2779                                         }
2780                                 } else {
2781                                         start = before->start();
2782                                 }
2783                         } else if (after) {
2784                                 start = after->start();
2785                         } else {
2786                                 /* relax */
2787                         }
2788                 }
2789                 break;
2790
2791         case SnapToRegionStart:
2792         case SnapToRegionEnd:
2793         case SnapToRegionSync:
2794         case SnapToRegionBoundary:
2795                 if (!region_boundary_cache.empty()) {
2796                         vector<jack_nframes_t>::iterator i;
2797
2798                         if (direction > 0) {
2799                                 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2800                         } else {
2801                                 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2802                         }
2803                         
2804                         if (i != region_boundary_cache.end()) {
2805                                 start = *i;
2806                         } else {
2807                                 start = region_boundary_cache.back();
2808                         }
2809                 }
2810                 break;
2811         }
2812
2813         switch (snap_mode) {
2814         case SnapNormal:
2815                 return;                 
2816                 
2817         case SnapMagnetic:
2818                 
2819                 if (presnap > start) {
2820                         if (presnap > (start + unit_to_frame(snap_threshold))) {
2821                                 start = presnap;
2822                         }
2823                         
2824                 } else if (presnap < start) {
2825                         if (presnap < (start - unit_to_frame(snap_threshold))) {
2826                                 start = presnap;
2827                         }
2828                 }
2829                 
2830         default:
2831                 return;
2832                 
2833         }
2834 }
2835
2836 void
2837 Editor::setup_toolbar ()
2838 {
2839         string pixmap_path;
2840         vector<ToggleButton *> mouse_mode_buttons;
2841
2842         mouse_mode_buttons.push_back (&mouse_move_button);
2843         mouse_mode_buttons.push_back (&mouse_select_button);
2844         mouse_mode_buttons.push_back (&mouse_gain_button);
2845         mouse_mode_buttons.push_back (&mouse_zoom_button);
2846         mouse_mode_buttons.push_back (&mouse_timefx_button);
2847         mouse_mode_buttons.push_back (&mouse_audition_button);
2848         mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2849
2850         mouse_mode_button_table.set_homogeneous (true);
2851         mouse_mode_button_table.set_col_spacings (2);
2852         mouse_mode_button_table.set_row_spacings (2);
2853         mouse_mode_button_table.set_border_width (5);
2854
2855         mouse_mode_button_table.attach (mouse_move_button, 0, 1, 0, 1);
2856         mouse_mode_button_table.attach (mouse_select_button, 1, 2, 0, 1);
2857         mouse_mode_button_table.attach (mouse_zoom_button, 2, 3, 0, 1);
2858  
2859         mouse_mode_button_table.attach (mouse_gain_button, 0, 1, 1, 2);
2860         mouse_mode_button_table.attach (mouse_timefx_button, 1, 2, 1, 2);
2861         mouse_mode_button_table.attach (mouse_audition_button, 2, 3, 1, 2);
2862
2863         mouse_mode_tearoff = manage (new TearOff (mouse_mode_button_table));
2864         mouse_mode_tearoff->set_name ("MouseModeBase");
2865
2866         mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox), 
2867                                                   mouse_mode_tearoff->tearoff_window()));
2868         mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox), 
2869                                                   mouse_mode_tearoff->tearoff_window(), 1));
2870
2871         mouse_move_button.set_name ("MouseModeButton");
2872         mouse_select_button.set_name ("MouseModeButton");
2873         mouse_gain_button.set_name ("MouseModeButton");
2874         mouse_zoom_button.set_name ("MouseModeButton");
2875         mouse_timefx_button.set_name ("MouseModeButton");
2876         mouse_audition_button.set_name ("MouseModeButton");
2877
2878         ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("select/move objects"));
2879         ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("select/move ranges"));
2880         ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("draw gain automation"));
2881         ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("select zoom range"));
2882         ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("stretch/shrink regions"));
2883         ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("listen to specific regions"));
2884
2885         mouse_move_button.unset_flags (Gtk::CAN_FOCUS);
2886         mouse_select_button.unset_flags (Gtk::CAN_FOCUS);
2887         mouse_gain_button.unset_flags (Gtk::CAN_FOCUS);
2888         mouse_zoom_button.unset_flags (Gtk::CAN_FOCUS);
2889         mouse_timefx_button.unset_flags (Gtk::CAN_FOCUS);
2890         mouse_audition_button.unset_flags (Gtk::CAN_FOCUS);
2891
2892         mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2893         mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2894
2895         mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2896         mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2897         mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2898         mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2899         mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2900
2901         // mouse_move_button.set_active (true);
2902
2903         /* automation control */
2904
2905         global_automation_button.set_name ("MouseModeButton");
2906         automation_mode_button.set_name ("MouseModeButton");
2907
2908         automation_box.set_spacing (2);
2909         automation_box.set_border_width (2);
2910         automation_box.pack_start (global_automation_button, false, false);
2911         automation_box.pack_start (automation_mode_button, false, false);
2912
2913         /* Edit mode */
2914
2915         edit_mode_label.set_name ("ToolBarLabel");
2916
2917         edit_mode_selector.set_name ("EditModeSelector");
2918
2919         edit_mode_box.set_spacing (3);
2920         edit_mode_box.set_border_width (3);
2921
2922         /* XXX another disgusting hack because of the way combo boxes size themselves */
2923
2924         Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "EdgtMode", 2, 10);
2925         set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings));
2926         edit_mode_box.pack_start (edit_mode_label, false, false);
2927         edit_mode_box.pack_start (edit_mode_selector, false, false);
2928
2929         edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2930
2931         /* Snap Type */
2932
2933         snap_type_label.set_name ("ToolBarLabel");
2934
2935         snap_type_selector.set_name ("SnapTypeSelector");
2936
2937         snap_type_box.set_spacing (3);
2938         snap_type_box.set_border_width (3);
2939
2940         /* XXX another disgusting hack because of the way combo boxes size themselves */
2941
2942         const guint32 FUDGE = 10; // Combo's are stupid - they steal space from the entry for the button
2943         Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "Region bounds", 2+FUDGE, 10);
2944         set_popdown_strings (snap_type_selector, internationalize (snap_type_strings));
2945
2946         snap_type_box.pack_start (snap_type_label, false, false);
2947         snap_type_box.pack_start (snap_type_selector, false, false);
2948
2949         snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2950
2951         /* Snap mode, not snap type */
2952
2953         snap_mode_label.set_name ("ToolBarLabel");
2954
2955         snap_mode_selector.set_name ("SnapModeSelector");
2956         
2957         snap_mode_box.set_spacing (3);
2958         snap_mode_box.set_border_width (3);
2959
2960         Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "SngpMode", 2, 10);
2961         set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings));
2962
2963         snap_mode_box.pack_start (snap_mode_label, false, false);
2964         snap_mode_box.pack_start (snap_mode_selector, false, false);
2965
2966         snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2967
2968         /* Zoom focus mode */
2969
2970         zoom_focus_label.set_name ("ToolBarLabel");
2971
2972         zoom_focus_selector.set_name ("ZoomFocusSelector");
2973
2974         zoom_focus_box.set_spacing (3);
2975         zoom_focus_box.set_border_width (3);
2976
2977         /* XXX another disgusting hack because of the way combo boxes size themselves */
2978
2979         Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edgt Cursor", 2, 10);
2980         set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings));
2981
2982         zoom_focus_box.pack_start (zoom_focus_label, false, false);
2983         zoom_focus_box.pack_start (zoom_focus_selector, false, false);
2984
2985         zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2986
2987         /* selection/cursor clocks */
2988
2989         toolbar_selection_cursor_label.set_name ("ToolBarLabel");
2990         selection_start_clock_label.set_name ("ToolBarLabel");
2991         selection_end_clock_label.set_name ("ToolBarLabel");
2992         edit_cursor_clock_label.set_name ("ToolBarLabel");
2993
2994         selection_start_clock_label.set_text (_("Start:"));
2995         selection_end_clock_label.set_text (_("End:"));
2996         edit_cursor_clock_label.set_text (_("Edit:"));
2997
2998         toolbar_selection_clock_table.set_border_width (5);
2999         toolbar_selection_clock_table.set_col_spacings (2);
3000         toolbar_selection_clock_table.set_homogeneous (false);
3001
3002 //      toolbar_selection_clock_table.attach (selection_start_clock_label, 0, 1, 0, 1, 0, 0, 0, 0);
3003 //      toolbar_selection_clock_table.attach (selection_end_clock_label, 1, 2, 0, 1, 0, 0, 0, 0);
3004         toolbar_selection_clock_table.attach (edit_cursor_clock_label, 2, 3, 0, 1, FILL, FILL, 0, 0);
3005
3006 //      toolbar_selection_clock_table.attach (selection_start_clock, 0, 1, 1, 2, 0, 0);
3007 //      toolbar_selection_clock_table.attach (selection_end_clock, 1, 2, 1, 2, 0, 0);
3008         toolbar_selection_clock_table.attach (edit_cursor_clock, 2, 3, 1, 2, FILL, FILL);
3009
3010
3011 //      toolbar_clock_vbox.set_spacing (2);
3012 //      toolbar_clock_vbox.set_border_width (10);
3013         /* the editor/mixer button will be enabled at session connect */
3014
3015         editor_mixer_button.set_active(false);
3016         editor_mixer_button.set_sensitive(false);
3017
3018         HBox* hbox = new HBox;
3019
3020         hbox->pack_start (editor_mixer_button, false, false);
3021         hbox->pack_start (toolbar_selection_clock_table, false, false);
3022         hbox->pack_start (zoom_indicator_vbox, false, false); 
3023         hbox->pack_start (zoom_focus_box, false, false);
3024         hbox->pack_start (snap_type_box, false, false);
3025         hbox->pack_start (snap_mode_box, false, false);
3026         hbox->pack_start (edit_mode_box, false, false);
3027
3028         VBox *vbox = manage (new VBox);
3029
3030         vbox->set_spacing (3);
3031         vbox->set_border_width (3);
3032
3033         HBox *nbox = manage (new HBox);
3034         
3035         nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
3036         nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
3037
3038         nbox->pack_start (nudge_backward_button, false, false);
3039         nbox->pack_start (nudge_forward_button, false, false);
3040         nbox->pack_start (nudge_clock, false, false, 5);
3041
3042         nudge_label.set_name ("ToolBarLabel");
3043
3044         vbox->pack_start (nudge_label, false, false);
3045         vbox->pack_start (*nbox, false, false);
3046
3047         hbox->pack_start (*vbox, false, false);
3048
3049         hbox->show_all ();
3050
3051         tools_tearoff = new TearOff (*hbox);
3052         tools_tearoff->set_name ("MouseModeBase");
3053
3054         tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox), 
3055                                              tools_tearoff->tearoff_window()));
3056         tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox), 
3057                                              tools_tearoff->tearoff_window(), 0));
3058
3059
3060         toolbar_hbox.set_spacing (8);
3061         toolbar_hbox.set_border_width (2);
3062
3063         toolbar_hbox.pack_start (*tools_tearoff, false, false);
3064         toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
3065         
3066         toolbar_base.set_name ("ToolBarBase");
3067         toolbar_base.add (toolbar_hbox);
3068
3069         toolbar_frame.set_shadow_type (Gtk::SHADOW_OUT);
3070         toolbar_frame.set_name ("BaseFrame");
3071         toolbar_frame.add (toolbar_base);
3072 }
3073
3074 gint
3075 Editor::_autoscroll_canvas (void *arg)
3076 {
3077         return ((Editor *) arg)->autoscroll_canvas ();
3078 }
3079
3080 gint
3081 Editor::autoscroll_canvas ()
3082 {
3083         jack_nframes_t new_frame;
3084         bool keep_calling = true;
3085
3086         if (autoscroll_direction < 0) {
3087                 if (leftmost_frame < autoscroll_distance) {
3088                         new_frame = 0;
3089                 } else {
3090                         new_frame = leftmost_frame - autoscroll_distance;
3091                 }
3092         } else {
3093                 if (leftmost_frame > max_frames - autoscroll_distance) {
3094                         new_frame = max_frames;
3095                 } else {
3096                         new_frame = leftmost_frame + autoscroll_distance;
3097                 }
3098         }
3099
3100         if (new_frame != leftmost_frame) {
3101                 reposition_x_origin (new_frame);
3102         }
3103
3104         if (new_frame == 0 || new_frame == max_frames) {
3105                 /* we are done */
3106                 return FALSE;
3107         }
3108
3109         autoscroll_cnt++;
3110
3111         if (autoscroll_cnt == 1) {
3112
3113                 /* connect the timeout so that we get called repeatedly */
3114                 
3115                 autoscroll_timeout_tag = gtk_timeout_add (100, _autoscroll_canvas, this);
3116                 keep_calling = false;
3117
3118         } else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) {
3119                 
3120                 /* after about a while, speed up a bit by changing the timeout interval */
3121
3122                 autoscroll_timeout_tag = gtk_timeout_add (50, _autoscroll_canvas, this);
3123                 keep_calling = false;
3124                 
3125         } else if (autoscroll_cnt >= 20 && autoscroll_cnt < 30) {
3126
3127                 /* after about another while, speed up some more */
3128
3129                 autoscroll_timeout_tag = gtk_timeout_add (25, _autoscroll_canvas, this);
3130                 keep_calling = false;
3131
3132         } else if (autoscroll_cnt >= 30) {
3133
3134                 /* we've been scrolling for a while ... crank it up */
3135
3136                 autoscroll_distance = 10 * (jack_nframes_t) floor (canvas_width * frames_per_unit);
3137         }
3138
3139         return keep_calling;
3140 }
3141
3142 void
3143 Editor::start_canvas_autoscroll (int dir)
3144 {
3145         if (!session) {
3146                 return;
3147         }
3148
3149         stop_canvas_autoscroll ();
3150
3151         autoscroll_direction = dir;
3152         autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/10.0);
3153         autoscroll_cnt = 0;
3154         
3155         /* do it right now, which will start the repeated callbacks */
3156         
3157         autoscroll_canvas ();
3158 }
3159
3160 void
3161 Editor::stop_canvas_autoscroll ()
3162 {
3163         if (autoscroll_timeout_tag >= 0) {
3164                 gtk_timeout_remove (autoscroll_timeout_tag);
3165                 autoscroll_timeout_tag = -1;
3166         }
3167 }
3168
3169 int
3170 Editor::convert_drop_to_paths (vector<string>& paths, 
3171                                GdkDragContext     *context,
3172                                gint                x,
3173                                gint                y,
3174                                GtkSelectionData   *data,
3175                                guint               info,
3176                                guint               time)                               
3177
3178 {       
3179         string spath;
3180         char *path;
3181         int state;
3182         gchar *tname = gdk_atom_name (data->type);
3183
3184         if (session == 0 || strcmp (tname, "text/plain") != 0) {
3185                 return -1;
3186         }
3187
3188         /* Parse the "uri-list" format that Nautilus provides, 
3189            where each pathname is delimited by \r\n
3190         */
3191
3192         path = (char *) data->data;
3193         state = 0;
3194
3195         for (int n = 0; n < data->length; ++n) {
3196
3197                 switch (state) {
3198                 case 0:
3199                         if (path[n] == '\r') {
3200                                 state = 1;
3201                         } else {
3202                                 spath += path[n];
3203                         }
3204                         break;
3205                 case 1:
3206                         if (path[n] == '\n') {
3207                                 paths.push_back (spath);
3208                                 spath = "";
3209                                 state = 0;
3210                         } else {
3211                                 warning << _("incorrectly formatted URI list, ignored")
3212                                         << endmsg;
3213                                 return -1;
3214                         }
3215                         break;
3216                 }
3217         }
3218
3219         /* nautilus and presumably some other file managers prefix even text/plain with file:// */
3220                 
3221         for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
3222
3223                 // cerr << "dropped text was " << *p << endl;
3224
3225                 url_decode (*p);
3226
3227                 // cerr << "decoded was " << *p << endl;
3228
3229                 if ((*p).substr (0,7) == "file://") {
3230                         (*p) = (*p).substr (7);
3231                 }
3232         }
3233         
3234         return 0;
3235 }
3236
3237 void  
3238 Editor::track_canvas_drag_data_received  (GdkDragContext     *context,
3239                                           gint                x,
3240                                           gint                y,
3241                                           GtkSelectionData   *data,
3242                                           guint               info,
3243                                           guint               time)
3244 {
3245         TimeAxisView* tvp;
3246         AudioTimeAxisView* tv;
3247         double cy;
3248         vector<string> paths;
3249         string spath;
3250         GdkEvent ev;
3251         jack_nframes_t frame;
3252
3253         if (convert_drop_to_paths (paths, context, x, y, data, info, time)) {
3254                 goto out;
3255         }
3256
3257         /* D-n-D coordinates are window-relative, so convert to "world" coordinates
3258          */
3259
3260         double wx;
3261         double wy;
3262
3263         track_canvas.c2w( x, y, wx, wy);
3264
3265         ev.type = GDK_BUTTON_RELEASE;
3266         ev.button.x = wx;
3267         ev.button.y = wy;
3268
3269         frame = event_frame (&ev, 0, &cy);
3270
3271         snap_to (frame);
3272
3273         if ((tvp = trackview_by_y_position (cy)) == 0) {
3274
3275                 /* drop onto canvas background: create a new track */
3276
3277                 insert_paths_as_new_tracks (paths, false);
3278
3279                 
3280         } else if ((tv = dynamic_cast<AudioTimeAxisView*>(tvp)) != 0) {
3281
3282                 /* check that its an audio track, not a bus */
3283
3284                 if (tv->get_diskstream()) {
3285
3286                         for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
3287                                 insert_sndfile_into (*p, true, tv, frame);
3288                         }
3289                 }
3290
3291         }
3292
3293   out:
3294         gtk_drag_finish (context, TRUE, FALSE, time);
3295 }
3296
3297 void
3298 Editor::new_tempo_section ()
3299
3300 {
3301 }
3302
3303 void
3304 Editor::map_transport_state ()
3305 {
3306         ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
3307
3308         if (session->transport_stopped()) {
3309                 have_pending_keyboard_selection = false;
3310         }
3311 }
3312
3313 /* UNDO/REDO */
3314
3315 Editor::State::State ()
3316 {
3317         selection = new Selection;
3318 }
3319
3320 Editor::State::~State ()
3321 {
3322         delete selection;
3323 }
3324
3325 UndoAction
3326 Editor::get_memento () const
3327 {
3328         State *state = new State;
3329
3330         store_state (*state);
3331         return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
3332 }
3333
3334 void
3335 Editor::store_state (State& state) const
3336 {
3337         *state.selection = *selection;
3338 }
3339
3340 void
3341 Editor::restore_state (State *state)
3342 {
3343         if (*selection == *state->selection) {
3344                 return;
3345         }
3346
3347         *selection = *state->selection;
3348         time_selection_changed ();
3349         region_selection_changed ();
3350
3351         /* XXX other selection change handlers? */
3352 }
3353
3354 void
3355 Editor::begin_reversible_command (string name)
3356 {
3357         if (session) {
3358                 UndoAction ua = get_memento();
3359                 session->begin_reversible_command (name, &ua);
3360         }
3361 }
3362
3363 void
3364 Editor::commit_reversible_command ()
3365 {
3366         if (session) {
3367                 UndoAction ua = get_memento();
3368                 session->commit_reversible_command (&ua);
3369         }
3370 }
3371
3372 void
3373 Editor::flush_track_canvas ()
3374 {
3375         /* I don't think this is necessary, and only causes more problems.
3376            I'm commenting it out
3377            and if the imageframe folks don't have any issues, we can take
3378            out this method entirely
3379         */
3380         
3381         //gnome_canvas_update_now (GNOME_CANVAS(track_canvas));
3382         //gtk_main_iteration ();
3383 }
3384
3385 void
3386 Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove)
3387 {
3388         if (!clicked_trackview) {
3389                 return;
3390         }
3391
3392         if (with_undo) {
3393                 begin_reversible_command (_("set selected trackview"));
3394         }
3395
3396         if (add) {
3397                 
3398                 if (selection->selected (clicked_trackview)) {
3399                         if (!no_remove) {
3400                                 selection->remove (clicked_trackview);
3401                         }
3402                 } else {
3403                         selection->add (clicked_trackview);
3404                 }
3405                 
3406         } else {
3407
3408                 if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) {
3409                         /* no commit necessary */
3410                         return;
3411                 } 
3412
3413                 selection->set (clicked_trackview);
3414         }
3415         
3416         if (with_undo) {
3417                 commit_reversible_command ();
3418         }
3419 }
3420
3421 void
3422 Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no_remove)
3423 {
3424         if (!clicked_control_point) {
3425                 return;
3426         }
3427
3428         if (with_undo) {
3429                 begin_reversible_command (_("set selected control point"));
3430         }
3431
3432         if (add) {
3433                 
3434         } else {
3435
3436         }
3437         
3438         if (with_undo) {
3439                 commit_reversible_command ();
3440         }
3441 }
3442
3443 void
3444 Editor::set_selected_regionview_from_click (bool add, bool no_track_remove)
3445 {
3446         if (!clicked_regionview) {
3447                 return;
3448         }
3449
3450         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&clicked_regionview->get_time_axis_view());
3451
3452         if (!atv) {
3453                 return;
3454         }
3455
3456         RouteGroup* group = atv->route().edit_group();
3457         vector<AudioRegionView*> all_equivalent_regions;
3458         
3459         if (group && group->is_active()) {
3460
3461                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3462
3463                         AudioTimeAxisView* tatv;
3464
3465                         if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3466
3467                                 if (tatv->route().edit_group() != group) {
3468                                         continue;
3469                                 }
3470                         
3471                                 AudioPlaylist* pl;
3472                                 vector<AudioRegion*> results;
3473                                 AudioRegionView* marv;
3474                                 DiskStream* ds;
3475                                 
3476                                 if ((ds = tatv->get_diskstream()) == 0) {
3477                                         /* bus */
3478                                         continue;
3479                                 }
3480                                 
3481                                 if ((pl = ds->playlist()) != 0) {
3482                                         pl->get_equivalent_regions (clicked_regionview->region, 
3483                                                                     results);
3484                                 }
3485                                 
3486                                 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3487                                         if ((marv = tatv->view->find_view (**ir)) != 0) {
3488                                                 all_equivalent_regions.push_back (marv);
3489                                         }
3490                                 }
3491                                 
3492                         }
3493                 }
3494
3495         } else {
3496
3497                 all_equivalent_regions.push_back (clicked_regionview);
3498
3499         }
3500         
3501         begin_reversible_command (_("set selected regionview"));
3502         
3503         if (add) {
3504
3505                 if (clicked_regionview->get_selected()) {
3506                         if (group && group->is_active() && selection->audio_regions.size() > 1) {
3507                                 /* reduce selection down to just the one clicked */
3508                                 selection->set (clicked_regionview);
3509                         } else {
3510                                 selection->remove (clicked_regionview);
3511                         }
3512                 } else {
3513                         selection->add (all_equivalent_regions);
3514                 }
3515
3516                 set_selected_track_from_click (add, false, no_track_remove);
3517                 
3518         } else {
3519
3520                 // karsten wiese suggested these two lines to make
3521                 // a selected region rise to the top. but this
3522                 // leads to a mismatch between actual layering
3523                 // and visual layering. resolution required ....
3524                 //
3525                 // gnome_canvas_item_raise_to_top (clicked_regionview->get_canvas_group());
3526                 // gnome_canvas_item_raise_to_top (clicked_regionview->get_time_axis_view().canvas_display);
3527
3528                 if (clicked_regionview->get_selected()) {
3529                         /* no commit necessary: we are the one selected. */
3530                         return;
3531
3532                 } else {
3533                         
3534                         selection->set (all_equivalent_regions);
3535                         set_selected_track_from_click (add, false, false);
3536                 }
3537         }
3538
3539         commit_reversible_command () ;
3540 }
3541
3542 void
3543 Editor::set_selected_regionview_from_region_list (Region& r, bool add)
3544 {
3545         vector<AudioRegionView*> all_equivalent_regions;
3546         AudioRegion* region;
3547
3548         if ((region = dynamic_cast<AudioRegion*>(&r)) == 0) {
3549                 return;
3550         }
3551
3552         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3553                 
3554                 AudioTimeAxisView* tatv;
3555                 
3556                 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3557                         
3558                         AudioPlaylist* pl;
3559                         vector<AudioRegion*> results;
3560                         AudioRegionView* marv;
3561                         DiskStream* ds;
3562                         
3563                         if ((ds = tatv->get_diskstream()) == 0) {
3564                                 /* bus */
3565                                 continue;
3566                         }
3567
3568                         if ((pl = ds->playlist()) != 0) {
3569                                 pl->get_region_list_equivalent_regions (*region, results);
3570                         }
3571                         
3572                         for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3573                                 if ((marv = tatv->view->find_view (**ir)) != 0) {
3574                                         all_equivalent_regions.push_back (marv);
3575                                 }
3576                         }
3577                         
3578                 }
3579         }
3580         
3581         begin_reversible_command (_("set selected regions"));
3582         
3583         if (add) {
3584
3585                 selection->add (all_equivalent_regions);
3586                 
3587         } else {
3588
3589                 selection->set (all_equivalent_regions);
3590         }
3591
3592         commit_reversible_command () ;
3593 }
3594
3595 bool
3596 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r)
3597 {
3598         AudioRegionView* rv;
3599         AudioRegion* ar;
3600
3601         if ((ar = dynamic_cast<AudioRegion*> (r)) == 0) {
3602                 return TRUE;
3603         }
3604
3605         if ((rv = sv->find_view (*ar)) == 0) {
3606                 return TRUE;
3607         }
3608
3609         /* don't reset the selection if its something other than 
3610            a single other region.
3611         */
3612
3613         if (selection->audio_regions.size() > 1) {
3614                 return TRUE;
3615         }
3616         
3617         begin_reversible_command (_("set selected regions"));
3618         
3619         selection->set (rv);
3620
3621         commit_reversible_command () ;
3622
3623         return TRUE;
3624 }
3625
3626 void
3627 Editor::set_edit_group_solo (Route& route, bool yn)
3628 {
3629         RouteGroup *edit_group;
3630
3631         if ((edit_group = route.edit_group()) != 0) {
3632                 edit_group->apply (&Route::set_solo, yn, this);
3633         } else {
3634                 route.set_solo (yn, this);
3635         }
3636 }
3637
3638 void
3639 Editor::set_edit_group_mute (Route& route, bool yn)
3640 {
3641         RouteGroup *edit_group = 0;
3642
3643         if ((edit_group == route.edit_group()) != 0) {
3644                 edit_group->apply (&Route::set_mute, yn, this);
3645         } else {
3646                 route.set_mute (yn, this);
3647         }
3648 }
3649                 
3650 void
3651 Editor::set_edit_menu (Menu& menu)
3652 {
3653         edit_menu = &menu;
3654         edit_menu->signal_map_event().connect (mem_fun(*this, &Editor::edit_menu_map_handler));
3655 }
3656
3657 bool
3658 Editor::edit_menu_map_handler (GdkEventAny* ev)
3659 {
3660         using namespace Menu_Helpers;
3661         MenuList& edit_items = edit_menu->items();
3662         string label;
3663
3664         /* Nuke all the old items */
3665                 
3666         edit_items.clear ();
3667
3668         if (session == 0) {
3669                 return false;
3670         }
3671
3672         if (session->undo_depth() == 0) {
3673                 label = _("Undo");
3674         } else {
3675                 label = string_compose(_("Undo (%1)"), session->next_undo());
3676         }
3677         
3678         edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::undo), 1U)));
3679         
3680         if (session->undo_depth() == 0) {
3681                 edit_items.back().set_sensitive (false);
3682         }
3683         
3684         if (session->redo_depth() == 0) {
3685                 label = _("Redo");
3686         } else {
3687                 label = string_compose(_("Redo (%1)"), session->next_redo());
3688         }
3689         
3690         edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::redo), 1U)));
3691         if (session->redo_depth() == 0) {
3692                 edit_items.back().set_sensitive (false);
3693         }
3694
3695         vector<MenuItem*> mitems;
3696
3697         edit_items.push_back (SeparatorElem());
3698         edit_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
3699         mitems.push_back (&edit_items.back());
3700         edit_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
3701         mitems.push_back (&edit_items.back());
3702         edit_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
3703         mitems.push_back (&edit_items.back());
3704         edit_items.push_back (SeparatorElem());
3705         edit_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
3706         mitems.push_back (&edit_items.back());
3707         edit_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
3708         mitems.push_back (&edit_items.back());
3709         edit_items.push_back (SeparatorElem());
3710
3711         if (selection->empty()) {
3712                 for (vector<MenuItem*>::iterator i = mitems.begin(); i != mitems.end(); ++i) {
3713                         (*i)->set_sensitive (false);
3714                 }
3715         }
3716
3717         Menu* import_menu = manage (new Menu());
3718         import_menu->set_name ("ArdourContextMenu");
3719         MenuList& import_items = import_menu->items();
3720         
3721         import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::import_audio), true)));
3722         import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::import_audio), false)));
3723
3724         Menu* embed_menu = manage (new Menu());
3725         embed_menu->set_name ("ArdourContextMenu");
3726         MenuList& embed_items = embed_menu->items();
3727
3728         embed_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::insert_sndfile), true)));
3729         embed_items.push_back (MenuElem (_("... as new region"), mem_fun(*this, &Editor::embed_audio)));
3730
3731         edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu));
3732         edit_items.push_back (MenuElem (_("Embed audio (link)"), *embed_menu));
3733         edit_items.push_back (SeparatorElem());
3734
3735         edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture)));
3736         if (!session->have_captured()) {
3737                 edit_items.back().set_sensitive (false);
3738         }
3739
3740         return false;
3741 }
3742
3743 void
3744 Editor::duplicate_dialog (bool dup_region)
3745 {
3746         if (dup_region) {
3747                 if (clicked_regionview == 0) {
3748                         return;
3749                 }
3750         } else {
3751                 if (selection->time.length() == 0) {
3752                         return;
3753                 }
3754         }
3755
3756         ArdourDialog win ("duplicate dialog");
3757         Entry  entry;
3758         Label  label (_("Duplicate how many times?"));
3759
3760         win.get_vbox()->pack_start (label);
3761         win.add_action_widget (entry, RESPONSE_ACCEPT);
3762         win.add_button (Stock::OK, RESPONSE_ACCEPT);
3763         win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3764
3765         win.set_position (Gtk::WIN_POS_MOUSE);
3766
3767         entry.set_text ("1");
3768         set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15);
3769         entry.select_region (0, entry.get_text_length());
3770         entry.grab_focus ();
3771
3772         // GTK2FIX
3773         // win.get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
3774
3775
3776         switch (win.run ()) {
3777         case RESPONSE_ACCEPT:
3778                 break;
3779         default:
3780                 return;
3781         }
3782
3783         string text = entry.get_text();
3784         float times;
3785
3786         if (sscanf (text.c_str(), "%f", &times) == 1) {
3787                 if (dup_region) {
3788                         AudioRegionSelection regions;
3789                         regions.add (clicked_regionview);
3790                         duplicate_some_regions (regions, times);
3791                 } else {
3792                         duplicate_selection (times);
3793                 }
3794         }
3795 }
3796
3797 void
3798 Editor::show_verbose_canvas_cursor ()
3799 {
3800         verbose_canvas_cursor->raise_to_top();
3801         verbose_canvas_cursor->show();
3802         verbose_cursor_visible = true;
3803 }
3804
3805 void
3806 Editor::hide_verbose_canvas_cursor ()
3807 {
3808         verbose_canvas_cursor->hide();
3809         verbose_cursor_visible = false;
3810 }
3811
3812 void
3813 Editor::set_verbose_canvas_cursor (string txt, double x, double y)
3814 {
3815         /* XXX get origin of canvas relative to root window,
3816            add x and y and check compared to gdk_screen_{width,height}
3817         */
3818         verbose_canvas_cursor->property_text() = txt.c_str();
3819         verbose_canvas_cursor->property_x() = x;
3820         verbose_canvas_cursor->property_y() = y;
3821 }
3822
3823 void
3824 Editor::set_verbose_canvas_cursor_text (string txt)
3825 {
3826         verbose_canvas_cursor->property_text() = txt.c_str();
3827 }
3828
3829 void
3830 Editor::edit_mode_selection_done ()
3831 {
3832         if (session == 0) {
3833                 return;
3834         }
3835
3836         string choice = edit_mode_selector.get_active_text();
3837         EditMode mode = Slide;
3838
3839         if (choice == _("Splice")) {
3840                 mode = Splice;
3841         } else if (choice == _("Slide")) {
3842                 mode = Slide;
3843         }
3844
3845         session->set_edit_mode (mode);
3846 }       
3847
3848 void
3849 Editor::snap_type_selection_done ()
3850 {
3851         if (session == 0) {
3852                 return;
3853         }
3854
3855         string choice = snap_type_selector.get_active_text();
3856         SnapType snaptype = SnapToFrame;
3857         
3858         if (choice == _("Beats/3")) {
3859                 snaptype = SnapToAThirdBeat;
3860         } else if (choice == _("Beats/4")) {
3861                 snaptype = SnapToAQuarterBeat;
3862         } else if (choice == _("Beats/8")) {
3863                 snaptype = SnapToAEighthBeat;
3864         } else if (choice == _("Beats/16")) {
3865                 snaptype = SnapToASixteenthBeat;
3866         } else if (choice == _("Beats/32")) {
3867                 snaptype = SnapToAThirtysecondBeat;
3868         } else if (choice == _("Beats")) {
3869                 snaptype = SnapToBeat;
3870         } else if (choice == _("Bars")) {
3871                 snaptype = SnapToBar;
3872         } else if (choice == _("Marks")) {
3873                 snaptype = SnapToMark;
3874         } else if (choice == _("Edit Cursor")) {
3875                 snaptype = SnapToEditCursor;
3876         } else if (choice == _("Region starts")) {
3877                 snaptype = SnapToRegionStart;
3878         } else if (choice == _("Region ends")) {
3879                 snaptype = SnapToRegionEnd;
3880         } else if (choice == _("Region bounds")) {
3881                 snaptype = SnapToRegionBoundary;
3882         } else if (choice == _("Region syncs")) {
3883                 snaptype = SnapToRegionSync;
3884         } else if (choice == _("CD Frames")) {
3885                 snaptype = SnapToCDFrame;
3886         } else if (choice == _("SMPTE Frames")) {
3887                 snaptype = SnapToSMPTEFrame;
3888         } else if (choice == _("SMPTE Seconds")) {
3889                 snaptype = SnapToSMPTESeconds;
3890         } else if (choice == _("SMPTE Minutes")) {
3891                 snaptype = SnapToSMPTEMinutes;
3892         } else if (choice == _("Seconds")) {
3893                 snaptype = SnapToSeconds;
3894         } else if (choice == _("Minutes")) {
3895                 snaptype = SnapToMinutes;
3896         } else if (choice == _("None")) {
3897                 snaptype = SnapToFrame;
3898         }
3899         
3900         set_snap_to (snaptype);
3901 }       
3902
3903 void
3904 Editor::snap_mode_selection_done ()
3905 {
3906         if(session == 0) {
3907                 return;
3908         }
3909
3910         string choice = snap_mode_selector.get_active_text();
3911         SnapMode mode = SnapNormal;
3912
3913         if (choice == _("Normal")) {
3914                 mode = SnapNormal;
3915         } else if (choice == _("Magnetic")) {
3916                 mode = SnapMagnetic;
3917         }
3918
3919         set_snap_mode (mode);
3920 }
3921
3922 void
3923 Editor::zoom_focus_selection_done ()
3924 {
3925         if (session == 0) {
3926                 return;
3927         }
3928
3929         string choice = zoom_focus_selector.get_active_text();
3930         ZoomFocus focus_type = ZoomFocusLeft;
3931
3932         if (choice == _("Left")) {
3933                 focus_type = ZoomFocusLeft;
3934         } else if (choice == _("Right")) {
3935                 focus_type = ZoomFocusRight;
3936         } else if (choice == _("Center")) {
3937                 focus_type = ZoomFocusCenter;
3938         } else if (choice == _("Playhead")) {
3939                 focus_type = ZoomFocusPlayhead;
3940         } else if (choice == _("Edit Cursor")) {
3941                 focus_type = ZoomFocusEdit;
3942         } 
3943
3944         set_zoom_focus (focus_type);
3945 }       
3946
3947 gint
3948 Editor::edit_controls_button_release (GdkEventButton* ev)
3949 {
3950         if (Keyboard::is_context_menu_event (ev)) {
3951                 ARDOUR_UI::instance()->add_route ();
3952         }
3953         return TRUE;
3954 }
3955
3956 void
3957 Editor::track_selection_changed ()
3958 {
3959         switch (selection->tracks.size()){
3960         case 0:
3961                 break;
3962         default:
3963                 set_selected_mixer_strip (*(selection->tracks.front()));
3964                 break;
3965         }
3966
3967         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3968                 (*i)->set_selected (false);
3969                 if (mouse_mode == MouseRange) {
3970                         (*i)->hide_selection ();
3971                 }
3972         }
3973
3974         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3975                 (*i)->set_selected (true);
3976                 if (mouse_mode == MouseRange) {
3977                         (*i)->show_selection (selection->time);
3978                 }
3979         }
3980 }
3981
3982 void
3983 Editor::time_selection_changed ()
3984 {
3985         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3986                 (*i)->hide_selection ();
3987         }
3988
3989         if (selection->tracks.empty()) {
3990                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3991                         (*i)->show_selection (selection->time);
3992                 }
3993         } else {
3994                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3995                         (*i)->show_selection (selection->time);
3996                 }
3997         }
3998 }
3999
4000 void
4001 Editor::region_selection_changed ()
4002 {
4003         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4004                 (*i)->set_selected_regionviews (selection->audio_regions);
4005         }
4006 }
4007
4008 void
4009 Editor::point_selection_changed ()
4010 {
4011         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4012                 (*i)->set_selected_points (selection->points);
4013         }
4014 }
4015
4016 void
4017 Editor::run_sub_event_loop ()
4018 {
4019         sub_event_loop_status = 0;
4020         Main::run ();
4021 }
4022
4023 void
4024 Editor::finish_sub_event_loop (int status)
4025 {
4026         Main::quit ();
4027         sub_event_loop_status = status;
4028 }
4029
4030 gint
4031 Editor::finish_sub_event_loop_on_delete (GdkEventAny *ignored, int32_t status)
4032 {
4033         finish_sub_event_loop (status);
4034         return TRUE;
4035 }
4036
4037 gint
4038 Editor::mouse_select_button_release (GdkEventButton* ev)
4039 {
4040         /* this handles just right-clicks */
4041
4042         if (ev->button != 3) {
4043                 return FALSE;
4044         }
4045
4046         return TRUE;
4047 }
4048
4049 Editor::TrackViewList *
4050 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
4051 {
4052         TrackViewList *v;
4053         TrackViewList::iterator i;
4054
4055         v = new TrackViewList;
4056
4057         if (track == 0 && group == 0) {
4058
4059                 /* all views */
4060
4061                 for (i = track_views.begin(); i != track_views.end (); ++i) {
4062                         v->push_back (*i);
4063                 }
4064
4065         } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
4066                 
4067                 /* just the view for this track
4068                  */
4069
4070                 v->push_back (track);
4071
4072         } else {
4073                 
4074                 /* views for all tracks in the edit group */
4075                 
4076                 for (i  = track_views.begin(); i != track_views.end (); ++i) {
4077
4078                         if (group == 0 || (*i)->edit_group() == group) {
4079                                 v->push_back (*i);
4080                         }
4081                 }
4082         }
4083         
4084         return v;
4085 }
4086
4087 void
4088 Editor::set_zoom_focus (ZoomFocus f)
4089 {
4090         if (zoom_focus != f) {
4091                 zoom_focus = f;
4092                 vector<string> txt = internationalize (zoom_focus_strings);
4093                 zoom_focus_selector.set_active_text (txt[(int)f]);
4094                 ZoomFocusChanged (); /* EMIT_SIGNAL */
4095
4096                 instant_save ();
4097         }
4098 }
4099
4100 void
4101 Editor::ensure_float (Window& win)
4102 {
4103         win.set_transient_for (*this);
4104 }
4105
4106 void 
4107 Editor::pane_allocation_handler (Gtk::Allocation &alloc, Gtk::Paned* which)
4108 {
4109         /* recover or initialize pane positions. do this here rather than earlier because
4110            we don't want the positions to change the child allocations, which they seem to do.
4111          */
4112
4113         int pos;
4114         XMLProperty* prop;
4115         char buf[32];
4116         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
4117         int width, height;
4118         static int32_t done[4] = { 0, 0, 0, 0 };
4119         XMLNode* geometry;
4120
4121         if ((geometry = find_named_node (*node, "geometry")) == 0) {
4122                 width = default_width;
4123                 height = default_height;
4124         } else {
4125                 width = atoi(geometry->property("x_size")->value());
4126                 height = atoi(geometry->property("y_size")->value());
4127         }
4128
4129         if (which == static_cast<Gtk::Paned*> (&track_list_canvas_pane)) {
4130
4131                 if (done[0]) {
4132                         return;
4133                 }
4134
4135                 if (!geometry || (prop = geometry->property("track_list_canvas_pane_pos")) == 0) {
4136                         pos = 75;
4137                         snprintf (buf, sizeof(buf), "%d", pos);
4138                 } else {
4139                         pos = atoi (prop->value());
4140                 }
4141
4142                 if ((done[0] = GTK_WIDGET(track_list_canvas_pane.gobj())->allocation.width > pos)) {
4143                         track_list_canvas_pane.set_position (pos);
4144                 }
4145
4146         } else if (which == static_cast<Gtk::Paned*> (&canvas_region_list_pane)) {
4147
4148                 if (done[1]) {
4149                         return;
4150                 }
4151
4152                 if (!geometry || (prop = geometry->property("canvas_region_list_pane_pos")) == 0) {
4153                         pos = width - (95 * 2);
4154                         snprintf (buf, sizeof(buf), "%d", pos);
4155                 } else {
4156                         pos = atoi (prop->value());
4157                 }
4158
4159                 if ((done[1] = GTK_WIDGET(canvas_region_list_pane.gobj())->allocation.width > pos)) {
4160                         canvas_region_list_pane.set_position (pos);
4161                 }
4162
4163         } else if (which == static_cast<Gtk::Paned*> (&route_group_vpane)) {
4164
4165                 if (done[2]) {
4166                         return;
4167                 }
4168
4169                 if (!geometry || (prop = geometry->property("route_group_pane_pos")) == 0) {
4170                         pos = width - (95 * 2);
4171                         snprintf (buf, sizeof(buf), "%d", pos);
4172                 } else {
4173                         pos = atoi (prop->value());
4174                 }
4175
4176                 if ((done[2] = GTK_WIDGET(route_group_vpane.gobj())->allocation.height > pos)) {
4177                         route_group_vpane.set_position (pos);
4178                 }
4179
4180         } else if (which == static_cast<Gtk::Paned*> (&region_selection_vpane)) {
4181
4182                 if (done[3]) {
4183                         return;
4184                 }
4185
4186                 if (!geometry || (prop = geometry->property("region_selection_pane_pos")) == 0) {
4187                         pos = width - (95 * 2);
4188                         snprintf (buf, sizeof(buf), "%d", pos);
4189                 } else {
4190                         pos = atoi (prop->value());
4191                 }
4192
4193                 if ((done[3] = GTK_WIDGET(region_selection_vpane.gobj())->allocation.height > pos)) { 
4194                         region_selection_vpane.set_position (pos);
4195                 }
4196         }
4197 }
4198
4199 void
4200 Editor::detach_tearoff (Gtk::Box* b, Gtk::Window* w)
4201 {
4202         if (tools_tearoff->torn_off() && 
4203             mouse_mode_tearoff->torn_off()) {
4204                 top_hbox.remove (toolbar_frame);
4205         }
4206         
4207         ensure_float (*w);
4208 }
4209
4210 void
4211 Editor::reattach_tearoff (Gtk::Box* b, Gtk::Window* w, int32_t n)
4212 {
4213         if (toolbar_frame.get_parent() == 0) {
4214                 top_hbox.pack_end (toolbar_frame);
4215         }
4216 }
4217
4218 void
4219 Editor::set_show_measures (bool yn)
4220 {
4221         if (_show_measures != yn) {
4222                 hide_measures ();
4223
4224                 if ((_show_measures = yn) == true) {
4225                         draw_measures ();
4226                 }
4227                 DisplayControlChanged (ShowMeasures);
4228                 instant_save ();
4229         }
4230 }
4231
4232 void
4233 Editor::set_follow_playhead (bool yn)
4234 {
4235         if (_follow_playhead != yn) {
4236                 if ((_follow_playhead = yn) == true) {
4237                         /* catch up */
4238                         update_current_screen ();
4239                 }
4240                 DisplayControlChanged (FollowPlayhead);
4241                 instant_save ();
4242         }
4243 }
4244
4245 void
4246 Editor::toggle_xfade_active (Crossfade* xfade)
4247 {
4248         xfade->set_active (!xfade->active());
4249 }
4250
4251 void
4252 Editor::toggle_xfade_length (Crossfade* xfade)
4253 {
4254         xfade->set_follow_overlap (!xfade->following_overlap());
4255 }
4256
4257 void
4258 Editor::edit_xfade (Crossfade* xfade)
4259 {
4260         CrossfadeEditor cew (*session, *xfade, xfade->fade_in().get_min_y(), 1.0);
4261                 
4262         ensure_float (cew);
4263         
4264         // GTK2FIX
4265         // cew.signal_delete_event().connect (mem_fun (cew, &ArdourDialog::wm_doi_event_stop));
4266
4267         switch (cew.run ()) {
4268         case RESPONSE_ACCEPT:
4269                 break;
4270         default:
4271                 return;
4272         }
4273         
4274         cew.apply ();
4275         xfade->StateChanged (Change (~0));
4276 }
4277
4278 PlaylistSelector&
4279 Editor::playlist_selector () const
4280 {
4281         return *_playlist_selector;
4282 }
4283
4284 jack_nframes_t
4285 Editor::get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next)
4286 {
4287         jack_nframes_t ret;
4288
4289         ret = nudge_clock.current_duration (pos);
4290         next = ret + 1; /* XXXX fix me */
4291
4292         return ret;
4293 }
4294
4295 void
4296 Editor::end_location_changed (Location* location)
4297 {
4298         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
4299         track_canvas_scroller.get_hadjustment()->set_upper (location->end() / frames_per_unit);
4300 }
4301
4302 int
4303 Editor::playlist_deletion_dialog (Playlist* pl)
4304 {
4305         ArdourDialog dialog ("playlist deletion dialog");
4306         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
4307                                  "If left alone, no audio files used by it will be cleaned.\n"
4308                                  "If deleted, audio files used by it alone by will cleaned."),
4309                                pl->name()));
4310
4311         dialog.set_position (Gtk::WIN_POS_CENTER);
4312         dialog.get_vbox()->pack_start (label);
4313
4314         dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
4315         dialog.add_button (_("Keep playlist"), RESPONSE_CANCEL);
4316         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4317
4318         switch (dialog.run ()) {
4319         case RESPONSE_ACCEPT:
4320                 /* delete the playlist */
4321                 return 0;
4322                 break;
4323
4324         case RESPONSE_REJECT:
4325                 /* keep the playlist */
4326                 return 1;
4327                 break;
4328
4329         default:
4330                 break;
4331         }
4332
4333         return -1;
4334 }
4335
4336 bool
4337 Editor::audio_region_selection_covers (jack_nframes_t where)
4338 {
4339         for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) {
4340                 if ((*a)->region.covers (where)) {
4341                         return true;
4342                 }
4343         }
4344
4345         return false;
4346 }
4347
4348 void
4349 Editor::prepare_for_cleanup ()
4350 {
4351         cut_buffer->clear_audio_regions ();
4352         cut_buffer->clear_playlists ();
4353
4354         selection->clear_audio_regions ();
4355         selection->clear_playlists ();
4356 }
4357
4358 void
4359 Editor::init_colormap ()
4360 {
4361         for (size_t x = 0; x < sizeof (color_id_strs) / sizeof (color_id_strs[0]); ++x) {
4362                 pair<ColorID,int> newpair;
4363                 
4364                 newpair.first = (ColorID) x;
4365                 newpair.second = rgba_from_style (enum2str (newpair.first), 0, 0, 0, 255);
4366                 color_map.insert (newpair);
4367         }
4368 }
4369
4370 Location*
4371 Editor::transport_loop_location()
4372 {
4373         if (session) {
4374                 return session->locations()->auto_loop_location();
4375         } else {
4376                 return 0;
4377         }
4378 }
4379
4380 Location*
4381 Editor::transport_punch_location()
4382 {
4383         if (session) {
4384                 return session->locations()->auto_punch_location();
4385         } else {
4386                 return 0;
4387         }
4388 }