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