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