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