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