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