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