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