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