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