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