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