Back out recent bad patch.
[ardour.git] / gtk2_ardour / editor.cc
1 /*
2     Copyright (C) 2000-2007 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <unistd.h>
23 #include <cstdlib>
24 #include <cmath>
25 #include <string>
26 #include <algorithm>
27
28 #include <boost/none.hpp>
29
30 #include <sigc++/bind.h>
31
32 #include <pbd/convert.h>
33 #include <pbd/error.h>
34 #include <pbd/enumwriter.h>
35 #include <pbd/memento_command.h>
36
37 #include <glibmm/miscutils.h>
38 #include <gtkmm/image.h>
39 #include <gdkmm/color.h>
40 #include <gdkmm/bitmap.h>
41
42 #include <gtkmm2ext/grouped_buttons.h>
43 #include <gtkmm2ext/gtk_ui.h>
44 #include <gtkmm2ext/tearoff.h>
45 #include <gtkmm2ext/utils.h>
46 #include <gtkmm2ext/window_title.h>
47 #include <gtkmm2ext/choice.h>
48
49 #include <ardour/audio_track.h>
50 #include <ardour/audio_diskstream.h>
51 #include <ardour/plugin_manager.h>
52 #include <ardour/location.h>
53 #include <ardour/audioplaylist.h>
54 #include <ardour/audioregion.h>
55 #include <ardour/midi_region.h>
56 #include <ardour/session_route.h>
57 #include <ardour/session_directory.h>
58 #include <ardour/session_state_utils.h>
59 #include <ardour/tempo.h>
60 #include <ardour/utils.h>
61 #include <ardour/profile.h>
62
63 #include <control_protocol/control_protocol.h>
64
65 #include "ardour_ui.h"
66 #include "editor.h"
67 #include "keyboard.h"
68 #include "marker.h"
69 #include "playlist_selector.h"
70 #include "audio_region_view.h"
71 #include "rgb_macros.h"
72 #include "selection.h"
73 #include "audio_streamview.h"
74 #include "time_axis_view.h"
75 #include "audio_time_axis.h"
76 #include "utils.h"
77 #include "crossfade_view.h"
78 #include "editing.h"
79 #include "public_editor.h"
80 #include "crossfade_edit.h"
81 #include "canvas_impl.h"
82 #include "actions.h"
83 #include "sfdb_ui.h"
84 #include "gui_thread.h"
85
86 #ifdef FFT_ANALYSIS
87 #include "analysis_window.h"
88 #endif
89
90 #include "i18n.h"
91
92 #ifdef WITH_CMT
93 #include "imageframe_socket_handler.h"
94 #endif
95
96 using namespace std;
97 using namespace sigc;
98 using namespace ARDOUR;
99 using namespace PBD;
100 using namespace Gtk;
101 using namespace Glib;
102 using namespace Gtkmm2ext;
103 using namespace Editing;
104
105 using PBD::internationalize;
106 using PBD::atoi;
107
108 const double Editor::timebar_height = 15.0;
109
110 #include "editor_xpms"
111
112 static const gchar *_snap_type_strings[] = {
113         N_("None"),
114         N_("CD Frames"),
115         N_("SMPTE Frames"),
116         N_("SMPTE Seconds"),
117         N_("SMPTE Minutes"),
118         N_("Seconds"),
119         N_("Minutes"),
120         N_("Beats/32"),
121         N_("Beats/16"),
122         N_("Beats/8"),
123         N_("Beats/4"),
124         N_("Beats/3"),
125         N_("Beats"),
126         N_("Bars"),
127         N_("Marks"),
128         N_("Edit Cursor"),
129         N_("Region starts"),
130         N_("Region ends"),
131         N_("Region syncs"),
132         N_("Region bounds"),
133         0
134 };
135
136 static const gchar *_snap_mode_strings[] = {
137         N_("Normal"),
138         N_("Magnetic"),
139         0
140 };
141
142 static const gchar *_zoom_focus_strings[] = {
143         N_("Left"),
144         N_("Right"),
145         N_("Center"),
146         N_("Playhead"),
147         N_("Edit Cursor"),
148         0
149 };
150
151 /* Soundfile  drag-n-drop */
152
153 Gdk::Cursor* Editor::cross_hair_cursor = 0;
154 Gdk::Cursor* Editor::selector_cursor = 0;
155 Gdk::Cursor* Editor::trimmer_cursor = 0;
156 Gdk::Cursor* Editor::grabber_cursor = 0;
157 Gdk::Cursor* Editor::zoom_cursor = 0;
158 Gdk::Cursor* Editor::time_fx_cursor = 0;
159 Gdk::Cursor* Editor::fader_cursor = 0;
160 Gdk::Cursor* Editor::speaker_cursor = 0;
161 Gdk::Cursor* Editor::midi_pencil_cursor = 0;
162 Gdk::Cursor* Editor::midi_select_cursor = 0;
163 Gdk::Cursor* Editor::midi_erase_cursor = 0;
164 Gdk::Cursor* Editor::wait_cursor = 0;
165 Gdk::Cursor* Editor::timebar_cursor = 0;
166
167 void
168 show_me_the_size (Requisition* r, const char* what)
169 {
170         cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
171 }
172
173 void 
174 check_adjustment (Gtk::Adjustment* adj)
175 {
176         cerr << "CHANGE adj  = " 
177              << adj->get_lower () <<  ' '
178              << adj->get_upper () <<  ' '
179              << adj->get_value () <<  ' '
180              << adj->get_step_increment () <<  ' '
181              << adj->get_page_increment () <<  ' '
182              << adj->get_page_size () <<  ' '
183              << endl;
184
185 }
186
187 Editor::Editor ()
188         : 
189           /* time display buttons */
190
191           minsec_label (_("Mins:Secs")),
192           bbt_label (_("Bars:Beats")),
193           smpte_label (_("Timecode")),
194           frame_label (_("Frames")),
195           tempo_label (_("Tempo")),
196           meter_label (_("Meter")),
197           mark_label (_("Location Markers")),
198           range_mark_label (_("Range Markers")),
199           transport_mark_label (_("Loop/Punch Ranges")),
200
201           edit_packer (3, 3, false),
202
203           /* the values here don't matter: layout widgets
204              reset them as needed.
205           */
206
207           vertical_adjustment (0.0, 0.0, 10.0, 400.0),
208           horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
209
210           tempo_lines(0),
211           marker_tempo_lines(0),
212
213           /* tool bar related */
214
215           edit_cursor_clock (X_("editcursor"), false, X_("EditCursorClock"), true),
216           zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
217           
218           toolbar_selection_clock_table (2,3),
219           
220           automation_mode_button (_("mode")),
221           global_automation_button (_("automation")),
222
223 #ifdef WITH_CMT
224           image_socket_listener(0),
225 #endif
226
227           /* nudge */
228
229           nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
230
231 {
232         constructed = false;
233
234         /* we are a singleton */
235
236         PublicEditor::_instance = this;
237
238         session = 0;
239
240         selection = new Selection (this);
241         cut_buffer = new Selection (this);
242
243         selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
244         selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
245         selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
246         selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
247
248         clicked_regionview = 0;
249         clicked_axisview = 0;
250         clicked_routeview = 0;
251         clicked_crossfadeview = 0;
252         clicked_control_point = 0;
253         latest_regionview = 0;
254         last_update_frame = 0;
255         drag_info.item = 0;
256         current_mixer_strip = 0;
257         current_bbt_points = 0;
258
259         snap_type_strings = I18N (_snap_type_strings);
260         snap_mode_strings = I18N (_snap_mode_strings);
261         zoom_focus_strings = I18N(_zoom_focus_strings);
262
263         snap_type = SnapToFrame;
264         set_snap_to (snap_type);
265         snap_mode = SnapNormal;
266         set_snap_mode (snap_mode);
267         snap_threshold = 5.0;
268         bbt_beat_subdivision = 4;
269         canvas_width = 0;
270         canvas_height = 0;
271         autoscroll_active = false;
272         autoscroll_timeout_tag = -1;
273         interthread_progress_window = 0;
274         logo_item = 0;
275
276 #ifdef FFT_ANALYSIS
277         analysis_window = 0;
278 #endif
279
280         current_interthread_info = 0;
281         _show_measures = true;
282         _show_waveforms = true;
283         _show_waveforms_recording = true;
284         first_action_message = 0;
285         export_dialog = 0;
286         export_range_markers_dialog = 0;
287         show_gain_after_trim = false;
288         ignore_route_list_reorder = false;
289         no_route_list_redisplay = false;
290         verbose_cursor_on = true;
291         route_removal = false;
292         show_automatic_regions_in_region_list = true;
293         region_list_sort_type = (Editing::RegionListSortType) 0; 
294         have_pending_keyboard_selection = false;
295         _follow_playhead = true;
296         _xfade_visibility = true;
297         editor_ruler_menu = 0;
298         no_ruler_shown_update = false;
299         edit_group_list_menu = 0;
300         route_list_menu = 0;
301         region_list_menu = 0;
302         marker_menu = 0;
303         start_end_marker_menu = 0;
304         range_marker_menu = 0;
305         marker_menu_item = 0;
306         tm_marker_menu = 0;
307         transport_marker_menu = 0;
308         new_transport_marker_menu = 0;
309         editor_mixer_strip_width = Wide;
310         show_editor_mixer_when_tracks_arrive = false;
311         region_edit_menu_split_multichannel_item = 0;
312         region_edit_menu_split_item = 0;
313         temp_location = 0;
314         leftmost_frame = 0;
315         ignore_mouse_mode_toggle = false;
316         ignore_midi_edit_mode_toggle = false;
317         current_stepping_trackview = 0;
318         entered_track = 0;
319         entered_regionview = 0;
320         clear_entered_track = false;
321         _new_regionviews_show_envelope = false;
322         current_timestretch = 0;
323         in_edit_group_row_change = false;
324         last_canvas_frame = 0;
325         edit_cursor = 0;
326         playhead_cursor = 0;
327         button_release_can_deselect = true;
328         canvas_idle_queued = false;
329         _dragging_playhead = false;
330         _dragging_hscrollbar = false;
331
332         _scrubbing = false;
333         mouse_direction = 1;
334         mouse_speed_update = -1;
335         mouse_speed_size = 16;
336         mouse_speed = new double[mouse_speed_size];
337         memset (mouse_speed, 0, sizeof(double) * mouse_speed_size);
338         mouse_speed_entries = 0;
339
340         sfbrowser = 0;
341         ignore_route_order_sync = false;
342
343         location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
344         location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
345         location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
346         location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
347         location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
348
349         range_marker_drag_rect = 0;
350         marker_drag_line = 0;
351         
352         set_midi_edit_mode (MidiEditPencil, 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_pencil_cursor = new Gdk::Cursor (PENCIL);
1314         midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
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
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                 MenuList& envelopes_items = envelopes_menu->items();
1677
1678                 RegionView* rv = sv->find_view (ar);
1679                 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1680
1681                 if (!Profile->get_sae()) {
1682                         envelopes_items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1683
1684                         envelopes_items.push_back (CheckMenuElem (_("Envelope Visible")));
1685                         region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1686                         fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1687                         if (arv->envelope_visible()) {
1688                                 fooc.block (true);
1689                                 region_envelope_visible_item->set_active (true);
1690                                 fooc.block (false);
1691                         }
1692                 
1693                         envelopes_items.push_back (CheckMenuElem (_("Envelope Active")));
1694                         region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1695                         fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1696                         
1697                         if (ar->envelope_active()) {
1698                                 fooc.block (true);
1699                                 region_envelope_active_item->set_active (true);
1700                                 fooc.block (false);
1701                         }
1702
1703                         items.push_back (SeparatorElem());
1704                 }
1705 #endif
1706
1707                 items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
1708                 
1709 #if FIXUP_REGION_MENU
1710                 if (ar->scale_amplitude() != 1.0f) {
1711                         items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_regions)));
1712                 } else {
1713                         items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_regions)));
1714                 }
1715 #endif
1716         }
1717         
1718         /* Find out if we have a selected MIDI region */
1719         i = selection->regions.begin();
1720         while (i != selection->regions.end() && boost::dynamic_pointer_cast<MidiRegion>((*i)->region()) == 0) {
1721                 ++i;
1722         }
1723         const bool have_selected_midi_region = (i != selection->regions.end());
1724         
1725         if (have_selected_midi_region) {
1726
1727                 items.push_back (MenuElem (_("Quantize"), mem_fun(*this, &Editor::quantize_regions)));
1728                 items.push_back (SeparatorElem());
1729
1730         }
1731
1732         /* range related stuff */
1733         
1734         add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
1735         
1736         add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
1737         
1738         items.push_back (SeparatorElem());
1739                          
1740         /* Nudge region */
1741
1742         Menu *nudge_menu = manage (new Menu());
1743         MenuList& nudge_items = nudge_menu->items();
1744         nudge_menu->set_name ("ArdourContextMenu");
1745         
1746         nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1747         nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1748         nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1749         nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1750
1751         items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1752
1753         Menu *trim_menu = manage (new Menu);
1754         MenuList& trim_items = trim_menu->items();
1755         trim_menu->set_name ("ArdourContextMenu");
1756         
1757         trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1758         trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1759                              
1760         items.push_back (MenuElem (_("Trim"), *trim_menu));
1761         items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1762         items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1763         items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1764         items.push_back (MenuElem (_("Fill track"), (mem_fun(*this, &Editor::region_fill_track))));
1765         items.push_back (SeparatorElem());
1766         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions)));
1767
1768         /* OK, stick the region submenu at the top of the list, and then add
1769            the standard items.
1770         */
1771
1772         string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
1773         edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1774 }
1775
1776 /** Add context menu items relevant to selection ranges.
1777  * @param edit_items List to add the items to.
1778  */
1779 void
1780 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1781 {
1782         using namespace Menu_Helpers;
1783         Menu     *selection_menu = manage (new Menu);
1784         MenuList& items       = selection_menu->items();
1785         selection_menu->set_name ("ArdourContextMenu");
1786
1787         items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1788         items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1789
1790 #ifdef FFT_ANALYSIS
1791         items.push_back (SeparatorElem());
1792         items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1793 #endif
1794         
1795         items.push_back (SeparatorElem());
1796         items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1797         items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1798
1799         items.push_back (SeparatorElem());
1800         items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1801         items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1802         
1803         items.push_back (SeparatorElem());
1804         items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1805
1806         items.push_back (SeparatorElem());
1807         items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1808         items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1809         
1810         items.push_back (SeparatorElem());
1811         items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1812         items.push_back (SeparatorElem());
1813         items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1814         items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1815         items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1816         items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1817         items.push_back (SeparatorElem());
1818         items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1819         items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1820 }
1821
1822 /** Add context menu items relevant to busses or audio tracks.
1823  * @param edit_items List to add the items to.
1824  */
1825 void
1826 Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
1827 {
1828         using namespace Menu_Helpers;
1829
1830         /* We add every possible action here, and de-sensitize things
1831            that aren't allowed.  The sensitivity logic is a bit spread out;
1832            on the one hand I'm using things like can_cut_copy (), which is
1833            reasonably complicated and so perhaps better near the function that
1834            it expresses sensitivity for, and on the other hand checks
1835            in this function as well.  You can't really have can_* for everything
1836            or the number of methods would get silly. */
1837
1838         bool const one_selected_region = selection->regions.size() == 1;
1839
1840         /* Count the number of selected audio tracks */
1841         int n_audio_tracks = 0;
1842         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1843                 RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
1844                 if (r && r->is_audio_track()) {
1845                         n_audio_tracks++;
1846                 }
1847         }
1848
1849         /* Playback */
1850
1851         Menu *play_menu = manage (new Menu);
1852         MenuList& play_items = play_menu->items();
1853         play_menu->set_name ("ArdourContextMenu");
1854         
1855         play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1856         play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1857         add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
1858         
1859         add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
1860         
1861         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1862
1863         /* Selection */
1864
1865         Menu *select_menu = manage (new Menu);
1866         MenuList& select_items = select_menu->items();
1867         select_menu->set_name ("ArdourContextMenu");
1868
1869         string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
1870
1871         select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
1872         
1873         select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1874
1875         str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
1876         
1877         select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
1878         
1879         select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1880         select_items.push_back (SeparatorElem());
1881
1882         if (n_audio_tracks) {
1883                 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1884                 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1885         }
1886         
1887         select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1888         select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1889         select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1890         select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1891
1892         if (n_audio_tracks) {
1893                 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1894         }
1895
1896         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1897
1898         /* Cut-n-Paste */
1899
1900         Menu *cutnpaste_menu = manage (new Menu);
1901         MenuList& cutnpaste_items = cutnpaste_menu->items();
1902         cutnpaste_menu->set_name ("ArdourContextMenu");
1903
1904         add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
1905         
1906         add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
1907         
1908         if (n_audio_tracks) {
1909                 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1910                 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1911                 
1912                 cutnpaste_items.push_back (SeparatorElem());
1913                 
1914                 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1915                 cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1916                 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1917         } else {
1918                 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1919         }
1920
1921         edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1922                 
1923         if (n_audio_tracks) {
1924
1925                 Menu *track_menu = manage (new Menu);
1926                 MenuList& track_items = track_menu->items();
1927                 track_menu->set_name ("ArdourContextMenu");
1928                 
1929                 /* Adding new material */
1930         
1931                 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);
1932                 add_item_with_sensitivity (track_items, MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1933                 
1934                 /* Nudge */
1935
1936                 Menu *nudge_menu = manage (new Menu());
1937                 MenuList& nudge_items = nudge_menu->items();
1938                 nudge_menu->set_name ("ArdourContextMenu");
1939
1940                 str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
1941                 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
1942
1943                 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1944                 
1945                 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1946
1947                 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1948                 
1949                 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1950
1951                 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1952                 
1953                 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1954                 
1955                 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1956
1957                 /* Freeze */
1958                 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1959                 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1960
1961                 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1962                 edit_items.push_back (MenuElem (str, *track_menu));
1963         }
1964 }
1965
1966 /* CURSOR SETTING AND MARKS AND STUFF */
1967
1968 void
1969 Editor::set_snap_to (SnapType st)
1970 {       
1971         snap_type = st;
1972         string str = snap_type_strings[(int) st];
1973
1974         if (str != snap_type_selector.get_active_text()) {
1975                 snap_type_selector.set_active_text (str);
1976         }
1977
1978         instant_save ();
1979
1980         switch (snap_type) {
1981         case SnapToAThirtysecondBeat:
1982         case SnapToASixteenthBeat:
1983         case SnapToAEighthBeat:
1984         case SnapToAQuarterBeat:
1985         case SnapToAThirdBeat:
1986                 update_tempo_based_rulers ();
1987         default:
1988                 /* relax */
1989                 break;
1990     }
1991 }
1992
1993 void
1994 Editor::set_snap_mode (SnapMode mode)
1995 {
1996         snap_mode = mode;
1997         string str = snap_mode_strings[(int)mode];
1998
1999         if (str != snap_mode_selector.get_active_text ()) {
2000                 snap_mode_selector.set_active_text (str);
2001         }
2002
2003         instant_save ();
2004 }
2005
2006 int
2007 Editor::set_state (const XMLNode& node)
2008 {
2009         const XMLProperty* prop;
2010         XMLNode* geometry;
2011         int x, y, xoff, yoff;
2012         Gdk::Geometry g;
2013
2014         if ((prop = node.property ("id")) != 0) {
2015                 _id = prop->value ();
2016         }
2017
2018         if ((geometry = find_named_node (node, "geometry")) == 0) {
2019
2020                 g.base_width = default_width;
2021                 g.base_height = default_height;
2022                 x = 1;
2023                 y = 1;
2024                 xoff = 0;
2025                 yoff = 21;
2026
2027         } else {
2028
2029                 g.base_width = atoi(geometry->property("x_size")->value());
2030                 g.base_height = atoi(geometry->property("y_size")->value());
2031                 x = atoi(geometry->property("x_pos")->value());
2032                 y = atoi(geometry->property("y_pos")->value());
2033                 xoff = atoi(geometry->property("x_off")->value());
2034                 yoff = atoi(geometry->property("y_off")->value());
2035         }
2036
2037         set_default_size (g.base_width, g.base_height);
2038         move (x, y);
2039
2040         if (session && (prop = node.property ("playhead"))) {
2041                 nframes_t pos = atol (prop->value().c_str());
2042                 playhead_cursor->set_position (pos);
2043         } else {
2044                 playhead_cursor->set_position (0);
2045
2046                 /* reset_x_origin() doesn't work right here, since the old
2047                    position may be zero already, and it does nothing in such
2048                    circumstances.
2049                 */
2050                 
2051                 leftmost_frame = 0;
2052                 horizontal_adjustment.set_value (0);
2053         }
2054
2055         if (session && (prop = node.property ("edit-cursor"))) {
2056                 nframes_t pos = atol (prop->value().c_str());
2057                 edit_cursor->set_position (pos);
2058         } else {
2059                 edit_cursor->set_position (0);
2060         }
2061
2062         if ((prop = node.property ("mixer-width"))) {
2063                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2064         }
2065
2066         if ((prop = node.property ("zoom-focus"))) {
2067                 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2068         }
2069
2070         if ((prop = node.property ("zoom"))) {
2071                 reset_zoom (PBD::atof (prop->value()));
2072         }
2073
2074         if ((prop = node.property ("snap-to"))) {
2075                 set_snap_to ((SnapType) atoi (prop->value()));
2076         }
2077
2078         if ((prop = node.property ("snap-mode"))) {
2079                 set_snap_mode ((SnapMode) atoi (prop->value()));
2080         }
2081
2082         if ((prop = node.property ("mouse-mode"))) {
2083                 MouseMode m = str2mousemode(prop->value());
2084                 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2085                 set_mouse_mode (m, true);
2086         } else {
2087                 mouse_mode = MouseGain; /* lie, to force the mode switch */
2088                 set_mouse_mode (MouseObject, true);
2089         }
2090
2091         if ((prop = node.property ("show-waveforms"))) {
2092                 bool yn = (prop->value() == "yes");
2093                 _show_waveforms = !yn;
2094                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2095                 if (act) {
2096                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2097                         /* do it twice to force the change */
2098                         tact->set_active (!yn);
2099                         tact->set_active (yn);
2100                 }
2101         }
2102
2103         if ((prop = node.property ("show-waveforms-recording"))) {
2104                 bool yn = (prop->value() == "yes");
2105                 _show_waveforms_recording = !yn;
2106                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2107                 if (act) {
2108                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2109                         /* do it twice to force the change */
2110                         tact->set_active (!yn);
2111                         tact->set_active (yn);
2112                 }
2113         }
2114         
2115         if ((prop = node.property ("show-measures"))) {
2116                 bool yn = (prop->value() == "yes");
2117                 _show_measures = !yn;
2118                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2119                 if (act) {
2120                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2121                         /* do it twice to force the change */
2122                         tact->set_active (!yn);
2123                         tact->set_active (yn);
2124                 }
2125         }
2126
2127         if ((prop = node.property ("follow-playhead"))) {
2128                 bool yn = (prop->value() == "yes");
2129                 set_follow_playhead (yn);
2130                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2131                 if (act) {
2132                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2133                         if (tact->get_active() != yn) {
2134                                 tact->set_active (yn);
2135                         }
2136                 }
2137         }
2138
2139         if ((prop = node.property ("region-list-sort-type"))) {
2140                 region_list_sort_type = (Editing::RegionListSortType) -1; // force change 
2141                 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2142         }
2143
2144         if ((prop = node.property ("xfades-visible"))) {
2145                 bool yn = (prop->value() == "yes");
2146                 _xfade_visibility = !yn;
2147                 // set_xfade_visibility (yn);
2148         }
2149
2150         if ((prop = node.property ("show-editor-mixer"))) {
2151
2152                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2153                 if (act) {
2154
2155                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2156                         bool yn = (prop->value() == X_("yes"));
2157
2158                         /* do it twice to force the change */
2159                         
2160                         tact->set_active (!yn);
2161                         tact->set_active (yn);
2162                 }
2163         }
2164         
2165         if ((prop = node.property ("show-editor-list"))) {
2166
2167                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2168                 assert(act);
2169                 if (act) {
2170
2171                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2172                         bool yn = (prop->value() == X_("yes"));
2173
2174                         /* do it twice to force the change */
2175                         
2176                         tact->set_active (!yn);
2177                         tact->set_active (yn);
2178                 }
2179         }
2180
2181
2182         return 0;
2183 }
2184
2185 XMLNode&
2186 Editor::get_state ()
2187 {
2188         XMLNode* node = new XMLNode ("Editor");
2189         char buf[32];
2190
2191         _id.print (buf, sizeof (buf));
2192         node->add_property ("id", buf);
2193         
2194         if (is_realized()) {
2195                 Glib::RefPtr<Gdk::Window> win = get_window();
2196                 
2197                 int x, y, xoff, yoff, width, height;
2198                 win->get_root_origin(x, y);
2199                 win->get_position(xoff, yoff);
2200                 win->get_size(width, height);
2201                 
2202                 XMLNode* geometry = new XMLNode ("geometry");
2203
2204                 snprintf(buf, sizeof(buf), "%d", width);
2205                 geometry->add_property("x_size", string(buf));
2206                 snprintf(buf, sizeof(buf), "%d", height);
2207                 geometry->add_property("y_size", string(buf));
2208                 snprintf(buf, sizeof(buf), "%d", x);
2209                 geometry->add_property("x_pos", string(buf));
2210                 snprintf(buf, sizeof(buf), "%d", y);
2211                 geometry->add_property("y_pos", string(buf));
2212                 snprintf(buf, sizeof(buf), "%d", xoff);
2213                 geometry->add_property("x_off", string(buf));
2214                 snprintf(buf, sizeof(buf), "%d", yoff);
2215                 geometry->add_property("y_off", string(buf));
2216                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2217                 geometry->add_property("edit_pane_pos", string(buf));
2218
2219                 node->add_child_nocopy (*geometry);
2220         }
2221
2222         maybe_add_mixer_strip_width (*node);
2223         
2224         snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2225         node->add_property ("zoom-focus", buf);
2226         snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2227         node->add_property ("zoom", buf);
2228         snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2229         node->add_property ("snap-to", buf);
2230         snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2231         node->add_property ("snap-mode", buf);
2232
2233         snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2234         node->add_property ("playhead", buf);
2235         snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2236         node->add_property ("edit-cursor", buf);
2237
2238         node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2239         node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2240         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2241         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2242         node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2243         node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2244         node->add_property ("mouse-mode", enum2str(mouse_mode));
2245         
2246         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2247         if (act) {
2248                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2249                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2250         }
2251         
2252         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2253         if (act) {
2254                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2255                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2256         }
2257
2258         return *node;
2259 }
2260
2261
2262
2263 TimeAxisView *
2264 Editor::trackview_by_y_position (double y)
2265 {
2266         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2267
2268                 TimeAxisView *tv;
2269
2270                 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2271                         return tv;
2272                 }
2273         }
2274
2275         return 0;
2276 }
2277
2278 void
2279 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2280 {
2281         Location* before = 0;
2282         Location* after = 0;
2283
2284         if (!session) {
2285                 return;
2286         }
2287
2288         const nframes64_t one_second = session->frame_rate();
2289         const nframes64_t one_minute = session->frame_rate() * 60;
2290         const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2291         nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2292         nframes64_t presnap = start;
2293
2294         switch (snap_type) {
2295         case SnapToFrame:
2296                 break;
2297
2298         case SnapToCDFrame:
2299                 if (direction) {
2300                         start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2301                 } else {
2302                         start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2303                 }
2304                 break;
2305
2306         case SnapToSMPTEFrame:
2307                 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2308                         start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2309                 } else {
2310                         start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) *  session->frames_per_smpte_frame());
2311                 }
2312                 break;
2313
2314         case SnapToSMPTESeconds:
2315                 if (session->smpte_offset_negative())
2316                 {
2317                         start += session->smpte_offset ();
2318                 } else {
2319                         start -= session->smpte_offset ();
2320                 }    
2321                 if (start % one_smpte_second > one_smpte_second / 2) {
2322                         start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2323                 } else {
2324                         start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2325                 }
2326                 
2327                 if (session->smpte_offset_negative())
2328                 {
2329                         start -= session->smpte_offset ();
2330                 } else {
2331                         start += session->smpte_offset ();
2332                 }
2333                 break;
2334                 
2335         case SnapToSMPTEMinutes:
2336                 if (session->smpte_offset_negative())
2337                 {
2338                         start += session->smpte_offset ();
2339                 } else {
2340                         start -= session->smpte_offset ();
2341                 }
2342                 if (start % one_smpte_minute > one_smpte_minute / 2) {
2343                         start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2344                 } else {
2345                         start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2346                 }
2347                 if (session->smpte_offset_negative())
2348                 {
2349                         start -= session->smpte_offset ();
2350                 } else {
2351                         start += session->smpte_offset ();
2352                 }
2353                 break;
2354                 
2355         case SnapToSeconds:
2356                 if (start % one_second > one_second / 2) {
2357                         start = (nframes_t) ceil ((double) start / one_second) * one_second;
2358                 } else {
2359                         start = (nframes_t) floor ((double) start / one_second) * one_second;
2360                 }
2361                 break;
2362                 
2363         case SnapToMinutes:
2364                 if (start % one_minute > one_minute / 2) {
2365                         start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2366                 } else {
2367                         start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2368                 }
2369                 break;
2370
2371         case SnapToBar:
2372                 start = session->tempo_map().round_to_bar (start, direction);
2373                 break;
2374
2375         case SnapToBeat:
2376                 start = session->tempo_map().round_to_beat (start, direction);
2377                 break;
2378
2379         case SnapToAThirtysecondBeat:
2380                 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2381                 break;
2382
2383         case SnapToASixteenthBeat:
2384                 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2385                 break;
2386
2387         case SnapToAEighthBeat:
2388                 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2389                 break;
2390
2391         case SnapToAQuarterBeat:
2392                 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2393                 break;
2394
2395         case SnapToAThirdBeat:
2396                 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2397                 break;
2398
2399         case SnapToEditCursor:
2400                 start = edit_cursor->current_frame;
2401                 break;
2402
2403         case SnapToMark:
2404                 if (for_mark) {
2405                         return;
2406                 }
2407
2408                 before = session->locations()->first_location_before (start);
2409                 after = session->locations()->first_location_after (start);
2410
2411                 if (direction < 0) {
2412                         if (before) {
2413                                 start = before->start();
2414                         } else {
2415                                 start = 0;
2416                         }
2417                 } else if (direction > 0) {
2418                         if (after) {
2419                                 start = after->start();
2420                         } else {
2421                                 start = session->current_end_frame();
2422                         }
2423                 } else {
2424                         if (before) {
2425                                 if (after) {
2426                                         /* find nearest of the two */
2427                                         if ((start - before->start()) < (after->start() - start)) {
2428                                                 start = before->start();
2429                                         } else {
2430                                                 start = after->start();
2431                                         }
2432                                 } else {
2433                                         start = before->start();
2434                                 }
2435                         } else if (after) {
2436                                 start = after->start();
2437                         } else {
2438                                 /* relax */
2439                         }
2440                 }
2441                 break;
2442
2443         case SnapToRegionStart:
2444         case SnapToRegionEnd:
2445         case SnapToRegionSync:
2446         case SnapToRegionBoundary:
2447                 if (!region_boundary_cache.empty()) {
2448                         vector<nframes_t>::iterator i;
2449
2450                         if (direction > 0) {
2451                                 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2452                         } else {
2453                                 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2454                         }
2455                         
2456                         if (i != region_boundary_cache.end()) {
2457                                 start = *i;
2458                         } else {
2459                                 start = region_boundary_cache.back();
2460                         }
2461                 }
2462                 break;
2463         }
2464
2465         switch (snap_mode) {
2466         case SnapNormal:
2467                 return;                 
2468                 
2469         case SnapMagnetic:
2470                 
2471                 if (presnap > start) {
2472                         if (presnap > (start + unit_to_frame(snap_threshold))) {
2473                                 start = presnap;
2474                         }
2475                         
2476                 } else if (presnap < start) {
2477                         if (presnap < (start - unit_to_frame(snap_threshold))) {
2478                                 start = presnap;
2479                         }
2480                 }
2481                 
2482         default:
2483                 return;
2484                 
2485         }
2486 }
2487
2488 double
2489 Editor::snap_length_beats (nframes_t start)
2490 {
2491         if (!session) {
2492                 return 1.0;
2493         }
2494
2495         /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */
2496
2497         switch (snap_type) {
2498         case SnapToBar:
2499                 return session->tempo_map().meter_at(start).beats_per_bar();
2500
2501         case SnapToBeat:
2502                 return 1.0;
2503
2504         case SnapToAThirtysecondBeat:
2505                 return 1.0 / (double)32.0;
2506                 break;
2507
2508         case SnapToASixteenthBeat:
2509                 return 1.0 / (double)16.0;
2510                 break;
2511
2512         case SnapToAEighthBeat:
2513                 return 1.0 / (double)8.0;
2514                 break;
2515
2516         case SnapToAQuarterBeat:
2517                 return 1.0 / (double)4.0;
2518                 break;
2519
2520         case SnapToAThirdBeat:
2521                 return 1.0 / (double)3.0;
2522
2523         default:
2524                 return 1.0;
2525         }
2526 }
2527
2528 void
2529 Editor::setup_toolbar ()
2530 {
2531         string pixmap_path;
2532
2533         const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2534
2535
2536         /* Mode Buttons (tool selection) */
2537
2538         vector<ToggleButton *> mouse_mode_buttons;
2539
2540         mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2541         mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2542         mouse_mode_buttons.push_back (&mouse_move_button);
2543         mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2544         mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2545         mouse_mode_buttons.push_back (&mouse_select_button);
2546         mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2547         mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2548         mouse_mode_buttons.push_back (&mouse_gain_button);
2549         mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2550         mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2551         mouse_mode_buttons.push_back (&mouse_zoom_button);
2552         mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2553         mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2554         mouse_mode_buttons.push_back (&mouse_timefx_button);
2555         mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2556         mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2557         mouse_note_button.add (*(manage (new Image (::get_icon("tool_note")))));
2558         mouse_note_button.set_relief(Gtk::RELIEF_NONE);
2559         mouse_mode_buttons.push_back (&mouse_note_button);
2560         mouse_mode_buttons.push_back (&mouse_audition_button);
2561         
2562         mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2563
2564         HBox* mode_box = manage(new HBox);
2565         mode_box->set_border_width (2);
2566         mode_box->set_spacing(4);
2567         mouse_mode_button_box.set_spacing(1);
2568         mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2569         mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2570         mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2571         mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2572         mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2573         mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2574         mouse_mode_button_box.pack_start(mouse_note_button, true, true);
2575         mouse_mode_button_box.set_homogeneous(true);
2576
2577         vector<string> edit_mode_strings;
2578         edit_mode_strings.push_back (edit_mode_to_string (Splice));
2579         edit_mode_strings.push_back (edit_mode_to_string (Slide));
2580
2581         edit_mode_selector.set_name ("EditModeSelector");
2582         Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2583         set_popdown_strings (edit_mode_selector, edit_mode_strings);
2584         edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2585
2586         mode_box->pack_start(edit_mode_selector);
2587         mode_box->pack_start(mouse_mode_button_box);
2588         
2589         mouse_mode_tearoff = manage (new TearOff (*mode_box));
2590         mouse_mode_tearoff->set_name ("MouseModeBase");
2591
2592         mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2593                                                   &mouse_mode_tearoff->tearoff_window()));
2594         mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2595                                                   &mouse_mode_tearoff->tearoff_window(), 1));
2596         mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2597                                                   &mouse_mode_tearoff->tearoff_window()));
2598         mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2599                                                    &mouse_mode_tearoff->tearoff_window(), 1));
2600
2601         mouse_move_button.set_name ("MouseModeButton");
2602         mouse_select_button.set_name ("MouseModeButton");
2603         mouse_gain_button.set_name ("MouseModeButton");
2604         mouse_zoom_button.set_name ("MouseModeButton");
2605         mouse_timefx_button.set_name ("MouseModeButton");
2606         mouse_audition_button.set_name ("MouseModeButton");
2607         mouse_note_button.set_name ("MouseModeButton");
2608
2609         ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2610         ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2611         ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2612         ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2613         ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2614         ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2615         ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes"));
2616
2617         mouse_move_button.unset_flags (CAN_FOCUS);
2618         mouse_select_button.unset_flags (CAN_FOCUS);
2619         mouse_gain_button.unset_flags (CAN_FOCUS);
2620         mouse_zoom_button.unset_flags (CAN_FOCUS);
2621         mouse_timefx_button.unset_flags (CAN_FOCUS);
2622         mouse_audition_button.unset_flags (CAN_FOCUS);
2623         mouse_note_button.unset_flags (CAN_FOCUS);
2624
2625         mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2626         mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2627
2628         mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2629         mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2630         mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2631         mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2632         mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2633         mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote));
2634
2635         // mouse_move_button.set_active (true);
2636         
2637
2638         /* Zoom */
2639         
2640         zoom_box.set_spacing (1);
2641         zoom_box.set_border_width (2);
2642
2643         zoom_in_button.set_name ("EditorTimeButton");
2644         zoom_in_button.set_size_request(-1,16);
2645         zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2646         zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2647         ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2648         
2649         zoom_out_button.set_name ("EditorTimeButton");
2650         zoom_out_button.set_size_request(-1,16);
2651         zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2652         zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2653         ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2654
2655         zoom_out_full_button.set_name ("EditorTimeButton");
2656         zoom_out_full_button.set_size_request(-1,16);
2657         zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2658         zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2659         ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2660
2661         zoom_focus_selector.set_name ("ZoomFocusSelector");
2662         Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Center", FUDGE, 0);
2663         set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2664         zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2665         ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2666
2667         zoom_box.pack_start (zoom_focus_selector, true, true);
2668         zoom_box.pack_start (zoom_out_button, false, false);
2669         zoom_box.pack_start (zoom_in_button, false, false);
2670         zoom_box.pack_start (zoom_out_full_button, false, false);
2671
2672         /* Edit Cursor / Snap */
2673
2674         snap_box.set_spacing (1);
2675         snap_box.set_border_width (2);
2676
2677         snap_type_selector.set_name ("SnapTypeSelector");
2678         Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2679         set_popdown_strings (snap_type_selector, snap_type_strings);
2680         snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2681         ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2682
2683         snap_mode_selector.set_name ("SnapModeSelector");
2684         Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2685         set_popdown_strings (snap_mode_selector, snap_mode_strings);
2686         snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2687
2688         snap_box.pack_start (edit_cursor_clock, false, false);
2689         snap_box.pack_start (snap_mode_selector, false, false);
2690         snap_box.pack_start (snap_type_selector, false, false);
2691
2692
2693         /* Nudge */
2694
2695         HBox *nudge_box = manage (new HBox);
2696         nudge_box->set_spacing(1);
2697         nudge_box->set_border_width (2);
2698
2699         nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2700         nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2701
2702         nudge_box->pack_start (nudge_backward_button, false, false);
2703         nudge_box->pack_start (nudge_forward_button, false, false);
2704         nudge_box->pack_start (nudge_clock, false, false);
2705
2706
2707         /* Pack everything in... */
2708
2709         HBox* hbox = new HBox;
2710         hbox->set_spacing(10);
2711
2712         tools_tearoff = new TearOff (*hbox);
2713         tools_tearoff->set_name ("MouseModeBase");
2714
2715         tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2716                                              &tools_tearoff->tearoff_window()));
2717         tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2718                                              &tools_tearoff->tearoff_window(), 0));
2719         tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2720                                              &tools_tearoff->tearoff_window()));
2721         tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2722                                               &tools_tearoff->tearoff_window(), 0));
2723
2724         toolbar_hbox.set_spacing (10);
2725         toolbar_hbox.set_border_width (1);
2726
2727         toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2728         toolbar_hbox.pack_start (*tools_tearoff, false, false);
2729
2730         
2731         hbox->pack_start (snap_box, false, false);
2732         // hbox->pack_start (zoom_box, false, false); 
2733         hbox->pack_start (*nudge_box, false, false);
2734
2735         hbox->show_all ();
2736         
2737         toolbar_base.set_name ("ToolBarBase");
2738         toolbar_base.add (toolbar_hbox);
2739
2740         toolbar_frame.set_shadow_type (SHADOW_OUT);
2741         toolbar_frame.set_name ("BaseFrame");
2742         toolbar_frame.add (toolbar_base);
2743 }
2744
2745
2746 void
2747 Editor::setup_midi_toolbar ()
2748 {
2749         string pixmap_path;
2750
2751         /* Mode Buttons (tool selection) */
2752
2753         vector<ToggleButton *> midi_tool_buttons;
2754
2755         midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil")))));
2756         midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE);
2757         midi_tool_buttons.push_back (&midi_tool_pencil_button);
2758         midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
2759         midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
2760         midi_tool_buttons.push_back (&midi_tool_select_button);
2761         midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
2762         midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
2763         midi_tool_buttons.push_back (&midi_tool_erase_button);
2764
2765         midi_tool_pencil_button.set_active(true);
2766         
2767         midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
2768
2769         midi_tool_button_box.set_border_width (2);
2770         midi_tool_button_box.set_spacing(4);
2771         midi_tool_button_box.set_spacing(1);
2772         midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
2773         midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
2774         midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
2775         midi_tool_button_box.set_homogeneous(true);
2776
2777         midi_tool_pencil_button.set_name ("MouseModeButton");
2778         midi_tool_select_button.set_name ("MouseModeButton");
2779         midi_tool_erase_button.set_name ("MouseModeButton");
2780
2781         ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
2782         ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
2783         ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
2784
2785         midi_tool_pencil_button.unset_flags (CAN_FOCUS);
2786         midi_tool_select_button.unset_flags (CAN_FOCUS);
2787         midi_tool_erase_button.unset_flags (CAN_FOCUS);
2788         
2789         midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
2790                                 &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
2791         midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
2792                                 &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
2793         midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
2794                                 &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
2795         
2796         /* Pack everything in... */
2797
2798         midi_tools_tearoff = new TearOff (midi_tool_button_box);
2799         midi_tools_tearoff->set_name ("MouseModeBase");
2800
2801         /*
2802         midi_tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox), 
2803                                              &midi_tools_tearoff->tearoff_window()));
2804         midi_tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox), 
2805                                              &midi_tools_tearoff->tearoff_window(), 0));
2806         midi_tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox), 
2807                                              &midi_tools_tearoff->tearoff_window()));
2808         midi_tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox), 
2809                                               &midi_tools_tearoff->tearoff_window(), 0));
2810         */
2811
2812         midi_toolbar_hbox.set_spacing (10);
2813         midi_toolbar_hbox.set_border_width (1);
2814
2815         midi_toolbar_hbox.pack_start (*midi_tools_tearoff, false, true);
2816
2817         midi_tool_button_box.show_all ();
2818         midi_toolbar_hbox.show_all();
2819         midi_tools_tearoff->show_all();
2820         
2821         midi_toolbar_base.set_name ("ToolBarBase");
2822         midi_toolbar_base.add (midi_toolbar_hbox);
2823
2824         midi_toolbar_frame.set_shadow_type (SHADOW_OUT);
2825         midi_toolbar_frame.set_name ("BaseFrame");
2826         midi_toolbar_frame.add (midi_toolbar_base);
2827 }
2828
2829 int
2830 Editor::convert_drop_to_paths (vector<ustring>& paths, 
2831                                const RefPtr<Gdk::DragContext>& context,
2832                                gint                x,
2833                                gint                y,
2834                                const SelectionData& data,
2835                                guint               info,
2836                                guint               time)                               
2837
2838 {       
2839         if (session == 0) {
2840                 return -1;
2841         }
2842
2843         vector<ustring> uris = data.get_uris();
2844
2845         cerr << "there were " << uris.size() << " in that drag data\n";
2846
2847         if (uris.empty()) {
2848
2849                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2850                    are actually URI lists. So do it by hand.
2851                 */
2852
2853                 if (data.get_target() != "text/plain") {
2854                         return -1;
2855                 }
2856   
2857                 /* Parse the "uri-list" format that Nautilus provides, 
2858                    where each pathname is delimited by \r\n
2859                 */
2860         
2861                 const char* p = data.get_text().c_str();
2862                 const char* q;
2863
2864                 while (p)
2865                 {
2866                         if (*p != '#')
2867                         {
2868                                 while (g_ascii_isspace (*p))
2869                                         p++;
2870                                 
2871                                 q = p;
2872                                 while (*q && (*q != '\n') && (*q != '\r'))
2873                                         q++;
2874                                 
2875                                 if (q > p)
2876                                 {
2877                                         q--;
2878                                         while (q > p && g_ascii_isspace (*q))
2879                                                 q--;
2880                                         
2881                                         if (q > p)
2882                                         {
2883                                                 uris.push_back (ustring (p, q - p + 1));
2884                                         }
2885                                 }
2886                         }
2887                         p = strchr (p, '\n');
2888                         if (p)
2889                                 p++;
2890                 }
2891
2892                 if (uris.empty()) {
2893                         return -1;
2894                 }
2895         }
2896         
2897         for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2898
2899                 if ((*i).substr (0,7) == "file://") {
2900                         
2901                         ustring p = *i;
2902                         PBD::url_decode (p);
2903
2904                         // scan forward past three slashes
2905                         
2906                         ustring::size_type slashcnt = 0;
2907                         ustring::size_type n = 0;
2908                         ustring::iterator x = p.begin();
2909
2910                         while (slashcnt < 3 && x != p.end()) {
2911                                 if ((*x) == '/') {
2912                                         slashcnt++;
2913                                 } else if (slashcnt == 3) {
2914                                         break;
2915                                 }
2916                                 ++n;
2917                                 ++x;
2918                         }
2919
2920                         if (slashcnt != 3 || x == p.end()) {
2921                                 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2922                                 continue;
2923                         }
2924
2925                         paths.push_back (p.substr (n - 1));
2926                 }
2927         }
2928
2929         return 0;
2930 }
2931
2932 void
2933 Editor::new_tempo_section ()
2934
2935 {
2936 }
2937
2938 void
2939 Editor::map_transport_state ()
2940 {
2941         ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2942
2943         if (session->transport_stopped()) {
2944                 have_pending_keyboard_selection = false;
2945         }
2946
2947         update_loop_range_view (true);
2948 }
2949
2950 /* UNDO/REDO */
2951
2952 Editor::State::State (PublicEditor const * e)
2953 {
2954         selection = new Selection (e);
2955 }
2956
2957 Editor::State::~State ()
2958 {
2959         delete selection;
2960 }
2961
2962 UndoAction
2963 Editor::get_memento () const
2964 {
2965         State *state = new State (this);
2966
2967         store_state (*state);
2968         return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2969 }
2970
2971 void
2972 Editor::store_state (State& state) const
2973 {
2974         *state.selection = *selection;
2975 }
2976
2977 void
2978 Editor::restore_state (State *state)
2979 {
2980         if (*selection == *state->selection) {
2981                 return;
2982         }
2983
2984         *selection = *state->selection;
2985         time_selection_changed ();
2986         region_selection_changed ();   
2987
2988         /* XXX other selection change handlers? */
2989 }
2990
2991 void
2992 Editor::begin_reversible_command (string name)
2993 {
2994         if (session) {
2995                 before = &get_state();
2996                 session->begin_reversible_command (name);
2997         }
2998 }
2999
3000 void
3001 Editor::commit_reversible_command ()
3002 {
3003         if (session) {
3004                 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
3005         }
3006 }
3007
3008 void
3009 Editor::set_edit_group_solo (Route& route, bool yn)
3010 {
3011         RouteGroup *edit_group;
3012
3013         if ((edit_group = route.edit_group()) != 0) {
3014                 edit_group->apply (&Route::set_solo, yn, this);
3015         } else {
3016                 route.set_solo (yn, this);
3017         }
3018 }
3019
3020 void
3021 Editor::set_edit_group_mute (Route& route, bool yn)
3022 {
3023         RouteGroup *edit_group = 0;
3024
3025         if ((edit_group == route.edit_group()) != 0) {
3026                 edit_group->apply (&Route::set_mute, yn, this);
3027         } else {
3028                 route.set_mute (yn, this);
3029         }
3030 }
3031                 
3032 void
3033 Editor::history_changed ()
3034 {
3035         string label;
3036
3037         if (undo_action && session) {
3038                 if (session->undo_depth() == 0) {
3039                         label = _("Undo");
3040                 } else {
3041                         label = string_compose(_("Undo (%1)"), session->next_undo());
3042                 }
3043                 undo_action->property_label() = label;
3044         }
3045
3046         if (redo_action && session) {
3047                 if (session->redo_depth() == 0) {
3048                         label = _("Redo");
3049                 } else {
3050                         label = string_compose(_("Redo (%1)"), session->next_redo());
3051                 }
3052                 redo_action->property_label() = label;
3053         }
3054 }
3055
3056 void
3057 Editor::duplicate_dialog (bool dup_region)
3058 {
3059         if (selection->regions.empty() && (selection->time.length() == 0)) {
3060                 return;
3061         }
3062
3063         ArdourDialog win ("duplicate dialog");
3064         Label  label (_("Duplicate how many times?"));
3065         Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3066         SpinButton spinner (adjustment);
3067
3068         win.get_vbox()->set_spacing (12);
3069         win.get_vbox()->pack_start (label);
3070
3071         /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3072            place, visually. so do this by hand.
3073         */
3074
3075         win.get_vbox()->pack_start (spinner);
3076         spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3077
3078         label.show ();
3079         spinner.show ();
3080
3081         win.add_button (Stock::OK, RESPONSE_ACCEPT);
3082         win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3083
3084         win.set_position (WIN_POS_MOUSE);
3085
3086         spinner.grab_focus ();
3087
3088         switch (win.run ()) {
3089         case RESPONSE_ACCEPT:
3090                 break;
3091         default:
3092                 return;
3093         }
3094
3095         float times = adjustment.get_value();
3096
3097         if (!selection->regions.empty()) {
3098                 duplicate_some_regions (selection->regions, times);
3099         } else {
3100                 duplicate_selection (times);
3101         }
3102 }
3103
3104 void
3105 Editor::show_verbose_canvas_cursor ()
3106 {
3107         verbose_canvas_cursor->raise_to_top();
3108         verbose_canvas_cursor->show();
3109         verbose_cursor_visible = true;
3110 }
3111
3112 void
3113 Editor::hide_verbose_canvas_cursor ()
3114 {
3115         verbose_canvas_cursor->hide();
3116         verbose_cursor_visible = false;
3117 }
3118
3119 void
3120 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3121 {
3122         /* XXX get origin of canvas relative to root window,
3123            add x and y and check compared to gdk_screen_{width,height}
3124         */
3125         verbose_canvas_cursor->property_text() = txt.c_str();
3126         verbose_canvas_cursor->property_x() = x;
3127         verbose_canvas_cursor->property_y() = y;
3128 }
3129
3130 void
3131 Editor::set_verbose_canvas_cursor_text (const string & txt)
3132 {
3133         verbose_canvas_cursor->property_text() = txt.c_str();
3134 }
3135
3136 void
3137 Editor::edit_mode_selection_done ()
3138 {
3139         if (session == 0) {
3140                 return;
3141         }
3142
3143         string choice = edit_mode_selector.get_active_text();
3144         EditMode mode = Slide;
3145
3146         if (choice == _("Splice Edit")) {
3147                 mode = Splice;
3148         } else if (choice == _("Slide Edit")) {
3149                 mode = Slide;
3150         }
3151
3152         Config->set_edit_mode (mode);
3153 }       
3154
3155 void
3156 Editor::snap_type_selection_done ()
3157 {
3158         string choice = snap_type_selector.get_active_text();
3159         SnapType snaptype = SnapToFrame;
3160
3161         if (choice == _("Beats/3")) {
3162                 snaptype = SnapToAThirdBeat;
3163         } else if (choice == _("Beats/4")) {
3164                 snaptype = SnapToAQuarterBeat;
3165         } else if (choice == _("Beats/8")) {
3166                 snaptype = SnapToAEighthBeat;
3167         } else if (choice == _("Beats/16")) {
3168                 snaptype = SnapToASixteenthBeat;
3169         } else if (choice == _("Beats/32")) {
3170                 snaptype = SnapToAThirtysecondBeat;
3171         } else if (choice == _("Beats")) {
3172                 snaptype = SnapToBeat;
3173         } else if (choice == _("Bars")) {
3174                 snaptype = SnapToBar;
3175         } else if (choice == _("Marks")) {
3176                 snaptype = SnapToMark;
3177         } else if (choice == _("Edit Cursor")) {
3178                 snaptype = SnapToEditCursor;
3179         } else if (choice == _("Region starts")) {
3180                 snaptype = SnapToRegionStart;
3181         } else if (choice == _("Region ends")) {
3182                 snaptype = SnapToRegionEnd;
3183         } else if (choice == _("Region bounds")) {
3184                 snaptype = SnapToRegionBoundary;
3185         } else if (choice == _("Region syncs")) {
3186                 snaptype = SnapToRegionSync;
3187         } else if (choice == _("CD Frames")) {
3188                 snaptype = SnapToCDFrame;
3189         } else if (choice == _("SMPTE Frames")) {
3190                 snaptype = SnapToSMPTEFrame;
3191         } else if (choice == _("SMPTE Seconds")) {
3192                 snaptype = SnapToSMPTESeconds;
3193         } else if (choice == _("SMPTE Minutes")) {
3194                 snaptype = SnapToSMPTEMinutes;
3195         } else if (choice == _("Seconds")) {
3196                 snaptype = SnapToSeconds;
3197         } else if (choice == _("Minutes")) {
3198                 snaptype = SnapToMinutes;
3199         } else if (choice == _("None")) {
3200                 snaptype = SnapToFrame;
3201         }
3202
3203         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3204         if (ract) {
3205                 ract->set_active ();
3206         }
3207 }       
3208
3209 void
3210 Editor::snap_mode_selection_done ()
3211 {
3212         string choice = snap_mode_selector.get_active_text();
3213         SnapMode mode = SnapNormal;
3214
3215         if (choice == _("Normal")) {
3216                 mode = SnapNormal;
3217         } else if (choice == _("Magnetic")) {
3218                 mode = SnapMagnetic;
3219         }
3220
3221         RefPtr<RadioAction> ract = snap_mode_action (mode);
3222
3223         if (ract) {
3224                 ract->set_active (true);
3225         }
3226 }
3227
3228 void
3229 Editor::zoom_focus_selection_done ()
3230 {
3231         string choice = zoom_focus_selector.get_active_text();
3232         ZoomFocus focus_type = ZoomFocusLeft;
3233
3234         if (choice == _("Left")) {
3235                 focus_type = ZoomFocusLeft;
3236         } else if (choice == _("Right")) {
3237                 focus_type = ZoomFocusRight;
3238         } else if (choice == _("Center")) {
3239                 focus_type = ZoomFocusCenter;
3240         } else if (choice == _("Play")) {
3241                 focus_type = ZoomFocusPlayhead;
3242         } else if (choice == _("Edit")) {
3243                 focus_type = ZoomFocusEdit;
3244         } 
3245         
3246         RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3247
3248         if (ract) {
3249                 ract->set_active ();
3250         }
3251 }       
3252
3253 gint
3254 Editor::edit_controls_button_release (GdkEventButton* ev)
3255 {
3256         if (Keyboard::is_context_menu_event (ev)) {
3257                 ARDOUR_UI::instance()->add_route (this);
3258         }
3259         return TRUE;
3260 }
3261
3262 gint
3263 Editor::mouse_select_button_release (GdkEventButton* ev)
3264 {
3265         /* this handles just right-clicks */
3266
3267         if (ev->button != 3) {
3268                 return false;
3269         }
3270
3271         return true;
3272 }
3273
3274 Editor::TrackViewList *
3275 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3276 {
3277         TrackViewList *v;
3278         TrackViewList::iterator i;
3279
3280         v = new TrackViewList;
3281
3282         if (track == 0 && group == 0) {
3283
3284                 /* all views */
3285
3286                 for (i = track_views.begin(); i != track_views.end (); ++i) {
3287                         v->push_back (*i);
3288                 }
3289
3290         } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3291                 
3292                 /* just the view for this track
3293                  */
3294
3295                 v->push_back (track);
3296
3297         } else {
3298                 
3299                 /* views for all tracks in the edit group */
3300                 
3301                 for (i  = track_views.begin(); i != track_views.end (); ++i) {
3302
3303                         if (group == 0 || (*i)->edit_group() == group) {
3304                                 v->push_back (*i);
3305                         }
3306                 }
3307         }
3308         
3309         return v;
3310 }
3311
3312 void
3313 Editor::set_zoom_focus (ZoomFocus f)
3314 {
3315         string str = zoom_focus_strings[(int)f];
3316
3317         if (str != zoom_focus_selector.get_active_text()) {
3318                 zoom_focus_selector.set_active_text (str);
3319         }
3320         
3321         if (zoom_focus != f) {
3322                 zoom_focus = f;
3323
3324                 ZoomFocusChanged (); /* EMIT_SIGNAL */
3325
3326                 instant_save ();
3327         }
3328 }
3329
3330 void
3331 Editor::ensure_float (Window& win)
3332 {
3333         win.set_transient_for (*this);
3334 }
3335
3336 void 
3337 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3338 {
3339         /* recover or initialize pane positions. do this here rather than earlier because
3340            we don't want the positions to change the child allocations, which they seem to do.
3341          */
3342
3343         int pos;
3344         XMLProperty* prop;
3345         char buf[32];
3346         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3347         int width, height;
3348         static int32_t done;
3349         XMLNode* geometry;
3350
3351         if ((geometry = find_named_node (*node, "geometry")) == 0) {
3352                 width = default_width;
3353                 height = default_height;
3354         } else {
3355                 width = atoi(geometry->property("x_size")->value());
3356                 height = atoi(geometry->property("y_size")->value());
3357         }
3358
3359         if (which == static_cast<Paned*> (&edit_pane)) {
3360
3361                 if (done) {
3362                         return;
3363                 }
3364
3365                 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3366                         /* initial allocation is 90% to canvas, 10% to notebook */
3367                         pos = (int) floor (alloc.get_width() * 0.90f);
3368                         snprintf (buf, sizeof(buf), "%d", pos);
3369                 } else {
3370                         pos = atoi (prop->value());
3371                 }
3372                 
3373                 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3374                         edit_pane.set_position (pos);
3375                         pre_maximal_pane_position = pos;
3376                 }
3377         }
3378 }
3379
3380 void
3381 Editor::detach_tearoff (Box* b, Window* w)
3382 {
3383         if (tools_tearoff->torn_off() && 
3384             mouse_mode_tearoff->torn_off()) {
3385                 top_hbox.remove (toolbar_frame);
3386         }
3387 }
3388
3389 void
3390 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3391 {
3392         if (toolbar_frame.get_parent() == 0) {
3393                 top_hbox.pack_end (toolbar_frame);
3394         }
3395 }
3396
3397 void
3398 Editor::set_show_measures (bool yn)
3399 {
3400         if (_show_measures != yn) {
3401                 hide_measures ();
3402
3403                 if ((_show_measures = yn) == true) {
3404                         draw_measures ();
3405                 }
3406                 instant_save ();
3407         }
3408 }
3409
3410 void
3411 Editor::toggle_follow_playhead ()
3412 {
3413         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3414         if (act) {
3415                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3416                 set_follow_playhead (tact->get_active());
3417         }
3418 }
3419
3420 void
3421 Editor::set_follow_playhead (bool yn)
3422 {
3423         if (_follow_playhead != yn) {
3424                 if ((_follow_playhead = yn) == true) {
3425                         /* catch up */
3426                         update_current_screen ();
3427                 }
3428                 instant_save ();
3429         }
3430 }
3431
3432 void
3433 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3434 {
3435         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3436         if (xfade) {
3437                 xfade->set_active (!xfade->active());
3438         }
3439 }
3440
3441 void
3442 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3443 {
3444         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3445         if (xfade) {
3446                 xfade->set_follow_overlap (!xfade->following_overlap());
3447         }
3448 }
3449
3450 void
3451 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3452 {
3453         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3454
3455         if (!xfade) {
3456                 return;
3457         }
3458
3459         CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3460                 
3461         ensure_float (cew);
3462         
3463         switch (cew.run ()) {
3464         case RESPONSE_ACCEPT:
3465                 break;
3466         default:
3467                 return;
3468         }
3469         
3470         cew.apply ();
3471         xfade->StateChanged (Change (~0));
3472 }
3473
3474 PlaylistSelector&
3475 Editor::playlist_selector () const
3476 {
3477         return *_playlist_selector;
3478 }
3479
3480 nframes_t
3481 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3482 {
3483         nframes_t ret;
3484
3485         ret = nudge_clock.current_duration (pos);
3486         next = ret + 1; /* XXXX fix me */
3487
3488         return ret;
3489 }
3490
3491 void
3492 Editor::end_location_changed (Location* location)
3493 {
3494         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3495         reset_scrolling_region ();
3496 }
3497
3498 int
3499 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3500 {
3501         ArdourDialog dialog ("playlist deletion dialog");
3502         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
3503                                         "If left alone, no audio files used by it will be cleaned.\n"
3504                                         "If deleted, audio files used by it alone by will cleaned."),
3505                                       pl->name()));
3506         
3507         dialog.set_position (WIN_POS_CENTER);
3508         dialog.get_vbox()->pack_start (label);
3509
3510         label.show ();
3511
3512         dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3513         dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3514         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3515
3516         switch (dialog.run ()) {
3517         case RESPONSE_ACCEPT:
3518                 /* delete the playlist */
3519                 return 0;
3520                 break;
3521
3522         case RESPONSE_REJECT:
3523                 /* keep the playlist */
3524                 return 1;
3525                 break;
3526
3527         default:
3528                 break;
3529         }
3530
3531         return -1;
3532 }
3533
3534 bool
3535 Editor::audio_region_selection_covers (nframes_t where)
3536 {
3537         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3538                 if ((*a)->region()->covers (where)) {
3539                         return true;
3540                 }
3541         }
3542
3543         return false;
3544 }
3545
3546 void
3547 Editor::prepare_for_cleanup ()
3548 {
3549         cut_buffer->clear_regions ();
3550         cut_buffer->clear_playlists ();
3551
3552         selection->clear_regions ();
3553         selection->clear_playlists ();
3554 }
3555
3556 Location*
3557 Editor::transport_loop_location()
3558 {
3559         if (session) {
3560                 return session->locations()->auto_loop_location();
3561         } else {
3562                 return 0;
3563         }
3564 }
3565
3566 Location*
3567 Editor::transport_punch_location()
3568 {
3569         if (session) {
3570                 return session->locations()->auto_punch_location();
3571         } else {
3572                 return 0;
3573         }
3574 }
3575
3576 bool
3577 Editor::control_layout_scroll (GdkEventScroll* ev)
3578 {
3579         switch (ev->direction) {
3580         case GDK_SCROLL_UP:
3581                 scroll_tracks_up_line ();
3582                 return true;
3583                 break;
3584
3585         case GDK_SCROLL_DOWN:
3586                 scroll_tracks_down_line ();
3587                 return true;
3588                 
3589         default:
3590                 /* no left/right handling yet */
3591                 break;
3592         }
3593
3594         return false;
3595 }
3596
3597
3598 /** A new snapshot has been selected.
3599  */
3600 void
3601 Editor::snapshot_display_selection_changed ()
3602 {
3603         if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3604
3605                 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3606                 
3607                 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3608
3609                 if (snap_name.length() == 0) {
3610                         return;
3611                 }
3612                 
3613                 if (session->snap_name() == snap_name) {
3614                         return;
3615                 }
3616                 
3617                 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3618         }
3619 }
3620
3621 bool
3622 Editor::snapshot_display_button_press (GdkEventButton* ev)
3623 {
3624         if (ev->button == 3) {
3625                 /* Right-click on the snapshot list. Work out which snapshot it
3626                    was over. */
3627                 Gtk::TreeModel::Path path;
3628                 Gtk::TreeViewColumn* col;
3629                 int cx;
3630                 int cy;
3631                 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3632                 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3633                 if (iter) {
3634                         Gtk::TreeModel::Row row = *iter;
3635                         popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3636                 }
3637                 return true;
3638         }
3639
3640         return false;
3641 }
3642
3643
3644 /** Pop up the snapshot display context menu.
3645  * @param button Button used to open the menu.
3646  * @param time Menu open time.
3647  * @snapshot_name Name of the snapshot that the menu click was over.
3648  */
3649
3650 void
3651 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3652 {
3653         using namespace Menu_Helpers;
3654
3655         MenuList& items (snapshot_context_menu.items());
3656         items.clear ();
3657
3658         const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3659
3660         add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3661
3662         add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3663
3664         snapshot_context_menu.popup (button, time);
3665 }
3666
3667 void
3668 Editor::rename_snapshot (Glib::ustring old_name)
3669 {
3670         ArdourPrompter prompter(true);
3671
3672         string new_name;
3673
3674         prompter.set_name ("Prompter");
3675         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3676         prompter.set_prompt (_("New name of snapshot"));
3677         prompter.set_initial_text (old_name);
3678         
3679         if (prompter.run() == RESPONSE_ACCEPT) {
3680                 prompter.get_result (new_name);
3681                 if (new_name.length()) {
3682                         session->rename_state (old_name, new_name);
3683                         redisplay_snapshots ();
3684                 }
3685         }
3686 }
3687
3688
3689 void
3690 Editor::remove_snapshot (Glib::ustring name)
3691 {
3692         vector<string> choices;
3693
3694         std::string prompt  = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3695
3696         choices.push_back (_("No, do nothing."));
3697         choices.push_back (_("Yes, remove it."));
3698
3699         Gtkmm2ext::Choice prompter (prompt, choices);
3700
3701         if (prompter.run () == 1) {
3702                 session->remove_state (name);
3703                 redisplay_snapshots ();
3704         }
3705 }
3706
3707 void
3708 Editor::redisplay_snapshots ()
3709 {
3710         if (session == 0) {
3711                 return;
3712         }
3713
3714         vector<sys::path> state_file_paths;
3715
3716         get_state_files_in_directory (session->session_directory().root_path(),
3717                         state_file_paths);
3718
3719         if (state_file_paths.empty()) return;
3720
3721         vector<string> state_file_names(get_file_names_no_extension(state_file_paths));
3722
3723         snapshot_display_model->clear ();
3724
3725         for (vector<string>::iterator i = state_file_names.begin();
3726                         i != state_file_names.end(); ++i)
3727         {
3728                 string statename = (*i);
3729                 TreeModel::Row row = *(snapshot_display_model->append());
3730                 
3731                 /* this lingers on in case we ever want to change the visible
3732                    name of the snapshot.
3733                 */
3734                 
3735                 string display_name;
3736                 display_name = statename;
3737
3738                 if (statename == session->snap_name()) {
3739                         snapshot_display.get_selection()->select(row);
3740                 } 
3741                 
3742                 row[snapshot_display_columns.visible_name] = display_name;
3743                 row[snapshot_display_columns.real_name] = statename;
3744         }
3745 }
3746
3747 void
3748 Editor::session_state_saved (string snap_name)
3749 {
3750         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3751         redisplay_snapshots ();
3752 }
3753
3754 void
3755 Editor::maximise_editing_space ()
3756 {
3757         initial_ruler_update_required = true;
3758
3759         mouse_mode_tearoff->set_visible (false);
3760         tools_tearoff->set_visible (false);
3761
3762         pre_maximal_pane_position = edit_pane.get_position();
3763         pre_maximal_editor_width = this->get_width();
3764
3765         if(post_maximal_pane_position == 0) {
3766                 post_maximal_pane_position = edit_pane.get_width();
3767         }
3768
3769
3770         fullscreen();
3771         if(post_maximal_editor_width) {
3772                 edit_pane.set_position (post_maximal_pane_position - 
3773                         abs(post_maximal_editor_width - pre_maximal_editor_width));
3774         } else {
3775                 edit_pane.set_position (post_maximal_pane_position);
3776         }
3777 }
3778
3779 void
3780 Editor::restore_editing_space ()
3781 {
3782         initial_ruler_update_required = true;
3783
3784         // user changed width of pane during fullscreen
3785         if(post_maximal_pane_position != edit_pane.get_position()) {
3786                 post_maximal_pane_position = edit_pane.get_position();
3787         }
3788
3789         unfullscreen();
3790
3791         mouse_mode_tearoff->set_visible (true);
3792         tools_tearoff->set_visible (true);
3793         post_maximal_editor_width = this->get_width();
3794
3795
3796         edit_pane.set_position (
3797                 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3798         );
3799 }
3800
3801 /**
3802  *  Make new playlists for a given track and also any others that belong
3803  *  to the same active edit group.
3804  *  @param v Track.
3805  */
3806
3807 void 
3808 Editor::new_playlists (TimeAxisView* v)
3809 {
3810         begin_reversible_command (_("new playlists"));
3811         mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3812         commit_reversible_command ();
3813 }
3814
3815 /**
3816  *  Use a copy of the current playlist for a given track and also any others that belong
3817  *  to the same active edit group.
3818  *  @param v Track.
3819  */
3820
3821 void
3822 Editor::copy_playlists (TimeAxisView* v)
3823 {
3824         begin_reversible_command (_("copy playlists"));
3825         mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3826         commit_reversible_command ();
3827 }
3828
3829 /**
3830  *  Clear the current playlist for a given track and also any others that belong
3831  *  to the same active edit group.
3832  *  @param v Track.
3833  */
3834
3835 void 
3836 Editor::clear_playlists (TimeAxisView* v)
3837 {
3838         begin_reversible_command (_("clear playlists"));
3839         mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3840         commit_reversible_command ();
3841 }
3842
3843 void 
3844 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3845 {
3846         atv.use_new_playlist (sz > 1 ? false : true);
3847 }
3848
3849 void
3850 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3851 {
3852         atv.use_copy_playlist (sz > 1 ? false : true);
3853 }
3854
3855 void 
3856 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3857 {
3858         atv.clear_playlist ();
3859 }
3860
3861 bool
3862 Editor::on_key_press_event (GdkEventKey* ev)
3863 {
3864         return key_press_focus_accelerator_handler (*this, ev);
3865 }
3866
3867 void
3868 Editor::reset_x_origin (nframes_t frame)
3869 {
3870         queue_visual_change (frame);
3871 }
3872
3873 void
3874 Editor::reset_zoom (double fpu)
3875 {
3876         queue_visual_change (fpu);
3877 }
3878
3879 void
3880 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3881 {
3882         reset_x_origin (frame);
3883         reset_zoom (fpu);
3884 }
3885
3886 void
3887 Editor::set_frames_per_unit (double fpu)
3888 {
3889         nframes_t frames;
3890
3891         /* this is the core function that controls the zoom level of the canvas. it is called
3892            whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3893         */
3894
3895         if (fpu == frames_per_unit) {
3896                 return;
3897         }
3898
3899         if (fpu < 2.0) {
3900                 fpu = 2.0;
3901         }
3902
3903         // convert fpu to frame count
3904
3905         frames = (nframes_t) floor (fpu * canvas_width);
3906         
3907         /* don't allow zooms that fit more than the maximum number
3908            of frames into an 800 pixel wide space.
3909         */
3910
3911         if (max_frames / fpu < 800.0) {
3912                 return;
3913         }
3914
3915         if (fpu == frames_per_unit) {
3916                 return;
3917         }
3918
3919         frames_per_unit = fpu;
3920
3921         if (frames != zoom_range_clock.current_duration()) {
3922                 zoom_range_clock.set (frames);
3923         }
3924
3925         if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3926                 if (!selection->tracks.empty()) {
3927                         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3928                                 (*i)->reshow_selection (selection->time);
3929                         }
3930                 } else {
3931                         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3932                                 (*i)->reshow_selection (selection->time);
3933                         }
3934                 }
3935         }
3936
3937         ZoomChanged (); /* EMIT_SIGNAL */
3938
3939         reset_hscrollbar_stepping ();
3940         reset_scrolling_region ();
3941         
3942         if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3943         if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3944
3945         instant_save ();
3946 }
3947
3948 void
3949 Editor::queue_visual_change (nframes_t where)
3950 {
3951         pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3952         pending_visual_change.time_origin = where;
3953
3954         if (pending_visual_change.idle_handler_id < 0) {
3955                 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3956         }
3957 }
3958
3959 void
3960 Editor::queue_visual_change (double fpu)
3961 {
3962         pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3963         pending_visual_change.frames_per_unit = fpu;
3964
3965         if (pending_visual_change.idle_handler_id < 0) {
3966                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3967         }
3968 }
3969
3970 int
3971 Editor::_idle_visual_changer (void* arg)
3972 {
3973         return static_cast<Editor*>(arg)->idle_visual_changer ();
3974 }
3975
3976 int
3977 Editor::idle_visual_changer ()
3978 {
3979         VisualChange::Type p = pending_visual_change.pending;
3980
3981         pending_visual_change.pending = (VisualChange::Type) 0;
3982         pending_visual_change.idle_handler_id = -1;
3983         
3984         if (p & VisualChange::ZoomLevel) {
3985                 set_frames_per_unit (pending_visual_change.frames_per_unit);
3986         }
3987
3988         if (p & VisualChange::TimeOrigin) {
3989                 if (pending_visual_change.time_origin != leftmost_frame) {
3990                         horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3991                         /* the signal handler will do the rest */
3992                 } else {
3993                         update_fixed_rulers();
3994                         redisplay_tempo (true);
3995                 }
3996         }
3997
3998         return 0; /* this is always a one-shot call */
3999 }
4000
4001 struct EditorOrderTimeAxisSorter {
4002     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4003             return a->order < b->order;
4004     }
4005 };
4006         
4007 void
4008 Editor::sort_track_selection ()
4009 {
4010         EditorOrderTimeAxisSorter cmp;
4011         selection->tracks.sort (cmp);
4012 }
4013
4014 nframes_t
4015 Editor::edit_cursor_position(bool sync)
4016 {
4017         if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
4018                 edit_cursor_clock.set(edit_cursor->current_frame, true);
4019         }
4020
4021         return edit_cursor->current_frame;
4022 }
4023
4024
4025 void
4026 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4027 {
4028         if (!session) return;
4029
4030         begin_reversible_command (cmd);
4031         
4032         Location* tll;
4033
4034         if ((tll = transport_loop_location()) == 0) {
4035                 Location* loc = new Location (start, end, _("Loop"),  Location::IsAutoLoop);
4036                 XMLNode &before = session->locations()->get_state();
4037                 session->locations()->add (loc, true);
4038                 session->set_auto_loop_location (loc);
4039                 XMLNode &after = session->locations()->get_state();
4040                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4041         }
4042         else {
4043                 XMLNode &before = tll->get_state();
4044                 tll->set_hidden (false, this);
4045                 tll->set (start, end);
4046                 XMLNode &after = tll->get_state();
4047                 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4048         }
4049         
4050         commit_reversible_command ();
4051 }
4052
4053 void
4054 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4055 {
4056         if (!session) return;
4057
4058         begin_reversible_command (cmd);
4059         
4060         Location* tpl;
4061
4062         if ((tpl = transport_punch_location()) == 0) {
4063                 Location* loc = new Location (start, end, _("Loop"),  Location::IsAutoPunch);
4064                 XMLNode &before = session->locations()->get_state();
4065                 session->locations()->add (loc, true);
4066                 session->set_auto_loop_location (loc);
4067                 XMLNode &after = session->locations()->get_state();
4068                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4069         }
4070         else {
4071                 XMLNode &before = tpl->get_state();
4072                 tpl->set_hidden (false, this);
4073                 tpl->set (start, end);
4074                 XMLNode &after = tpl->get_state();
4075                 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4076         }
4077         
4078         commit_reversible_command ();
4079 }
4080