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