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