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