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