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