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