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