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