fixup botched xfade-as-audioregion; apply work from 2.0-ongoing
[ardour.git] / gtk2_ardour / editor.cc
1 /*
2     Copyright (C) 2000-2007 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 */
19
20 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <unistd.h>
23 #include <cstdlib>
24 #include <cmath>
25 #include <string>
26 #include <algorithm>
27
28 #include <sigc++/bind.h>
29
30 #include <pbd/convert.h>
31 #include <pbd/error.h>
32 #include <pbd/enumwriter.h>
33 #include <pbd/memento_command.h>
34
35 #include <glibmm/miscutils.h>
36 #include <gtkmm/image.h>
37 #include <gdkmm/color.h>
38 #include <gdkmm/bitmap.h>
39
40 #include <gtkmm2ext/grouped_buttons.h>
41 #include <gtkmm2ext/gtk_ui.h>
42 #include <gtkmm2ext/tearoff.h>
43 #include <gtkmm2ext/utils.h>
44 #include <gtkmm2ext/window_title.h>
45 #include <gtkmm2ext/choice.h>
46
47 #include <ardour/audio_track.h>
48 #include <ardour/audio_diskstream.h>
49 #include <ardour/plugin_manager.h>
50 #include <ardour/location.h>
51 #include <ardour/audioplaylist.h>
52 #include <ardour/audioregion.h>
53 #include <ardour/region.h>
54 #include <ardour/session_route.h>
55 #include <ardour/tempo.h>
56 #include <ardour/utils.h>
57
58 #include <control_protocol/control_protocol.h>
59
60 #include "ardour_ui.h"
61 #include "editor.h"
62 #include "keyboard.h"
63 #include "marker.h"
64 #include "playlist_selector.h"
65 #include "audio_region_view.h"
66 #include "rgb_macros.h"
67 #include "selection.h"
68 #include "audio_streamview.h"
69 #include "time_axis_view.h"
70 #include "audio_time_axis.h"
71 #include "utils.h"
72 #include "crossfade_view.h"
73 #include "editing.h"
74 #include "public_editor.h"
75 #include "crossfade_edit.h"
76 #include "canvas_impl.h"
77 #include "actions.h"
78 #include "gui_thread.h"
79
80 #ifdef FFT_ANALYSIS
81 #include "analysis_window.h"
82 #endif
83
84 #include "i18n.h"
85
86 #ifdef WITH_CMT
87 #include "imageframe_socket_handler.h"
88 #endif
89
90 using namespace std;
91 using namespace sigc;
92 using namespace ARDOUR;
93 using namespace PBD;
94 using namespace Gtk;
95 using namespace Glib;
96 using namespace Gtkmm2ext;
97 using namespace Editing;
98
99 using PBD::internationalize;
100 using PBD::atoi;
101
102 const double Editor::timebar_height = 15.0;
103
104 #include "editor_xpms"
105
106 static const gchar *_snap_type_strings[] = {
107         N_("None"),
108         N_("CD Frames"),
109         N_("SMPTE Frames"),
110         N_("SMPTE Seconds"),
111         N_("SMPTE Minutes"),
112         N_("Seconds"),
113         N_("Minutes"),
114         N_("Beats/32"),
115         N_("Beats/16"),
116         N_("Beats/8"),
117         N_("Beats/4"),
118         N_("Beats/3"),
119         N_("Beats"),
120         N_("Bars"),
121         N_("Marks"),
122         N_("Edit Cursor"),
123         N_("Region starts"),
124         N_("Region ends"),
125         N_("Region syncs"),
126         N_("Region bounds"),
127         0
128 };
129
130 static const gchar *_snap_mode_strings[] = {
131         N_("Normal"),
132         N_("Magnetic"),
133         0
134 };
135
136 static const gchar *_zoom_focus_strings[] = {
137         N_("Left"),
138         N_("Right"),
139         N_("Center"),
140         N_("Playhead"),
141         N_("Edit Cursor"),
142         0
143 };
144
145 /* Soundfile  drag-n-drop */
146
147 Gdk::Cursor* Editor::cross_hair_cursor = 0;
148 Gdk::Cursor* Editor::selector_cursor = 0;
149 Gdk::Cursor* Editor::trimmer_cursor = 0;
150 Gdk::Cursor* Editor::grabber_cursor = 0;
151 Gdk::Cursor* Editor::zoom_cursor = 0;
152 Gdk::Cursor* Editor::time_fx_cursor = 0;
153 Gdk::Cursor* Editor::fader_cursor = 0;
154 Gdk::Cursor* Editor::speaker_cursor = 0;
155 Gdk::Cursor* Editor::wait_cursor = 0;
156 Gdk::Cursor* Editor::timebar_cursor = 0;
157
158 void
159 show_me_the_size (Requisition* r, const char* what)
160 {
161         cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
162 }
163
164 void 
165 check_adjustment (Gtk::Adjustment* adj)
166 {
167         cerr << "CHANGE adj  = " 
168              << adj->get_lower () <<  ' '
169              << adj->get_upper () <<  ' '
170              << adj->get_value () <<  ' '
171              << adj->get_step_increment () <<  ' '
172              << adj->get_page_increment () <<  ' '
173              << adj->get_page_size () <<  ' '
174              << endl;
175
176 }
177
178 Editor::Editor ()
179         : 
180           /* time display buttons */
181
182           minsec_label (_("Mins:Secs")),
183           bbt_label (_("Bars:Beats")),
184           smpte_label (_("Timecode")),
185           frame_label (_("Frames")),
186           tempo_label (_("Tempo")),
187           meter_label (_("Meter")),
188           mark_label (_("Location Markers")),
189           range_mark_label (_("Range Markers")),
190           transport_mark_label (_("Loop/Punch Ranges")),
191
192           edit_packer (3, 3, false),
193
194           /* the values here don't matter: layout widgets
195              reset them as needed.
196           */
197
198           vertical_adjustment (0.0, 0.0, 10.0, 400.0),
199           horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
200
201           /* tool bar related */
202
203           edit_cursor_clock (X_("editcursor"), false, X_("EditCursorClock"), true),
204           zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
205           
206           toolbar_selection_clock_table (2,3),
207           
208           automation_mode_button (_("mode")),
209           global_automation_button (_("automation")),
210
211 #ifdef WITH_CMT
212           image_socket_listener(0),
213 #endif
214
215           /* nudge */
216
217           nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
218
219 {
220         constructed = false;
221
222         /* we are a singleton */
223
224         PublicEditor::_instance = this;
225
226         session = 0;
227
228         selection = new Selection;
229         cut_buffer = new Selection;
230
231         selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
232         selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
233         selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
234         selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
235
236         clicked_regionview = 0;
237         clicked_axisview = 0;
238         clicked_routeview = 0;
239         clicked_crossfadeview = 0;
240         clicked_control_point = 0;
241         latest_regionview = 0;
242         last_update_frame = 0;
243         drag_info.item = 0;
244         current_mixer_strip = 0;
245         current_bbt_points = 0;
246
247         snap_type_strings = I18N (_snap_type_strings);
248         snap_mode_strings = I18N (_snap_mode_strings);
249         zoom_focus_strings = I18N(_zoom_focus_strings);
250
251         snap_type = SnapToFrame;
252         set_snap_to (snap_type);
253         snap_mode = SnapNormal;
254         set_snap_mode (snap_mode);
255         snap_threshold = 5.0;
256         bbt_beat_subdivision = 4;
257         canvas_width = 0;
258         canvas_height = 0;
259         autoscroll_active = false;
260         autoscroll_timeout_tag = -1;
261         interthread_progress_window = 0;
262
263 #ifdef FFT_ANALYSIS
264         analysis_window = 0;
265 #endif
266
267         current_interthread_info = 0;
268         _show_measures = true;
269         _show_waveforms = true;
270         _show_waveforms_recording = true;
271         first_action_message = 0;
272         export_dialog = 0;
273         show_gain_after_trim = false;
274         ignore_route_list_reorder = false;
275         no_route_list_redisplay = false;
276         verbose_cursor_on = true;
277         route_removal = false;
278         show_automatic_regions_in_region_list = true;
279         region_list_sort_type = (Editing::RegionListSortType) 0; 
280         have_pending_keyboard_selection = false;
281         _follow_playhead = true;
282         _xfade_visibility = true;
283         editor_ruler_menu = 0;
284         no_ruler_shown_update = false;
285         edit_group_list_menu = 0;
286         route_list_menu = 0;
287         region_list_menu = 0;
288         marker_menu = 0;
289         start_end_marker_menu = 0;
290         range_marker_menu = 0;
291         marker_menu_item = 0;
292         tm_marker_menu = 0;
293         transport_marker_menu = 0;
294         new_transport_marker_menu = 0;
295         editor_mixer_strip_width = Wide;
296         show_editor_mixer_when_tracks_arrive = false;
297         temp_location = 0;
298         leftmost_frame = 0;
299         ignore_mouse_mode_toggle = false;
300         current_stepping_trackview = 0;
301         entered_track = 0;
302         entered_regionview = 0;
303         clear_entered_track = false;
304         _new_regionviews_show_envelope = false;
305         current_timestretch = 0;
306         in_edit_group_row_change = false;
307         last_canvas_frame = 0;
308         edit_cursor = 0;
309         playhead_cursor = 0;
310         button_release_can_deselect = true;
311         canvas_idle_queued = false;
312         _dragging_playhead = false;
313         _dragging_hscrollbar = false;
314
315         location_marker_color = color_map[cLocationMarker];
316         location_range_color = color_map[cLocationRange];
317         location_cd_marker_color = color_map[cLocationCDMarker];
318         location_loop_color = color_map[cLocationLoop];
319         location_punch_color = color_map[cLocationPunch];
320
321         range_marker_drag_rect = 0;
322         marker_drag_line = 0;
323         
324         set_mouse_mode (MouseObject, true);
325
326         frames_per_unit = 2048; /* too early to use reset_zoom () */
327         reset_hscrollbar_stepping ();
328         
329         zoom_focus = ZoomFocusLeft;
330         set_zoom_focus (ZoomFocusLeft);
331         zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
332
333         initialize_rulers ();
334         initialize_canvas ();
335
336         edit_controls_vbox.set_spacing (0);
337         horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
338         vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
339         
340         track_canvas.set_hadjustment (horizontal_adjustment);
341         track_canvas.set_vadjustment (vertical_adjustment);
342         time_canvas.set_hadjustment (horizontal_adjustment);
343
344         track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
345         time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
346         
347         controls_layout.add (edit_controls_vbox);
348         controls_layout.set_name ("EditControlsBase");
349         controls_layout.add_events (Gdk::SCROLL_MASK);
350         controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
351         
352         controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
353         controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
354         controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
355
356         edit_vscrollbar.set_adjustment (vertical_adjustment);
357         edit_hscrollbar.set_adjustment (horizontal_adjustment);
358
359         edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
360         edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
361         edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
362
363         edit_hscrollbar.set_name ("EditorHScrollbar");
364
365         build_cursors ();
366         setup_toolbar ();
367
368         edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
369         
370         time_canvas_vbox.pack_start (*_ruler_separator, false, false);
371         time_canvas_vbox.pack_start (*minsec_ruler, false, false);
372         time_canvas_vbox.pack_start (*smpte_ruler, false, false);
373         time_canvas_vbox.pack_start (*frames_ruler, false, false);
374         time_canvas_vbox.pack_start (*bbt_ruler, false, false);
375         time_canvas_vbox.pack_start (time_canvas, true, true);
376         time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
377
378         bbt_label.set_name ("EditorTimeButton");
379         bbt_label.set_size_request (-1, (int)timebar_height);
380         bbt_label.set_alignment (1.0, 0.5);
381         bbt_label.set_padding (5,0);
382         minsec_label.set_name ("EditorTimeButton");
383         minsec_label.set_size_request (-1, (int)timebar_height);
384         minsec_label.set_alignment (1.0, 0.5);
385         minsec_label.set_padding (5,0);
386         smpte_label.set_name ("EditorTimeButton");
387         smpte_label.set_size_request (-1, (int)timebar_height);
388         smpte_label.set_alignment (1.0, 0.5);
389         smpte_label.set_padding (5,0);
390         frame_label.set_name ("EditorTimeButton");
391         frame_label.set_size_request (-1, (int)timebar_height);
392         frame_label.set_alignment (1.0, 0.5);
393         frame_label.set_padding (5,0);
394         tempo_label.set_name ("EditorTimeButton");
395         tempo_label.set_size_request (-1, (int)timebar_height);
396         tempo_label.set_alignment (1.0, 0.5);
397         tempo_label.set_padding (5,0);
398         meter_label.set_name ("EditorTimeButton");
399         meter_label.set_size_request (-1, (int)timebar_height);
400         meter_label.set_alignment (1.0, 0.5);
401         meter_label.set_padding (5,0);
402         mark_label.set_name ("EditorTimeButton");
403         mark_label.set_size_request (-1, (int)timebar_height);
404         mark_label.set_alignment (1.0, 0.5);
405         mark_label.set_padding (5,0);
406         range_mark_label.set_name ("EditorTimeButton");
407         range_mark_label.set_size_request (-1, (int)timebar_height);
408         range_mark_label.set_alignment (1.0, 0.5);
409         range_mark_label.set_padding (5,0);
410         transport_mark_label.set_name ("EditorTimeButton");
411         transport_mark_label.set_size_request (-1, (int)timebar_height);
412         transport_mark_label.set_alignment (1.0, 0.5);
413         transport_mark_label.set_padding (5,0);
414         
415         time_button_vbox.pack_start (minsec_label, false, false);
416         time_button_vbox.pack_start (smpte_label, false, false);
417         time_button_vbox.pack_start (frame_label, false, false);
418         time_button_vbox.pack_start (bbt_label, false, false);
419         time_button_vbox.pack_start (meter_label, false, false);
420         time_button_vbox.pack_start (tempo_label, false, false);
421         time_button_vbox.pack_start (mark_label, false, false);
422
423         time_button_event_box.add (time_button_vbox);
424         
425         time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
426         time_button_event_box.set_name ("TimebarLabelBase");
427         time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
428
429         time_button_frame.add(time_button_event_box);
430         time_button_frame.property_shadow_type() = Gtk::SHADOW_OUT;
431
432         /* these enable us to have a dedicated window (for cursor setting, etc.) 
433            for the canvas areas.
434         */
435
436         track_canvas_event_box.add (track_canvas);
437
438         time_canvas_event_box.add (time_canvas_vbox);
439         time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
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_border_width (0);
445         edit_packer.set_name ("EditorWindow");
446         
447         edit_packer.attach (edit_vscrollbar,         3, 4, 1, 2,    FILL,        FILL|EXPAND, 0, 0);
448
449         edit_packer.attach (time_button_frame,       0, 2, 0, 1,    FILL,        FILL, 0, 0);
450         edit_packer.attach (time_canvas_event_box,   2, 3, 0, 1,    FILL|EXPAND, FILL, 0, 0);
451
452         edit_packer.attach (controls_layout,         1, 2, 1, 2,    FILL,        FILL|EXPAND, 0, 0);
453         edit_packer.attach (track_canvas_event_box,  2, 3, 1, 2,    FILL|EXPAND, FILL|EXPAND, 0, 0);
454
455         edit_packer.attach (zoom_box,                1, 2, 2, 3,    FILL,         FILL, 0, 0);
456         edit_packer.attach (edit_hscrollbar,         2, 3, 2, 3,    FILL|EXPAND,  FILL, 0, 0);
457
458         bottom_hbox.set_border_width (2);
459         bottom_hbox.set_spacing (3);
460
461         route_display_model = ListStore::create(route_display_columns);
462         route_list_display.set_model (route_display_model);
463         route_list_display.append_column (_("Show"), route_display_columns.visible);
464         route_list_display.append_column (_("Name"), route_display_columns.text);
465         route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
466         route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
467         route_list_display.set_headers_visible (true);
468         route_list_display.set_name ("TrackListDisplay");
469         route_list_display.get_selection()->set_mode (SELECTION_NONE);
470         route_list_display.set_reorderable (true);
471         route_list_display.set_size_request (100,-1);
472
473         CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
474         route_list_visible_cell->property_activatable() = true;
475         route_list_visible_cell->property_radio() = false;
476         
477         route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
478         route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
479
480         route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
481
482         route_list_scroller.add (route_list_display);
483         route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
484
485         group_model = ListStore::create(group_columns);
486         edit_group_display.set_model (group_model);
487         edit_group_display.append_column (_("Name"), group_columns.text);
488         edit_group_display.append_column (_("Active"), group_columns.is_active);
489         edit_group_display.append_column (_("Show"), group_columns.is_visible);
490         edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
491         edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
492         edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
493         edit_group_display.get_column (0)->set_expand (true);
494         edit_group_display.get_column (1)->set_expand (false);
495         edit_group_display.get_column (2)->set_expand (false);
496         edit_group_display.set_headers_visible (true);
497
498         /* name is directly editable */
499
500         CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
501         name_cell->property_editable() = true;
502         name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
503
504         /* use checkbox for the active + visible columns */
505
506         CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
507         active_cell->property_activatable() = true;
508         active_cell->property_radio() = false;
509
510         active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
511         active_cell->property_activatable() = true;
512         active_cell->property_radio() = false;
513
514         group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
515
516         edit_group_display.set_name ("EditGroupList");
517         edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
518         edit_group_display.set_headers_visible (true);
519         edit_group_display.set_reorderable (false);
520         edit_group_display.set_rules_hint (true);
521         edit_group_display.set_size_request (75, -1);
522
523         edit_group_display_scroller.add (edit_group_display);
524         edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
525
526         edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
527
528         VBox* edit_group_display_packer = manage (new VBox());
529         HBox* edit_group_display_button_box = manage (new HBox());
530         edit_group_display_button_box->set_homogeneous (true);
531
532         Button* edit_group_add_button = manage (new Button ());
533         Button* edit_group_remove_button = manage (new Button ());
534
535         Widget* w;
536
537         w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
538         w->show();
539         edit_group_add_button->add (*w);
540
541         w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
542         w->show();
543         edit_group_remove_button->add (*w);
544
545         edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
546         edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
547         
548         edit_group_display_button_box->pack_start (*edit_group_add_button);
549         edit_group_display_button_box->pack_start (*edit_group_remove_button);
550
551         edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
552         edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
553
554         region_list_display.set_size_request (100, -1);
555         region_list_display.set_name ("RegionListDisplay");
556
557         region_list_model = TreeStore::create (region_list_columns);
558         region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
559         region_list_model->set_sort_column (0, SORT_ASCENDING);
560
561         region_list_display.set_model (region_list_model);
562         region_list_display.append_column (_("Regions"), region_list_columns.name);
563         region_list_display.set_headers_visible (false);
564
565         region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
566         
567         TreeViewColumn* tv_col = region_list_display.get_column(0);
568         CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
569         tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
570         tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
571         
572         region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
573         region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
574
575         /* setup DnD handling */
576         
577         list<TargetEntry> region_list_target_table;
578         
579         region_list_target_table.push_back (TargetEntry ("text/plain"));
580         region_list_target_table.push_back (TargetEntry ("text/uri-list"));
581         region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
582         
583         region_list_display.add_drop_targets (region_list_target_table);
584         region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
585
586         region_list_scroller.add (region_list_display);
587         region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
588
589         region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
590         region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
591         region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
592         region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
593         region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
594         // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
595         
596         named_selection_scroller.add (named_selection_display);
597         named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
598
599         named_selection_model = TreeStore::create (named_selection_columns);
600         named_selection_display.set_model (named_selection_model);
601         named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
602         named_selection_display.set_headers_visible (false);
603         named_selection_display.set_size_request (100, -1);
604         named_selection_display.set_name ("NamedSelectionDisplay");
605         
606         named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
607         named_selection_display.set_size_request (100, -1);
608         named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
609         named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
610         named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
611
612         /* SNAPSHOTS */
613
614         snapshot_display_model = ListStore::create (snapshot_display_columns);
615         snapshot_display.set_model (snapshot_display_model);
616         snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
617         snapshot_display.set_name ("SnapshotDisplay");
618         snapshot_display.set_size_request (75, -1);
619         snapshot_display.set_headers_visible (false);
620         snapshot_display.set_reorderable (false);
621         snapshot_display_scroller.add (snapshot_display);
622         snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
623
624         snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
625         snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
626
627         Gtk::Label* nlabel;
628
629         nlabel = manage (new Label (_("Regions")));
630         nlabel->set_angle (-90);
631         the_notebook.append_page (region_list_scroller, *nlabel);
632         nlabel = manage (new Label (_("Tracks/Busses")));
633         nlabel->set_angle (-90);
634         the_notebook.append_page (route_list_scroller, *nlabel);
635         nlabel = manage (new Label (_("Snapshots")));
636         nlabel->set_angle (-90);
637         the_notebook.append_page (snapshot_display_scroller, *nlabel);
638         nlabel = manage (new Label (_("Edit Groups")));
639         nlabel->set_angle (-90);
640         the_notebook.append_page (*edit_group_display_packer, *nlabel);
641         nlabel = manage (new Label (_("Chunks")));
642         nlabel->set_angle (-90);
643         the_notebook.append_page (named_selection_scroller, *nlabel);
644
645         the_notebook.set_show_tabs (true);
646         the_notebook.set_scrollable (true);
647         the_notebook.popup_enable ();
648         the_notebook.set_tab_pos (Gtk::POS_RIGHT);
649
650         post_maximal_editor_width = 0;
651         post_maximal_pane_position = 0;
652         edit_pane.pack1 (edit_packer, true, true);
653         edit_pane.pack2 (the_notebook, false, true);
654         
655         edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
656
657         top_hbox.pack_start (toolbar_frame, true, true);
658
659         HBox *hbox = manage (new HBox);
660         hbox->pack_start (edit_pane, true, true);
661
662         global_vpacker.pack_start (top_hbox, false, false);
663         global_vpacker.pack_start (*hbox, true, true);
664
665         global_hpacker.pack_start (global_vpacker, true, true);
666
667         set_name ("EditorWindow");
668         add_accel_group (ActionManager::ui_manager->get_accel_group());
669
670         vpacker.pack_end (global_hpacker, true, true);
671
672         /* register actions now so that set_state() can find them and set toggles/checks etc */
673         
674         register_actions ();
675         
676         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
677         set_state (*node);
678
679         _playlist_selector = new PlaylistSelector();
680         _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
681
682         RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
683
684         /* nudge stuff */
685
686         nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
687         nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
688
689         ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
690         ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
691
692         nudge_forward_button.set_name ("TransportButton");
693         nudge_backward_button.set_name ("TransportButton");
694
695         fade_context_menu.set_name ("ArdourContextMenu");
696
697         /* icons, titles, WM stuff */
698
699         list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
700         Glib::RefPtr<Gdk::Pixbuf> icon;
701
702         if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
703                 window_icons.push_back (icon);
704         }
705         if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
706                 window_icons.push_back (icon);
707         }
708         if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
709                 window_icons.push_back (icon);
710         }
711         if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
712                 window_icons.push_back (icon);
713         }
714         if (!window_icons.empty()) {
715                 set_icon_list (window_icons);
716                 set_default_icon_list (window_icons);
717         }
718
719         WindowTitle title(Glib::get_application_name());
720         title += _("Editor");
721         set_title (title.get_string());
722         set_wmclass (X_("ardour_editor"), "Ardour");
723
724         add (vpacker);
725         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
726
727         signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
728         signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
729
730         /* allow external control surfaces/protocols to do various things */
731
732         ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
733         ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
734         ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
735         ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
736
737         Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
738
739         constructed = true;
740         instant_save ();
741 }
742
743 Editor::~Editor()
744 {
745 #ifdef WITH_CMT
746         if(image_socket_listener)
747         {
748                 if(image_socket_listener->is_connected())
749                 {
750                         image_socket_listener->close_connection() ;
751                 }
752                 
753                 delete image_socket_listener ;
754                 image_socket_listener = 0 ;
755         }
756 #endif
757 }
758
759 void
760 Editor::add_toplevel_controls (Container& cont)
761 {
762         vpacker.pack_start (cont, false, false);
763         cont.show_all ();
764 }
765
766 void
767 Editor::catch_vanishing_regionview (RegionView *rv)
768 {
769         /* note: the selection will take care of the vanishing
770            audioregionview by itself.
771         */
772
773         if (clicked_regionview == rv) {
774                 clicked_regionview = 0;
775         }
776
777         if (entered_regionview == rv) {
778                 set_entered_regionview (0);
779         }
780 }
781
782 void
783 Editor::set_entered_regionview (RegionView* rv)
784 {
785         if (rv == entered_regionview) {
786                 return;
787         }
788
789         if (entered_regionview) {
790                 entered_regionview->exited ();
791         }
792
793         if ((entered_regionview = rv) != 0) {
794                 entered_regionview->entered ();
795         }
796 }
797
798 void
799 Editor::set_entered_track (TimeAxisView* tav)
800 {
801         if (entered_track) {
802                 entered_track->exited ();
803         }
804
805         if ((entered_track = tav) != 0) {
806                 entered_track->entered ();
807         }
808 }
809
810 void
811 Editor::show_window ()
812 {
813         show_all ();
814         present ();
815
816         /* now reset all audio_time_axis heights, because widgets might need
817            to be re-hidden
818         */
819         
820         TimeAxisView *tv;
821         
822         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
823                 tv = (static_cast<TimeAxisView*>(*i));
824                 tv->reset_height ();
825         }
826 }
827
828 void
829 Editor::tie_vertical_scrolling ()
830 {
831         double y1 = vertical_adjustment.get_value();
832         controls_layout.get_vadjustment()->set_value (y1);
833         playhead_cursor->set_y_axis(y1);
834         edit_cursor->set_y_axis(y1);
835 }
836
837 void
838 Editor::instant_save ()
839 {
840         if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
841                 return;
842         }
843
844         if (session) {
845                 session->add_instant_xml(get_state(), session->path());
846         } else {
847                 Config->add_instant_xml(get_state(), get_user_ardour_path());
848         }
849 }
850
851 void
852 Editor::edit_cursor_clock_changed()
853 {
854         if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
855                 edit_cursor->set_position (edit_cursor_clock.current_time());
856         }
857 }
858
859
860 void
861 Editor::zoom_adjustment_changed ()
862 {
863         if (session == 0) {
864                 return;
865         }
866
867         double fpu = zoom_range_clock.current_duration() / canvas_width;
868
869         if (fpu < 1.0) {
870                 fpu = 1.0;
871                 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
872         } else if (fpu > session->current_end_frame() / canvas_width) {
873                 fpu = session->current_end_frame() / canvas_width;
874                 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
875         }
876         
877         temporal_zoom (fpu);
878 }
879
880 void
881 Editor::control_scroll (float fraction)
882 {
883         ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
884
885         if (!session) {
886                 return;
887         }
888
889         double step = fraction * current_page_frames();
890         nframes_t target;
891
892         if ((fraction < 0.0f) && (session->transport_frame() < (nframes_t) fabs(step))) {
893                 target = 0;
894         } else if ((fraction > 0.0f) && (max_frames - session->transport_frame() < step)) {
895                 target = (max_frames - (current_page_frames()*2)); // allow room for slop in where the PH is on the screen
896         } else {
897                 target = (session->transport_frame() + (nframes_t) floor ((fraction * current_page_frames())));
898         }
899
900         /* move visuals, we'll catch up with it later */
901
902         playhead_cursor->set_position (target);
903
904         if (target > (current_page_frames() / 2)) {
905                 /* try to center PH in window */
906                 reset_x_origin (target - (current_page_frames()/2));
907         } else {
908                 reset_x_origin (0);
909         }
910
911         /* cancel the existing */
912
913         control_scroll_connection.disconnect ();
914
915         /* add the next one */
916
917         control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), target), 50);
918 }
919
920 bool
921 Editor::deferred_control_scroll (nframes_t target)
922 {
923         session->request_locate (target);
924         return false;
925 }
926
927 void
928 Editor::on_realize ()
929 {
930         Window::on_realize ();
931         Realized ();
932 }
933
934 void
935 Editor::start_scrolling ()
936 {
937         scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect 
938                 (mem_fun(*this, &Editor::update_current_screen));
939 }
940
941 void
942 Editor::stop_scrolling ()
943 {
944         scroll_connection.disconnect ();
945 }
946
947 void
948 Editor::map_position_change (nframes_t frame)
949 {
950         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
951
952         if (session == 0 || !_follow_playhead) {
953                 return;
954         }
955
956         center_screen (frame);
957         playhead_cursor->set_position (frame);
958 }       
959
960 void
961 Editor::center_screen (nframes_t frame)
962 {
963         double page = canvas_width * frames_per_unit;
964
965         /* if we're off the page, then scroll.
966          */
967         
968         if (frame < leftmost_frame || frame >= leftmost_frame + page) {
969                 center_screen_internal (frame, page);
970         }
971 }
972
973 void
974 Editor::center_screen_internal (nframes_t frame, float page)
975 {
976         page /= 2;
977                 
978         if (frame > page) {
979                 frame -= (nframes_t) page;
980         } else {
981                 frame = 0;
982         }
983
984         reset_x_origin (frame);
985 }
986
987 void
988 Editor::handle_new_duration ()
989 {
990         ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
991
992         nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
993                                   
994         if (new_end > last_canvas_frame) {
995                 last_canvas_frame = new_end;
996                 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
997                 reset_scrolling_region ();
998         }
999
1000         horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1001 }
1002
1003 void
1004 Editor::update_title_s (const string & snap_name)
1005 {
1006         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1007         
1008         update_title ();
1009 }
1010
1011 void
1012 Editor::update_title ()
1013 {
1014         ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1015
1016         if (session) {
1017                 bool dirty = session->dirty();
1018
1019                 string session_name;
1020
1021                 if (session->snap_name() != session->name()) {
1022                         session_name = session->snap_name();
1023                 } else {
1024                         session_name = session->name();
1025                 }
1026
1027                 if (dirty) {
1028                         session_name = "*" + session_name;
1029                 }
1030
1031                 WindowTitle title(session_name);
1032                 title += Glib::get_application_name();
1033                 set_title (title.get_string());
1034         }
1035 }
1036
1037 void
1038 Editor::connect_to_session (Session *t)
1039 {
1040         session = t;
1041
1042         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1043         set_state (*node);
1044
1045         /* catch up with the playhead */
1046
1047         session->request_locate (playhead_cursor->current_frame);
1048
1049         if (first_action_message) {
1050                 first_action_message->hide();
1051         }
1052
1053         update_title ();
1054
1055         session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1056         session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1057
1058         /* These signals can all be emitted by a non-GUI thread. Therefore the
1059            handlers for them must not attempt to directly interact with the GUI,
1060            but use Gtkmm2ext::UI::instance()->call_slot();
1061         */
1062
1063         session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1064         session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1065         session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1066         session_connections.push_back (session->RegionAdded.connect (mem_fun(*this, &Editor::handle_new_region)));
1067         session_connections.push_back (session->RegionRemoved.connect (mem_fun(*this, &Editor::handle_region_removed)));
1068         session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1069         session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1070         session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1071         session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1072         session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1073         session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1074         session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1075         session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1076         session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1077
1078         session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1079
1080         session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1081
1082         edit_groups_changed ();
1083
1084         edit_cursor_clock.set_session (session);
1085         zoom_range_clock.set_session (session);
1086         _playlist_selector->set_session (session);
1087         nudge_clock.set_session (session);
1088
1089 #ifdef FFT_ANALYSIS
1090         if (analysis_window != 0)
1091                 analysis_window->set_session (session);
1092 #endif
1093
1094         Location* loc = session->locations()->auto_loop_location();
1095         if (loc == 0) {
1096                 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1097                 if (loc->start() == loc->end()) {
1098                         loc->set_end (loc->start() + 1);
1099                 }
1100                 session->locations()->add (loc, false);
1101                 session->set_auto_loop_location (loc);
1102         } else {
1103                 // force name
1104                 loc->set_name (_("Loop"));
1105         }
1106         
1107         loc = session->locations()->auto_punch_location();
1108         if (loc == 0) {
1109                 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1110                 if (loc->start() == loc->end()) {
1111                         loc->set_end (loc->start() + 1);
1112                 }
1113                 session->locations()->add (loc, false);
1114                 session->set_auto_punch_location (loc);
1115         } else {
1116                 // force name
1117                 loc->set_name (_("Punch"));
1118         }
1119
1120         Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1121         
1122         session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1123         
1124         refresh_location_display ();
1125         session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1126         session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1127         session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1128         session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1129         session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1130
1131         handle_new_duration ();
1132
1133         redisplay_regions ();
1134         redisplay_named_selections ();
1135         redisplay_snapshots ();
1136
1137         initial_route_list_display ();
1138
1139         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1140                 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1141         }
1142
1143         restore_ruler_visibility ();
1144         //tempo_map_changed (Change (0));
1145         session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1146
1147         start_scrolling ();
1148
1149         /* don't show master bus in a new session */
1150
1151         if (ARDOUR_UI::instance()->session_is_new ()) {
1152
1153                 TreeModel::Children rows = route_display_model->children();
1154                 TreeModel::Children::iterator i;
1155         
1156                 no_route_list_redisplay = true;
1157                 
1158                 for (i = rows.begin(); i != rows.end(); ++i) {
1159                         TimeAxisView *tv =  (*i)[route_display_columns.tv];
1160                         RouteTimeAxisView *rtv;
1161                         
1162                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1163                                 if (rtv->route()->master()) {
1164                                         route_list_display.get_selection()->unselect (i);
1165                                 }
1166                         }
1167                 }
1168                 
1169                 no_route_list_redisplay = false;
1170                 redisplay_route_list ();
1171         }
1172
1173         /* register for undo history */
1174
1175         session->register_with_memento_command_factory(_id, this);
1176 }
1177
1178 void
1179 Editor::build_cursors ()
1180 {
1181         using namespace Gdk;
1182         
1183         Gdk::Color mbg ("#000000" ); /* Black */
1184         Gdk::Color mfg ("#0000ff" ); /* Blue. */
1185
1186         {
1187                 RefPtr<Bitmap> source, mask;
1188                 source = Bitmap::create (mag_bits, mag_width, mag_height);
1189                 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1190                 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1191         }
1192
1193         Gdk::Color fbg ("#ffffff" );
1194         Gdk::Color ffg  ("#000000" );
1195         
1196         {
1197                 RefPtr<Bitmap> source, mask;
1198                 
1199                 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1200                 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1201                 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1202         }
1203         
1204         { 
1205                 RefPtr<Bitmap> source, mask;
1206                 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1207                 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1208                 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1209         }
1210
1211         grabber_cursor = new Gdk::Cursor (HAND2);
1212         cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1213         trimmer_cursor =  new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1214         selector_cursor = new Gdk::Cursor (XTERM);
1215         time_fx_cursor = new Gdk::Cursor (SIZING);
1216         wait_cursor = new Gdk::Cursor  (WATCH);
1217         timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1218 }
1219
1220 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1221 void
1222 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1223 {
1224         using namespace Menu_Helpers;
1225         AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1226
1227         if (arv == 0) {
1228                 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1229                 /*NOTREACHED*/
1230         }
1231
1232         MenuList& items (fade_context_menu.items());
1233
1234         items.clear ();
1235
1236         switch (item_type) {
1237         case FadeInItem:
1238         case FadeInHandleItem:
1239                 if (arv->audio_region()->fade_in_active()) {
1240                         items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1241                 } else {
1242                         items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1243                 }
1244                 
1245                 items.push_back (SeparatorElem());
1246                 
1247                 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1248                 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1249                 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1250                 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1251                 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1252                 break;
1253
1254         case FadeOutItem:
1255         case FadeOutHandleItem:
1256                 if (arv->audio_region()->fade_out_active()) {
1257                         items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1258                 } else {
1259                         items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1260                 }
1261                 
1262                 items.push_back (SeparatorElem());
1263                 
1264                 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1265                 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1266                 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1267                 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1268                 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1269
1270                 break;
1271
1272         default:
1273                 fatal << _("programming error: ")
1274                       << X_("non-fade canvas item passed to popup_fade_context_menu()")
1275                       << endmsg;
1276                 /*NOTREACHED*/
1277         }
1278
1279         fade_context_menu.popup (button, time);
1280 }
1281
1282 /* Pop up the general track context menu for when the user clicks pretty much anywhere in a track or bus */
1283 void
1284 Editor::popup_track_context_menu (int button, int32_t time, nframes_t frame)
1285 {
1286         build_track_context_menu (frame)->popup (button, time);
1287 }
1288
1289 Menu*
1290 Editor::build_track_context_menu (nframes_t frame)
1291 {
1292         using namespace Menu_Helpers;
1293
1294         Menu* menu = manage (new Menu);
1295         MenuList& edit_items = menu->items();
1296         edit_items.clear();
1297
1298         /* Build the general `track' context menu, adding what is appropriate given
1299            the current selection */
1300
1301         /* XXX: currently crossfades can't be selected, so we can't use the selection
1302            to decide which crossfades to mention in the menu.  I believe this will
1303            change at some point.  For now we have to use clicked_trackview to decide. */
1304         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1305
1306         if (atv) {
1307                 boost::shared_ptr<Diskstream> ds;
1308                 boost::shared_ptr<Playlist> pl;
1309                 boost::shared_ptr<AudioPlaylist> apl;
1310
1311                 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1312
1313                         AudioPlaylist::Crossfades xfades;
1314                         apl->crossfades_at (frame, xfades);
1315
1316                         bool many = xfades.size() > 1;
1317
1318                         for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1319                                 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1320                         }
1321                 }
1322         }       
1323
1324         if (!selection->time.empty()) {
1325                 add_selection_context_items (edit_items);
1326         }
1327
1328         if (!selection->regions.empty()) {
1329                 add_region_context_items (edit_items);
1330         }
1331
1332         if (!selection->tracks.empty()) {
1333                 add_bus_or_audio_track_context_items (edit_items);
1334         }
1335         
1336         menu->set_name ("ArdourContextMenu");
1337
1338         return menu;
1339 }
1340
1341 #ifdef FFT_ANALYSIS
1342 void
1343 Editor::analyze_region_selection()
1344 {
1345         if (analysis_window == 0) {
1346                 analysis_window = new AnalysisWindow();
1347
1348                 if (session != 0)
1349                         analysis_window->set_session(session);
1350
1351                 analysis_window->show_all();
1352         }
1353
1354         analysis_window->set_regionmode();
1355         analysis_window->analyze();
1356         
1357         analysis_window->present();
1358 }
1359
1360 void
1361 Editor::analyze_range_selection()
1362 {
1363         if (analysis_window == 0) {
1364                 analysis_window = new AnalysisWindow();
1365
1366                 if (session != 0)
1367                         analysis_window->set_session(session);
1368
1369                 analysis_window->show_all();
1370         }
1371
1372         analysis_window->set_rangemode();
1373         analysis_window->analyze();
1374         
1375         analysis_window->present();
1376 }
1377 #endif /* FFT_ANALYSIS */
1378
1379
1380 /** Add context menu items relevant to crossfades.
1381  * @param edit_items List to add the items to.
1382  */
1383 void
1384 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1385 {
1386         using namespace Menu_Helpers;
1387         Menu     *xfade_menu = manage (new Menu);
1388         MenuList& items       = xfade_menu->items();
1389         xfade_menu->set_name ("ArdourContextMenu");
1390         string str;
1391
1392         if (xfade->active()) {
1393                 str = _("Mute");
1394         } else { 
1395                 str = _("Unmute");
1396         }
1397
1398         items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1399         items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1400
1401         if (xfade->can_follow_overlap()) {
1402
1403                 if (xfade->following_overlap()) {
1404                         str = _("Convert to short");
1405                 } else {
1406                         str = _("Convert to full");
1407                 }
1408
1409                 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1410         }
1411
1412         if (many) {
1413                 str = xfade->out()->name();
1414                 str += "->";
1415                 str += xfade->in()->name();
1416         } else {
1417                 str = _("Crossfade");
1418         }
1419
1420         edit_items.push_back (MenuElem (str, *xfade_menu));
1421         edit_items.push_back (SeparatorElem());
1422 }
1423
1424 void
1425 Editor::xfade_edit_left_region ()
1426 {
1427         if (clicked_crossfadeview) {
1428                 clicked_crossfadeview->left_view.show_region_editor ();
1429         }
1430 }
1431
1432 void
1433 Editor::xfade_edit_right_region ()
1434 {
1435         if (clicked_crossfadeview) {
1436                 clicked_crossfadeview->right_view.show_region_editor ();
1437         }
1438 }
1439
1440 /** Add an element to a menu, settings its sensitivity.
1441  * @param m Menu to add to.
1442  * @param e Element to add.
1443  * @param s true to make sensitive, false to make insensitive
1444  */
1445 void
1446 Editor::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) const
1447 {
1448         m.push_back (e);
1449         if (!s) {
1450                 m.back().set_sensitive (false);
1451         }
1452 }
1453
1454 /** Add context menu items relevant to regions.
1455  * @param edit_items List to add the items to.
1456  */
1457 void
1458 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
1459 {
1460         using namespace Menu_Helpers;
1461         Menu *region_menu = manage (new Menu);
1462         MenuList& items = region_menu->items();
1463         region_menu->set_name ("ArdourContextMenu");
1464         
1465         items.push_back (MenuElem (_("Edit..."), mem_fun(*this, &Editor::edit_region)));
1466         items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1467         items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun  (*this, &Editor::lower_region_to_bottom)));
1468
1469         Menu* sync_point_menu = manage (new Menu);
1470         MenuList& sync_point_items = sync_point_menu->items();
1471         sync_point_menu->set_name("ArdourContextMenu");
1472         
1473         sync_point_items.push_back (MenuElem (_("Define"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1474         sync_point_items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_region_sync)));
1475
1476         items.push_back (MenuElem (_("Sync points"), *sync_point_menu));
1477
1478         add_item_with_sensitivity (items, MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)), selection->regions.size() == 1);
1479         
1480         add_item_with_sensitivity (items, MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)), selection->regions.size() == 1);
1481
1482         items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1483
1484 #ifdef FFT_ANALYSIS
1485         items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1486 #endif
1487
1488         items.push_back (SeparatorElem());
1489
1490         items.push_back (MenuElem (_("Lock"), bind (mem_fun (*this, &Editor::set_region_lock), true)));
1491         items.push_back (MenuElem (_("Unlock"), bind (mem_fun (*this, &Editor::set_region_lock), false)));
1492         items.push_back (MenuElem (_("Lock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), true)));
1493         items.push_back (MenuElem (_("Unlock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), false)));
1494         items.push_back (MenuElem (_("Mute"), bind (mem_fun (*this, &Editor::set_region_mute), true)));
1495         items.push_back (MenuElem (_("Unmute"), bind (mem_fun (*this, &Editor::set_region_mute), false)));
1496         items.push_back (MenuElem (_("Opaque"), bind (mem_fun (*this, &Editor::set_region_opaque), true)));
1497         items.push_back (MenuElem (_("Transparent"), bind (mem_fun (*this, &Editor::set_region_opaque), false)));
1498
1499         /* We allow "Original position" if at least one region is not at its
1500            natural position 
1501         */
1502         RegionSelection::iterator i = selection->regions.begin();
1503         while (i != selection->regions.end() && (*i)->region()->at_natural_position() == true) {
1504                 ++i;
1505         }
1506
1507         add_item_with_sensitivity (items, MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)), i != selection->regions.end());
1508         
1509         items.push_back (SeparatorElem());
1510
1511         /* Find out if we have a selected audio region */
1512         i = selection->regions.begin();
1513         while (i != selection->regions.end() && boost::dynamic_pointer_cast<AudioRegion>((*i)->region()) == 0) {
1514                 ++i;
1515         }
1516         bool const have_selected_audio_region = (i != selection->regions.end());
1517
1518         if (have_selected_audio_region) {
1519
1520                 Menu* envelopes_menu = manage (new Menu);
1521                 MenuList& envelopes_items = envelopes_menu->items();
1522                 envelopes_menu->set_name ("ArdourContextMenu");
1523
1524                 envelopes_items.push_back (MenuElem (_("Reset"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1525                 envelopes_items.push_back (MenuElem (_("Visible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), true)));
1526                 envelopes_items.push_back (MenuElem (_("Invisible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), false)));
1527                 envelopes_items.push_back (MenuElem (_("Active"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), true)));
1528                 envelopes_items.push_back (MenuElem (_("Inactive"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), false)));
1529
1530                 items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
1531                 
1532                 items.push_back (MenuElem (_("Denormalize"), mem_fun (*this, &Editor::denormalize_regions)));
1533                 items.push_back (MenuElem (_("Normalize"), mem_fun (*this, &Editor::normalize_regions)));
1534         }
1535         
1536         items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_regions)));
1537         items.push_back (SeparatorElem());
1538
1539
1540         /* range related stuff */
1541         
1542         add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
1543         
1544         add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
1545         
1546         items.push_back (SeparatorElem());
1547                          
1548         /* Nudge region */
1549
1550         Menu *nudge_menu = manage (new Menu());
1551         MenuList& nudge_items = nudge_menu->items();
1552         nudge_menu->set_name ("ArdourContextMenu");
1553         
1554         nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1555         nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1556         nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1557         nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1558
1559         items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1560
1561         Menu *trim_menu = manage (new Menu);
1562         MenuList& trim_items = trim_menu->items();
1563         trim_menu->set_name ("ArdourContextMenu");
1564         
1565         trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1566         trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1567                              
1568         items.push_back (MenuElem (_("Trim"), *trim_menu));
1569         items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1570         items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1571         items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1572         items.push_back (MenuElem (_("Fill track"), (mem_fun(*this, &Editor::region_fill_track))));
1573         items.push_back (SeparatorElem());
1574         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions)));
1575
1576         /* OK, stick the region submenu at the top of the list, and then add
1577            the standard items.
1578         */
1579
1580         string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
1581         edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1582 }
1583
1584 /** Add context menu items relevant to selection ranges.
1585  * @param edit_items List to add the items to.
1586  */
1587 void
1588 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1589 {
1590         using namespace Menu_Helpers;
1591         Menu     *selection_menu = manage (new Menu);
1592         MenuList& items       = selection_menu->items();
1593         selection_menu->set_name ("ArdourContextMenu");
1594
1595         items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1596         items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
1597
1598 #ifdef FFT_ANALYSIS
1599         items.push_back (SeparatorElem());
1600         items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1601 #endif
1602         
1603         items.push_back (SeparatorElem());
1604         items.push_back (MenuElem (_("Separate range to track"), mem_fun(*this, &Editor::separate_region_from_selection)));
1605         items.push_back (MenuElem (_("Separate range to region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1606         
1607         items.push_back (SeparatorElem());
1608         items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1609         items.push_back (SeparatorElem());
1610         items.push_back (MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1611         items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1612         items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1613         items.push_back (SeparatorElem());
1614         items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1615         items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1616         items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1617         items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1618         items.push_back (SeparatorElem());
1619         items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1620         items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1621
1622         edit_items.push_back (MenuElem (_("Range"), *selection_menu));
1623         edit_items.push_back (SeparatorElem());
1624 }
1625
1626 /** Add context menu items relevant to busses or audio tracks.
1627  * @param edit_items List to add the items to.
1628  */
1629 void
1630 Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
1631 {
1632         using namespace Menu_Helpers;
1633
1634         /* We add every possible action here, and de-sensitize things
1635            that aren't allowed.  The sensitivity logic is a bit spread out;
1636            on the one hand I'm using things like can_cut_copy (), which is
1637            reasonably complicated and so perhaps better near the function that
1638            it expresses sensitivity for, and on the other hand checks
1639            in this function as well.  You can't really have can_* for everything
1640            or the number of methods would get silly. */
1641
1642         bool const one_selected_region = selection->regions.size() == 1;
1643
1644         /* Count the number of selected audio tracks */
1645         int n_audio_tracks = 0;
1646         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1647                 RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
1648                 if (r && r->is_audio_track()) {
1649                         n_audio_tracks++;
1650                 }
1651         }
1652
1653         /* Playback */
1654
1655         Menu *play_menu = manage (new Menu);
1656         MenuList& play_items = play_menu->items();
1657         play_menu->set_name ("ArdourContextMenu");
1658         
1659         play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1660         play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1661         add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
1662         
1663         add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
1664         
1665         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1666
1667         /* Selection */
1668
1669         Menu *select_menu = manage (new Menu);
1670         MenuList& select_items = select_menu->items();
1671         select_menu->set_name ("ArdourContextMenu");
1672
1673         string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
1674
1675         select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
1676         
1677         select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1678
1679         str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
1680         
1681         select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
1682         
1683         select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1684         select_items.push_back (SeparatorElem());
1685
1686         if (n_audio_tracks) {
1687                 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1688                 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1689         }
1690         
1691         select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1692         select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1693         select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1694         select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1695
1696         if (n_audio_tracks) {
1697                 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1698         }
1699
1700         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1701
1702         /* Cut-n-Paste */
1703
1704         Menu *cutnpaste_menu = manage (new Menu);
1705         MenuList& cutnpaste_items = cutnpaste_menu->items();
1706         cutnpaste_menu->set_name ("ArdourContextMenu");
1707
1708         add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
1709         
1710         add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
1711         
1712         if (n_audio_tracks) {
1713                 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1714                 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1715                 
1716                 cutnpaste_items.push_back (SeparatorElem());
1717                 
1718                 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1719                 cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1720                 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1721         } else {
1722                 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1723         }
1724
1725         edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1726                 
1727         if (n_audio_tracks) {
1728
1729                 Menu *track_menu = manage (new Menu);
1730                 MenuList& track_items = track_menu->items();
1731                 track_menu->set_name ("ArdourContextMenu");
1732                 
1733                 /* Adding new material */
1734         
1735                 add_item_with_sensitivity (track_items, MenuElem (_("Insert selected region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)), n_audio_tracks == 1);
1736                 
1737                 add_item_with_sensitivity (track_items, MenuElem (_("Insert existing audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1738                 
1739                 /* Nudge */
1740
1741                 Menu *nudge_menu = manage (new Menu());
1742                 MenuList& nudge_items = nudge_menu->items();
1743                 nudge_menu->set_name ("ArdourContextMenu");
1744
1745                 str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
1746                 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
1747
1748                 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1749                 
1750                 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1751
1752                 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1753                 
1754                 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1755
1756                 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1757                 
1758                 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1759                 
1760                 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1761
1762                 /* Freeze */
1763                 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1764                 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1765
1766                 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1767                 edit_items.push_back (MenuElem (str, *track_menu));
1768         }
1769 }
1770
1771 /* CURSOR SETTING AND MARKS AND STUFF */
1772
1773 void
1774 Editor::set_snap_to (SnapType st)
1775 {       
1776         snap_type = st;
1777         string str = snap_type_strings[(int) st];
1778
1779         if (str != snap_type_selector.get_active_text()) {
1780                 snap_type_selector.set_active_text (str);
1781         }
1782
1783         instant_save ();
1784
1785         switch (snap_type) {
1786         case SnapToAThirtysecondBeat:
1787         case SnapToASixteenthBeat:
1788         case SnapToAEighthBeat:
1789         case SnapToAQuarterBeat:
1790         case SnapToAThirdBeat:
1791                 update_tempo_based_rulers ();
1792         default:
1793                 /* relax */
1794                 break;
1795     }
1796 }
1797
1798 void
1799 Editor::set_snap_mode (SnapMode mode)
1800 {
1801         snap_mode = mode;
1802         string str = snap_mode_strings[(int)mode];
1803
1804         if (str != snap_mode_selector.get_active_text ()) {
1805                 snap_mode_selector.set_active_text (str);
1806         }
1807
1808         instant_save ();
1809 }
1810
1811 int
1812 Editor::set_state (const XMLNode& node)
1813 {
1814         const XMLProperty* prop;
1815         XMLNode* geometry;
1816         int x, y, xoff, yoff;
1817         Gdk::Geometry g;
1818
1819         if ((prop = node.property ("id")) != 0) {
1820                 _id = prop->value ();
1821         }
1822
1823         if ((geometry = find_named_node (node, "geometry")) == 0) {
1824
1825                 g.base_width = default_width;
1826                 g.base_height = default_height;
1827                 x = 1;
1828                 y = 1;
1829                 xoff = 0;
1830                 yoff = 21;
1831
1832         } else {
1833
1834                 g.base_width = atoi(geometry->property("x_size")->value());
1835                 g.base_height = atoi(geometry->property("y_size")->value());
1836                 x = atoi(geometry->property("x_pos")->value());
1837                 y = atoi(geometry->property("y_pos")->value());
1838                 xoff = atoi(geometry->property("x_off")->value());
1839                 yoff = atoi(geometry->property("y_off")->value());
1840         }
1841
1842         set_default_size (g.base_width, g.base_height);
1843         move (x, y);
1844
1845         if (session && (prop = node.property ("playhead"))) {
1846                 nframes_t pos = atol (prop->value().c_str());
1847                 playhead_cursor->set_position (pos);
1848         } else {
1849                 playhead_cursor->set_position (0);
1850
1851                 /* reset_x_origin() doesn't work right here, since the old
1852                    position may be zero already, and it does nothing in such
1853                    circumstances.
1854                 */
1855                 
1856                 leftmost_frame = 0;
1857                 horizontal_adjustment.set_value (0);
1858         }
1859
1860         if (session && (prop = node.property ("edit-cursor"))) {
1861                 nframes_t pos = atol (prop->value().c_str());
1862                 edit_cursor->set_position (pos);
1863         } else {
1864                 edit_cursor->set_position (0);
1865         }
1866
1867         if ((prop = node.property ("mixer-width"))) {
1868                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
1869         }
1870
1871         if ((prop = node.property ("zoom-focus"))) {
1872                 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
1873         }
1874
1875         if ((prop = node.property ("zoom"))) {
1876                 reset_zoom (PBD::atof (prop->value()));
1877         }
1878
1879         if ((prop = node.property ("snap-to"))) {
1880                 set_snap_to ((SnapType) atoi (prop->value()));
1881         }
1882
1883         if ((prop = node.property ("snap-mode"))) {
1884                 set_snap_mode ((SnapMode) atoi (prop->value()));
1885         }
1886
1887         if ((prop = node.property ("mouse-mode"))) {
1888                 MouseMode m = str2mousemode(prop->value());
1889                 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
1890                 set_mouse_mode (m, true);
1891         } else {
1892                 mouse_mode = MouseGain; /* lie, to force the mode switch */
1893                 set_mouse_mode (MouseObject, true);
1894         }
1895
1896         if ((prop = node.property ("show-waveforms"))) {
1897                 bool yn = (prop->value() == "yes");
1898                 _show_waveforms = !yn;
1899                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
1900                 if (act) {
1901                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1902                         /* do it twice to force the change */
1903                         tact->set_active (!yn);
1904                         tact->set_active (yn);
1905                 }
1906         }
1907
1908         if ((prop = node.property ("show-waveforms-recording"))) {
1909                 bool yn = (prop->value() == "yes");
1910                 _show_waveforms_recording = !yn;
1911                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
1912                 if (act) {
1913                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1914                         /* do it twice to force the change */
1915                         tact->set_active (!yn);
1916                         tact->set_active (yn);
1917                 }
1918         }
1919         
1920         if ((prop = node.property ("show-measures"))) {
1921                 bool yn = (prop->value() == "yes");
1922                 _show_measures = !yn;
1923                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
1924                 if (act) {
1925                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1926                         /* do it twice to force the change */
1927                         tact->set_active (!yn);
1928                         tact->set_active (yn);
1929                 }
1930         }
1931
1932         if ((prop = node.property ("follow-playhead"))) {
1933                 bool yn = (prop->value() == "yes");
1934                 set_follow_playhead (yn);
1935                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
1936                 if (act) {
1937                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1938                         if (tact->get_active() != yn) {
1939                                 tact->set_active (yn);
1940                         }
1941                 }
1942         }
1943
1944         if ((prop = node.property ("region-list-sort-type"))) {
1945                 region_list_sort_type = (Editing::RegionListSortType) -1; // force change 
1946                 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
1947         }
1948
1949         if ((prop = node.property ("xfades-visible"))) {
1950                 bool yn = (prop->value() == "yes");
1951                 _xfade_visibility = !yn;
1952                 // set_xfade_visibility (yn);
1953         }
1954
1955         if ((prop = node.property ("show-editor-mixer"))) {
1956
1957                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
1958                 if (act) {
1959
1960                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1961                         bool yn = (prop->value() == X_("yes"));
1962
1963                         /* do it twice to force the change */
1964                         
1965                         tact->set_active (!yn);
1966                         tact->set_active (yn);
1967                 }
1968         }
1969
1970
1971         return 0;
1972 }
1973
1974 XMLNode&
1975 Editor::get_state ()
1976 {
1977         XMLNode* node = new XMLNode ("Editor");
1978         char buf[32];
1979
1980         _id.print (buf, sizeof (buf));
1981         node->add_property ("id", buf);
1982         
1983         if (is_realized()) {
1984                 Glib::RefPtr<Gdk::Window> win = get_window();
1985                 
1986                 int x, y, xoff, yoff, width, height;
1987                 win->get_root_origin(x, y);
1988                 win->get_position(xoff, yoff);
1989                 win->get_size(width, height);
1990                 
1991                 XMLNode* geometry = new XMLNode ("geometry");
1992
1993                 snprintf(buf, sizeof(buf), "%d", width);
1994                 geometry->add_property("x_size", string(buf));
1995                 snprintf(buf, sizeof(buf), "%d", height);
1996                 geometry->add_property("y_size", string(buf));
1997                 snprintf(buf, sizeof(buf), "%d", x);
1998                 geometry->add_property("x_pos", string(buf));
1999                 snprintf(buf, sizeof(buf), "%d", y);
2000                 geometry->add_property("y_pos", string(buf));
2001                 snprintf(buf, sizeof(buf), "%d", xoff);
2002                 geometry->add_property("x_off", string(buf));
2003                 snprintf(buf, sizeof(buf), "%d", yoff);
2004                 geometry->add_property("y_off", string(buf));
2005                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2006                 geometry->add_property("edit_pane_pos", string(buf));
2007
2008                 node->add_child_nocopy (*geometry);
2009         }
2010
2011         maybe_add_mixer_strip_width (*node);
2012         
2013         snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2014         node->add_property ("zoom-focus", buf);
2015         snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2016         node->add_property ("zoom", buf);
2017         snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2018         node->add_property ("snap-to", buf);
2019         snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2020         node->add_property ("snap-mode", buf);
2021
2022         snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2023         node->add_property ("playhead", buf);
2024         snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2025         node->add_property ("edit-cursor", buf);
2026
2027         node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2028         node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2029         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2030         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2031         node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2032         node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2033         node->add_property ("mouse-mode", enum2str(mouse_mode));
2034         
2035         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2036         if (act) {
2037                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2038                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2039         }
2040
2041         return *node;
2042 }
2043
2044
2045
2046 TimeAxisView *
2047 Editor::trackview_by_y_position (double y)
2048 {
2049         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2050
2051                 TimeAxisView *tv;
2052
2053                 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2054                         return tv;
2055                 }
2056         }
2057
2058         return 0;
2059 }
2060
2061 void
2062 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2063 {
2064         Location* before = 0;
2065         Location* after = 0;
2066
2067         if (!session) {
2068                 return;
2069         }
2070
2071         const nframes64_t one_second = session->frame_rate();
2072         const nframes64_t one_minute = session->frame_rate() * 60;
2073         const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2074         nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2075         nframes64_t presnap = start;
2076
2077         switch (snap_type) {
2078         case SnapToFrame:
2079                 break;
2080
2081         case SnapToCDFrame:
2082                 if (direction) {
2083                         start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2084                 } else {
2085                         start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2086                 }
2087                 break;
2088
2089         case SnapToSMPTEFrame:
2090                 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2091                         start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2092                 } else {
2093                         start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) *  session->frames_per_smpte_frame());
2094                 }
2095                 break;
2096
2097         case SnapToSMPTESeconds:
2098                 if (session->smpte_offset_negative())
2099                 {
2100                         start += session->smpte_offset ();
2101                 } else {
2102                         start -= session->smpte_offset ();
2103                 }    
2104                 if (start % one_smpte_second > one_smpte_second / 2) {
2105                         start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2106                 } else {
2107                         start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2108                 }
2109                 
2110                 if (session->smpte_offset_negative())
2111                 {
2112                         start -= session->smpte_offset ();
2113                 } else {
2114                         start += session->smpte_offset ();
2115                 }
2116                 break;
2117                 
2118         case SnapToSMPTEMinutes:
2119                 if (session->smpte_offset_negative())
2120                 {
2121                         start += session->smpte_offset ();
2122                 } else {
2123                         start -= session->smpte_offset ();
2124                 }
2125                 if (start % one_smpte_minute > one_smpte_minute / 2) {
2126                         start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2127                 } else {
2128                         start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2129                 }
2130                 if (session->smpte_offset_negative())
2131                 {
2132                         start -= session->smpte_offset ();
2133                 } else {
2134                         start += session->smpte_offset ();
2135                 }
2136                 break;
2137                 
2138         case SnapToSeconds:
2139                 if (start % one_second > one_second / 2) {
2140                         start = (nframes_t) ceil ((double) start / one_second) * one_second;
2141                 } else {
2142                         start = (nframes_t) floor ((double) start / one_second) * one_second;
2143                 }
2144                 break;
2145                 
2146         case SnapToMinutes:
2147                 if (start % one_minute > one_minute / 2) {
2148                         start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2149                 } else {
2150                         start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2151                 }
2152                 break;
2153
2154         case SnapToBar:
2155                 start = session->tempo_map().round_to_bar (start, direction);
2156                 break;
2157
2158         case SnapToBeat:
2159                 start = session->tempo_map().round_to_beat (start, direction);
2160                 break;
2161
2162         case SnapToAThirtysecondBeat:
2163                 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2164                 break;
2165
2166         case SnapToASixteenthBeat:
2167                 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2168                 break;
2169
2170         case SnapToAEighthBeat:
2171                 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2172                 break;
2173
2174         case SnapToAQuarterBeat:
2175                 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2176                 break;
2177
2178         case SnapToAThirdBeat:
2179                 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2180                 break;
2181
2182         case SnapToEditCursor:
2183                 start = edit_cursor->current_frame;
2184                 break;
2185
2186         case SnapToMark:
2187                 if (for_mark) {
2188                         return;
2189                 }
2190
2191                 before = session->locations()->first_location_before (start);
2192                 after = session->locations()->first_location_after (start);
2193
2194                 if (direction < 0) {
2195                         if (before) {
2196                                 start = before->start();
2197                         } else {
2198                                 start = 0;
2199                         }
2200                 } else if (direction > 0) {
2201                         if (after) {
2202                                 start = after->start();
2203                         } else {
2204                                 start = session->current_end_frame();
2205                         }
2206                 } else {
2207                         if (before) {
2208                                 if (after) {
2209                                         /* find nearest of the two */
2210                                         if ((start - before->start()) < (after->start() - start)) {
2211                                                 start = before->start();
2212                                         } else {
2213                                                 start = after->start();
2214                                         }
2215                                 } else {
2216                                         start = before->start();
2217                                 }
2218                         } else if (after) {
2219                                 start = after->start();
2220                         } else {
2221                                 /* relax */
2222                         }
2223                 }
2224                 break;
2225
2226         case SnapToRegionStart:
2227         case SnapToRegionEnd:
2228         case SnapToRegionSync:
2229         case SnapToRegionBoundary:
2230                 if (!region_boundary_cache.empty()) {
2231                         vector<nframes_t>::iterator i;
2232
2233                         if (direction > 0) {
2234                                 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2235                         } else {
2236                                 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2237                         }
2238                         
2239                         if (i != region_boundary_cache.end()) {
2240                                 start = *i;
2241                         } else {
2242                                 start = region_boundary_cache.back();
2243                         }
2244                 }
2245                 break;
2246         }
2247
2248         switch (snap_mode) {
2249         case SnapNormal:
2250                 return;                 
2251                 
2252         case SnapMagnetic:
2253                 
2254                 if (presnap > start) {
2255                         if (presnap > (start + unit_to_frame(snap_threshold))) {
2256                                 start = presnap;
2257                         }
2258                         
2259                 } else if (presnap < start) {
2260                         if (presnap < (start - unit_to_frame(snap_threshold))) {
2261                                 start = presnap;
2262                         }
2263                 }
2264                 
2265         default:
2266                 return;
2267                 
2268         }
2269 }
2270
2271 void
2272 Editor::setup_toolbar ()
2273 {
2274         string pixmap_path;
2275
2276         const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2277
2278
2279         /* Mode Buttons (tool selection) */
2280
2281         vector<ToggleButton *> mouse_mode_buttons;
2282
2283         mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2284         mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2285         mouse_mode_buttons.push_back (&mouse_move_button);
2286         mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2287         mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2288         mouse_mode_buttons.push_back (&mouse_select_button);
2289         mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2290         mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2291         mouse_mode_buttons.push_back (&mouse_gain_button);
2292         mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2293         mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2294         mouse_mode_buttons.push_back (&mouse_zoom_button);
2295         mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2296         mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2297         mouse_mode_buttons.push_back (&mouse_timefx_button);
2298         mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2299         mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2300         mouse_mode_buttons.push_back (&mouse_audition_button);
2301         
2302         mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2303
2304         HBox* mode_box = manage(new HBox);
2305         mode_box->set_border_width (2);
2306         mode_box->set_spacing(4);
2307         mouse_mode_button_box.set_spacing(1);
2308         mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2309         mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2310         mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2311         mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2312         mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2313         mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2314         mouse_mode_button_box.set_homogeneous(true);
2315
2316         vector<string> edit_mode_strings;
2317         edit_mode_strings.push_back (edit_mode_to_string (Splice));
2318         edit_mode_strings.push_back (edit_mode_to_string (Slide));
2319
2320         edit_mode_selector.set_name ("EditModeSelector");
2321         Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2322         set_popdown_strings (edit_mode_selector, edit_mode_strings);
2323         edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2324
2325         mode_box->pack_start(edit_mode_selector);
2326         mode_box->pack_start(mouse_mode_button_box);
2327         
2328         mouse_mode_tearoff = manage (new TearOff (*mode_box));
2329         mouse_mode_tearoff->set_name ("MouseModeBase");
2330
2331         mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2332                                                   &mouse_mode_tearoff->tearoff_window()));
2333         mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2334                                                   &mouse_mode_tearoff->tearoff_window(), 1));
2335         mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2336                                                   &mouse_mode_tearoff->tearoff_window()));
2337         mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2338                                                    &mouse_mode_tearoff->tearoff_window(), 1));
2339
2340         mouse_move_button.set_name ("MouseModeButton");
2341         mouse_select_button.set_name ("MouseModeButton");
2342         mouse_gain_button.set_name ("MouseModeButton");
2343         mouse_zoom_button.set_name ("MouseModeButton");
2344         mouse_timefx_button.set_name ("MouseModeButton");
2345         mouse_audition_button.set_name ("MouseModeButton");
2346
2347         ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2348         ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2349         ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2350         ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2351         ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2352         ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2353
2354         mouse_move_button.unset_flags (CAN_FOCUS);
2355         mouse_select_button.unset_flags (CAN_FOCUS);
2356         mouse_gain_button.unset_flags (CAN_FOCUS);
2357         mouse_zoom_button.unset_flags (CAN_FOCUS);
2358         mouse_timefx_button.unset_flags (CAN_FOCUS);
2359         mouse_audition_button.unset_flags (CAN_FOCUS);
2360
2361         mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2362         mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2363
2364         mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2365         mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2366         mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2367         mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2368         mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2369
2370         // mouse_move_button.set_active (true);
2371         
2372
2373         /* Zoom */
2374         
2375         zoom_box.set_spacing (1);
2376         zoom_box.set_border_width (2);
2377
2378         zoom_in_button.set_name ("EditorTimeButton");
2379         zoom_in_button.set_size_request(-1,16);
2380         zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2381         zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2382         ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2383         
2384         zoom_out_button.set_name ("EditorTimeButton");
2385         zoom_out_button.set_size_request(-1,16);
2386         zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2387         zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2388         ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2389
2390         zoom_out_full_button.set_name ("EditorTimeButton");
2391         zoom_out_full_button.set_size_request(-1,16);
2392         zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2393         zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2394         ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2395
2396         zoom_focus_selector.set_name ("ZoomFocusSelector");
2397         Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edit Cursor", FUDGE, 0);
2398         set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2399         zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2400         ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2401
2402         zoom_box.pack_start (zoom_focus_selector, true, true);
2403         zoom_box.pack_start (zoom_out_button, false, false);
2404         zoom_box.pack_start (zoom_in_button, false, false);
2405         zoom_box.pack_start (zoom_out_full_button, false, false);
2406
2407         /* Edit Cursor / Snap */
2408
2409         snap_box.set_spacing (1);
2410         snap_box.set_border_width (2);
2411
2412         snap_type_selector.set_name ("SnapTypeSelector");
2413         Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2414         set_popdown_strings (snap_type_selector, snap_type_strings);
2415         snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2416         ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2417
2418         snap_mode_selector.set_name ("SnapModeSelector");
2419         Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2420         set_popdown_strings (snap_mode_selector, snap_mode_strings);
2421         snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2422
2423         snap_box.pack_start (edit_cursor_clock, false, false);
2424         snap_box.pack_start (snap_mode_selector, false, false);
2425         snap_box.pack_start (snap_type_selector, false, false);
2426
2427
2428         /* Nudge */
2429
2430         HBox *nudge_box = manage (new HBox);
2431         nudge_box->set_spacing(1);
2432         nudge_box->set_border_width (2);
2433
2434         nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2435         nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2436
2437         nudge_box->pack_start (nudge_backward_button, false, false);
2438         nudge_box->pack_start (nudge_forward_button, false, false);
2439         nudge_box->pack_start (nudge_clock, false, false);
2440
2441
2442         /* Pack everything in... */
2443
2444         HBox* hbox = new HBox;
2445         hbox->set_spacing(10);
2446
2447         tools_tearoff = new TearOff (*hbox);
2448         tools_tearoff->set_name ("MouseModeBase");
2449
2450         tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2451                                              &tools_tearoff->tearoff_window()));
2452         tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2453                                              &tools_tearoff->tearoff_window(), 0));
2454         tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2455                                              &tools_tearoff->tearoff_window()));
2456         tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2457                                               &tools_tearoff->tearoff_window(), 0));
2458
2459         toolbar_hbox.set_spacing (10);
2460         toolbar_hbox.set_border_width (1);
2461
2462         toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2463         toolbar_hbox.pack_start (*tools_tearoff, false, false);
2464
2465         
2466         hbox->pack_start (snap_box, false, false);
2467         // hbox->pack_start (zoom_box, false, false); 
2468         hbox->pack_start (*nudge_box, false, false);
2469
2470         hbox->show_all ();
2471         
2472         toolbar_base.set_name ("ToolBarBase");
2473         toolbar_base.add (toolbar_hbox);
2474
2475         toolbar_frame.set_shadow_type (SHADOW_OUT);
2476         toolbar_frame.set_name ("BaseFrame");
2477         toolbar_frame.add (toolbar_base);
2478 }
2479
2480 int
2481 Editor::convert_drop_to_paths (vector<ustring>& paths, 
2482                                const RefPtr<Gdk::DragContext>& context,
2483                                gint                x,
2484                                gint                y,
2485                                const SelectionData& data,
2486                                guint               info,
2487                                guint               time)                               
2488
2489 {       
2490         if (session == 0) {
2491                 return -1;
2492         }
2493
2494         vector<ustring> uris = data.get_uris();
2495
2496         if (uris.empty()) {
2497                 
2498                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2499                    are actually URI lists. So do it by hand.
2500                 */
2501
2502                 if (data.get_target() != "text/plain") {
2503                         return -1;
2504                 }
2505   
2506                 /* Parse the "uri-list" format that Nautilus provides, 
2507                    where each pathname is delimited by \r\n
2508                 */
2509         
2510                 const char* p = data.get_text().c_str();
2511                 const char* q;
2512
2513                 while (p)
2514                 {
2515                         if (*p != '#')
2516                         {
2517                                 while (g_ascii_isspace (*p))
2518                                         p++;
2519                                 
2520                                 q = p;
2521                                 while (*q && (*q != '\n') && (*q != '\r'))
2522                                         q++;
2523                                 
2524                                 if (q > p)
2525                                 {
2526                                         q--;
2527                                         while (q > p && g_ascii_isspace (*q))
2528                                                 q--;
2529                                         
2530                                         if (q > p)
2531                                         {
2532                                                 uris.push_back (ustring (p, q - p + 1));
2533                                         }
2534                                 }
2535                         }
2536                         p = strchr (p, '\n');
2537                         if (p)
2538                                 p++;
2539                 }
2540
2541                 if (uris.empty()) {
2542                         return -1;
2543                 }
2544         }
2545         
2546         for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2547                 if ((*i).substr (0,7) == "file://") {
2548                         string p = *i;
2549                         PBD::url_decode (p);
2550                         paths.push_back (p.substr (7));
2551                 }
2552         }
2553
2554         return 0;
2555 }
2556
2557 void
2558 Editor::new_tempo_section ()
2559
2560 {
2561 }
2562
2563 void
2564 Editor::map_transport_state ()
2565 {
2566         ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2567
2568         if (session->transport_stopped()) {
2569                 have_pending_keyboard_selection = false;
2570         }
2571
2572         update_loop_range_view (true);
2573 }
2574
2575 /* UNDO/REDO */
2576
2577 Editor::State::State ()
2578 {
2579         selection = new Selection;
2580 }
2581
2582 Editor::State::~State ()
2583 {
2584         delete selection;
2585 }
2586
2587 UndoAction
2588 Editor::get_memento () const
2589 {
2590         State *state = new State;
2591
2592         store_state (*state);
2593         return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2594 }
2595
2596 void
2597 Editor::store_state (State& state) const
2598 {
2599         *state.selection = *selection;
2600 }
2601
2602 void
2603 Editor::restore_state (State *state)
2604 {
2605         if (*selection == *state->selection) {
2606                 return;
2607         }
2608
2609         *selection = *state->selection;
2610         time_selection_changed ();
2611         region_selection_changed ();   
2612
2613         /* XXX other selection change handlers? */
2614 }
2615
2616 void
2617 Editor::begin_reversible_command (string name)
2618 {
2619         if (session) {
2620                 before = &get_state();
2621                 session->begin_reversible_command (name);
2622         }
2623 }
2624
2625 void
2626 Editor::commit_reversible_command ()
2627 {
2628         if (session) {
2629                 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2630         }
2631 }
2632
2633 void
2634 Editor::set_edit_group_solo (Route& route, bool yn)
2635 {
2636         RouteGroup *edit_group;
2637
2638         if ((edit_group = route.edit_group()) != 0) {
2639                 edit_group->apply (&Route::set_solo, yn, this);
2640         } else {
2641                 route.set_solo (yn, this);
2642         }
2643 }
2644
2645 void
2646 Editor::set_edit_group_mute (Route& route, bool yn)
2647 {
2648         RouteGroup *edit_group = 0;
2649
2650         if ((edit_group == route.edit_group()) != 0) {
2651                 edit_group->apply (&Route::set_mute, yn, this);
2652         } else {
2653                 route.set_mute (yn, this);
2654         }
2655 }
2656                 
2657 void
2658 Editor::history_changed ()
2659 {
2660         string label;
2661
2662         if (undo_action && session) {
2663                 if (session->undo_depth() == 0) {
2664                         label = _("Undo");
2665                 } else {
2666                         label = string_compose(_("Undo (%1)"), session->next_undo());
2667                 }
2668                 undo_action->property_label() = label;
2669         }
2670
2671         if (redo_action && session) {
2672                 if (session->redo_depth() == 0) {
2673                         label = _("Redo");
2674                 } else {
2675                         label = string_compose(_("Redo (%1)"), session->next_redo());
2676                 }
2677                 redo_action->property_label() = label;
2678         }
2679 }
2680
2681 void
2682 Editor::duplicate_dialog (bool dup_region)
2683 {
2684         if (selection->regions.empty() && (selection->time.length() == 0)) {
2685                 return;
2686         }
2687
2688         ArdourDialog win ("duplicate dialog");
2689         Label  label (_("Duplicate how many times?"));
2690         Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
2691         SpinButton spinner (adjustment);
2692
2693         win.get_vbox()->set_spacing (12);
2694         win.get_vbox()->pack_start (label);
2695
2696         /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
2697            place, visually. so do this by hand.
2698         */
2699
2700         win.get_vbox()->pack_start (spinner);
2701         spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
2702
2703         label.show ();
2704         spinner.show ();
2705
2706         win.add_button (Stock::OK, RESPONSE_ACCEPT);
2707         win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2708
2709         win.set_position (WIN_POS_MOUSE);
2710
2711         spinner.grab_focus ();
2712
2713         switch (win.run ()) {
2714         case RESPONSE_ACCEPT:
2715                 break;
2716         default:
2717                 return;
2718         }
2719
2720         float times = adjustment.get_value();
2721
2722         if (!selection->regions.empty()) {
2723                 duplicate_some_regions (selection->regions, times);
2724         } else {
2725                 duplicate_selection (times);
2726         }
2727 }
2728
2729 void
2730 Editor::show_verbose_canvas_cursor ()
2731 {
2732         verbose_canvas_cursor->raise_to_top();
2733         verbose_canvas_cursor->show();
2734         verbose_cursor_visible = true;
2735 }
2736
2737 void
2738 Editor::hide_verbose_canvas_cursor ()
2739 {
2740         verbose_canvas_cursor->hide();
2741         verbose_cursor_visible = false;
2742 }
2743
2744 void
2745 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
2746 {
2747         /* XXX get origin of canvas relative to root window,
2748            add x and y and check compared to gdk_screen_{width,height}
2749         */
2750         verbose_canvas_cursor->property_text() = txt.c_str();
2751         verbose_canvas_cursor->property_x() = x;
2752         verbose_canvas_cursor->property_y() = y;
2753 }
2754
2755 void
2756 Editor::set_verbose_canvas_cursor_text (const string & txt)
2757 {
2758         verbose_canvas_cursor->property_text() = txt.c_str();
2759 }
2760
2761 void
2762 Editor::edit_mode_selection_done ()
2763 {
2764         if (session == 0) {
2765                 return;
2766         }
2767
2768         string choice = edit_mode_selector.get_active_text();
2769         EditMode mode = Slide;
2770
2771         if (choice == _("Splice Edit")) {
2772                 mode = Splice;
2773         } else if (choice == _("Slide Edit")) {
2774                 mode = Slide;
2775         }
2776
2777         Config->set_edit_mode (mode);
2778 }       
2779
2780 void
2781 Editor::snap_type_selection_done ()
2782 {
2783         string choice = snap_type_selector.get_active_text();
2784         SnapType snaptype = SnapToFrame;
2785
2786         if (choice == _("Beats/3")) {
2787                 snaptype = SnapToAThirdBeat;
2788         } else if (choice == _("Beats/4")) {
2789                 snaptype = SnapToAQuarterBeat;
2790         } else if (choice == _("Beats/8")) {
2791                 snaptype = SnapToAEighthBeat;
2792         } else if (choice == _("Beats/16")) {
2793                 snaptype = SnapToASixteenthBeat;
2794         } else if (choice == _("Beats/32")) {
2795                 snaptype = SnapToAThirtysecondBeat;
2796         } else if (choice == _("Beats")) {
2797                 snaptype = SnapToBeat;
2798         } else if (choice == _("Bars")) {
2799                 snaptype = SnapToBar;
2800         } else if (choice == _("Marks")) {
2801                 snaptype = SnapToMark;
2802         } else if (choice == _("Edit Cursor")) {
2803                 snaptype = SnapToEditCursor;
2804         } else if (choice == _("Region starts")) {
2805                 snaptype = SnapToRegionStart;
2806         } else if (choice == _("Region ends")) {
2807                 snaptype = SnapToRegionEnd;
2808         } else if (choice == _("Region bounds")) {
2809                 snaptype = SnapToRegionBoundary;
2810         } else if (choice == _("Region syncs")) {
2811                 snaptype = SnapToRegionSync;
2812         } else if (choice == _("CD Frames")) {
2813                 snaptype = SnapToCDFrame;
2814         } else if (choice == _("SMPTE Frames")) {
2815                 snaptype = SnapToSMPTEFrame;
2816         } else if (choice == _("SMPTE Seconds")) {
2817                 snaptype = SnapToSMPTESeconds;
2818         } else if (choice == _("SMPTE Minutes")) {
2819                 snaptype = SnapToSMPTEMinutes;
2820         } else if (choice == _("Seconds")) {
2821                 snaptype = SnapToSeconds;
2822         } else if (choice == _("Minutes")) {
2823                 snaptype = SnapToMinutes;
2824         } else if (choice == _("None")) {
2825                 snaptype = SnapToFrame;
2826         }
2827
2828         RefPtr<RadioAction> ract = snap_type_action (snaptype);
2829         if (ract) {
2830                 ract->set_active ();
2831         }
2832 }       
2833
2834 void
2835 Editor::snap_mode_selection_done ()
2836 {
2837         string choice = snap_mode_selector.get_active_text();
2838         SnapMode mode = SnapNormal;
2839
2840         if (choice == _("Normal")) {
2841                 mode = SnapNormal;
2842         } else if (choice == _("Magnetic")) {
2843                 mode = SnapMagnetic;
2844         }
2845
2846         RefPtr<RadioAction> ract = snap_mode_action (mode);
2847
2848         if (ract) {
2849                 ract->set_active (true);
2850         }
2851 }
2852
2853 void
2854 Editor::zoom_focus_selection_done ()
2855 {
2856         string choice = zoom_focus_selector.get_active_text();
2857         ZoomFocus focus_type = ZoomFocusLeft;
2858
2859         if (choice == _("Left")) {
2860                 focus_type = ZoomFocusLeft;
2861         } else if (choice == _("Right")) {
2862                 focus_type = ZoomFocusRight;
2863         } else if (choice == _("Center")) {
2864                 focus_type = ZoomFocusCenter;
2865         } else if (choice == _("Playhead")) {
2866                 focus_type = ZoomFocusPlayhead;
2867         } else if (choice == _("Edit Cursor")) {
2868                 focus_type = ZoomFocusEdit;
2869         } 
2870         
2871         RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
2872
2873         if (ract) {
2874                 ract->set_active ();
2875         }
2876 }       
2877
2878 gint
2879 Editor::edit_controls_button_release (GdkEventButton* ev)
2880 {
2881         if (Keyboard::is_context_menu_event (ev)) {
2882                 ARDOUR_UI::instance()->add_route (this);
2883         }
2884         return TRUE;
2885 }
2886
2887 gint
2888 Editor::mouse_select_button_release (GdkEventButton* ev)
2889 {
2890         /* this handles just right-clicks */
2891
2892         if (ev->button != 3) {
2893                 return false;
2894         }
2895
2896         return true;
2897 }
2898
2899 Editor::TrackViewList *
2900 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
2901 {
2902         TrackViewList *v;
2903         TrackViewList::iterator i;
2904
2905         v = new TrackViewList;
2906
2907         if (track == 0 && group == 0) {
2908
2909                 /* all views */
2910
2911                 for (i = track_views.begin(); i != track_views.end (); ++i) {
2912                         v->push_back (*i);
2913                 }
2914
2915         } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
2916                 
2917                 /* just the view for this track
2918                  */
2919
2920                 v->push_back (track);
2921
2922         } else {
2923                 
2924                 /* views for all tracks in the edit group */
2925                 
2926                 for (i  = track_views.begin(); i != track_views.end (); ++i) {
2927
2928                         if (group == 0 || (*i)->edit_group() == group) {
2929                                 v->push_back (*i);
2930                         }
2931                 }
2932         }
2933         
2934         return v;
2935 }
2936
2937 void
2938 Editor::set_zoom_focus (ZoomFocus f)
2939 {
2940         string str = zoom_focus_strings[(int)f];
2941
2942         if (str != zoom_focus_selector.get_active_text()) {
2943                 zoom_focus_selector.set_active_text (str);
2944         }
2945         
2946         if (zoom_focus != f) {
2947                 zoom_focus = f;
2948
2949                 ZoomFocusChanged (); /* EMIT_SIGNAL */
2950
2951                 instant_save ();
2952         }
2953 }
2954
2955 void
2956 Editor::ensure_float (Window& win)
2957 {
2958         win.set_transient_for (*this);
2959 }
2960
2961 void 
2962 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
2963 {
2964         /* recover or initialize pane positions. do this here rather than earlier because
2965            we don't want the positions to change the child allocations, which they seem to do.
2966          */
2967
2968         int pos;
2969         XMLProperty* prop;
2970         char buf[32];
2971         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
2972         int width, height;
2973         static int32_t done;
2974         XMLNode* geometry;
2975
2976         if ((geometry = find_named_node (*node, "geometry")) == 0) {
2977                 width = default_width;
2978                 height = default_height;
2979         } else {
2980                 width = atoi(geometry->property("x_size")->value());
2981                 height = atoi(geometry->property("y_size")->value());
2982         }
2983
2984         if (which == static_cast<Paned*> (&edit_pane)) {
2985
2986                 if (done) {
2987                         return;
2988                 }
2989
2990                 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
2991                         /* initial allocation is 90% to canvas, 10% to notebook */
2992                         pos = (int) floor (alloc.get_width() * 0.90f);
2993                         snprintf (buf, sizeof(buf), "%d", pos);
2994                 } else {
2995                         pos = atoi (prop->value());
2996                 }
2997                 
2998                 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
2999                         edit_pane.set_position (pos);
3000                         pre_maximal_pane_position = pos;
3001                 }
3002         }
3003 }
3004
3005 void
3006 Editor::detach_tearoff (Box* b, Window* w)
3007 {
3008         if (tools_tearoff->torn_off() && 
3009             mouse_mode_tearoff->torn_off()) {
3010                 top_hbox.remove (toolbar_frame);
3011         }
3012 }
3013
3014 void
3015 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3016 {
3017         if (toolbar_frame.get_parent() == 0) {
3018                 top_hbox.pack_end (toolbar_frame);
3019         }
3020 }
3021
3022 void
3023 Editor::set_show_measures (bool yn)
3024 {
3025         if (_show_measures != yn) {
3026                 hide_measures ();
3027
3028                 if ((_show_measures = yn) == true) {
3029                         draw_measures ();
3030                 }
3031                 instant_save ();
3032         }
3033 }
3034
3035 void
3036 Editor::toggle_follow_playhead ()
3037 {
3038         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3039         if (act) {
3040                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3041                 set_follow_playhead (tact->get_active());
3042         }
3043 }
3044
3045 void
3046 Editor::set_follow_playhead (bool yn)
3047 {
3048         if (_follow_playhead != yn) {
3049                 if ((_follow_playhead = yn) == true) {
3050                         /* catch up */
3051                         update_current_screen ();
3052                 }
3053                 instant_save ();
3054         }
3055 }
3056
3057 void
3058 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3059 {
3060         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3061         if (xfade) {
3062                 xfade->set_active (!xfade->active());
3063         }
3064 }
3065
3066 void
3067 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3068 {
3069         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3070         if (xfade) {
3071                 xfade->set_follow_overlap (!xfade->following_overlap());
3072         }
3073 }
3074
3075 void
3076 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3077 {
3078         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3079
3080         if (!xfade) {
3081                 return;
3082         }
3083
3084         CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3085                 
3086         ensure_float (cew);
3087         
3088         switch (cew.run ()) {
3089         case RESPONSE_ACCEPT:
3090                 break;
3091         default:
3092                 return;
3093         }
3094         
3095         cew.apply ();
3096         xfade->StateChanged (Change (~0));
3097 }
3098
3099 PlaylistSelector&
3100 Editor::playlist_selector () const
3101 {
3102         return *_playlist_selector;
3103 }
3104
3105 nframes_t
3106 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3107 {
3108         nframes_t ret;
3109
3110         ret = nudge_clock.current_duration (pos);
3111         next = ret + 1; /* XXXX fix me */
3112
3113         return ret;
3114 }
3115
3116 void
3117 Editor::end_location_changed (Location* location)
3118 {
3119         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3120         reset_scrolling_region ();
3121 }
3122
3123 int
3124 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3125 {
3126         ArdourDialog dialog ("playlist deletion dialog");
3127         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
3128                                         "If left alone, no audio files used by it will be cleaned.\n"
3129                                         "If deleted, audio files used by it alone by will cleaned."),
3130                                       pl->name()));
3131         
3132         dialog.set_position (WIN_POS_CENTER);
3133         dialog.get_vbox()->pack_start (label);
3134
3135         label.show ();
3136
3137         dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3138         dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3139         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3140
3141         switch (dialog.run ()) {
3142         case RESPONSE_ACCEPT:
3143                 /* delete the playlist */
3144                 return 0;
3145                 break;
3146
3147         case RESPONSE_REJECT:
3148                 /* keep the playlist */
3149                 return 1;
3150                 break;
3151
3152         default:
3153                 break;
3154         }
3155
3156         return -1;
3157 }
3158
3159 bool
3160 Editor::audio_region_selection_covers (nframes_t where)
3161 {
3162         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3163                 if ((*a)->region()->covers (where)) {
3164                         return true;
3165                 }
3166         }
3167
3168         return false;
3169 }
3170
3171 void
3172 Editor::prepare_for_cleanup ()
3173 {
3174         cut_buffer->clear_regions ();
3175         cut_buffer->clear_playlists ();
3176
3177         selection->clear_regions ();
3178         selection->clear_playlists ();
3179 }
3180
3181 Location*
3182 Editor::transport_loop_location()
3183 {
3184         if (session) {
3185                 return session->locations()->auto_loop_location();
3186         } else {
3187                 return 0;
3188         }
3189 }
3190
3191 Location*
3192 Editor::transport_punch_location()
3193 {
3194         if (session) {
3195                 return session->locations()->auto_punch_location();
3196         } else {
3197                 return 0;
3198         }
3199 }
3200
3201 bool
3202 Editor::control_layout_scroll (GdkEventScroll* ev)
3203 {
3204         switch (ev->direction) {
3205         case GDK_SCROLL_UP:
3206                 scroll_tracks_up_line ();
3207                 return true;
3208                 break;
3209
3210         case GDK_SCROLL_DOWN:
3211                 scroll_tracks_down_line ();
3212                 return true;
3213                 
3214         default:
3215                 /* no left/right handling yet */
3216                 break;
3217         }
3218
3219         return false;
3220 }
3221
3222
3223 /** A new snapshot has been selected.
3224  */
3225 void
3226 Editor::snapshot_display_selection_changed ()
3227 {
3228         if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3229
3230                 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3231                 
3232                 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3233
3234                 if (snap_name.length() == 0) {
3235                         return;
3236                 }
3237                 
3238                 if (session->snap_name() == snap_name) {
3239                         return;
3240                 }
3241                 
3242                 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3243         }
3244 }
3245
3246 bool
3247 Editor::snapshot_display_button_press (GdkEventButton* ev)
3248 {
3249         if (ev->button == 3) {
3250                 /* Right-click on the snapshot list. Work out which snapshot it
3251                    was over. */
3252                 Gtk::TreeModel::Path path;
3253                 Gtk::TreeViewColumn* col;
3254                 int cx;
3255                 int cy;
3256                 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3257                 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3258                 if (iter) {
3259                         Gtk::TreeModel::Row row = *iter;
3260                         popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3261                 }
3262                 return true;
3263         }
3264
3265         return false;
3266 }
3267
3268
3269 /** Pop up the snapshot display context menu.
3270  * @param button Button used to open the menu.
3271  * @param time Menu open time.
3272  * @snapshot_name Name of the snapshot that the menu click was over.
3273  */
3274
3275 void
3276 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3277 {
3278         using namespace Menu_Helpers;
3279
3280         MenuList& items (snapshot_context_menu.items());
3281         items.clear ();
3282
3283         const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3284
3285         add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3286
3287         add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3288
3289         snapshot_context_menu.popup (button, time);
3290 }
3291
3292 void
3293 Editor::rename_snapshot (Glib::ustring old_name)
3294 {
3295         ArdourPrompter prompter(true);
3296
3297         string new_name;
3298
3299         prompter.set_name ("Prompter");
3300         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3301         prompter.set_prompt (_("New name of snapshot"));
3302         prompter.set_initial_text (old_name);
3303         
3304         if (prompter.run() == RESPONSE_ACCEPT) {
3305                 prompter.get_result (new_name);
3306                 if (new_name.length()) {
3307                         session->rename_state (old_name, new_name);
3308                         redisplay_snapshots ();
3309                 }
3310         }
3311 }
3312
3313
3314 void
3315 Editor::remove_snapshot (Glib::ustring name)
3316 {
3317         vector<string> choices;
3318
3319         std::string prompt  = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3320
3321         choices.push_back (_("No, do nothing."));
3322         choices.push_back (_("Yes, remove it."));
3323
3324         Gtkmm2ext::Choice prompter (prompt, choices);
3325
3326         if (prompter.run () == 1) {
3327                 session->remove_state (name);
3328                 redisplay_snapshots ();
3329         }
3330 }
3331
3332 void
3333 Editor::redisplay_snapshots ()
3334 {
3335         if (session == 0) {
3336                 return;
3337         }
3338
3339         vector<string*>* states;
3340
3341         if ((states = session->possible_states()) == 0) {
3342                 return;
3343         }
3344
3345         snapshot_display_model->clear ();
3346
3347         for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3348                 string statename = *(*i);
3349                 TreeModel::Row row = *(snapshot_display_model->append());
3350                 
3351                 /* this lingers on in case we ever want to change the visible
3352                    name of the snapshot.
3353                 */
3354                 
3355                 string display_name;
3356                 display_name = statename;
3357
3358                 if (statename == session->snap_name()) {
3359                         snapshot_display.get_selection()->select(row);
3360                 } 
3361                 
3362                 row[snapshot_display_columns.visible_name] = display_name;
3363                 row[snapshot_display_columns.real_name] = statename;
3364         }
3365
3366         delete states;
3367 }
3368
3369 void
3370 Editor::session_state_saved (string snap_name)
3371 {
3372         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3373         redisplay_snapshots ();
3374 }
3375
3376 void
3377 Editor::maximise_editing_space ()
3378 {
3379         initial_ruler_update_required = true;
3380
3381         mouse_mode_tearoff->set_visible (false);
3382         tools_tearoff->set_visible (false);
3383
3384         pre_maximal_pane_position = edit_pane.get_position();
3385         pre_maximal_editor_width = this->get_width();
3386
3387         if(post_maximal_pane_position == 0) {
3388                 post_maximal_pane_position = edit_pane.get_width();
3389         }
3390
3391
3392         fullscreen();
3393         if(post_maximal_editor_width) {
3394                 edit_pane.set_position (post_maximal_pane_position - 
3395                         abs(post_maximal_editor_width - pre_maximal_editor_width));
3396         } else {
3397                 edit_pane.set_position (post_maximal_pane_position);
3398         }
3399 }
3400
3401 void
3402 Editor::restore_editing_space ()
3403 {
3404         initial_ruler_update_required = true;
3405
3406         // user changed width of pane during fullscreen
3407         if(post_maximal_pane_position != edit_pane.get_position()) {
3408                 post_maximal_pane_position = edit_pane.get_position();
3409         }
3410
3411         unfullscreen();
3412
3413         mouse_mode_tearoff->set_visible (true);
3414         tools_tearoff->set_visible (true);
3415         post_maximal_editor_width = this->get_width();
3416
3417
3418         edit_pane.set_position (
3419                 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3420         );
3421 }
3422
3423 void 
3424 Editor::new_playlists ()
3425 {
3426         begin_reversible_command (_("new playlists"));
3427         mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist));
3428         commit_reversible_command ();
3429 }
3430
3431 void
3432 Editor::copy_playlists ()
3433 {
3434         begin_reversible_command (_("copy playlists"));
3435         mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist));
3436         commit_reversible_command ();
3437 }
3438
3439 void 
3440 Editor::clear_playlists ()
3441 {
3442         begin_reversible_command (_("clear playlists"));
3443         mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist));
3444         commit_reversible_command ();
3445 }
3446
3447 void 
3448 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3449 {
3450         atv.use_new_playlist (sz > 1 ? false : true);
3451 }
3452
3453 void
3454 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3455 {
3456         atv.use_copy_playlist (sz > 1 ? false : true);
3457 }
3458
3459 void 
3460 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3461 {
3462         atv.clear_playlist ();
3463 }
3464
3465 bool
3466 Editor::on_key_press_event (GdkEventKey* ev)
3467 {
3468         return key_press_focus_accelerator_handler (*this, ev);
3469 }
3470
3471 void
3472 Editor::reset_x_origin (nframes_t frame)
3473 {
3474         queue_visual_change (frame);
3475 }
3476
3477 void
3478 Editor::reset_zoom (double fpu)
3479 {
3480         queue_visual_change (fpu);
3481 }
3482
3483 void
3484 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3485 {
3486         reset_x_origin (frame);
3487         reset_zoom (fpu);
3488 }
3489
3490 void
3491 Editor::set_frames_per_unit (double fpu)
3492 {
3493         nframes_t frames;
3494
3495         /* this is the core function that controls the zoom level of the canvas. it is called
3496            whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3497         */
3498
3499         if (fpu == frames_per_unit) {
3500                 return;
3501         }
3502
3503         if (fpu < 2.0) {
3504                 fpu = 2.0;
3505         }
3506
3507         // convert fpu to frame count
3508
3509         frames = (nframes_t) floor (fpu * canvas_width);
3510         
3511         /* don't allow zooms that fit more than the maximum number
3512            of frames into an 800 pixel wide space.
3513         */
3514
3515         if (max_frames / fpu < 800.0) {
3516                 return;
3517         }
3518
3519         if (fpu == frames_per_unit) {
3520                 return;
3521         }
3522
3523         frames_per_unit = fpu;
3524
3525         if (frames != zoom_range_clock.current_duration()) {
3526                 zoom_range_clock.set (frames);
3527         }
3528
3529         if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3530                 if (!selection->tracks.empty()) {
3531                         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3532                                 (*i)->reshow_selection (selection->time);
3533                         }
3534                 } else {
3535                         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3536                                 (*i)->reshow_selection (selection->time);
3537                         }
3538                 }
3539         }
3540
3541         ZoomChanged (); /* EMIT_SIGNAL */
3542
3543         reset_hscrollbar_stepping ();
3544         reset_scrolling_region ();
3545         
3546         if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3547         if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3548
3549         instant_save ();
3550 }
3551
3552 void
3553 Editor::queue_visual_change (nframes_t where)
3554 {
3555         pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3556         pending_visual_change.time_origin = where;
3557
3558         if (pending_visual_change.idle_handler_id < 0) {
3559                 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3560         }
3561 }
3562
3563 void
3564 Editor::queue_visual_change (double fpu)
3565 {
3566         pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3567         pending_visual_change.frames_per_unit = fpu;
3568
3569         if (pending_visual_change.idle_handler_id < 0) {
3570                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3571         }
3572 }
3573
3574 int
3575 Editor::_idle_visual_changer (void* arg)
3576 {
3577         return static_cast<Editor*>(arg)->idle_visual_changer ();
3578 }
3579
3580 int
3581 Editor::idle_visual_changer ()
3582 {
3583         VisualChange::Type p = pending_visual_change.pending;
3584
3585         pending_visual_change.pending = (VisualChange::Type) 0;
3586         pending_visual_change.idle_handler_id = -1;
3587         
3588         if (p & VisualChange::ZoomLevel) {
3589                 set_frames_per_unit (pending_visual_change.frames_per_unit);
3590         }
3591
3592         if (p & VisualChange::TimeOrigin) {
3593                 if (pending_visual_change.time_origin != leftmost_frame) {
3594                         horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3595                         /* the signal handler will do the rest */
3596                 } else {
3597                         update_fixed_rulers();
3598                         redisplay_tempo (true);
3599                 }
3600         }
3601
3602         return 0; /* this is always a one-shot call */
3603 }
3604
3605 struct EditorOrderTimeAxisSorter {
3606     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
3607             return a->order < b->order;
3608     }
3609 };
3610         
3611 void
3612 Editor::sort_track_selection ()
3613 {
3614         EditorOrderTimeAxisSorter cmp;
3615         selection->tracks.sort (cmp);
3616 }
3617
3618 nframes_t
3619 Editor::edit_cursor_position(bool sync)
3620 {
3621         if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
3622                 edit_cursor_clock.set(edit_cursor->current_frame, true);
3623         }
3624
3625         return edit_cursor->current_frame;
3626 }