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