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