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