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