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