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