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