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