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