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