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