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