3a7009e7b73f2d034268fe73b35647fc23169f3e
[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                 
1933                 add_item_with_sensitivity (track_items, MenuElem (_("Insert existing audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1934                 
1935                 /* Nudge */
1936
1937                 Menu *nudge_menu = manage (new Menu());
1938                 MenuList& nudge_items = nudge_menu->items();
1939                 nudge_menu->set_name ("ArdourContextMenu");
1940
1941                 str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
1942                 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
1943
1944                 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1945                 
1946                 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1947
1948                 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1949                 
1950                 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1951
1952                 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1953                 
1954                 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1955                 
1956                 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1957
1958                 /* Freeze */
1959                 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1960                 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1961
1962                 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1963                 edit_items.push_back (MenuElem (str, *track_menu));
1964         }
1965 }
1966
1967 /* CURSOR SETTING AND MARKS AND STUFF */
1968
1969 void
1970 Editor::set_snap_to (SnapType st)
1971 {       
1972         snap_type = st;
1973         string str = snap_type_strings[(int) st];
1974
1975         if (str != snap_type_selector.get_active_text()) {
1976                 snap_type_selector.set_active_text (str);
1977         }
1978
1979         instant_save ();
1980
1981         switch (snap_type) {
1982         case SnapToAThirtysecondBeat:
1983         case SnapToASixteenthBeat:
1984         case SnapToAEighthBeat:
1985         case SnapToAQuarterBeat:
1986         case SnapToAThirdBeat:
1987                 update_tempo_based_rulers ();
1988         default:
1989                 /* relax */
1990                 break;
1991     }
1992 }
1993
1994 void
1995 Editor::set_snap_mode (SnapMode mode)
1996 {
1997         snap_mode = mode;
1998         string str = snap_mode_strings[(int)mode];
1999
2000         if (str != snap_mode_selector.get_active_text ()) {
2001                 snap_mode_selector.set_active_text (str);
2002         }
2003
2004         instant_save ();
2005 }
2006
2007 int
2008 Editor::set_state (const XMLNode& node)
2009 {
2010         const XMLProperty* prop;
2011         XMLNode* geometry;
2012         int x, y, xoff, yoff;
2013         Gdk::Geometry g;
2014
2015         if ((prop = node.property ("id")) != 0) {
2016                 _id = prop->value ();
2017         }
2018
2019         if ((geometry = find_named_node (node, "geometry")) == 0) {
2020
2021                 g.base_width = default_width;
2022                 g.base_height = default_height;
2023                 x = 1;
2024                 y = 1;
2025                 xoff = 0;
2026                 yoff = 21;
2027
2028         } else {
2029
2030                 g.base_width = atoi(geometry->property("x_size")->value());
2031                 g.base_height = atoi(geometry->property("y_size")->value());
2032                 x = atoi(geometry->property("x_pos")->value());
2033                 y = atoi(geometry->property("y_pos")->value());
2034                 xoff = atoi(geometry->property("x_off")->value());
2035                 yoff = atoi(geometry->property("y_off")->value());
2036         }
2037
2038         set_default_size (g.base_width, g.base_height);
2039         move (x, y);
2040
2041         if (session && (prop = node.property ("playhead"))) {
2042                 nframes_t pos = atol (prop->value().c_str());
2043                 playhead_cursor->set_position (pos);
2044         } else {
2045                 playhead_cursor->set_position (0);
2046
2047                 /* reset_x_origin() doesn't work right here, since the old
2048                    position may be zero already, and it does nothing in such
2049                    circumstances.
2050                 */
2051                 
2052                 leftmost_frame = 0;
2053                 horizontal_adjustment.set_value (0);
2054         }
2055
2056         if (session && (prop = node.property ("edit-cursor"))) {
2057                 nframes_t pos = atol (prop->value().c_str());
2058                 edit_cursor->set_position (pos);
2059         } else {
2060                 edit_cursor->set_position (0);
2061         }
2062
2063         if ((prop = node.property ("mixer-width"))) {
2064                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2065         }
2066
2067         if ((prop = node.property ("zoom-focus"))) {
2068                 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2069         }
2070
2071         if ((prop = node.property ("zoom"))) {
2072                 reset_zoom (PBD::atof (prop->value()));
2073         }
2074
2075         if ((prop = node.property ("snap-to"))) {
2076                 set_snap_to ((SnapType) atoi (prop->value()));
2077         }
2078
2079         if ((prop = node.property ("snap-mode"))) {
2080                 set_snap_mode ((SnapMode) atoi (prop->value()));
2081         }
2082
2083         if ((prop = node.property ("mouse-mode"))) {
2084                 MouseMode m = str2mousemode(prop->value());
2085                 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2086                 set_mouse_mode (m, true);
2087         } else {
2088                 mouse_mode = MouseGain; /* lie, to force the mode switch */
2089                 set_mouse_mode (MouseObject, true);
2090         }
2091
2092         if ((prop = node.property ("show-waveforms"))) {
2093                 bool yn = (prop->value() == "yes");
2094                 _show_waveforms = !yn;
2095                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2096                 if (act) {
2097                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2098                         /* do it twice to force the change */
2099                         tact->set_active (!yn);
2100                         tact->set_active (yn);
2101                 }
2102         }
2103
2104         if ((prop = node.property ("show-waveforms-recording"))) {
2105                 bool yn = (prop->value() == "yes");
2106                 _show_waveforms_recording = !yn;
2107                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2108                 if (act) {
2109                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2110                         /* do it twice to force the change */
2111                         tact->set_active (!yn);
2112                         tact->set_active (yn);
2113                 }
2114         }
2115         
2116         if ((prop = node.property ("show-measures"))) {
2117                 bool yn = (prop->value() == "yes");
2118                 _show_measures = !yn;
2119                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2120                 if (act) {
2121                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2122                         /* do it twice to force the change */
2123                         tact->set_active (!yn);
2124                         tact->set_active (yn);
2125                 }
2126         }
2127
2128         if ((prop = node.property ("follow-playhead"))) {
2129                 bool yn = (prop->value() == "yes");
2130                 set_follow_playhead (yn);
2131                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2132                 if (act) {
2133                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2134                         if (tact->get_active() != yn) {
2135                                 tact->set_active (yn);
2136                         }
2137                 }
2138         }
2139
2140         if ((prop = node.property ("region-list-sort-type"))) {
2141                 region_list_sort_type = (Editing::RegionListSortType) -1; // force change 
2142                 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2143         }
2144
2145         if ((prop = node.property ("xfades-visible"))) {
2146                 bool yn = (prop->value() == "yes");
2147                 _xfade_visibility = !yn;
2148                 // set_xfade_visibility (yn);
2149         }
2150
2151         if ((prop = node.property ("show-editor-mixer"))) {
2152
2153                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2154                 if (act) {
2155
2156                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2157                         bool yn = (prop->value() == X_("yes"));
2158
2159                         /* do it twice to force the change */
2160                         
2161                         tact->set_active (!yn);
2162                         tact->set_active (yn);
2163                 }
2164         }
2165         
2166         if ((prop = node.property ("show-editor-list"))) {
2167
2168                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2169                 assert(act);
2170                 if (act) {
2171
2172                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2173                         bool yn = (prop->value() == X_("yes"));
2174
2175                         /* do it twice to force the change */
2176                         
2177                         tact->set_active (!yn);
2178                         tact->set_active (yn);
2179                 }
2180         }
2181
2182
2183         return 0;
2184 }
2185
2186 XMLNode&
2187 Editor::get_state ()
2188 {
2189         XMLNode* node = new XMLNode ("Editor");
2190         char buf[32];
2191
2192         _id.print (buf, sizeof (buf));
2193         node->add_property ("id", buf);
2194         
2195         if (is_realized()) {
2196                 Glib::RefPtr<Gdk::Window> win = get_window();
2197                 
2198                 int x, y, xoff, yoff, width, height;
2199                 win->get_root_origin(x, y);
2200                 win->get_position(xoff, yoff);
2201                 win->get_size(width, height);
2202                 
2203                 XMLNode* geometry = new XMLNode ("geometry");
2204
2205                 snprintf(buf, sizeof(buf), "%d", width);
2206                 geometry->add_property("x_size", string(buf));
2207                 snprintf(buf, sizeof(buf), "%d", height);
2208                 geometry->add_property("y_size", string(buf));
2209                 snprintf(buf, sizeof(buf), "%d", x);
2210                 geometry->add_property("x_pos", string(buf));
2211                 snprintf(buf, sizeof(buf), "%d", y);
2212                 geometry->add_property("y_pos", string(buf));
2213                 snprintf(buf, sizeof(buf), "%d", xoff);
2214                 geometry->add_property("x_off", string(buf));
2215                 snprintf(buf, sizeof(buf), "%d", yoff);
2216                 geometry->add_property("y_off", string(buf));
2217                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2218                 geometry->add_property("edit_pane_pos", string(buf));
2219
2220                 node->add_child_nocopy (*geometry);
2221         }
2222
2223         maybe_add_mixer_strip_width (*node);
2224         
2225         snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2226         node->add_property ("zoom-focus", buf);
2227         snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2228         node->add_property ("zoom", buf);
2229         snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2230         node->add_property ("snap-to", buf);
2231         snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2232         node->add_property ("snap-mode", buf);
2233
2234         snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2235         node->add_property ("playhead", buf);
2236         snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2237         node->add_property ("edit-cursor", buf);
2238
2239         node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2240         node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2241         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2242         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2243         node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2244         node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2245         node->add_property ("mouse-mode", enum2str(mouse_mode));
2246         
2247         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2248         if (act) {
2249                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2250                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2251         }
2252         
2253         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2254         if (act) {
2255                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2256                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2257         }
2258
2259         return *node;
2260 }
2261
2262
2263
2264 TimeAxisView *
2265 Editor::trackview_by_y_position (double y)
2266 {
2267         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2268
2269                 TimeAxisView *tv;
2270
2271                 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2272                         return tv;
2273                 }
2274         }
2275
2276         return 0;
2277 }
2278
2279 void
2280 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2281 {
2282         Location* before = 0;
2283         Location* after = 0;
2284
2285         if (!session) {
2286                 return;
2287         }
2288
2289         const nframes64_t one_second = session->frame_rate();
2290         const nframes64_t one_minute = session->frame_rate() * 60;
2291         const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2292         nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2293         nframes64_t presnap = start;
2294
2295         switch (snap_type) {
2296         case SnapToFrame:
2297                 break;
2298
2299         case SnapToCDFrame:
2300                 if (direction) {
2301                         start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2302                 } else {
2303                         start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2304                 }
2305                 break;
2306
2307         case SnapToSMPTEFrame:
2308                 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2309                         start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2310                 } else {
2311                         start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) *  session->frames_per_smpte_frame());
2312                 }
2313                 break;
2314
2315         case SnapToSMPTESeconds:
2316                 if (session->smpte_offset_negative())
2317                 {
2318                         start += session->smpte_offset ();
2319                 } else {
2320                         start -= session->smpte_offset ();
2321                 }    
2322                 if (start % one_smpte_second > one_smpte_second / 2) {
2323                         start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2324                 } else {
2325                         start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2326                 }
2327                 
2328                 if (session->smpte_offset_negative())
2329                 {
2330                         start -= session->smpte_offset ();
2331                 } else {
2332                         start += session->smpte_offset ();
2333                 }
2334                 break;
2335                 
2336         case SnapToSMPTEMinutes:
2337                 if (session->smpte_offset_negative())
2338                 {
2339                         start += session->smpte_offset ();
2340                 } else {
2341                         start -= session->smpte_offset ();
2342                 }
2343                 if (start % one_smpte_minute > one_smpte_minute / 2) {
2344                         start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2345                 } else {
2346                         start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2347                 }
2348                 if (session->smpte_offset_negative())
2349                 {
2350                         start -= session->smpte_offset ();
2351                 } else {
2352                         start += session->smpte_offset ();
2353                 }
2354                 break;
2355                 
2356         case SnapToSeconds:
2357                 if (start % one_second > one_second / 2) {
2358                         start = (nframes_t) ceil ((double) start / one_second) * one_second;
2359                 } else {
2360                         start = (nframes_t) floor ((double) start / one_second) * one_second;
2361                 }
2362                 break;
2363                 
2364         case SnapToMinutes:
2365                 if (start % one_minute > one_minute / 2) {
2366                         start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2367                 } else {
2368                         start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2369                 }
2370                 break;
2371
2372         case SnapToBar:
2373                 start = session->tempo_map().round_to_bar (start, direction);
2374                 break;
2375
2376         case SnapToBeat:
2377                 start = session->tempo_map().round_to_beat (start, direction);
2378                 break;
2379
2380         case SnapToAThirtysecondBeat:
2381                 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2382                 break;
2383
2384         case SnapToASixteenthBeat:
2385                 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2386                 break;
2387
2388         case SnapToAEighthBeat:
2389                 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2390                 break;
2391
2392         case SnapToAQuarterBeat:
2393                 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2394                 break;
2395
2396         case SnapToAThirdBeat:
2397                 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2398                 break;
2399
2400         case SnapToEditCursor:
2401                 start = edit_cursor->current_frame;
2402                 break;
2403
2404         case SnapToMark:
2405                 if (for_mark) {
2406                         return;
2407                 }
2408
2409                 before = session->locations()->first_location_before (start);
2410                 after = session->locations()->first_location_after (start);
2411
2412                 if (direction < 0) {
2413                         if (before) {
2414                                 start = before->start();
2415                         } else {
2416                                 start = 0;
2417                         }
2418                 } else if (direction > 0) {
2419                         if (after) {
2420                                 start = after->start();
2421                         } else {
2422                                 start = session->current_end_frame();
2423                         }
2424                 } else {
2425                         if (before) {
2426                                 if (after) {
2427                                         /* find nearest of the two */
2428                                         if ((start - before->start()) < (after->start() - start)) {
2429                                                 start = before->start();
2430                                         } else {
2431                                                 start = after->start();
2432                                         }
2433                                 } else {
2434                                         start = before->start();
2435                                 }
2436                         } else if (after) {
2437                                 start = after->start();
2438                         } else {
2439                                 /* relax */
2440                         }
2441                 }
2442                 break;
2443
2444         case SnapToRegionStart:
2445         case SnapToRegionEnd:
2446         case SnapToRegionSync:
2447         case SnapToRegionBoundary:
2448                 if (!region_boundary_cache.empty()) {
2449                         vector<nframes_t>::iterator i;
2450
2451                         if (direction > 0) {
2452                                 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2453                         } else {
2454                                 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2455                         }
2456                         
2457                         if (i != region_boundary_cache.end()) {
2458                                 start = *i;
2459                         } else {
2460                                 start = region_boundary_cache.back();
2461                         }
2462                 }
2463                 break;
2464         }
2465
2466         switch (snap_mode) {
2467         case SnapNormal:
2468                 return;                 
2469                 
2470         case SnapMagnetic:
2471                 
2472                 if (presnap > start) {
2473                         if (presnap > (start + unit_to_frame(snap_threshold))) {
2474                                 start = presnap;
2475                         }
2476                         
2477                 } else if (presnap < start) {
2478                         if (presnap < (start - unit_to_frame(snap_threshold))) {
2479                                 start = presnap;
2480                         }
2481                 }
2482                 
2483         default:
2484                 return;
2485                 
2486         }
2487 }
2488
2489 double
2490 Editor::snap_length_beats (nframes_t start)
2491 {
2492         if (!session) {
2493                 return 1.0;
2494         }
2495
2496         /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */
2497
2498         switch (snap_type) {
2499         case SnapToBar:
2500                 return session->tempo_map().meter_at(start).beats_per_bar();
2501
2502         case SnapToBeat:
2503                 return 1.0;
2504
2505         case SnapToAThirtysecondBeat:
2506                 return 1.0 / (double)32.0;
2507                 break;
2508
2509         case SnapToASixteenthBeat:
2510                 return 1.0 / (double)16.0;
2511                 break;
2512
2513         case SnapToAEighthBeat:
2514                 return 1.0 / (double)8.0;
2515                 break;
2516
2517         case SnapToAQuarterBeat:
2518                 return 1.0 / (double)4.0;
2519                 break;
2520
2521         case SnapToAThirdBeat:
2522                 return 1.0 / (double)3.0;
2523
2524         default:
2525                 return 1.0;
2526         }
2527 }
2528
2529 void
2530 Editor::setup_toolbar ()
2531 {
2532         string pixmap_path;
2533
2534         const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2535
2536
2537         /* Mode Buttons (tool selection) */
2538
2539         vector<ToggleButton *> mouse_mode_buttons;
2540
2541         mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2542         mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2543         mouse_mode_buttons.push_back (&mouse_move_button);
2544         mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2545         mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2546         mouse_mode_buttons.push_back (&mouse_select_button);
2547         mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2548         mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2549         mouse_mode_buttons.push_back (&mouse_gain_button);
2550         mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2551         mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2552         mouse_mode_buttons.push_back (&mouse_zoom_button);
2553         mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2554         mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2555         mouse_mode_buttons.push_back (&mouse_timefx_button);
2556         mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2557         mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2558         mouse_note_button.add (*(manage (new Image (::get_icon("tool_note")))));
2559         mouse_note_button.set_relief(Gtk::RELIEF_NONE);
2560         mouse_mode_buttons.push_back (&mouse_note_button);
2561         mouse_mode_buttons.push_back (&mouse_audition_button);
2562         
2563         mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2564
2565         HBox* mode_box = manage(new HBox);
2566         mode_box->set_border_width (2);
2567         mode_box->set_spacing(4);
2568         mouse_mode_button_box.set_spacing(1);
2569         mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2570         mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2571         mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2572         mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2573         mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2574         mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2575         mouse_mode_button_box.pack_start(mouse_note_button, true, true);
2576         mouse_mode_button_box.set_homogeneous(true);
2577
2578         vector<string> edit_mode_strings;
2579         edit_mode_strings.push_back (edit_mode_to_string (Splice));
2580         edit_mode_strings.push_back (edit_mode_to_string (Slide));
2581
2582         edit_mode_selector.set_name ("EditModeSelector");
2583         Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2584         set_popdown_strings (edit_mode_selector, edit_mode_strings);
2585         edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2586
2587         mode_box->pack_start(edit_mode_selector);
2588         mode_box->pack_start(mouse_mode_button_box);
2589         
2590         mouse_mode_tearoff = manage (new TearOff (*mode_box));
2591         mouse_mode_tearoff->set_name ("MouseModeBase");
2592
2593         mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2594                                                   &mouse_mode_tearoff->tearoff_window()));
2595         mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2596                                                   &mouse_mode_tearoff->tearoff_window(), 1));
2597         mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2598                                                   &mouse_mode_tearoff->tearoff_window()));
2599         mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2600                                                    &mouse_mode_tearoff->tearoff_window(), 1));
2601
2602         mouse_move_button.set_name ("MouseModeButton");
2603         mouse_select_button.set_name ("MouseModeButton");
2604         mouse_gain_button.set_name ("MouseModeButton");
2605         mouse_zoom_button.set_name ("MouseModeButton");
2606         mouse_timefx_button.set_name ("MouseModeButton");
2607         mouse_audition_button.set_name ("MouseModeButton");
2608         mouse_note_button.set_name ("MouseModeButton");
2609
2610         ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2611         ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2612         ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2613         ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2614         ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2615         ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2616         ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes"));
2617
2618         mouse_move_button.unset_flags (CAN_FOCUS);
2619         mouse_select_button.unset_flags (CAN_FOCUS);
2620         mouse_gain_button.unset_flags (CAN_FOCUS);
2621         mouse_zoom_button.unset_flags (CAN_FOCUS);
2622         mouse_timefx_button.unset_flags (CAN_FOCUS);
2623         mouse_audition_button.unset_flags (CAN_FOCUS);
2624         mouse_note_button.unset_flags (CAN_FOCUS);
2625
2626         mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2627         mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2628
2629         mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2630         mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2631         mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2632         mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2633         mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2634         mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote));
2635
2636         // mouse_move_button.set_active (true);
2637         
2638
2639         /* Zoom */
2640         
2641         zoom_box.set_spacing (1);
2642         zoom_box.set_border_width (2);
2643
2644         zoom_in_button.set_name ("EditorTimeButton");
2645         zoom_in_button.set_size_request(-1,16);
2646         zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2647         zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2648         ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2649         
2650         zoom_out_button.set_name ("EditorTimeButton");
2651         zoom_out_button.set_size_request(-1,16);
2652         zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2653         zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2654         ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2655
2656         zoom_out_full_button.set_name ("EditorTimeButton");
2657         zoom_out_full_button.set_size_request(-1,16);
2658         zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2659         zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2660         ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2661
2662         zoom_focus_selector.set_name ("ZoomFocusSelector");
2663         Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Center", FUDGE, 0);
2664         set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2665         zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2666         ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2667
2668         zoom_box.pack_start (zoom_focus_selector, true, true);
2669         zoom_box.pack_start (zoom_out_button, false, false);
2670         zoom_box.pack_start (zoom_in_button, false, false);
2671         zoom_box.pack_start (zoom_out_full_button, false, false);
2672
2673         /* Edit Cursor / Snap */
2674
2675         snap_box.set_spacing (1);
2676         snap_box.set_border_width (2);
2677
2678         snap_type_selector.set_name ("SnapTypeSelector");
2679         Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2680         set_popdown_strings (snap_type_selector, snap_type_strings);
2681         snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2682         ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2683
2684         snap_mode_selector.set_name ("SnapModeSelector");
2685         Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2686         set_popdown_strings (snap_mode_selector, snap_mode_strings);
2687         snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2688
2689         snap_box.pack_start (edit_cursor_clock, false, false);
2690         snap_box.pack_start (snap_mode_selector, false, false);
2691         snap_box.pack_start (snap_type_selector, false, false);
2692
2693
2694         /* Nudge */
2695
2696         HBox *nudge_box = manage (new HBox);
2697         nudge_box->set_spacing(1);
2698         nudge_box->set_border_width (2);
2699
2700         nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2701         nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2702
2703         nudge_box->pack_start (nudge_backward_button, false, false);
2704         nudge_box->pack_start (nudge_forward_button, false, false);
2705         nudge_box->pack_start (nudge_clock, false, false);
2706
2707
2708         /* Pack everything in... */
2709
2710         HBox* hbox = new HBox;
2711         hbox->set_spacing(10);
2712
2713         tools_tearoff = new TearOff (*hbox);
2714         tools_tearoff->set_name ("MouseModeBase");
2715
2716         tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2717                                              &tools_tearoff->tearoff_window()));
2718         tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2719                                              &tools_tearoff->tearoff_window(), 0));
2720         tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
2721                                              &tools_tearoff->tearoff_window()));
2722         tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
2723                                               &tools_tearoff->tearoff_window(), 0));
2724
2725         toolbar_hbox.set_spacing (10);
2726         toolbar_hbox.set_border_width (1);
2727
2728         toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2729         toolbar_hbox.pack_start (*tools_tearoff, false, false);
2730
2731         
2732         hbox->pack_start (snap_box, false, false);
2733         // hbox->pack_start (zoom_box, false, false); 
2734         hbox->pack_start (*nudge_box, false, false);
2735
2736         hbox->show_all ();
2737         
2738         toolbar_base.set_name ("ToolBarBase");
2739         toolbar_base.add (toolbar_hbox);
2740
2741         toolbar_frame.set_shadow_type (SHADOW_OUT);
2742         toolbar_frame.set_name ("BaseFrame");
2743         toolbar_frame.add (toolbar_base);
2744 }
2745
2746
2747 void
2748 Editor::setup_midi_toolbar ()
2749 {
2750         string pixmap_path;
2751
2752         /* Mode Buttons (tool selection) */
2753
2754         vector<ToggleButton *> midi_tool_buttons;
2755
2756         midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil")))));
2757         midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE);
2758         midi_tool_buttons.push_back (&midi_tool_pencil_button);
2759         midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
2760         midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
2761         midi_tool_buttons.push_back (&midi_tool_select_button);
2762         midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
2763         midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
2764         midi_tool_buttons.push_back (&midi_tool_erase_button);
2765
2766         midi_tool_pencil_button.set_active(true);
2767         
2768         midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
2769
2770         midi_tool_button_box.set_border_width (2);
2771         midi_tool_button_box.set_spacing(4);
2772         midi_tool_button_box.set_spacing(1);
2773         midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
2774         midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
2775         midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
2776         midi_tool_button_box.set_homogeneous(true);
2777
2778         midi_tool_pencil_button.set_name ("MouseModeButton");
2779         midi_tool_select_button.set_name ("MouseModeButton");
2780         midi_tool_erase_button.set_name ("MouseModeButton");
2781
2782         ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
2783         ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
2784         ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
2785
2786         midi_tool_pencil_button.unset_flags (CAN_FOCUS);
2787         midi_tool_select_button.unset_flags (CAN_FOCUS);
2788         midi_tool_erase_button.unset_flags (CAN_FOCUS);
2789         
2790         midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
2791                                 &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
2792         midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
2793                                 &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
2794         midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
2795                                 &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
2796         
2797         /* Pack everything in... */
2798
2799         midi_tools_tearoff = new TearOff (midi_tool_button_box);
2800         midi_tools_tearoff->set_name ("MouseModeBase");
2801
2802         /*
2803         midi_tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox), 
2804                                              &midi_tools_tearoff->tearoff_window()));
2805         midi_tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox), 
2806                                              &midi_tools_tearoff->tearoff_window(), 0));
2807         midi_tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox), 
2808                                              &midi_tools_tearoff->tearoff_window()));
2809         midi_tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox), 
2810                                               &midi_tools_tearoff->tearoff_window(), 0));
2811         */
2812
2813         midi_toolbar_hbox.set_spacing (10);
2814         midi_toolbar_hbox.set_border_width (1);
2815
2816         midi_toolbar_hbox.pack_start (*midi_tools_tearoff, false, true);
2817
2818         midi_tool_button_box.show_all ();
2819         midi_toolbar_hbox.show_all();
2820         midi_tools_tearoff->show_all();
2821         
2822         midi_toolbar_base.set_name ("ToolBarBase");
2823         midi_toolbar_base.add (midi_toolbar_hbox);
2824
2825         midi_toolbar_frame.set_shadow_type (SHADOW_OUT);
2826         midi_toolbar_frame.set_name ("BaseFrame");
2827         midi_toolbar_frame.add (midi_toolbar_base);
2828 }
2829
2830 int
2831 Editor::convert_drop_to_paths (vector<ustring>& paths, 
2832                                const RefPtr<Gdk::DragContext>& context,
2833                                gint                x,
2834                                gint                y,
2835                                const SelectionData& data,
2836                                guint               info,
2837                                guint               time)                               
2838
2839 {       
2840         if (session == 0) {
2841                 return -1;
2842         }
2843
2844         vector<ustring> uris = data.get_uris();
2845
2846         cerr << "there were " << uris.size() << " in that drag data\n";
2847
2848         if (uris.empty()) {
2849
2850                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2851                    are actually URI lists. So do it by hand.
2852                 */
2853
2854                 if (data.get_target() != "text/plain") {
2855                         return -1;
2856                 }
2857   
2858                 /* Parse the "uri-list" format that Nautilus provides, 
2859                    where each pathname is delimited by \r\n
2860                 */
2861         
2862                 const char* p = data.get_text().c_str();
2863                 const char* q;
2864
2865                 while (p)
2866                 {
2867                         if (*p != '#')
2868                         {
2869                                 while (g_ascii_isspace (*p))
2870                                         p++;
2871                                 
2872                                 q = p;
2873                                 while (*q && (*q != '\n') && (*q != '\r'))
2874                                         q++;
2875                                 
2876                                 if (q > p)
2877                                 {
2878                                         q--;
2879                                         while (q > p && g_ascii_isspace (*q))
2880                                                 q--;
2881                                         
2882                                         if (q > p)
2883                                         {
2884                                                 uris.push_back (ustring (p, q - p + 1));
2885                                         }
2886                                 }
2887                         }
2888                         p = strchr (p, '\n');
2889                         if (p)
2890                                 p++;
2891                 }
2892
2893                 if (uris.empty()) {
2894                         return -1;
2895                 }
2896         }
2897         
2898         for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2899
2900                 if ((*i).substr (0,7) == "file://") {
2901                         
2902                         ustring p = *i;
2903                         PBD::url_decode (p);
2904
2905                         // scan forward past three slashes
2906                         
2907                         ustring::size_type slashcnt = 0;
2908                         ustring::size_type n = 0;
2909                         ustring::iterator x = p.begin();
2910
2911                         while (slashcnt < 3 && x != p.end()) {
2912                                 if ((*x) == '/') {
2913                                         slashcnt++;
2914                                 } else if (slashcnt == 3) {
2915                                         break;
2916                                 }
2917                                 ++n;
2918                                 ++x;
2919                         }
2920
2921                         if (slashcnt != 3 || x == p.end()) {
2922                                 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2923                                 continue;
2924                         }
2925
2926                         paths.push_back (p.substr (n - 1));
2927                 }
2928         }
2929
2930         return 0;
2931 }
2932
2933 void
2934 Editor::new_tempo_section ()
2935
2936 {
2937 }
2938
2939 void
2940 Editor::map_transport_state ()
2941 {
2942         ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2943
2944         if (session->transport_stopped()) {
2945                 have_pending_keyboard_selection = false;
2946         }
2947
2948         update_loop_range_view (true);
2949 }
2950
2951 /* UNDO/REDO */
2952
2953 Editor::State::State (PublicEditor const * e)
2954 {
2955         selection = new Selection (e);
2956 }
2957
2958 Editor::State::~State ()
2959 {
2960         delete selection;
2961 }
2962
2963 UndoAction
2964 Editor::get_memento () const
2965 {
2966         State *state = new State (this);
2967
2968         store_state (*state);
2969         return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2970 }
2971
2972 void
2973 Editor::store_state (State& state) const
2974 {
2975         *state.selection = *selection;
2976 }
2977
2978 void
2979 Editor::restore_state (State *state)
2980 {
2981         if (*selection == *state->selection) {
2982                 return;
2983         }
2984
2985         *selection = *state->selection;
2986         time_selection_changed ();
2987         region_selection_changed ();   
2988
2989         /* XXX other selection change handlers? */
2990 }
2991
2992 void
2993 Editor::begin_reversible_command (string name)
2994 {
2995         if (session) {
2996                 before = &get_state();
2997                 session->begin_reversible_command (name);
2998         }
2999 }
3000
3001 void
3002 Editor::commit_reversible_command ()
3003 {
3004         if (session) {
3005                 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
3006         }
3007 }
3008
3009 void
3010 Editor::set_edit_group_solo (Route& route, bool yn)
3011 {
3012         RouteGroup *edit_group;
3013
3014         if ((edit_group = route.edit_group()) != 0) {
3015                 edit_group->apply (&Route::set_solo, yn, this);
3016         } else {
3017                 route.set_solo (yn, this);
3018         }
3019 }
3020
3021 void
3022 Editor::set_edit_group_mute (Route& route, bool yn)
3023 {
3024         RouteGroup *edit_group = 0;
3025
3026         if ((edit_group == route.edit_group()) != 0) {
3027                 edit_group->apply (&Route::set_mute, yn, this);
3028         } else {
3029                 route.set_mute (yn, this);
3030         }
3031 }
3032                 
3033 void
3034 Editor::history_changed ()
3035 {
3036         string label;
3037
3038         if (undo_action && session) {
3039                 if (session->undo_depth() == 0) {
3040                         label = _("Undo");
3041                 } else {
3042                         label = string_compose(_("Undo (%1)"), session->next_undo());
3043                 }
3044                 undo_action->property_label() = label;
3045         }
3046
3047         if (redo_action && session) {
3048                 if (session->redo_depth() == 0) {
3049                         label = _("Redo");
3050                 } else {
3051                         label = string_compose(_("Redo (%1)"), session->next_redo());
3052                 }
3053                 redo_action->property_label() = label;
3054         }
3055 }
3056
3057 void
3058 Editor::duplicate_dialog (bool dup_region)
3059 {
3060         if (selection->regions.empty() && (selection->time.length() == 0)) {
3061                 return;
3062         }
3063
3064         ArdourDialog win ("duplicate dialog");
3065         Label  label (_("Duplicate how many times?"));
3066         Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3067         SpinButton spinner (adjustment);
3068
3069         win.get_vbox()->set_spacing (12);
3070         win.get_vbox()->pack_start (label);
3071
3072         /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3073            place, visually. so do this by hand.
3074         */
3075
3076         win.get_vbox()->pack_start (spinner);
3077         spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3078
3079         label.show ();
3080         spinner.show ();
3081
3082         win.add_button (Stock::OK, RESPONSE_ACCEPT);
3083         win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3084
3085         win.set_position (WIN_POS_MOUSE);
3086
3087         spinner.grab_focus ();
3088
3089         switch (win.run ()) {
3090         case RESPONSE_ACCEPT:
3091                 break;
3092         default:
3093                 return;
3094         }
3095
3096         float times = adjustment.get_value();
3097
3098         if (!selection->regions.empty()) {
3099                 duplicate_some_regions (selection->regions, times);
3100         } else {
3101                 duplicate_selection (times);
3102         }
3103 }
3104
3105 void
3106 Editor::show_verbose_canvas_cursor ()
3107 {
3108         verbose_canvas_cursor->raise_to_top();
3109         verbose_canvas_cursor->show();
3110         verbose_cursor_visible = true;
3111 }
3112
3113 void
3114 Editor::hide_verbose_canvas_cursor ()
3115 {
3116         verbose_canvas_cursor->hide();
3117         verbose_cursor_visible = false;
3118 }
3119
3120 void
3121 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3122 {
3123         /* XXX get origin of canvas relative to root window,
3124            add x and y and check compared to gdk_screen_{width,height}
3125         */
3126         verbose_canvas_cursor->property_text() = txt.c_str();
3127         verbose_canvas_cursor->property_x() = x;
3128         verbose_canvas_cursor->property_y() = y;
3129 }
3130
3131 void
3132 Editor::set_verbose_canvas_cursor_text (const string & txt)
3133 {
3134         verbose_canvas_cursor->property_text() = txt.c_str();
3135 }
3136
3137 void
3138 Editor::edit_mode_selection_done ()
3139 {
3140         if (session == 0) {
3141                 return;
3142         }
3143
3144         string choice = edit_mode_selector.get_active_text();
3145         EditMode mode = Slide;
3146
3147         if (choice == _("Splice Edit")) {
3148                 mode = Splice;
3149         } else if (choice == _("Slide Edit")) {
3150                 mode = Slide;
3151         }
3152
3153         Config->set_edit_mode (mode);
3154 }       
3155
3156 void
3157 Editor::snap_type_selection_done ()
3158 {
3159         string choice = snap_type_selector.get_active_text();
3160         SnapType snaptype = SnapToFrame;
3161
3162         if (choice == _("Beats/3")) {
3163                 snaptype = SnapToAThirdBeat;
3164         } else if (choice == _("Beats/4")) {
3165                 snaptype = SnapToAQuarterBeat;
3166         } else if (choice == _("Beats/8")) {
3167                 snaptype = SnapToAEighthBeat;
3168         } else if (choice == _("Beats/16")) {
3169                 snaptype = SnapToASixteenthBeat;
3170         } else if (choice == _("Beats/32")) {
3171                 snaptype = SnapToAThirtysecondBeat;
3172         } else if (choice == _("Beats")) {
3173                 snaptype = SnapToBeat;
3174         } else if (choice == _("Bars")) {
3175                 snaptype = SnapToBar;
3176         } else if (choice == _("Marks")) {
3177                 snaptype = SnapToMark;
3178         } else if (choice == _("Edit Cursor")) {
3179                 snaptype = SnapToEditCursor;
3180         } else if (choice == _("Region starts")) {
3181                 snaptype = SnapToRegionStart;
3182         } else if (choice == _("Region ends")) {
3183                 snaptype = SnapToRegionEnd;
3184         } else if (choice == _("Region bounds")) {
3185                 snaptype = SnapToRegionBoundary;
3186         } else if (choice == _("Region syncs")) {
3187                 snaptype = SnapToRegionSync;
3188         } else if (choice == _("CD Frames")) {
3189                 snaptype = SnapToCDFrame;
3190         } else if (choice == _("SMPTE Frames")) {
3191                 snaptype = SnapToSMPTEFrame;
3192         } else if (choice == _("SMPTE Seconds")) {
3193                 snaptype = SnapToSMPTESeconds;
3194         } else if (choice == _("SMPTE Minutes")) {
3195                 snaptype = SnapToSMPTEMinutes;
3196         } else if (choice == _("Seconds")) {
3197                 snaptype = SnapToSeconds;
3198         } else if (choice == _("Minutes")) {
3199                 snaptype = SnapToMinutes;
3200         } else if (choice == _("None")) {
3201                 snaptype = SnapToFrame;
3202         }
3203
3204         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3205         if (ract) {
3206                 ract->set_active ();
3207         }
3208 }       
3209
3210 void
3211 Editor::snap_mode_selection_done ()
3212 {
3213         string choice = snap_mode_selector.get_active_text();
3214         SnapMode mode = SnapNormal;
3215
3216         if (choice == _("Normal")) {
3217                 mode = SnapNormal;
3218         } else if (choice == _("Magnetic")) {
3219                 mode = SnapMagnetic;
3220         }
3221
3222         RefPtr<RadioAction> ract = snap_mode_action (mode);
3223
3224         if (ract) {
3225                 ract->set_active (true);
3226         }
3227 }
3228
3229 void
3230 Editor::zoom_focus_selection_done ()
3231 {
3232         string choice = zoom_focus_selector.get_active_text();
3233         ZoomFocus focus_type = ZoomFocusLeft;
3234
3235         if (choice == _("Left")) {
3236                 focus_type = ZoomFocusLeft;
3237         } else if (choice == _("Right")) {
3238                 focus_type = ZoomFocusRight;
3239         } else if (choice == _("Center")) {
3240                 focus_type = ZoomFocusCenter;
3241         } else if (choice == _("Play")) {
3242                 focus_type = ZoomFocusPlayhead;
3243         } else if (choice == _("Edit")) {
3244                 focus_type = ZoomFocusEdit;
3245         } 
3246         
3247         RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3248
3249         if (ract) {
3250                 ract->set_active ();
3251         }
3252 }       
3253
3254 gint
3255 Editor::edit_controls_button_release (GdkEventButton* ev)
3256 {
3257         if (Keyboard::is_context_menu_event (ev)) {
3258                 ARDOUR_UI::instance()->add_route (this);
3259         }
3260         return TRUE;
3261 }
3262
3263 gint
3264 Editor::mouse_select_button_release (GdkEventButton* ev)
3265 {
3266         /* this handles just right-clicks */
3267
3268         if (ev->button != 3) {
3269                 return false;
3270         }
3271
3272         return true;
3273 }
3274
3275 Editor::TrackViewList *
3276 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3277 {
3278         TrackViewList *v;
3279         TrackViewList::iterator i;
3280
3281         v = new TrackViewList;
3282
3283         if (track == 0 && group == 0) {
3284
3285                 /* all views */
3286
3287                 for (i = track_views.begin(); i != track_views.end (); ++i) {
3288                         v->push_back (*i);
3289                 }
3290
3291         } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3292                 
3293                 /* just the view for this track
3294                  */
3295
3296                 v->push_back (track);
3297
3298         } else {
3299                 
3300                 /* views for all tracks in the edit group */
3301                 
3302                 for (i  = track_views.begin(); i != track_views.end (); ++i) {
3303
3304                         if (group == 0 || (*i)->edit_group() == group) {
3305                                 v->push_back (*i);
3306                         }
3307                 }
3308         }
3309         
3310         return v;
3311 }
3312
3313 void
3314 Editor::set_zoom_focus (ZoomFocus f)
3315 {
3316         string str = zoom_focus_strings[(int)f];
3317
3318         if (str != zoom_focus_selector.get_active_text()) {
3319                 zoom_focus_selector.set_active_text (str);
3320         }
3321         
3322         if (zoom_focus != f) {
3323                 zoom_focus = f;
3324
3325                 ZoomFocusChanged (); /* EMIT_SIGNAL */
3326
3327                 instant_save ();
3328         }
3329 }
3330
3331 void
3332 Editor::ensure_float (Window& win)
3333 {
3334         win.set_transient_for (*this);
3335 }
3336
3337 void 
3338 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3339 {
3340         /* recover or initialize pane positions. do this here rather than earlier because
3341            we don't want the positions to change the child allocations, which they seem to do.
3342          */
3343
3344         int pos;
3345         XMLProperty* prop;
3346         char buf[32];
3347         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3348         int width, height;
3349         static int32_t done;
3350         XMLNode* geometry;
3351
3352         if ((geometry = find_named_node (*node, "geometry")) == 0) {
3353                 width = default_width;
3354                 height = default_height;
3355         } else {
3356                 width = atoi(geometry->property("x_size")->value());
3357                 height = atoi(geometry->property("y_size")->value());
3358         }
3359
3360         if (which == static_cast<Paned*> (&edit_pane)) {
3361
3362                 if (done) {
3363                         return;
3364                 }
3365
3366                 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3367                         /* initial allocation is 90% to canvas, 10% to notebook */
3368                         pos = (int) floor (alloc.get_width() * 0.90f);
3369                         snprintf (buf, sizeof(buf), "%d", pos);
3370                 } else {
3371                         pos = atoi (prop->value());
3372                 }
3373                 
3374                 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3375                         edit_pane.set_position (pos);
3376                         pre_maximal_pane_position = pos;
3377                 }
3378         }
3379 }
3380
3381 void
3382 Editor::detach_tearoff (Box* b, Window* w)
3383 {
3384         if (tools_tearoff->torn_off() && 
3385             mouse_mode_tearoff->torn_off()) {
3386                 top_hbox.remove (toolbar_frame);
3387         }
3388 }
3389
3390 void
3391 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3392 {
3393         if (toolbar_frame.get_parent() == 0) {
3394                 top_hbox.pack_end (toolbar_frame);
3395         }
3396 }
3397
3398 void
3399 Editor::set_show_measures (bool yn)
3400 {
3401         if (_show_measures != yn) {
3402                 hide_measures ();
3403
3404                 if ((_show_measures = yn) == true) {
3405                         draw_measures ();
3406                 }
3407                 instant_save ();
3408         }
3409 }
3410
3411 void
3412 Editor::toggle_follow_playhead ()
3413 {
3414         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3415         if (act) {
3416                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3417                 set_follow_playhead (tact->get_active());
3418         }
3419 }
3420
3421 void
3422 Editor::set_follow_playhead (bool yn)
3423 {
3424         if (_follow_playhead != yn) {
3425                 if ((_follow_playhead = yn) == true) {
3426                         /* catch up */
3427                         update_current_screen ();
3428                 }
3429                 instant_save ();
3430         }
3431 }
3432
3433 void
3434 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3435 {
3436         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3437         if (xfade) {
3438                 xfade->set_active (!xfade->active());
3439         }
3440 }
3441
3442 void
3443 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3444 {
3445         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3446         if (xfade) {
3447                 xfade->set_follow_overlap (!xfade->following_overlap());
3448         }
3449 }
3450
3451 void
3452 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3453 {
3454         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3455
3456         if (!xfade) {
3457                 return;
3458         }
3459
3460         CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3461                 
3462         ensure_float (cew);
3463         
3464         switch (cew.run ()) {
3465         case RESPONSE_ACCEPT:
3466                 break;
3467         default:
3468                 return;
3469         }
3470         
3471         cew.apply ();
3472         xfade->StateChanged (Change (~0));
3473 }
3474
3475 PlaylistSelector&
3476 Editor::playlist_selector () const
3477 {
3478         return *_playlist_selector;
3479 }
3480
3481 nframes_t
3482 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3483 {
3484         nframes_t ret;
3485
3486         ret = nudge_clock.current_duration (pos);
3487         next = ret + 1; /* XXXX fix me */
3488
3489         return ret;
3490 }
3491
3492 void
3493 Editor::end_location_changed (Location* location)
3494 {
3495         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3496         reset_scrolling_region ();
3497 }
3498
3499 int
3500 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3501 {
3502         ArdourDialog dialog ("playlist deletion dialog");
3503         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
3504                                         "If left alone, no audio files used by it will be cleaned.\n"
3505                                         "If deleted, audio files used by it alone by will cleaned."),
3506                                       pl->name()));
3507         
3508         dialog.set_position (WIN_POS_CENTER);
3509         dialog.get_vbox()->pack_start (label);
3510
3511         label.show ();
3512
3513         dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3514         dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3515         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3516
3517         switch (dialog.run ()) {
3518         case RESPONSE_ACCEPT:
3519                 /* delete the playlist */
3520                 return 0;
3521                 break;
3522
3523         case RESPONSE_REJECT:
3524                 /* keep the playlist */
3525                 return 1;
3526                 break;
3527
3528         default:
3529                 break;
3530         }
3531
3532         return -1;
3533 }
3534
3535 bool
3536 Editor::audio_region_selection_covers (nframes_t where)
3537 {
3538         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3539                 if ((*a)->region()->covers (where)) {
3540                         return true;
3541                 }
3542         }
3543
3544         return false;
3545 }
3546
3547 void
3548 Editor::prepare_for_cleanup ()
3549 {
3550         cut_buffer->clear_regions ();
3551         cut_buffer->clear_playlists ();
3552
3553         selection->clear_regions ();
3554         selection->clear_playlists ();
3555 }
3556
3557 Location*
3558 Editor::transport_loop_location()
3559 {
3560         if (session) {
3561                 return session->locations()->auto_loop_location();
3562         } else {
3563                 return 0;
3564         }
3565 }
3566
3567 Location*
3568 Editor::transport_punch_location()
3569 {
3570         if (session) {
3571                 return session->locations()->auto_punch_location();
3572         } else {
3573                 return 0;
3574         }
3575 }
3576
3577 bool
3578 Editor::control_layout_scroll (GdkEventScroll* ev)
3579 {
3580         switch (ev->direction) {
3581         case GDK_SCROLL_UP:
3582                 scroll_tracks_up_line ();
3583                 return true;
3584                 break;
3585
3586         case GDK_SCROLL_DOWN:
3587                 scroll_tracks_down_line ();
3588                 return true;
3589                 
3590         default:
3591                 /* no left/right handling yet */
3592                 break;
3593         }
3594
3595         return false;
3596 }
3597
3598
3599 /** A new snapshot has been selected.
3600  */
3601 void
3602 Editor::snapshot_display_selection_changed ()
3603 {
3604         if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3605
3606                 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3607                 
3608                 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3609
3610                 if (snap_name.length() == 0) {
3611                         return;
3612                 }
3613                 
3614                 if (session->snap_name() == snap_name) {
3615                         return;
3616                 }
3617                 
3618                 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3619         }
3620 }
3621
3622 bool
3623 Editor::snapshot_display_button_press (GdkEventButton* ev)
3624 {
3625         if (ev->button == 3) {
3626                 /* Right-click on the snapshot list. Work out which snapshot it
3627                    was over. */
3628                 Gtk::TreeModel::Path path;
3629                 Gtk::TreeViewColumn* col;
3630                 int cx;
3631                 int cy;
3632                 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3633                 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3634                 if (iter) {
3635                         Gtk::TreeModel::Row row = *iter;
3636                         popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3637                 }
3638                 return true;
3639         }
3640
3641         return false;
3642 }
3643
3644
3645 /** Pop up the snapshot display context menu.
3646  * @param button Button used to open the menu.
3647  * @param time Menu open time.
3648  * @snapshot_name Name of the snapshot that the menu click was over.
3649  */
3650
3651 void
3652 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3653 {
3654         using namespace Menu_Helpers;
3655
3656         MenuList& items (snapshot_context_menu.items());
3657         items.clear ();
3658
3659         const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3660
3661         add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3662
3663         add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3664
3665         snapshot_context_menu.popup (button, time);
3666 }
3667
3668 void
3669 Editor::rename_snapshot (Glib::ustring old_name)
3670 {
3671         ArdourPrompter prompter(true);
3672
3673         string new_name;
3674
3675         prompter.set_name ("Prompter");
3676         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3677         prompter.set_prompt (_("New name of snapshot"));
3678         prompter.set_initial_text (old_name);
3679         
3680         if (prompter.run() == RESPONSE_ACCEPT) {
3681                 prompter.get_result (new_name);
3682                 if (new_name.length()) {
3683                         session->rename_state (old_name, new_name);
3684                         redisplay_snapshots ();
3685                 }
3686         }
3687 }
3688
3689
3690 void
3691 Editor::remove_snapshot (Glib::ustring name)
3692 {
3693         vector<string> choices;
3694
3695         std::string prompt  = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3696
3697         choices.push_back (_("No, do nothing."));
3698         choices.push_back (_("Yes, remove it."));
3699
3700         Gtkmm2ext::Choice prompter (prompt, choices);
3701
3702         if (prompter.run () == 1) {
3703                 session->remove_state (name);
3704                 redisplay_snapshots ();
3705         }
3706 }
3707
3708 void
3709 Editor::redisplay_snapshots ()
3710 {
3711         if (session == 0) {
3712                 return;
3713         }
3714
3715         vector<sys::path> state_file_paths;
3716
3717         get_state_files_in_directory (session->session_directory().root_path(),
3718                         state_file_paths);
3719
3720         if (state_file_paths.empty()) return;
3721
3722         vector<string> state_file_names(get_file_names_no_extension(state_file_paths));
3723
3724         snapshot_display_model->clear ();
3725
3726         for (vector<string>::iterator i = state_file_names.begin();
3727                         i != state_file_names.end(); ++i)
3728         {
3729                 string statename = (*i);
3730                 TreeModel::Row row = *(snapshot_display_model->append());
3731                 
3732                 /* this lingers on in case we ever want to change the visible
3733                    name of the snapshot.
3734                 */
3735                 
3736                 string display_name;
3737                 display_name = statename;
3738
3739                 if (statename == session->snap_name()) {
3740                         snapshot_display.get_selection()->select(row);
3741                 } 
3742                 
3743                 row[snapshot_display_columns.visible_name] = display_name;
3744                 row[snapshot_display_columns.real_name] = statename;
3745         }
3746 }
3747
3748 void
3749 Editor::session_state_saved (string snap_name)
3750 {
3751         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3752         redisplay_snapshots ();
3753 }
3754
3755 void
3756 Editor::maximise_editing_space ()
3757 {
3758         initial_ruler_update_required = true;
3759
3760         mouse_mode_tearoff->set_visible (false);
3761         tools_tearoff->set_visible (false);
3762
3763         pre_maximal_pane_position = edit_pane.get_position();
3764         pre_maximal_editor_width = this->get_width();
3765
3766         if(post_maximal_pane_position == 0) {
3767                 post_maximal_pane_position = edit_pane.get_width();
3768         }
3769
3770
3771         fullscreen();
3772         if(post_maximal_editor_width) {
3773                 edit_pane.set_position (post_maximal_pane_position - 
3774                         abs(post_maximal_editor_width - pre_maximal_editor_width));
3775         } else {
3776                 edit_pane.set_position (post_maximal_pane_position);
3777         }
3778 }
3779
3780 void
3781 Editor::restore_editing_space ()
3782 {
3783         initial_ruler_update_required = true;
3784
3785         // user changed width of pane during fullscreen
3786         if(post_maximal_pane_position != edit_pane.get_position()) {
3787                 post_maximal_pane_position = edit_pane.get_position();
3788         }
3789
3790         unfullscreen();
3791
3792         mouse_mode_tearoff->set_visible (true);
3793         tools_tearoff->set_visible (true);
3794         post_maximal_editor_width = this->get_width();
3795
3796
3797         edit_pane.set_position (
3798                 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3799         );
3800 }
3801
3802 /**
3803  *  Make new playlists for a given track and also any others that belong
3804  *  to the same active edit group.
3805  *  @param v Track.
3806  */
3807
3808 void 
3809 Editor::new_playlists (TimeAxisView* v)
3810 {
3811         begin_reversible_command (_("new playlists"));
3812         mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3813         commit_reversible_command ();
3814 }
3815
3816 /**
3817  *  Use a copy of the current playlist for a given track and also any others that belong
3818  *  to the same active edit group.
3819  *  @param v Track.
3820  */
3821
3822 void
3823 Editor::copy_playlists (TimeAxisView* v)
3824 {
3825         begin_reversible_command (_("copy playlists"));
3826         mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3827         commit_reversible_command ();
3828 }
3829
3830 /**
3831  *  Clear the current playlist for a given track and also any others that belong
3832  *  to the same active edit group.
3833  *  @param v Track.
3834  */
3835
3836 void 
3837 Editor::clear_playlists (TimeAxisView* v)
3838 {
3839         begin_reversible_command (_("clear playlists"));
3840         mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3841         commit_reversible_command ();
3842 }
3843
3844 void 
3845 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3846 {
3847         atv.use_new_playlist (sz > 1 ? false : true);
3848 }
3849
3850 void
3851 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3852 {
3853         atv.use_copy_playlist (sz > 1 ? false : true);
3854 }
3855
3856 void 
3857 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3858 {
3859         atv.clear_playlist ();
3860 }
3861
3862 bool
3863 Editor::on_key_press_event (GdkEventKey* ev)
3864 {
3865         return key_press_focus_accelerator_handler (*this, ev);
3866 }
3867
3868 void
3869 Editor::reset_x_origin (nframes_t frame)
3870 {
3871         queue_visual_change (frame);
3872 }
3873
3874 void
3875 Editor::reset_zoom (double fpu)
3876 {
3877         queue_visual_change (fpu);
3878 }
3879
3880 void
3881 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3882 {
3883         reset_x_origin (frame);
3884         reset_zoom (fpu);
3885 }
3886
3887 void
3888 Editor::set_frames_per_unit (double fpu)
3889 {
3890         nframes_t frames;
3891
3892         /* this is the core function that controls the zoom level of the canvas. it is called
3893            whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3894         */
3895
3896         if (fpu == frames_per_unit) {
3897                 return;
3898         }
3899
3900         if (fpu < 2.0) {
3901                 fpu = 2.0;
3902         }
3903
3904         // convert fpu to frame count
3905
3906         frames = (nframes_t) floor (fpu * canvas_width);
3907         
3908         /* don't allow zooms that fit more than the maximum number
3909            of frames into an 800 pixel wide space.
3910         */
3911
3912         if (max_frames / fpu < 800.0) {
3913                 return;
3914         }
3915
3916         if (fpu == frames_per_unit) {
3917                 return;
3918         }
3919
3920         frames_per_unit = fpu;
3921
3922         if (frames != zoom_range_clock.current_duration()) {
3923                 zoom_range_clock.set (frames);
3924         }
3925
3926         if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3927                 if (!selection->tracks.empty()) {
3928                         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3929                                 (*i)->reshow_selection (selection->time);
3930                         }
3931                 } else {
3932                         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3933                                 (*i)->reshow_selection (selection->time);
3934                         }
3935                 }
3936         }
3937
3938         ZoomChanged (); /* EMIT_SIGNAL */
3939
3940         reset_hscrollbar_stepping ();
3941         reset_scrolling_region ();
3942         
3943         if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3944         if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3945
3946         instant_save ();
3947 }
3948
3949 void
3950 Editor::queue_visual_change (nframes_t where)
3951 {
3952         pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3953         pending_visual_change.time_origin = where;
3954
3955         if (pending_visual_change.idle_handler_id < 0) {
3956                 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3957         }
3958 }
3959
3960 void
3961 Editor::queue_visual_change (double fpu)
3962 {
3963         pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3964         pending_visual_change.frames_per_unit = fpu;
3965
3966         if (pending_visual_change.idle_handler_id < 0) {
3967                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3968         }
3969 }
3970
3971 int
3972 Editor::_idle_visual_changer (void* arg)
3973 {
3974         return static_cast<Editor*>(arg)->idle_visual_changer ();
3975 }
3976
3977 int
3978 Editor::idle_visual_changer ()
3979 {
3980         VisualChange::Type p = pending_visual_change.pending;
3981
3982         pending_visual_change.pending = (VisualChange::Type) 0;
3983         pending_visual_change.idle_handler_id = -1;
3984         
3985         if (p & VisualChange::ZoomLevel) {
3986                 set_frames_per_unit (pending_visual_change.frames_per_unit);
3987         }
3988
3989         if (p & VisualChange::TimeOrigin) {
3990                 if (pending_visual_change.time_origin != leftmost_frame) {
3991                         horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3992                         /* the signal handler will do the rest */
3993                 } else {
3994                         update_fixed_rulers();
3995                         redisplay_tempo (true);
3996                 }
3997         }
3998
3999         return 0; /* this is always a one-shot call */
4000 }
4001
4002 struct EditorOrderTimeAxisSorter {
4003     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4004             return a->order < b->order;
4005     }
4006 };
4007         
4008 void
4009 Editor::sort_track_selection ()
4010 {
4011         EditorOrderTimeAxisSorter cmp;
4012         selection->tracks.sort (cmp);
4013 }
4014
4015 nframes_t
4016 Editor::edit_cursor_position(bool sync)
4017 {
4018         if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
4019                 edit_cursor_clock.set(edit_cursor->current_frame, true);
4020         }
4021
4022         return edit_cursor->current_frame;
4023 }
4024
4025
4026 void
4027 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4028 {
4029         if (!session) return;
4030
4031         begin_reversible_command (cmd);
4032         
4033         Location* tll;
4034
4035         if ((tll = transport_loop_location()) == 0) {
4036                 Location* loc = new Location (start, end, _("Loop"),  Location::IsAutoLoop);
4037                 XMLNode &before = session->locations()->get_state();
4038                 session->locations()->add (loc, true);
4039                 session->set_auto_loop_location (loc);
4040                 XMLNode &after = session->locations()->get_state();
4041                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4042         }
4043         else {
4044                 XMLNode &before = tll->get_state();
4045                 tll->set_hidden (false, this);
4046                 tll->set (start, end);
4047                 XMLNode &after = tll->get_state();
4048                 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4049         }
4050         
4051         commit_reversible_command ();
4052 }
4053
4054 void
4055 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4056 {
4057         if (!session) return;
4058
4059         begin_reversible_command (cmd);
4060         
4061         Location* tpl;
4062
4063         if ((tpl = transport_punch_location()) == 0) {
4064                 Location* loc = new Location (start, end, _("Loop"),  Location::IsAutoPunch);
4065                 XMLNode &before = session->locations()->get_state();
4066                 session->locations()->add (loc, true);
4067                 session->set_auto_loop_location (loc);
4068                 XMLNode &after = session->locations()->get_state();
4069                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4070         }
4071         else {
4072                 XMLNode &before = tpl->get_state();
4073                 tpl->set_hidden (false, this);
4074                 tpl->set (start, end);
4075                 XMLNode &after = tpl->get_state();
4076                 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4077         }
4078         
4079         commit_reversible_command ();
4080 }
4081