update drobilla's fascistic dir-locals.el to force emacs users into whitespace submis...
[ardour.git] / gtk2_ardour / editor.cc
1 /*
2     Copyright (C) 2000-2009 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 */
19
20 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <stdint.h>
23 #include <unistd.h>
24 #include <cstdlib>
25 #include <cmath>
26 #include <string>
27 #include <algorithm>
28 #include <map>
29
30 #include "ardour_ui.h"
31 /*
32  * ardour_ui.h include was moved to the top of the list
33  * due to a conflicting definition of 'Style' between
34  * Apple's MacTypes.h and BarController.
35  */
36
37 #include <boost/none.hpp>
38
39 #include <sigc++/bind.h>
40
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46
47 #include <glibmm/miscutils.h>
48 #include <gtkmm/image.h>
49 #include <gdkmm/color.h>
50 #include <gdkmm/bitmap.h>
51
52 #include "gtkmm2ext/bindings.h"
53 #include "gtkmm2ext/grouped_buttons.h"
54 #include "gtkmm2ext/gtk_ui.h"
55 #include "gtkmm2ext/tearoff.h"
56 #include "gtkmm2ext/utils.h"
57 #include "gtkmm2ext/window_title.h"
58 #include "gtkmm2ext/choice.h"
59 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
60
61 #include "ardour/audio_diskstream.h"
62 #include "ardour/audio_track.h"
63 #include "ardour/audioplaylist.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/midi_region.h"
67 #include "ardour/plugin_manager.h"
68 #include "ardour/profile.h"
69 #include "ardour/route_group.h"
70 #include "ardour/session_directory.h"
71 #include "ardour/session_route.h"
72 #include "ardour/session_state_utils.h"
73 #include "ardour/tempo.h"
74 #include "ardour/utils.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/audioengine.h"
77
78 #include "control_protocol/control_protocol.h"
79
80 #include "editor.h"
81 #include "debug.h"
82 #include "keyboard.h"
83 #include "marker.h"
84 #include "playlist_selector.h"
85 #include "audio_region_view.h"
86 #include "rgb_macros.h"
87 #include "selection.h"
88 #include "audio_streamview.h"
89 #include "time_axis_view.h"
90 #include "audio_time_axis.h"
91 #include "utils.h"
92 #include "crossfade_view.h"
93 #include "canvas-noevent-text.h"
94 #include "editing.h"
95 #include "public_editor.h"
96 #include "crossfade_edit.h"
97 #include "canvas_impl.h"
98 #include "actions.h"
99 #include "sfdb_ui.h"
100 #include "gui_thread.h"
101 #include "simpleline.h"
102 #include "rhythm_ferret.h"
103 #include "actions.h"
104 #include "tempo_lines.h"
105 #include "analysis_window.h"
106 #include "bundle_manager.h"
107 #include "global_port_matrix.h"
108 #include "editor_drag.h"
109 #include "editor_group_tabs.h"
110 #include "automation_time_axis.h"
111 #include "editor_routes.h"
112 #include "midi_time_axis.h"
113 #include "mixer_strip.h"
114 #include "editor_route_groups.h"
115 #include "editor_regions.h"
116 #include "editor_locations.h"
117 #include "editor_snapshots.h"
118 #include "editor_summary.h"
119 #include "region_layering_order_editor.h"
120 #include "mouse_cursors.h"
121 #include "editor_cursors.h"
122
123 #include "i18n.h"
124
125 #ifdef WITH_CMT
126 #include "imageframe_socket_handler.h"
127 #endif
128
129 using namespace std;
130 using namespace ARDOUR;
131 using namespace PBD;
132 using namespace Gtk;
133 using namespace Glib;
134 using namespace Gtkmm2ext;
135 using namespace Editing;
136
137 using PBD::internationalize;
138 using PBD::atoi;
139 using Gtkmm2ext::Keyboard;
140
141 const double Editor::timebar_height = 15.0;
142
143 static const gchar *_snap_type_strings[] = {
144         N_("CD Frames"),
145         N_("Timecode Frames"),
146         N_("Timecode Seconds"),
147         N_("Timecode Minutes"),
148         N_("Seconds"),
149         N_("Minutes"),
150         N_("Beats/32"),
151         N_("Beats/28"),
152         N_("Beats/24"),
153         N_("Beats/20"),
154         N_("Beats/16"),
155         N_("Beats/14"),
156         N_("Beats/12"),
157         N_("Beats/10"),
158         N_("Beats/8"),
159         N_("Beats/7"),
160         N_("Beats/6"),
161         N_("Beats/5"),
162         N_("Beats/4"),
163         N_("Beats/3"),
164         N_("Beats/2"),
165         N_("Beats"),
166         N_("Bars"),
167         N_("Marks"),
168         N_("Region starts"),
169         N_("Region ends"),
170         N_("Region syncs"),
171         N_("Region bounds"),
172         0
173 };
174
175 static const gchar *_snap_mode_strings[] = {
176         N_("No Grid"),
177         N_("Grid"),
178         N_("Magnetic"),
179         0
180 };
181
182 static const gchar *_edit_point_strings[] = {
183         N_("Playhead"),
184         N_("Marker"),
185         N_("Mouse"),
186         0
187 };
188
189 static const gchar *_zoom_focus_strings[] = {
190         N_("Left"),
191         N_("Right"),
192         N_("Center"),
193         N_("Playhead"),
194         N_("Mouse"),
195         N_("Edit point"),
196         0
197 };
198
199 #ifdef USE_RUBBERBAND
200 static const gchar *_rb_opt_strings[] = {
201         N_("Mushy"),
202         N_("Smooth"),
203         N_("Balanced multitimbral mixture"),
204         N_("Unpitched percussion with stable notes"),
205         N_("Crisp monophonic instrumental"),
206         N_("Unpitched solo percussion"),
207         N_("Resample without preserving pitch"),
208         0
209 };
210 #endif
211
212 void
213 show_me_the_size (Requisition* r, const char* what)
214 {
215         cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
216 }
217
218 #ifdef GTKOSX
219 static void
220 pane_size_watcher (Paned* pane)
221 {
222         /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
223            it is no longer accessible. so stop that. this doesn't happen on X11,
224            just the quartz backend.
225
226            ugh.
227         */
228
229         int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
230
231         gint pos = pane->get_position ();
232
233         if (pos > max_width_of_lhs) {
234                 pane->set_position (max_width_of_lhs);
235         }
236 }
237 #endif
238
239 Editor::Editor ()
240         : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
241
242           /* time display buttons */
243         , minsec_label (_("Mins:Secs"))
244         , bbt_label (_("Bars:Beats"))
245         , timecode_label (_("Timecode"))
246         , samples_label (_("Samples"))
247         , tempo_label (_("Tempo"))
248         , meter_label (_("Meter"))
249         , mark_label (_("Location Markers"))
250         , range_mark_label (_("Range Markers"))
251         , transport_mark_label (_("Loop/Punch Ranges"))
252         , cd_mark_label (_("CD Markers"))
253         , edit_packer (4, 4, true)
254
255           /* the values here don't matter: layout widgets
256              reset them as needed.
257           */
258
259         , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
260
261           /* tool bar related */
262
263         , zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, false, true)
264
265         , toolbar_selection_clock_table (2,3)
266
267         , automation_mode_button (_("mode"))
268         , global_automation_button (_("automation"))
269
270         , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
271         , midi_panic_button (_("Panic"))
272
273 #ifdef WITH_CMT
274         , image_socket_listener(0)
275 #endif
276
277           /* nudge */
278
279         , nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, false, true)
280         , meters_running(false)
281         , _pending_locate_request (false)
282         , _pending_initial_locate (false)
283         , _last_cut_copy_source_track (0)
284
285         , _region_selection_change_updates_region_list (true)
286 {
287         constructed = false;
288
289         /* we are a singleton */
290
291         PublicEditor::_instance = this;
292
293         _have_idled = false;
294
295         selection = new Selection (this);
296         cut_buffer = new Selection (this);
297
298         clicked_regionview = 0;
299         clicked_axisview = 0;
300         clicked_routeview = 0;
301         clicked_crossfadeview = 0;
302         clicked_control_point = 0;
303         last_update_frame = 0;
304         pre_press_cursor = 0;
305         _drags = new DragManager (this);
306         current_mixer_strip = 0;
307         current_bbt_points = 0;
308         tempo_lines = 0;
309
310         snap_type_strings =  I18N (_snap_type_strings);
311         snap_mode_strings =  I18N (_snap_mode_strings);
312         zoom_focus_strings = I18N (_zoom_focus_strings);
313         edit_point_strings = I18N (_edit_point_strings);
314 #ifdef USE_RUBBERBAND
315         rb_opt_strings = I18N (_rb_opt_strings);
316         rb_current_opt = 4;
317 #endif
318
319         snap_threshold = 5.0;
320         bbt_beat_subdivision = 4;
321         _canvas_width = 0;
322         _canvas_height = 0;
323         last_autoscroll_x = 0;
324         last_autoscroll_y = 0;
325         autoscroll_active = false;
326         autoscroll_timeout_tag = -1;
327         logo_item = 0;
328
329         analysis_window = 0;
330
331         current_interthread_info = 0;
332         _show_measures = true;
333         show_gain_after_trim = false;
334         verbose_cursor_on = true;
335         last_item_entered = 0;
336
337         have_pending_keyboard_selection = false;
338         _follow_playhead = true;
339         _stationary_playhead = false;
340         _xfade_visibility = true;
341         editor_ruler_menu = 0;
342         no_ruler_shown_update = false;
343         marker_menu = 0;
344         range_marker_menu = 0;
345         marker_menu_item = 0;
346         tempo_or_meter_marker_menu = 0;
347         transport_marker_menu = 0;
348         new_transport_marker_menu = 0;
349         editor_mixer_strip_width = Wide;
350         show_editor_mixer_when_tracks_arrive = false;
351         region_edit_menu_split_multichannel_item = 0;
352         region_edit_menu_split_item = 0;
353         temp_location = 0;
354         leftmost_frame = 0;
355         current_stepping_trackview = 0;
356         entered_track = 0;
357         entered_regionview = 0;
358         entered_marker = 0;
359         clear_entered_track = false;
360         current_timefx = 0;
361         playhead_cursor = 0;
362         button_release_can_deselect = true;
363         _dragging_playhead = false;
364         _dragging_edit_point = false;
365         select_new_marker = false;
366         rhythm_ferret = 0;
367         layering_order_editor = 0;
368         _bundle_manager = 0;
369         no_save_visual = false;
370         resize_idle_id = -1;
371
372         scrubbing_direction = 0;
373
374         sfbrowser = 0;
375
376         location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
377         location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
378         location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
379         location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
380         location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
381
382         _edit_point = EditAtMouse;
383         _internal_editing = false;
384         current_canvas_cursor = 0;
385
386         frames_per_unit = 2048; /* too early to use reset_zoom () */
387
388         _scroll_callbacks = 0;
389
390         zoom_focus = ZoomFocusLeft;
391         set_zoom_focus (ZoomFocusLeft);
392         zoom_range_clock.ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
393
394         bbt_label.set_name ("EditorTimeButton");
395         bbt_label.set_size_request (-1, (int)timebar_height);
396         bbt_label.set_alignment (1.0, 0.5);
397         bbt_label.set_padding (5,0);
398         bbt_label.hide ();
399         bbt_label.set_no_show_all();
400         minsec_label.set_name ("EditorTimeButton");
401         minsec_label.set_size_request (-1, (int)timebar_height);
402         minsec_label.set_alignment (1.0, 0.5);
403         minsec_label.set_padding (5,0);
404         minsec_label.hide ();
405         minsec_label.set_no_show_all();
406         timecode_label.set_name ("EditorTimeButton");
407         timecode_label.set_size_request (-1, (int)timebar_height);
408         timecode_label.set_alignment (1.0, 0.5);
409         timecode_label.set_padding (5,0);
410         timecode_label.hide ();
411         timecode_label.set_no_show_all();
412         samples_label.set_name ("EditorTimeButton");
413         samples_label.set_size_request (-1, (int)timebar_height);
414         samples_label.set_alignment (1.0, 0.5);
415         samples_label.set_padding (5,0);
416         samples_label.hide ();
417         samples_label.set_no_show_all();
418
419         tempo_label.set_name ("EditorTimeButton");
420         tempo_label.set_size_request (-1, (int)timebar_height);
421         tempo_label.set_alignment (1.0, 0.5);
422         tempo_label.set_padding (5,0);
423         tempo_label.hide();
424         tempo_label.set_no_show_all();
425         
426         meter_label.set_name ("EditorTimeButton");
427         meter_label.set_size_request (-1, (int)timebar_height);
428         meter_label.set_alignment (1.0, 0.5);
429         meter_label.set_padding (5,0);
430         meter_label.hide();
431         meter_label.set_no_show_all();
432         
433         mark_label.set_name ("EditorTimeButton");
434         mark_label.set_size_request (-1, (int)timebar_height);
435         mark_label.set_alignment (1.0, 0.5);
436         mark_label.set_padding (5,0);
437         mark_label.hide();
438         mark_label.set_no_show_all();
439         
440         cd_mark_label.set_name ("EditorTimeButton");
441         cd_mark_label.set_size_request (-1, (int)timebar_height);
442         cd_mark_label.set_alignment (1.0, 0.5);
443         cd_mark_label.set_padding (5,0);
444         cd_mark_label.hide();
445         cd_mark_label.set_no_show_all();
446         
447         range_mark_label.set_name ("EditorTimeButton");
448         range_mark_label.set_size_request (-1, (int)timebar_height);
449         range_mark_label.set_alignment (1.0, 0.5);
450         range_mark_label.set_padding (5,0);
451         range_mark_label.hide();
452         range_mark_label.set_no_show_all();
453         
454         transport_mark_label.set_name ("EditorTimeButton");
455         transport_mark_label.set_size_request (-1, (int)timebar_height);
456         transport_mark_label.set_alignment (1.0, 0.5);
457         transport_mark_label.set_padding (5,0);
458         transport_mark_label.hide();
459         transport_mark_label.set_no_show_all();
460
461         initialize_rulers ();
462         initialize_canvas ();
463         
464         _summary = new EditorSummary (this);
465
466         selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
467         selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
468         
469         editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
470         
471         selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
472         selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
473
474         edit_controls_vbox.set_spacing (0);
475         vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
476         track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
477
478         HBox* h = manage (new HBox);
479         _group_tabs = new EditorGroupTabs (this);
480         h->pack_start (*_group_tabs, PACK_SHRINK);
481         h->pack_start (edit_controls_vbox);
482         controls_layout.add (*h);
483
484         controls_layout.set_name ("EditControlsBase");
485         controls_layout.add_events (Gdk::SCROLL_MASK);
486         controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
487
488         controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
489         controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
490
491         _cursors = new MouseCursors;
492
493         ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
494         ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
495                         0.0, 1.0, 100.0, 1.0));
496         
497         pad_line_1->property_color_rgba() = 0xFF0000FF;
498         pad_line_1->show();
499         
500         time_pad->show();
501
502         time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
503         time_canvas_vbox.set_size_request (-1, -1);
504
505         ruler_label_event_box.add (ruler_label_vbox);
506         ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
507         ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
508
509         time_button_event_box.add (time_button_vbox);
510         time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
511         time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
512
513         /* these enable us to have a dedicated window (for cursor setting, etc.)
514            for the canvas areas.
515         */
516
517         track_canvas_event_box.add (*track_canvas);
518
519         time_canvas_event_box.add (time_canvas_vbox);
520         time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
521
522         edit_packer.set_col_spacings (0);
523         edit_packer.set_row_spacings (0);
524         edit_packer.set_homogeneous (false);
525         edit_packer.set_border_width (0);
526         edit_packer.set_name ("EditorWindow");
527
528         /* labels for the rulers */
529         edit_packer.attach (ruler_label_event_box,   1, 2, 0, 1,    FILL,        SHRINK, 0, 0);
530         /* labels for the marker "tracks" */
531         edit_packer.attach (time_button_event_box,   1, 2, 1, 2,    FILL,        SHRINK, 0, 0);
532         /* the rulers */
533         edit_packer.attach (time_canvas_event_box,   2, 3, 0, 1,    FILL|EXPAND, FILL, 0, 0);
534         /* track controls */
535         edit_packer.attach (controls_layout,         0, 2, 2, 3,    FILL,        FILL|EXPAND, 0, 0);
536         /* main canvas */
537         edit_packer.attach (track_canvas_event_box,  2, 3, 1, 3,    FILL|EXPAND, FILL|EXPAND, 0, 0);
538
539         bottom_hbox.set_border_width (2);
540         bottom_hbox.set_spacing (3);
541
542         _route_groups = new EditorRouteGroups (this);
543         _routes = new EditorRoutes (this);
544         _regions = new EditorRegions (this);
545         _snapshots = new EditorSnapshots (this);
546         _locations = new EditorLocations (this);
547
548         add_notebook_page (_("Regions"), _regions->widget ());
549         add_notebook_page (_("Tracks & Busses"), _routes->widget ());
550         add_notebook_page (_("Snapshots"), _snapshots->widget ());
551         add_notebook_page (_("Route Groups"), _route_groups->widget ());
552         add_notebook_page (_("Ranges & Marks"), _locations->widget ());
553
554         _the_notebook.set_show_tabs (true);
555         _the_notebook.set_scrollable (true);
556         _the_notebook.popup_disable ();
557         _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
558         _the_notebook.show_all ();
559
560         post_maximal_editor_width = 0;
561         post_maximal_horizontal_pane_position = 0;
562         post_maximal_editor_height = 0;
563         post_maximal_vertical_pane_position = 0;
564         _notebook_shrunk = false;
565
566         editor_summary_pane.pack1(edit_packer);
567
568         Button* summary_arrows_left_left = manage (new Button);
569         summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
570         summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
571         summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
572         
573         Button* summary_arrows_left_right = manage (new Button);
574         summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
575         summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
576         summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
577         
578         VBox* summary_arrows_left = manage (new VBox);
579         summary_arrows_left->pack_start (*summary_arrows_left_left);
580         summary_arrows_left->pack_start (*summary_arrows_left_right);
581
582         Button* summary_arrows_right_up = manage (new Button);
583         summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
584         summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
585         summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
586         
587         Button* summary_arrows_right_down = manage (new Button);
588         summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
589         summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
590         summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
591         
592         VBox* summary_arrows_right = manage (new VBox);
593         summary_arrows_right->pack_start (*summary_arrows_right_up);
594         summary_arrows_right->pack_start (*summary_arrows_right_down);
595
596         Frame* summary_frame = manage (new Frame);
597         summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
598         
599         summary_frame->add (*_summary);
600         summary_frame->show ();
601
602         _summary_hbox.pack_start (*summary_arrows_left, false, false);
603         _summary_hbox.pack_start (*summary_frame, true, true);
604         _summary_hbox.pack_start (*summary_arrows_right, false, false);
605         
606         editor_summary_pane.pack2 (_summary_hbox);
607
608         edit_pane.pack1 (editor_summary_pane, true, true);
609         edit_pane.pack2 (_the_notebook, false, true);
610
611         editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
612
613         /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
614
615         edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
616 #ifdef GTKOSX
617         Glib::PropertyProxy<int> proxy = edit_pane.property_position();
618         proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
619 #endif
620         top_hbox.pack_start (toolbar_frame);
621
622         HBox *hbox = manage (new HBox);
623         hbox->pack_start (edit_pane, true, true);
624
625         global_vpacker.pack_start (top_hbox, false, false);
626         global_vpacker.pack_start (*hbox, true, true);
627
628         global_hpacker.pack_start (global_vpacker, true, true);
629
630         set_name ("EditorWindow");
631         add_accel_group (ActionManager::ui_manager->get_accel_group());
632
633         status_bar_hpacker.show ();
634
635         vpacker.pack_end (status_bar_hpacker, false, false);
636         vpacker.pack_end (global_hpacker, true, true);
637
638         /* register actions now so that set_state() can find them and set toggles/checks etc */
639
640         register_actions ();
641
642         setup_toolbar ();
643         setup_midi_toolbar ();
644
645         _snap_type = SnapToBeat;
646         set_snap_to (_snap_type);
647         _snap_mode = SnapOff;
648         set_snap_mode (_snap_mode);
649         set_mouse_mode (MouseObject, true);
650         pre_internal_mouse_mode = MouseObject;
651         set_edit_point_preference (EditAtMouse, true);
652
653         _playlist_selector = new PlaylistSelector();
654         _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
655
656         RegionView::RegionViewGoingAway.connect (*this, invalidator (*this),  ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
657
658         /* nudge stuff */
659
660         nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
661         nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
662
663         nudge_forward_button.set_name ("TransportButton");
664         nudge_backward_button.set_name ("TransportButton");
665
666         fade_context_menu.set_name ("ArdourContextMenu");
667
668         /* icons, titles, WM stuff */
669
670         list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
671         Glib::RefPtr<Gdk::Pixbuf> icon;
672
673         if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
674                 window_icons.push_back (icon);
675         }
676         if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
677                 window_icons.push_back (icon);
678         }
679         if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
680                 window_icons.push_back (icon);
681         }
682         if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
683                 window_icons.push_back (icon);
684         }
685         if (!window_icons.empty()) {
686                 // set_icon_list (window_icons);
687                 set_default_icon_list (window_icons);
688         }
689
690         WindowTitle title(Glib::get_application_name());
691         title += _("Editor");
692         set_title (title.get_string());
693         set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
694
695         add (vpacker);
696         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
697
698         signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
699         signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
700
701         /* allow external control surfaces/protocols to do various things */
702
703         ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
704         ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
705         ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
706         ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
707         BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
708         
709         /* problematic: has to return a value and thus cannot be x-thread */
710
711         Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
712
713         Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
714
715         TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
716
717         _ignore_region_action = false;
718         _last_region_menu_was_main = false;
719         _popup_region_menu_item = 0;
720
721         _show_marker_lines = false;
722         _over_region_trim_target = false;
723
724         /* Button bindings */
725
726         button_bindings = new Bindings;
727
728         XMLNode* node = button_settings();
729         if (node) {
730                 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
731                         button_bindings->load (**i);
732                 }
733         }
734
735         constructed = true;
736         instant_save ();
737
738         setup_fade_images ();
739 }
740
741 Editor::~Editor()
742 {
743 #ifdef WITH_CMT
744         if(image_socket_listener) {
745                 if(image_socket_listener->is_connected())
746                 {
747                         image_socket_listener->close_connection() ;
748                 }
749
750                 delete image_socket_listener ;
751                 image_socket_listener = 0 ;
752         }
753 #endif
754
755         delete button_bindings;
756         delete _routes;
757         delete _route_groups;
758         delete track_canvas;
759         delete _drags;
760 }
761
762 XMLNode*
763 Editor::button_settings () const
764 {
765         XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
766         XMLNode* node = find_named_node (*settings, X_("Buttons"));
767
768         if (!node) {
769                 cerr << "new empty Button node\n";
770                 node = new XMLNode (X_("Buttons"));
771         }
772
773         return node;
774 }
775
776 void
777 Editor::add_toplevel_controls (Container& cont)
778 {
779         vpacker.pack_start (cont, false, false);
780         cont.show_all ();
781 }
782
783 void
784 Editor::catch_vanishing_regionview (RegionView *rv)
785 {
786         /* note: the selection will take care of the vanishing
787            audioregionview by itself.
788         */
789
790         if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
791                 _drags->abort ();
792         }
793
794         if (clicked_regionview == rv) {
795                 clicked_regionview = 0;
796         }
797
798         if (entered_regionview == rv) {
799                 set_entered_regionview (0);
800         }
801
802         if (!_all_region_actions_sensitized) {
803                 sensitize_all_region_actions (true);
804         }
805 }
806
807 void
808 Editor::set_entered_regionview (RegionView* rv)
809 {
810         if (rv == entered_regionview) {
811                 return;
812         }
813
814         if (entered_regionview) {
815                 entered_regionview->exited ();
816         }
817
818         if ((entered_regionview = rv) != 0) {
819                 entered_regionview->entered (internal_editing ());
820         }
821
822         if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
823                 /* This RegionView entry might have changed what region actions
824                    are allowed, so sensitize them all in case a key is pressed.
825                 */
826                 sensitize_all_region_actions (true);
827         }
828 }
829
830 void
831 Editor::set_entered_track (TimeAxisView* tav)
832 {
833         if (entered_track) {
834                 entered_track->exited ();
835         }
836
837         if ((entered_track = tav) != 0) {
838                 entered_track->entered ();
839         }
840 }
841
842 void
843 Editor::show_window ()
844 {
845         if (!is_visible ()) {
846                 show_all ();
847
848                 /* XXX: this is a bit unfortunate; it would probably
849                    be nicer if we could just call show () above rather
850                    than needing the show_all ()
851                 */
852
853                 /* re-hide stuff if necessary */
854                 editor_list_button_toggled ();
855                 parameter_changed ("show-summary");
856                 parameter_changed ("show-group-tabs");
857                 parameter_changed ("show-zoom-tools");
858
859                 /* now reset all audio_time_axis heights, because widgets might need
860                    to be re-hidden
861                 */
862
863                 TimeAxisView *tv;
864
865                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
866                         tv = (static_cast<TimeAxisView*>(*i));
867                         tv->reset_height ();
868                 }
869
870                 if (current_mixer_strip) {
871                         current_mixer_strip->hide_things ();
872                 }
873         }
874
875         present ();
876 }
877
878 void
879 Editor::instant_save ()
880 {
881         if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
882                 return;
883         }
884
885         if (_session) {
886                 _session->add_instant_xml(get_state());
887         } else {
888                 Config->add_instant_xml(get_state());
889         }
890 }
891
892 void
893 Editor::zoom_adjustment_changed ()
894 {
895         if (_session == 0) {
896                 return;
897         }
898
899         double fpu = zoom_range_clock.current_duration() / _canvas_width;
900
901         if (fpu < 1.0) {
902                 fpu = 1.0;
903                 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
904         } else if (fpu > _session->current_end_frame() / _canvas_width) {
905                 fpu = _session->current_end_frame() / _canvas_width;
906                 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
907         }
908
909         temporal_zoom (fpu);
910 }
911
912 void
913 Editor::control_scroll (float fraction)
914 {
915         ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
916
917         if (!_session) {
918                 return;
919         }
920
921         double step = fraction * current_page_frames();
922
923         /*
924                 _control_scroll_target is an optional<T>
925
926                 it acts like a pointer to an framepos_t, with
927                 a operator conversion to boolean to check
928                 that it has a value could possibly use
929                 playhead_cursor->current_frame to store the
930                 value and a boolean in the class to know
931                 when it's out of date
932         */
933
934         if (!_control_scroll_target) {
935                 _control_scroll_target = _session->transport_frame();
936                 _dragging_playhead = true;
937         }
938
939         if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
940                 *_control_scroll_target = 0;
941         } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
942                 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
943         } else {
944                 *_control_scroll_target += (framepos_t) floor (step);
945         }
946
947         /* move visuals, we'll catch up with it later */
948
949         playhead_cursor->set_position (*_control_scroll_target);
950         UpdateAllTransportClocks (*_control_scroll_target);
951
952         if (*_control_scroll_target > (current_page_frames() / 2)) {
953                 /* try to center PH in window */
954                 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
955         } else {
956                 reset_x_origin (0);
957         }
958
959         /*
960                 Now we do a timeout to actually bring the session to the right place
961                 according to the playhead. This is to avoid reading disk buffers on every
962                 call to control_scroll, which is driven by ScrollTimeline and therefore
963                 probably by a control surface wheel which can generate lots of events.
964         */
965         /* cancel the existing timeout */
966
967         control_scroll_connection.disconnect ();
968
969         /* add the next timeout */
970
971         control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
972 }
973
974 bool
975 Editor::deferred_control_scroll (framepos_t /*target*/)
976 {
977         _session->request_locate (*_control_scroll_target, _session->transport_rolling());
978         // reset for next stream
979         _control_scroll_target = boost::none;
980         _dragging_playhead = false;
981         return false;
982 }
983
984 void
985 Editor::access_action (std::string action_group, std::string action_item)
986 {
987         if (!_session) {
988                 return;
989         }
990
991         ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
992
993         RefPtr<Action> act;
994         act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
995
996         if (act) {
997                 act->activate();
998         }
999 }
1000
1001 void
1002 Editor::on_realize ()
1003 {
1004         Window::on_realize ();
1005         Realized ();
1006 }
1007
1008 void
1009 Editor::map_position_change (framepos_t frame)
1010 {
1011         ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1012
1013         if (_session == 0) {
1014                 return;
1015         }
1016
1017         if (_follow_playhead) {
1018                 center_screen (frame);
1019         }
1020
1021         playhead_cursor->set_position (frame);
1022 }
1023
1024 void
1025 Editor::center_screen (framepos_t frame)
1026 {
1027         double page = _canvas_width * frames_per_unit;
1028
1029         /* if we're off the page, then scroll.
1030          */
1031
1032         if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1033                 center_screen_internal (frame, page);
1034         }
1035 }
1036
1037 void
1038 Editor::center_screen_internal (framepos_t frame, float page)
1039 {
1040         page /= 2;
1041
1042         if (frame > page) {
1043                 frame -= (framepos_t) page;
1044         } else {
1045                 frame = 0;
1046         }
1047
1048         reset_x_origin (frame);
1049 }
1050
1051
1052 void
1053 Editor::update_title ()
1054 {
1055         ENSURE_GUI_THREAD (*this, &Editor::update_title)
1056
1057         if (_session) {
1058                 bool dirty = _session->dirty();
1059
1060                 string session_name;
1061
1062                 if (_session->snap_name() != _session->name()) {
1063                         session_name = _session->snap_name();
1064                 } else {
1065                         session_name = _session->name();
1066                 }
1067
1068                 if (dirty) {
1069                         session_name = "*" + session_name;
1070                 }
1071
1072                 WindowTitle title(session_name);
1073                 title += Glib::get_application_name();
1074                 set_title (title.get_string());
1075         }
1076 }
1077
1078 void
1079 Editor::set_session (Session *t)
1080 {
1081         SessionHandlePtr::set_session (t);
1082
1083         if (!_session) {
1084                 return;
1085         }
1086
1087         zoom_range_clock.set_session (_session);
1088         _playlist_selector->set_session (_session);
1089         nudge_clock.set_session (_session);
1090         _summary->set_session (_session);
1091         _group_tabs->set_session (_session);
1092         _route_groups->set_session (_session);
1093         _regions->set_session (_session);
1094         _snapshots->set_session (_session);
1095         _routes->set_session (_session);
1096         _locations->set_session (_session);
1097
1098         if (rhythm_ferret) {
1099                 rhythm_ferret->set_session (_session);
1100         }
1101
1102         if (analysis_window) {
1103                 analysis_window->set_session (_session);
1104         }
1105
1106         if (sfbrowser) {
1107                 sfbrowser->set_session (_session);
1108         }
1109
1110         compute_fixed_ruler_scale ();
1111
1112         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1113         set_state (*node, Stateful::loading_state_version);
1114
1115         /* catch up with the playhead */
1116
1117         _session->request_locate (playhead_cursor->current_frame);
1118         _pending_initial_locate = true;
1119
1120         update_title ();
1121
1122         /* These signals can all be emitted by a non-GUI thread. Therefore the
1123            handlers for them must not attempt to directly interact with the GUI,
1124            but use Gtkmm2ext::UI::instance()->call_slot();
1125         */
1126
1127         _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1128         _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1129         _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1130         _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1131         _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1132         _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1133         _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1134         _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1135         _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1136         _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1137         _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1138         _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1139         _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display_s, this, _1), gui_context());
1140         _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1141
1142         if (Profile->get_sae()) {
1143                 Timecode::BBT_Time bbt;
1144                 bbt.bars = 0;
1145                 bbt.beats = 0;
1146                 bbt.ticks = 120;
1147                 framepos_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1148                 nudge_clock.set_mode(AudioClock::BBT);
1149                 nudge_clock.set (pos, true, 0, AudioClock::BBT);
1150
1151         } else {
1152                 nudge_clock.set (_session->frame_rate() * 5, true, 0, AudioClock::Timecode); // default of 5 seconds
1153         }
1154
1155         playhead_cursor->canvas_item.show ();
1156
1157         Location* loc = _session->locations()->auto_loop_location();
1158         if (loc == 0) {
1159                 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1160                 
1161                 if (loc->start() == loc->end()) {
1162                         loc->set_end (loc->start() + 1);
1163                 }
1164                 
1165                 _session->locations()->add (loc, false);
1166                 _session->set_auto_loop_location (loc);
1167         } else {
1168                 // force name
1169                 loc->set_name (_("Loop"));
1170         }
1171
1172         loc = _session->locations()->auto_punch_location();
1173         
1174         if (loc == 0) {
1175                 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1176                 
1177                 if (loc->start() == loc->end()) {
1178                         loc->set_end (loc->start() + 1);
1179                 }
1180                 
1181                 _session->locations()->add (loc, false);
1182                 _session->set_auto_punch_location (loc);
1183         } else {
1184                 // force name
1185                 loc->set_name (_("Punch"));
1186         }
1187
1188         boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1189         Config->map_parameters (pc);
1190         _session->config.map_parameters (pc);
1191
1192         refresh_location_display ();
1193
1194         restore_ruler_visibility ();
1195         //tempo_map_changed (PropertyChange (0));
1196         _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1197
1198         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1199                 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1200         }
1201
1202         super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1203                 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1204                 );
1205         
1206         switch (_snap_type) {
1207         case SnapToRegionStart:
1208         case SnapToRegionEnd:
1209         case SnapToRegionSync:
1210         case SnapToRegionBoundary:
1211                 build_region_boundary_cache ();
1212                 break;
1213
1214         default:
1215                 break;
1216         }
1217
1218         /* register for undo history */
1219         _session->register_with_memento_command_factory(_id, this);
1220
1221         ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1222
1223         start_updating_meters ();
1224 }
1225
1226 void
1227 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1228 {
1229         if (a->get_name() == "RegionMenu") {
1230                 /* When the main menu's region menu is opened, we setup the actions so that they look right
1231                    in the menu.  I can't find a way of getting a signal when this menu is subsequently closed,
1232                    so we resensitize all region actions when the entered regionview or the region selection
1233                    changes.  HOWEVER we can't always resensitize on entered_regionview change because that
1234                    happens after the region context menu is opened.  So we set a flag here, too.
1235
1236                    What a carry on :(
1237                 */
1238                 sensitize_the_right_region_actions ();
1239                 _last_region_menu_was_main = true;
1240         }
1241 }
1242
1243 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1244 void
1245 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1246 {
1247         using namespace Menu_Helpers;
1248         AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1249
1250         if (arv == 0) {
1251                 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1252                 /*NOTREACHED*/
1253         }
1254
1255         MenuList& items (fade_context_menu.items());
1256
1257         items.clear ();
1258
1259         switch (item_type) {
1260         case FadeInItem:
1261         case FadeInHandleItem:
1262                 if (arv->audio_region()->fade_in_active()) {
1263                         items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1264                 } else {
1265                         items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1266                 }
1267
1268                 items.push_back (SeparatorElem());
1269
1270                 if (Profile->get_sae()) {
1271                         
1272                         items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1273                         items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1274                         
1275                 } else {
1276
1277                         items.push_back (
1278                                 ImageMenuElem (
1279                                         _("Linear"),
1280                                         *_fade_in_images[FadeLinear],
1281                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1282                                         )
1283                                 );
1284
1285                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1286
1287                         items.push_back (
1288                                 ImageMenuElem (
1289                                         _("Slowest"),
1290                                         *_fade_in_images[FadeFast],
1291                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1292                                         ));
1293                         
1294                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1295                         
1296                         items.push_back (
1297                                 ImageMenuElem (
1298                                         _("Slow"),
1299                                         *_fade_in_images[FadeLogB],
1300                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1301                                         ));
1302                         
1303                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1304                         
1305                         items.push_back (
1306                                 ImageMenuElem (
1307                                         _("Fast"),
1308                                         *_fade_in_images[FadeLogA],
1309                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1310                                         ));
1311                         
1312                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1313                         
1314                         items.push_back (
1315                                 ImageMenuElem (
1316                                         _("Fastest"),
1317                                         *_fade_in_images[FadeSlow],
1318                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1319                                         ));
1320                         
1321                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1322                 }
1323
1324                 break;
1325
1326         case FadeOutItem:
1327         case FadeOutHandleItem:
1328                 if (arv->audio_region()->fade_out_active()) {
1329                         items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1330                 } else {
1331                         items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1332                 }
1333
1334                 items.push_back (SeparatorElem());
1335
1336                 if (Profile->get_sae()) {
1337                         items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1338                         items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1339                 } else {
1340
1341                         items.push_back (
1342                                 ImageMenuElem (
1343                                         _("Linear"),
1344                                         *_fade_out_images[FadeLinear],
1345                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1346                                         )
1347                                 );
1348
1349                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1350
1351                         items.push_back (
1352                                 ImageMenuElem (
1353                                         _("Slowest"),
1354                                         *_fade_out_images[FadeFast],
1355                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1356                                         ));
1357                         
1358                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1359                         
1360                         items.push_back (
1361                                 ImageMenuElem (
1362                                         _("Slow"),
1363                                         *_fade_out_images[FadeLogB],
1364                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1365                                         ));
1366                         
1367                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1368                         
1369                         items.push_back (
1370                                 ImageMenuElem (
1371                                         _("Fast"),
1372                                         *_fade_out_images[FadeLogA],
1373                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1374                                         ));
1375                         
1376                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1377                         
1378                         items.push_back (
1379                                 ImageMenuElem (
1380                                         _("Fastest"),
1381                                         *_fade_out_images[FadeSlow],
1382                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1383                                         ));
1384                         
1385                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1386                 }
1387
1388                 break;
1389
1390         default:
1391                 fatal << _("programming error: ")
1392                       << X_("non-fade canvas item passed to popup_fade_context_menu()")
1393                       << endmsg;
1394                 /*NOTREACHED*/
1395         }
1396
1397         fade_context_menu.popup (button, time);
1398 }
1399
1400 void
1401 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1402 {
1403         using namespace Menu_Helpers;
1404         Menu* (Editor::*build_menu_function)();
1405         Menu *menu;
1406
1407         switch (item_type) {
1408         case RegionItem:
1409         case RegionViewName:
1410         case RegionViewNameHighlight:
1411         case LeftFrameHandle:
1412         case RightFrameHandle:
1413                 if (with_selection) {
1414                         build_menu_function = &Editor::build_track_selection_context_menu;
1415                 } else {
1416                         build_menu_function = &Editor::build_track_region_context_menu;
1417                 }
1418                 break;
1419
1420         case SelectionItem:
1421                 if (with_selection) {
1422                         build_menu_function = &Editor::build_track_selection_context_menu;
1423                 } else {
1424                         build_menu_function = &Editor::build_track_context_menu;
1425                 }
1426                 break;
1427
1428         case CrossfadeViewItem:
1429                 build_menu_function = &Editor::build_track_crossfade_context_menu;
1430                 break;
1431
1432         case StreamItem:
1433                 if (clicked_routeview->track()) {
1434                         build_menu_function = &Editor::build_track_context_menu;
1435                 } else {
1436                         build_menu_function = &Editor::build_track_bus_context_menu;
1437                 }
1438                 break;
1439
1440         default:
1441                 /* probably shouldn't happen but if it does, we don't care */
1442                 return;
1443         }
1444
1445         menu = (this->*build_menu_function)();
1446         menu->set_name ("ArdourContextMenu");
1447
1448         /* now handle specific situations */
1449
1450         switch (item_type) {
1451         case RegionItem:
1452         case RegionViewName:
1453         case RegionViewNameHighlight:
1454         case LeftFrameHandle:
1455         case RightFrameHandle:
1456                 if (!with_selection) {
1457                         if (region_edit_menu_split_item) {
1458                                 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1459                                         ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1460                                 } else {
1461                                         ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1462                                 }
1463                         }
1464                         if (region_edit_menu_split_multichannel_item) {
1465                                 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1466                                         region_edit_menu_split_multichannel_item->set_sensitive (true);
1467                                 } else {
1468                                         region_edit_menu_split_multichannel_item->set_sensitive (false);
1469                                 }
1470                         }
1471                 }
1472                 break;
1473
1474         case SelectionItem:
1475                 break;
1476
1477         case CrossfadeViewItem:
1478                 break;
1479
1480         case StreamItem:
1481                 break;
1482
1483         default:
1484                 /* probably shouldn't happen but if it does, we don't care */
1485                 return;
1486         }
1487
1488         if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1489
1490                 /* Bounce to disk */
1491
1492                 using namespace Menu_Helpers;
1493                 MenuList& edit_items  = menu->items();
1494
1495                 edit_items.push_back (SeparatorElem());
1496
1497                 switch (clicked_routeview->audio_track()->freeze_state()) {
1498                 case AudioTrack::NoFreeze:
1499                         edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1500                         break;
1501
1502                 case AudioTrack::Frozen:
1503                         edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1504                         break;
1505
1506                 case AudioTrack::UnFrozen:
1507                         edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1508                         break;
1509                 }
1510
1511         }
1512
1513         if (item_type == StreamItem && clicked_routeview) {
1514                 clicked_routeview->build_underlay_menu(menu);
1515         }
1516
1517         /* When the region menu is opened, we setup the actions so that they look right
1518            in the menu.
1519         */
1520         sensitize_the_right_region_actions ();
1521         _last_region_menu_was_main = false;
1522
1523         menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1524         menu->popup (button, time);
1525 }
1526
1527 Menu*
1528 Editor::build_track_context_menu ()
1529 {
1530         using namespace Menu_Helpers;
1531
1532         MenuList& edit_items = track_context_menu.items();
1533         edit_items.clear();
1534
1535         add_dstream_context_items (edit_items);
1536         return &track_context_menu;
1537 }
1538
1539 Menu*
1540 Editor::build_track_bus_context_menu ()
1541 {
1542         using namespace Menu_Helpers;
1543
1544         MenuList& edit_items = track_context_menu.items();
1545         edit_items.clear();
1546
1547         add_bus_context_items (edit_items);
1548         return &track_context_menu;
1549 }
1550
1551 Menu*
1552 Editor::build_track_region_context_menu ()
1553 {
1554         using namespace Menu_Helpers;
1555         MenuList& edit_items  = track_region_context_menu.items();
1556         edit_items.clear();
1557
1558         /* we've just cleared the track region context menu, so the menu that these
1559            two items were on will have disappeared; stop them dangling.
1560         */
1561         region_edit_menu_split_item = 0;
1562         region_edit_menu_split_multichannel_item = 0;
1563
1564         /* we might try to use items that are currently attached to a crossfade menu,
1565            so clear that, too.
1566         */
1567         track_crossfade_context_menu.items().clear ();
1568
1569         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1570
1571         if (rtv) {
1572                 boost::shared_ptr<Track> tr;
1573                 boost::shared_ptr<Playlist> pl;
1574
1575                 if ((tr = rtv->track())) {
1576                         add_region_context_items (edit_items, tr);
1577                 }
1578         }
1579
1580         add_dstream_context_items (edit_items);
1581
1582         return &track_region_context_menu;
1583 }
1584
1585 Menu*
1586 Editor::build_track_crossfade_context_menu ()
1587 {
1588         using namespace Menu_Helpers;
1589         MenuList& edit_items  = track_crossfade_context_menu.items();
1590         edit_items.clear ();
1591
1592         /* we might try to use items that are currently attached to a crossfade menu,
1593            so clear that, too.
1594         */
1595         track_region_context_menu.items().clear ();
1596
1597         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1598
1599         if (atv) {
1600                 boost::shared_ptr<Track> tr;
1601                 boost::shared_ptr<Playlist> pl;
1602                 boost::shared_ptr<AudioPlaylist> apl;
1603
1604                 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1605
1606                         AudioPlaylist::Crossfades xfades;
1607                         framepos_t where;
1608                         bool ignored;
1609
1610                         /* The xfade menu is a bit of a special case, as we always use the mouse position
1611                            to decide whether or not to display it (rather than the edit point).  No particularly
1612                            strong reasons for this, other than it is a bit surprising to right-click on a xfade
1613                            and not get a menu.
1614                         */
1615                         mouse_frame (where, ignored);
1616                         apl->crossfades_at (where, xfades);
1617
1618                         bool const many = xfades.size() > 1;
1619
1620                         for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1621                                 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1622                         }
1623
1624                         add_region_context_items (edit_items, tr);
1625                 }
1626         }
1627
1628         add_dstream_context_items (edit_items);
1629
1630         return &track_crossfade_context_menu;
1631 }
1632
1633 void
1634 Editor::analyze_region_selection ()
1635 {
1636         if (analysis_window == 0) {
1637                 analysis_window = new AnalysisWindow();
1638
1639                 if (_session != 0)
1640                         analysis_window->set_session(_session);
1641
1642                 analysis_window->show_all();
1643         }
1644
1645         analysis_window->set_regionmode();
1646         analysis_window->analyze();
1647
1648         analysis_window->present();
1649 }
1650
1651 void
1652 Editor::analyze_range_selection()
1653 {
1654         if (analysis_window == 0) {
1655                 analysis_window = new AnalysisWindow();
1656
1657                 if (_session != 0)
1658                         analysis_window->set_session(_session);
1659
1660                 analysis_window->show_all();
1661         }
1662
1663         analysis_window->set_rangemode();
1664         analysis_window->analyze();
1665
1666         analysis_window->present();
1667 }
1668
1669 Menu*
1670 Editor::build_track_selection_context_menu ()
1671 {
1672         using namespace Menu_Helpers;
1673         MenuList& edit_items  = track_selection_context_menu.items();
1674         edit_items.clear ();
1675
1676         add_selection_context_items (edit_items);
1677         // edit_items.push_back (SeparatorElem());
1678         // add_dstream_context_items (edit_items);
1679
1680         return &track_selection_context_menu;
1681 }
1682
1683 /** Add context menu items relevant to crossfades.
1684  * @param edit_items List to add the items to.
1685  */
1686 void
1687 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1688 {
1689         using namespace Menu_Helpers;
1690         Menu     *xfade_menu = manage (new Menu);
1691         MenuList& items       = xfade_menu->items();
1692         xfade_menu->set_name ("ArdourContextMenu");
1693         string str;
1694
1695         if (xfade->active()) {
1696                 str = _("Mute");
1697         } else {
1698                 str = _("Unmute");
1699         }
1700
1701         items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1702         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1703
1704         if (xfade->can_follow_overlap()) {
1705
1706                 if (xfade->following_overlap()) {
1707                         str = _("Convert to Short");
1708                 } else {
1709                         str = _("Convert to Full");
1710                 }
1711
1712                 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1713         }
1714
1715         if (many) {
1716                 str = xfade->out()->name();
1717                 str += "->";
1718                 str += xfade->in()->name();
1719         } else {
1720                 str = _("Crossfade");
1721         }
1722
1723         edit_items.push_back (MenuElem (str, *xfade_menu));
1724         edit_items.push_back (SeparatorElem());
1725 }
1726
1727 void
1728 Editor::xfade_edit_left_region ()
1729 {
1730         if (clicked_crossfadeview) {
1731                 clicked_crossfadeview->left_view.show_region_editor ();
1732         }
1733 }
1734
1735 void
1736 Editor::xfade_edit_right_region ()
1737 {
1738         if (clicked_crossfadeview) {
1739                 clicked_crossfadeview->right_view.show_region_editor ();
1740         }
1741 }
1742
1743 void
1744 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1745 {
1746         using namespace Menu_Helpers;
1747         
1748         /* OK, stick the region submenu at the top of the list, and then add
1749            the standard items.
1750         */
1751
1752         RegionSelection rs = get_regions_from_selection_and_entered ();
1753         
1754         string::size_type pos = 0;
1755         string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1756
1757         /* we have to hack up the region name because "_" has a special
1758            meaning for menu titles.
1759         */
1760
1761         while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1762                 menu_item_name.replace (pos, 1, "__");
1763                 pos += 2;
1764         }
1765
1766         if (_popup_region_menu_item == 0) {
1767                 _popup_region_menu_item = new MenuItem (menu_item_name);
1768                 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1769                 _popup_region_menu_item->show ();
1770         } else {
1771                 _popup_region_menu_item->set_label (menu_item_name);
1772         }
1773
1774         /* Use the mouse position rather than the edit point to decide whether to show the `choose top region'
1775            dialogue.  If we use the edit point it gets a bit messy because the user still has to click over
1776            *some* region in order to get the region context menu stuff to be displayed at all.
1777         */
1778         
1779         framepos_t mouse;
1780         bool ignored;
1781         mouse_frame (mouse, ignored);
1782
1783         edit_items.push_back (*_popup_region_menu_item);
1784         if (track->playlist()->count_regions_at (mouse) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1785                 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region")->create_menu_item ()));
1786         }
1787         edit_items.push_back (SeparatorElem());
1788 }
1789
1790 /** Add context menu items relevant to selection ranges.
1791  * @param edit_items List to add the items to.
1792  */
1793 void
1794 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1795 {
1796         using namespace Menu_Helpers;
1797
1798         edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1799         edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1800
1801         edit_items.push_back (SeparatorElem());
1802         edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1803
1804         if (!selection->regions.empty()) {
1805                 edit_items.push_back (SeparatorElem());
1806                 edit_items.push_back (MenuElem (_("Extend Range to End of Region"), sigc::bind (sigc::mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1807                 edit_items.push_back (MenuElem (_("Extend Range to Start of Region"), sigc::bind (sigc::mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1808         }
1809
1810         edit_items.push_back (SeparatorElem());
1811         edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1812         edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1813
1814         edit_items.push_back (SeparatorElem());
1815         edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1816
1817         edit_items.push_back (SeparatorElem());
1818         edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1819         edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1820
1821         edit_items.push_back (SeparatorElem());
1822         edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1823
1824         edit_items.push_back (SeparatorElem());
1825         edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1826         edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1827         edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1828
1829         edit_items.push_back (SeparatorElem());
1830         edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1831         edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1832         edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1833         edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1834         edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection)));
1835 }
1836
1837
1838 void
1839 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1840 {
1841         using namespace Menu_Helpers;
1842
1843         /* Playback */
1844
1845         Menu *play_menu = manage (new Menu);
1846         MenuList& play_items = play_menu->items();
1847         play_menu->set_name ("ArdourContextMenu");
1848
1849         play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1850         play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1851         play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1852         play_items.push_back (SeparatorElem());
1853         play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1854
1855         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1856
1857         /* Selection */
1858
1859         Menu *select_menu = manage (new Menu);
1860         MenuList& select_items = select_menu->items();
1861         select_menu->set_name ("ArdourContextMenu");
1862
1863         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1864         select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1865         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1866         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1867         select_items.push_back (SeparatorElem());
1868         select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1869         select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1870         select_items.push_back (SeparatorElem());
1871         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1872         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1873         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1874         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1875         select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1876         select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1877         select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1878
1879         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1880
1881         /* Cut-n-Paste */
1882
1883         Menu *cutnpaste_menu = manage (new Menu);
1884         MenuList& cutnpaste_items = cutnpaste_menu->items();
1885         cutnpaste_menu->set_name ("ArdourContextMenu");
1886
1887         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1888         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1889         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1890
1891         cutnpaste_items.push_back (SeparatorElem());
1892
1893         cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1894         cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1895
1896         edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1897
1898         /* Adding new material */
1899
1900         edit_items.push_back (SeparatorElem());
1901         edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1902         edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1903
1904         /* Nudge track */
1905
1906         Menu *nudge_menu = manage (new Menu());
1907         MenuList& nudge_items = nudge_menu->items();
1908         nudge_menu->set_name ("ArdourContextMenu");
1909
1910         edit_items.push_back (SeparatorElem());
1911         nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1912         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1913         nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1914         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1915
1916         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1917 }
1918
1919 void
1920 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1921 {
1922         using namespace Menu_Helpers;
1923
1924         /* Playback */
1925
1926         Menu *play_menu = manage (new Menu);
1927         MenuList& play_items = play_menu->items();
1928         play_menu->set_name ("ArdourContextMenu");
1929
1930         play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1931         play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1932         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1933
1934         /* Selection */
1935
1936         Menu *select_menu = manage (new Menu);
1937         MenuList& select_items = select_menu->items();
1938         select_menu->set_name ("ArdourContextMenu");
1939
1940         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1941         select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1942         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1943         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1944         select_items.push_back (SeparatorElem());
1945         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1946         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1947         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1948         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1949
1950         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1951
1952         /* Cut-n-Paste */
1953
1954         Menu *cutnpaste_menu = manage (new Menu);
1955         MenuList& cutnpaste_items = cutnpaste_menu->items();
1956         cutnpaste_menu->set_name ("ArdourContextMenu");
1957
1958         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1959         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1960         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1961
1962         Menu *nudge_menu = manage (new Menu());
1963         MenuList& nudge_items = nudge_menu->items();
1964         nudge_menu->set_name ("ArdourContextMenu");
1965
1966         edit_items.push_back (SeparatorElem());
1967         nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1968         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1969         nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1970         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1971
1972         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1973 }
1974
1975 SnapType
1976 Editor::snap_type() const
1977 {
1978         return _snap_type;
1979 }
1980
1981 SnapMode
1982 Editor::snap_mode() const
1983 {
1984         return _snap_mode;
1985 }
1986
1987 void
1988 Editor::set_snap_to (SnapType st)
1989 {
1990         unsigned int snap_ind = (unsigned int)st;
1991
1992         _snap_type = st;
1993
1994         if (snap_ind > snap_type_strings.size() - 1) {
1995                 snap_ind = 0;
1996                 _snap_type = (SnapType)snap_ind;
1997         }
1998
1999         string str = snap_type_strings[snap_ind];
2000
2001         if (str != snap_type_selector.get_active_text()) {
2002                 snap_type_selector.set_active_text (str);
2003         }
2004
2005         instant_save ();
2006
2007         switch (_snap_type) {
2008         case SnapToBeatDiv32:
2009         case SnapToBeatDiv28:
2010         case SnapToBeatDiv24:
2011         case SnapToBeatDiv20:
2012         case SnapToBeatDiv16:
2013         case SnapToBeatDiv14:
2014         case SnapToBeatDiv12:
2015         case SnapToBeatDiv10:
2016         case SnapToBeatDiv8:
2017         case SnapToBeatDiv7:
2018         case SnapToBeatDiv6:
2019         case SnapToBeatDiv5:
2020         case SnapToBeatDiv4:
2021         case SnapToBeatDiv3:
2022         case SnapToBeatDiv2:
2023                 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2024                 update_tempo_based_rulers ();
2025                 break;
2026
2027         case SnapToRegionStart:
2028         case SnapToRegionEnd:
2029         case SnapToRegionSync:
2030         case SnapToRegionBoundary:
2031                 build_region_boundary_cache ();
2032                 break;
2033
2034         default:
2035                 /* relax */
2036                 break;
2037         }
2038
2039         SnapChanged (); /* EMIT SIGNAL */
2040 }
2041
2042 void
2043 Editor::set_snap_mode (SnapMode mode)
2044 {
2045         _snap_mode = mode;
2046         string str = snap_mode_strings[(int)mode];
2047
2048         if (str != snap_mode_selector.get_active_text ()) {
2049                 snap_mode_selector.set_active_text (str);
2050         }
2051
2052         instant_save ();
2053 }
2054 void
2055 Editor::set_edit_point_preference (EditPoint ep, bool force)
2056 {
2057         bool changed = (_edit_point != ep);
2058
2059         _edit_point = ep;
2060         string str = edit_point_strings[(int)ep];
2061
2062         if (str != edit_point_selector.get_active_text ()) {
2063                 edit_point_selector.set_active_text (str);
2064         }
2065
2066         set_canvas_cursor ();
2067
2068         if (!force && !changed) {
2069                 return;
2070         }
2071
2072         const char* action=NULL;
2073
2074         switch (_edit_point) {
2075         case EditAtPlayhead:
2076                 action = "edit-at-playhead";
2077                 break;
2078         case EditAtSelectedMarker:
2079                 action = "edit-at-marker";
2080                 break;
2081         case EditAtMouse:
2082                 action = "edit-at-mouse";
2083                 break;
2084         }
2085
2086         Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2087         if (act) {
2088                 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2089         }
2090
2091         framepos_t foo;
2092         bool in_track_canvas;
2093
2094         if (!mouse_frame (foo, in_track_canvas)) {
2095                 in_track_canvas = false;
2096         }
2097
2098         reset_canvas_action_sensitivity (in_track_canvas);
2099
2100         instant_save ();
2101 }
2102
2103 int
2104 Editor::set_state (const XMLNode& node, int /*version*/)
2105 {
2106         const XMLProperty* prop;
2107         XMLNode* geometry;
2108         int x, y, xoff, yoff;
2109         Gdk::Geometry g;
2110
2111         if ((prop = node.property ("id")) != 0) {
2112                 _id = prop->value ();
2113         }
2114
2115         g.base_width = default_width;
2116         g.base_height = default_height;
2117         x = 1;
2118         y = 1;
2119         xoff = 0;
2120         yoff = 21;
2121
2122         if ((geometry = find_named_node (node, "geometry")) != 0) {
2123
2124                 XMLProperty* prop;
2125
2126                 if ((prop = geometry->property("x_size")) == 0) {
2127                         prop = geometry->property ("x-size");
2128                 }
2129                 if (prop) {
2130                         g.base_width = atoi(prop->value());
2131                 }
2132                 if ((prop = geometry->property("y_size")) == 0) {
2133                         prop = geometry->property ("y-size");
2134                 }
2135                 if (prop) {
2136                         g.base_height = atoi(prop->value());
2137                 }
2138
2139                 if ((prop = geometry->property ("x_pos")) == 0) {
2140                         prop = geometry->property ("x-pos");
2141                 }
2142                 if (prop) {
2143                         x = atoi (prop->value());
2144
2145                 }
2146                 if ((prop = geometry->property ("y_pos")) == 0) {
2147                         prop = geometry->property ("y-pos");
2148                 }
2149                 if (prop) {
2150                         y = atoi (prop->value());
2151                 }
2152
2153                 if ((prop = geometry->property ("x_off")) == 0) {
2154                         prop = geometry->property ("x-off");
2155                 }
2156                 if (prop) {
2157                         xoff = atoi (prop->value());
2158                 }
2159                 if ((prop = geometry->property ("y_off")) == 0) {
2160                         prop = geometry->property ("y-off");
2161                 }
2162                 if (prop) {
2163                         yoff = atoi (prop->value());
2164                 }
2165         }
2166
2167         set_default_size (g.base_width, g.base_height);
2168         move (x, y);
2169         
2170         if (_session && (prop = node.property ("playhead"))) {
2171                 framepos_t pos;
2172                 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2173                 playhead_cursor->set_position (pos);
2174         } else {
2175                 playhead_cursor->set_position (0);
2176         }
2177         
2178         if ((prop = node.property ("mixer-width"))) {
2179                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2180         }
2181
2182         if ((prop = node.property ("zoom-focus"))) {
2183                 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2184         }
2185
2186         if ((prop = node.property ("zoom"))) {
2187                 reset_zoom (PBD::atof (prop->value()));
2188         } else {
2189                 reset_zoom (frames_per_unit);
2190         }
2191
2192         if ((prop = node.property ("snap-to"))) {
2193                 set_snap_to ((SnapType) atoi (prop->value()));
2194         }
2195
2196         if ((prop = node.property ("snap-mode"))) {
2197                 set_snap_mode ((SnapMode) atoi (prop->value()));
2198         }
2199
2200         if ((prop = node.property ("mouse-mode"))) {
2201                 MouseMode m = str2mousemode(prop->value());
2202                 set_mouse_mode (m, true);
2203         } else {
2204                 set_mouse_mode (MouseObject, true);
2205         }
2206
2207         if ((prop = node.property ("left-frame")) != 0) {
2208                 framepos_t pos;
2209                 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2210                         reset_x_origin (pos);
2211                 }
2212         }
2213
2214         if ((prop = node.property ("y-origin")) != 0) {
2215                 reset_y_origin (atof (prop->value ()));
2216         }
2217
2218         if ((prop = node.property ("internal-edit"))) {
2219                 bool yn = string_is_affirmative (prop->value());
2220                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2221                 if (act) {
2222                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2223                         tact->set_active (!yn);
2224                         tact->set_active (yn);
2225                 }
2226         }
2227
2228         if ((prop = node.property ("join-object-range"))) {
2229                 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2230         }
2231
2232         if ((prop = node.property ("edit-point"))) {
2233                 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2234         }
2235
2236         if ((prop = node.property ("show-measures"))) {
2237                 bool yn = string_is_affirmative (prop->value());
2238                 _show_measures = yn;
2239                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2240                 if (act) {
2241                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2242                         /* do it twice to force the change */
2243                         tact->set_active (!yn);
2244                         tact->set_active (yn);
2245                 }
2246         }
2247
2248         if ((prop = node.property ("follow-playhead"))) {
2249                 bool yn = string_is_affirmative (prop->value());
2250                 set_follow_playhead (yn);
2251                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2252                 if (act) {
2253                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2254                         if (tact->get_active() != yn) {
2255                                 tact->set_active (yn);
2256                         }
2257                 }
2258         }
2259
2260         if ((prop = node.property ("stationary-playhead"))) {
2261                 bool yn = (prop->value() == "yes");
2262                 set_stationary_playhead (yn);
2263                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2264                 if (act) {
2265                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2266                         if (tact->get_active() != yn) {
2267                                 tact->set_active (yn);
2268                         }
2269                 }
2270         }
2271         
2272         if ((prop = node.property ("region-list-sort-type"))) {
2273                 RegionListSortType st;
2274                 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2275         }
2276
2277         if ((prop = node.property ("xfades-visible"))) {
2278                 bool yn = string_is_affirmative (prop->value());
2279                 _xfade_visibility = !yn;
2280                 // set_xfade_visibility (yn);
2281         }
2282
2283         if ((prop = node.property ("show-editor-mixer"))) {
2284
2285                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2286                 assert (act);
2287
2288                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2289                 bool yn = string_is_affirmative (prop->value());
2290                 
2291                 /* do it twice to force the change */
2292                 
2293                 tact->set_active (!yn);
2294                 tact->set_active (yn);
2295         }
2296
2297         if ((prop = node.property ("show-editor-list"))) {
2298
2299                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2300                 assert (act);
2301
2302                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2303                 bool yn = string_is_affirmative (prop->value());
2304                 
2305                 /* do it twice to force the change */
2306                 
2307                 tact->set_active (!yn);
2308                 tact->set_active (yn);
2309         }
2310
2311         if ((prop = node.property (X_("editor-list-page")))) {
2312                 _the_notebook.set_current_page (atoi (prop->value ()));
2313         }
2314
2315         if ((prop = node.property (X_("show-marker-lines")))) {
2316                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2317                 assert (act);
2318                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2319                 bool yn = string_is_affirmative (prop->value ());
2320
2321                 tact->set_active (!yn);
2322                 tact->set_active (yn);
2323         }
2324
2325         XMLNodeList children = node.children ();
2326         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2327                 selection->set_state (**i, Stateful::current_state_version);
2328                 _regions->set_state (**i);
2329         }
2330
2331         return 0;
2332 }
2333
2334 XMLNode&
2335 Editor::get_state ()
2336 {
2337         XMLNode* node = new XMLNode ("Editor");
2338         char buf[32];
2339
2340         _id.print (buf, sizeof (buf));
2341         node->add_property ("id", buf);
2342
2343         if (is_realized()) {
2344                 Glib::RefPtr<Gdk::Window> win = get_window();
2345
2346                 int x, y, xoff, yoff, width, height;
2347                 win->get_root_origin(x, y);
2348                 win->get_position(xoff, yoff);
2349                 win->get_size(width, height);
2350
2351                 XMLNode* geometry = new XMLNode ("geometry");
2352
2353                 snprintf(buf, sizeof(buf), "%d", width);
2354                 geometry->add_property("x-size", string(buf));
2355                 snprintf(buf, sizeof(buf), "%d", height);
2356                 geometry->add_property("y-size", string(buf));
2357                 snprintf(buf, sizeof(buf), "%d", x);
2358                 geometry->add_property("x-pos", string(buf));
2359                 snprintf(buf, sizeof(buf), "%d", y);
2360                 geometry->add_property("y-pos", string(buf));
2361                 snprintf(buf, sizeof(buf), "%d", xoff);
2362                 geometry->add_property("x-off", string(buf));
2363                 snprintf(buf, sizeof(buf), "%d", yoff);
2364                 geometry->add_property("y-off", string(buf));
2365                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2366                 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2367                 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2368                 snprintf(buf,sizeof(buf), "%d",pre_maximal_horizontal_pane_position);
2369                 geometry->add_property("pre-maximal-horizontal-pane-position", string(buf));
2370                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2371                 geometry->add_property("edit-vertical-pane-pos", string(buf));
2372
2373                 node->add_child_nocopy (*geometry);
2374         }
2375
2376         maybe_add_mixer_strip_width (*node);
2377
2378         snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2379         node->add_property ("zoom-focus", buf);
2380         snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2381         node->add_property ("zoom", buf);
2382         snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2383         node->add_property ("snap-to", buf);
2384         snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2385         node->add_property ("snap-mode", buf);
2386
2387         node->add_property ("edit-point", enum_2_string (_edit_point));
2388
2389         snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2390         node->add_property ("playhead", buf);
2391         snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2392         node->add_property ("left-frame", buf);
2393         snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2394         node->add_property ("y-origin", buf);
2395
2396         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2397         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2398         node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2399         node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2400         node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2401         node->add_property ("mouse-mode", enum2str(mouse_mode));
2402         node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2403         node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2404
2405         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2406         if (act) {
2407                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2408                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2409         }
2410
2411         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2412         if (act) {
2413                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2414                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2415         }
2416
2417         snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2418         node->add_property (X_("editor-list-page"), buf);
2419
2420         if (button_bindings) {
2421                 XMLNode* bb = new XMLNode (X_("Buttons"));
2422                 button_bindings->save (*bb);
2423                 node->add_child_nocopy (*bb);
2424         } 
2425
2426         node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2427
2428         node->add_child_nocopy (selection->get_state ());
2429         node->add_child_nocopy (_regions->get_state ());
2430         
2431         return *node;
2432 }
2433
2434
2435
2436 /** @param y y offset from the top of all trackviews.
2437  *  @return pair: TimeAxisView that y is over, layer index.
2438  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2439  *  in stacked region display mode, otherwise 0.
2440  */
2441 std::pair<TimeAxisView *, layer_t>
2442 Editor::trackview_by_y_position (double y)
2443 {
2444         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2445
2446                 std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
2447                 if (r.first) {
2448                         return r;
2449                 }
2450         }
2451
2452         return std::make_pair ( (TimeAxisView *) 0, 0);
2453 }
2454
2455 /** Snap a position to the grid, if appropriate, taking into account current
2456  *  grid settings and also the state of any snap modifier keys that may be pressed.
2457  *  @param start Position to snap.
2458  *  @param event Event to get current key modifier information from, or 0.
2459  */
2460 void
2461 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2462 {
2463         if (!_session || !event) {
2464                 return;
2465         }
2466
2467         if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2468                 if (_snap_mode == SnapOff) {
2469                         snap_to_internal (start, direction, for_mark);
2470                 }
2471         } else {
2472                 if (_snap_mode != SnapOff) {
2473                         snap_to_internal (start, direction, for_mark);
2474                 }
2475         }
2476 }
2477
2478 void
2479 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2480 {
2481         if (!_session || _snap_mode == SnapOff) {
2482                 return;
2483         }
2484
2485         snap_to_internal (start, direction, for_mark);
2486 }
2487
2488 void
2489 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2490 {
2491         const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2492         framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2493
2494         switch (_snap_type) {
2495         case SnapToTimecodeFrame:
2496                 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2497                         start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2498                 } else {
2499                         start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) *  _session->frames_per_timecode_frame());
2500                 }
2501                 break;
2502
2503         case SnapToTimecodeSeconds:
2504                 if (_session->config.get_timecode_offset_negative()) {
2505                         start += _session->config.get_timecode_offset ();
2506                 } else {
2507                         start -= _session->config.get_timecode_offset ();
2508                 }
2509                 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2510                         start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2511                 } else {
2512                         start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2513                 }
2514
2515                 if (_session->config.get_timecode_offset_negative()) {
2516                         start -= _session->config.get_timecode_offset ();
2517                 } else {
2518                         start += _session->config.get_timecode_offset ();
2519                 }
2520                 break;
2521
2522         case SnapToTimecodeMinutes:
2523                 if (_session->config.get_timecode_offset_negative()) {
2524                         start += _session->config.get_timecode_offset ();
2525                 } else {
2526                         start -= _session->config.get_timecode_offset ();
2527                 }
2528                 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2529                         start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2530                 } else {
2531                         start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2532                 }
2533                 if (_session->config.get_timecode_offset_negative()) {
2534                         start -= _session->config.get_timecode_offset ();
2535                 } else {
2536                         start += _session->config.get_timecode_offset ();
2537                 }
2538                 break;
2539         default:
2540                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2541                 /*NOTREACHED*/
2542         }
2543 }
2544
2545 void
2546 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2547 {
2548         const framepos_t one_second = _session->frame_rate();
2549         const framepos_t one_minute = _session->frame_rate() * 60;
2550         framepos_t presnap = start;
2551         framepos_t before;
2552         framepos_t after;
2553
2554         switch (_snap_type) {
2555         case SnapToTimecodeFrame:
2556         case SnapToTimecodeSeconds:
2557         case SnapToTimecodeMinutes:
2558                 return timecode_snap_to_internal (start, direction, for_mark);
2559
2560         case SnapToCDFrame:
2561                 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2562                         start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2563                 } else {
2564                         start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2565                 }
2566                 break;
2567
2568         case SnapToSeconds:
2569                 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2570                         start = (framepos_t) ceil ((double) start / one_second) * one_second;
2571                 } else {
2572                         start = (framepos_t) floor ((double) start / one_second) * one_second;
2573                 }
2574                 break;
2575
2576         case SnapToMinutes:
2577                 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2578                         start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2579                 } else {
2580                         start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2581                 }
2582                 break;
2583
2584         case SnapToBar:
2585                 start = _session->tempo_map().round_to_bar (start, direction);
2586                 break;
2587
2588         case SnapToBeat:
2589                 start = _session->tempo_map().round_to_beat (start, direction);
2590                 break;
2591
2592         case SnapToBeatDiv32:
2593                 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2594                 break;
2595         case SnapToBeatDiv28:
2596                 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2597                 break;
2598         case SnapToBeatDiv24:
2599                 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2600                 break;
2601         case SnapToBeatDiv20:
2602                 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2603                 break;
2604         case SnapToBeatDiv16:
2605                 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2606                 break;
2607         case SnapToBeatDiv14:
2608                 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2609                 break;
2610         case SnapToBeatDiv12:
2611                 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2612                 break;
2613         case SnapToBeatDiv10:
2614                 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2615                 break;
2616         case SnapToBeatDiv8:
2617                 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2618                 break;
2619         case SnapToBeatDiv7:
2620                 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2621                 break;
2622         case SnapToBeatDiv6:
2623                 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2624                 break;
2625         case SnapToBeatDiv5:
2626                 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2627                 break;
2628         case SnapToBeatDiv4:
2629                 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2630                 break;
2631         case SnapToBeatDiv3:
2632                 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2633                 break;
2634         case SnapToBeatDiv2:
2635                 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2636                 break;
2637
2638         case SnapToMark:
2639                 if (for_mark) {
2640                         return;
2641                 }
2642
2643                 _session->locations()->marks_either_side (start, before, after);
2644
2645                 if (before == max_framepos) {
2646                         start = after;
2647                 } else if (after == max_framepos) {
2648                         start = before;
2649                 } else if (before != max_framepos && after != max_framepos) {
2650                         /* have before and after */
2651                         if ((start - before) < (after - start)) {
2652                                 start = before;
2653                         } else {
2654                                 start = after;
2655                         }
2656                 }
2657
2658                 break;
2659
2660         case SnapToRegionStart:
2661         case SnapToRegionEnd:
2662         case SnapToRegionSync:
2663         case SnapToRegionBoundary:
2664                 if (!region_boundary_cache.empty()) {
2665
2666                         vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2667                         vector<framepos_t>::iterator next = region_boundary_cache.end ();
2668
2669                         if (direction > 0) {
2670                                 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2671                         } else {
2672                                 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2673                         }
2674
2675                         if (next != region_boundary_cache.begin ()) {
2676                                 prev = next;
2677                                 prev--;
2678                         }
2679
2680                         framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2681                         framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2682
2683                         if (start > (p + n) / 2) {
2684                                 start = n;
2685                         } else {
2686                                 start = p;
2687                         }
2688                 }
2689                 break;
2690         }
2691
2692         switch (_snap_mode) {
2693         case SnapNormal:
2694                 return;
2695
2696         case SnapMagnetic:
2697
2698                 if (presnap > start) {
2699                         if (presnap > (start + unit_to_frame(snap_threshold))) {
2700                                 start = presnap;
2701                         }
2702
2703                 } else if (presnap < start) {
2704                         if (presnap < (start - unit_to_frame(snap_threshold))) {
2705                                 start = presnap;
2706                         }
2707                 }
2708
2709         default:
2710                 /* handled at entry */
2711                 return;
2712
2713         }
2714 }
2715
2716
2717 void
2718 Editor::setup_toolbar ()
2719 {
2720         string pixmap_path;
2721
2722         /* Mode Buttons (tool selection) */
2723
2724         mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2725         mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2726         mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2727         mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2728         mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2729         mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2730         // internal_edit_button.set_relief(Gtk::RELIEF_NONE);
2731         join_object_range_button.set_relief(Gtk::RELIEF_NONE);
2732
2733         HBox* mode_box = manage(new HBox);
2734         mode_box->set_border_width (2);
2735         mode_box->set_spacing(4);
2736
2737         /* table containing mode buttons */
2738
2739         HBox* mouse_mode_button_box = manage (new HBox ());
2740
2741         if (Profile->get_sae()) {
2742                 mouse_mode_button_box->pack_start (mouse_move_button);
2743         } else {
2744                 mouse_mode_button_box->pack_start (mouse_move_button);
2745                 mouse_mode_button_box->pack_start (join_object_range_button);
2746                 mouse_mode_button_box->pack_start (mouse_select_button);
2747         }
2748
2749         mouse_mode_button_box->pack_start (mouse_zoom_button);
2750
2751         if (!Profile->get_sae()) {
2752                 mouse_mode_button_box->pack_start (mouse_gain_button);
2753         }
2754
2755         mouse_mode_button_box->pack_start (mouse_timefx_button);
2756         mouse_mode_button_box->pack_start (mouse_audition_button);
2757         mouse_mode_button_box->pack_start (internal_edit_button);
2758
2759         edit_mode_strings.push_back (edit_mode_to_string (Slide));
2760         if (!Profile->get_sae()) {
2761                 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2762         }
2763         edit_mode_strings.push_back (edit_mode_to_string (Lock));
2764
2765         edit_mode_selector.set_name ("EditModeSelector");
2766         set_popdown_strings (edit_mode_selector, edit_mode_strings, true);
2767         edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2768
2769         mode_box->pack_start (edit_mode_selector);
2770         mode_box->pack_start (*mouse_mode_button_box);
2771
2772         _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2773         _mouse_mode_tearoff->set_name ("MouseModeBase");
2774         _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2775
2776         if (Profile->get_sae()) {
2777                 _mouse_mode_tearoff->set_can_be_torn_off (false);
2778         }
2779
2780         _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2781                                                          &_mouse_mode_tearoff->tearoff_window()));
2782         _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2783                                                          &_mouse_mode_tearoff->tearoff_window(), 1));
2784         _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2785                                                          &_mouse_mode_tearoff->tearoff_window()));
2786         _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2787                                                           &_mouse_mode_tearoff->tearoff_window(), 1));
2788
2789         mouse_move_button.set_mode (false);
2790         mouse_select_button.set_mode (false);
2791         mouse_gain_button.set_mode (false);
2792         mouse_zoom_button.set_mode (false);
2793         mouse_timefx_button.set_mode (false);
2794         mouse_audition_button.set_mode (false);
2795         join_object_range_button.set_mode (false);
2796
2797         mouse_move_button.set_name ("MouseModeButton");
2798         mouse_select_button.set_name ("MouseModeButton");
2799         mouse_gain_button.set_name ("MouseModeButton");
2800         mouse_zoom_button.set_name ("MouseModeButton");
2801         mouse_timefx_button.set_name ("MouseModeButton");
2802         mouse_audition_button.set_name ("MouseModeButton");
2803         internal_edit_button.set_name ("MouseModeButton");
2804         join_object_range_button.set_name ("MouseModeButton");
2805
2806         mouse_move_button.unset_flags (CAN_FOCUS);
2807         mouse_select_button.unset_flags (CAN_FOCUS);
2808         mouse_gain_button.unset_flags (CAN_FOCUS);
2809         mouse_zoom_button.unset_flags (CAN_FOCUS);
2810         mouse_timefx_button.unset_flags (CAN_FOCUS);
2811         mouse_audition_button.unset_flags (CAN_FOCUS);
2812         internal_edit_button.unset_flags (CAN_FOCUS);
2813         join_object_range_button.unset_flags (CAN_FOCUS);
2814
2815         /* Zoom */
2816
2817         _zoom_box.set_spacing (1);
2818         _zoom_box.set_border_width (0);
2819
2820         zoom_in_button.set_name ("EditorTimeButton");
2821         zoom_in_button.set_image (*(manage (new Image (::get_icon ("zoom_in")))));
2822         zoom_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), false));
2823
2824         zoom_out_button.set_name ("EditorTimeButton");
2825         zoom_out_button.set_image (*(manage (new Image (::get_icon ("zoom_out")))));
2826         zoom_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), true));
2827
2828         zoom_out_full_button.set_name ("EditorTimeButton");
2829         zoom_out_full_button.set_image (*(manage (new Image (::get_icon ("zoom_full")))));
2830         zoom_out_full_button.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session));
2831
2832         zoom_focus_selector.set_name ("ZoomFocusSelector");
2833         set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true);
2834         zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2835
2836         _zoom_box.pack_start (zoom_out_button, false, false);
2837         _zoom_box.pack_start (zoom_in_button, false, false);
2838         _zoom_box.pack_start (zoom_out_full_button, false, false);
2839
2840         _zoom_box.pack_start (zoom_focus_selector);
2841         
2842         /* Track zoom buttons */
2843         tav_expand_button.set_name ("TrackHeightButton");
2844         tav_expand_button.set_size_request (-1, 20);
2845         tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2846         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2847         act->connect_proxy (tav_expand_button);
2848
2849         tav_shrink_button.set_name ("TrackHeightButton");
2850         tav_shrink_button.set_size_request (-1, 20);
2851         tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2852         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2853         act->connect_proxy (tav_shrink_button);
2854
2855         _zoom_box.pack_start (tav_shrink_button);
2856         _zoom_box.pack_start (tav_expand_button);
2857         
2858         _zoom_tearoff = manage (new TearOff (_zoom_box));
2859
2860         _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2861                                                    &_zoom_tearoff->tearoff_window()));
2862         _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2863                                                    &_zoom_tearoff->tearoff_window(), 0));
2864         _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2865                                                    &_zoom_tearoff->tearoff_window()));
2866         _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2867                                                     &_zoom_tearoff->tearoff_window(), 0));
2868         
2869         snap_box.set_spacing (1);
2870         snap_box.set_border_width (2);
2871
2872         snap_type_selector.set_name ("SnapTypeSelector");
2873         set_popdown_strings (snap_type_selector, snap_type_strings, true);
2874         snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2875
2876         snap_mode_selector.set_name ("SnapModeSelector");
2877         set_popdown_strings (snap_mode_selector, snap_mode_strings, true);
2878         snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2879
2880         edit_point_selector.set_name ("EditPointSelector");
2881         set_popdown_strings (edit_point_selector, edit_point_strings, true);
2882         edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2883
2884         snap_box.pack_start (snap_mode_selector, false, false);
2885         snap_box.pack_start (snap_type_selector, false, false);
2886         snap_box.pack_start (edit_point_selector, false, false);
2887
2888         /* Nudge */
2889
2890         HBox *nudge_box = manage (new HBox);
2891         nudge_box->set_spacing(1);
2892         nudge_box->set_border_width (2);
2893
2894         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2895         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2896
2897         nudge_box->pack_start (nudge_backward_button, false, false);
2898         nudge_box->pack_start (nudge_forward_button, false, false);
2899         nudge_box->pack_start (nudge_clock, false, false);
2900
2901
2902         /* Pack everything in... */
2903
2904         HBox* hbox = manage (new HBox);
2905         hbox->set_spacing(10);
2906
2907         _tools_tearoff = manage (new TearOff (*hbox));
2908         _tools_tearoff->set_name ("MouseModeBase");
2909         _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2910         
2911         if (Profile->get_sae()) {
2912                 _tools_tearoff->set_can_be_torn_off (false);
2913         }
2914
2915         _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2916                                                     &_tools_tearoff->tearoff_window()));
2917         _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2918                                                     &_tools_tearoff->tearoff_window(), 0));
2919         _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2920                                                     &_tools_tearoff->tearoff_window()));
2921         _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2922                                                      &_tools_tearoff->tearoff_window(), 0));
2923
2924         toolbar_hbox.set_spacing (10);
2925         toolbar_hbox.set_border_width (1);
2926
2927         toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2928         toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2929         toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2930
2931         hbox->pack_start (snap_box, false, false);
2932         if (!Profile->get_small_screen()) {
2933                 hbox->pack_start (*nudge_box, false, false);
2934         } else {
2935                 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2936         }
2937         hbox->pack_start (panic_box, false, false);
2938
2939         hbox->show_all ();
2940
2941         toolbar_base.set_name ("ToolBarBase");
2942         toolbar_base.add (toolbar_hbox);
2943
2944         _toolbar_viewport.add (toolbar_base);
2945         /* stick to the required height but allow width to vary if there's not enough room */
2946         _toolbar_viewport.set_size_request (1, -1);
2947
2948         toolbar_frame.set_shadow_type (SHADOW_OUT);
2949         toolbar_frame.set_name ("BaseFrame");
2950         toolbar_frame.add (_toolbar_viewport);
2951         
2952         DPIReset.connect (sigc::mem_fun (*this, &Editor::resize_text_widgets));
2953 }
2954
2955 void
2956 Editor::setup_tooltips ()
2957 {
2958         ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2959         ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
2960         ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
2961         ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
2962         ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2963         ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
2964         ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
2965         ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
2966         ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
2967         ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
2968         ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
2969         ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
2970         ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
2971         ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
2972         ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
2973         ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
2974         ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
2975         ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2976         ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
2977         ARDOUR_UI::instance()->set_tip (midi_sound_notes, _("Sound Notes"));
2978         ARDOUR_UI::instance()->set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels"));
2979         ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
2980 }
2981
2982 void
2983 Editor::midi_panic ()
2984 {
2985         cerr << "MIDI panic\n";
2986
2987         if (_session) {
2988                 _session->midi_panic();
2989         }
2990 }
2991
2992 void
2993 Editor::setup_midi_toolbar ()
2994 {
2995         RefPtr<Action> act;
2996
2997         /* Midi sound notes */
2998         midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
2999         midi_sound_notes.set_relief(Gtk::RELIEF_NONE);
3000         midi_sound_notes.unset_flags (CAN_FOCUS);
3001
3002         /* Panic */
3003
3004         act = ActionManager::get_action (X_("MIDI"), X_("panic"));
3005         midi_panic_button.set_name("MidiPanicButton");
3006         act->connect_proxy (midi_panic_button);
3007
3008         panic_box.pack_start (midi_sound_notes , true, true);
3009         panic_box.pack_start (midi_panic_button, true, true);
3010 }
3011
3012 int
3013 Editor::convert_drop_to_paths (
3014                 vector<string>&                paths,
3015                 const RefPtr<Gdk::DragContext>& /*context*/,
3016                 gint                            /*x*/,
3017                 gint                            /*y*/,
3018                 const SelectionData&            data,
3019                 guint                           /*info*/,
3020                 guint                           /*time*/)
3021 {
3022         if (_session == 0) {
3023                 return -1;
3024         }
3025         
3026         vector<string> uris = data.get_uris();
3027
3028         if (uris.empty()) {
3029
3030                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3031                    are actually URI lists. So do it by hand.
3032                 */
3033
3034                 if (data.get_target() != "text/plain") {
3035                         return -1;
3036                 }
3037
3038                 /* Parse the "uri-list" format that Nautilus provides,
3039                    where each pathname is delimited by \r\n.
3040
3041                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3042                 */
3043
3044                 string txt = data.get_text();
3045                 const char* p;
3046                 const char* q;
3047
3048                 p = (const char *) malloc (txt.length() + 1);
3049                 txt.copy ((char *) p, txt.length(), 0);
3050                 ((char*)p)[txt.length()] = '\0';
3051
3052                 while (p)
3053                 {
3054                         if (*p != '#')
3055                         {
3056                                 while (g_ascii_isspace (*p))
3057                                         p++;
3058
3059                                 q = p;
3060                                 while (*q && (*q != '\n') && (*q != '\r')) {
3061                                         q++;
3062                                 }
3063
3064                                 if (q > p)
3065                                 {
3066                                         q--;
3067                                         while (q > p && g_ascii_isspace (*q))
3068                                                 q--;
3069
3070                                         if (q > p)
3071                                         {
3072                                                 uris.push_back (string (p, q - p + 1));
3073                                         }
3074                                 }
3075                         }
3076                         p = strchr (p, '\n');
3077                         if (p)
3078                                 p++;
3079                 }
3080
3081                 free ((void*)p);
3082
3083                 if (uris.empty()) {
3084                         return -1;
3085                 }
3086         }
3087
3088         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3089
3090                 if ((*i).substr (0,7) == "file://") {
3091
3092                         string p = *i;
3093                         PBD::url_decode (p);
3094
3095                         // scan forward past three slashes
3096
3097                         string::size_type slashcnt = 0;
3098                         string::size_type n = 0;
3099                         string::iterator x = p.begin();
3100
3101                         while (slashcnt < 3 && x != p.end()) {
3102                                 if ((*x) == '/') {
3103                                         slashcnt++;
3104                                 } else if (slashcnt == 3) {
3105                                         break;
3106                                 }
3107                                 ++n;
3108                                 ++x;
3109                         }
3110
3111                         if (slashcnt != 3 || x == p.end()) {
3112                                 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3113                                 continue;
3114                         }
3115
3116                         paths.push_back (p.substr (n - 1));
3117                 }
3118         }
3119
3120         return 0;
3121 }
3122
3123 void
3124 Editor::new_tempo_section ()
3125
3126 {
3127 }
3128
3129 void
3130 Editor::map_transport_state ()
3131 {
3132         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3133
3134         if (_session && _session->transport_stopped()) {
3135                 have_pending_keyboard_selection = false;
3136         }
3137
3138         update_loop_range_view (true);
3139 }
3140
3141 /* UNDO/REDO */
3142
3143 Editor::State::State (PublicEditor const * e)
3144 {
3145         selection = new Selection (e);
3146 }
3147
3148 Editor::State::~State ()
3149 {
3150         delete selection;
3151 }
3152
3153 void
3154 Editor::begin_reversible_command (string name)
3155 {
3156         if (_session) {
3157                 _session->begin_reversible_command (name);
3158         }
3159 }
3160
3161 void
3162 Editor::begin_reversible_command (GQuark q)
3163 {
3164         if (_session) {
3165                 _session->begin_reversible_command (q);
3166         }
3167 }
3168
3169 void
3170 Editor::commit_reversible_command ()
3171 {
3172         if (_session) {
3173                 _session->commit_reversible_command ();
3174         }
3175 }
3176
3177 void
3178 Editor::history_changed ()
3179 {
3180         string label;
3181
3182         if (undo_action && _session) {
3183                 if (_session->undo_depth() == 0) {
3184                         label = _("Undo");
3185                 } else {
3186                         label = string_compose(_("Undo (%1)"), _session->next_undo());
3187                 }
3188                 undo_action->property_label() = label;
3189         }
3190
3191         if (redo_action && _session) {
3192                 if (_session->redo_depth() == 0) {
3193                         label = _("Redo");
3194                 } else {
3195                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3196                 }
3197                 redo_action->property_label() = label;
3198         }
3199 }
3200
3201 void
3202 Editor::duplicate_dialog (bool with_dialog)
3203 {
3204         float times = 1.0f;
3205
3206         if (mouse_mode == MouseRange) {
3207                 if (selection->time.length() == 0) {
3208                         return;
3209                 }
3210         }
3211
3212         RegionSelection rs = get_regions_from_selection_and_entered ();
3213
3214         if (mouse_mode != MouseRange && rs.empty()) {
3215                 return;
3216         }
3217
3218         if (with_dialog) {
3219
3220                 ArdourDialog win (_("Duplicate"));
3221                 Label label (_("Number of duplications:"));
3222                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3223                 SpinButton spinner (adjustment, 0.0, 1);
3224                 HBox hbox;
3225
3226                 win.get_vbox()->set_spacing (12);
3227                 win.get_vbox()->pack_start (hbox);
3228                 hbox.set_border_width (6);
3229                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3230
3231                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3232                    place, visually. so do this by hand.
3233                 */
3234
3235                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3236                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3237                 spinner.grab_focus();
3238
3239                 hbox.show ();
3240                 label.show ();
3241                 spinner.show ();
3242
3243                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3244                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3245                 win.set_default_response (RESPONSE_ACCEPT);
3246
3247                 win.set_position (WIN_POS_MOUSE);
3248
3249                 spinner.grab_focus ();
3250
3251                 switch (win.run ()) {
3252                 case RESPONSE_ACCEPT:
3253                         break;
3254                 default:
3255                         return;
3256                 }
3257
3258                 times = adjustment.get_value();
3259         }
3260
3261         if (mouse_mode == MouseRange) {
3262                 duplicate_selection (times);
3263         } else {
3264                 duplicate_some_regions (rs, times);
3265         }
3266 }
3267
3268 void
3269 Editor::show_verbose_canvas_cursor ()
3270 {
3271         verbose_canvas_cursor->raise_to_top();
3272         verbose_canvas_cursor->show();
3273         verbose_cursor_visible = true;
3274 }
3275
3276 void
3277 Editor::hide_verbose_canvas_cursor ()
3278 {
3279         verbose_canvas_cursor->hide();
3280         verbose_cursor_visible = false;
3281 }
3282
3283 double
3284 Editor::clamp_verbose_cursor_x (double x)
3285 {
3286         if (x < 0) {
3287                 x = 0;
3288         } else {
3289                 x = min (_canvas_width - 200.0, x);
3290         }
3291         return x;
3292 }
3293
3294 double
3295 Editor::clamp_verbose_cursor_y (double y)
3296 {
3297         if (y < canvas_timebars_vsize) {
3298                 y = canvas_timebars_vsize;
3299         } else {
3300                 y = min (_canvas_height - 50, y);
3301         }
3302         return y;
3303 }
3304
3305 void
3306 Editor::show_verbose_canvas_cursor_with (const string & txt, int32_t xoffset, int32_t yoffset)
3307 {
3308         verbose_canvas_cursor->property_text() = txt.c_str();
3309
3310         int x, y;
3311         double wx, wy;
3312
3313         track_canvas->get_pointer (x, y);
3314         track_canvas->window_to_world (x, y, wx, wy);
3315
3316         wx += xoffset;
3317         wy += yoffset;
3318
3319         /* don't get too close to the edge */
3320         verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (wx);
3321         verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (wy);
3322
3323         show_verbose_canvas_cursor ();
3324 }
3325
3326 void
3327 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3328 {
3329         verbose_canvas_cursor->property_text() = txt.c_str();
3330         /* don't get too close to the edge */
3331         verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (x);
3332         verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (y);
3333 }
3334
3335 void
3336 Editor::set_verbose_canvas_cursor_text (const string & txt)
3337 {
3338         verbose_canvas_cursor->property_text() = txt.c_str();
3339 }
3340
3341 void
3342 Editor::set_edit_mode (EditMode m)
3343 {
3344         Config->set_edit_mode (m);
3345 }
3346
3347 void
3348 Editor::cycle_edit_mode ()
3349 {
3350         switch (Config->get_edit_mode()) {
3351         case Slide:
3352                 if (Profile->get_sae()) {
3353                         Config->set_edit_mode (Lock);
3354                 } else {
3355                         Config->set_edit_mode (Splice);
3356                 }
3357                 break;
3358         case Splice:
3359                 Config->set_edit_mode (Lock);
3360                 break;
3361         case Lock:
3362                 Config->set_edit_mode (Slide);
3363                 break;
3364         }
3365 }
3366
3367 void
3368 Editor::edit_mode_selection_done ()
3369 {
3370         string s = edit_mode_selector.get_active_text ();
3371
3372         if (!s.empty()) {
3373                 Config->set_edit_mode (string_to_edit_mode (s));
3374         }
3375 }
3376
3377 void
3378 Editor::snap_type_selection_done ()
3379 {
3380         string choice = snap_type_selector.get_active_text();
3381         SnapType snaptype = SnapToBeat;
3382
3383         if (choice == _("Beats/2")) {
3384                 snaptype = SnapToBeatDiv2;
3385         } else if (choice == _("Beats/3")) {
3386                 snaptype = SnapToBeatDiv3;
3387         } else if (choice == _("Beats/4")) {
3388                 snaptype = SnapToBeatDiv4;
3389         } else if (choice == _("Beats/5")) {
3390                 snaptype = SnapToBeatDiv5;
3391         } else if (choice == _("Beats/6")) {
3392                 snaptype = SnapToBeatDiv6;
3393         } else if (choice == _("Beats/7")) {
3394                 snaptype = SnapToBeatDiv7;
3395         } else if (choice == _("Beats/8")) {
3396                 snaptype = SnapToBeatDiv8;
3397         } else if (choice == _("Beats/10")) {
3398                 snaptype = SnapToBeatDiv10;
3399         } else if (choice == _("Beats/12")) {
3400                 snaptype = SnapToBeatDiv12;
3401         } else if (choice == _("Beats/14")) {
3402                 snaptype = SnapToBeatDiv14;
3403         } else if (choice == _("Beats/16")) {
3404                 snaptype = SnapToBeatDiv16;
3405         } else if (choice == _("Beats/20")) {
3406                 snaptype = SnapToBeatDiv20;
3407         } else if (choice == _("Beats/24")) {
3408                 snaptype = SnapToBeatDiv24;
3409         } else if (choice == _("Beats/28")) {
3410                 snaptype = SnapToBeatDiv28;
3411         } else if (choice == _("Beats/32")) {
3412                 snaptype = SnapToBeatDiv32;
3413         } else if (choice == _("Beats")) {
3414                 snaptype = SnapToBeat;
3415         } else if (choice == _("Bars")) {
3416                 snaptype = SnapToBar;
3417         } else if (choice == _("Marks")) {
3418                 snaptype = SnapToMark;
3419         } else if (choice == _("Region starts")) {
3420                 snaptype = SnapToRegionStart;
3421         } else if (choice == _("Region ends")) {
3422                 snaptype = SnapToRegionEnd;
3423         } else if (choice == _("Region bounds")) {
3424                 snaptype = SnapToRegionBoundary;
3425         } else if (choice == _("Region syncs")) {
3426                 snaptype = SnapToRegionSync;
3427         } else if (choice == _("CD Frames")) {
3428                 snaptype = SnapToCDFrame;
3429         } else if (choice == _("Timecode Frames")) {
3430                 snaptype = SnapToTimecodeFrame;
3431         } else if (choice == _("Timecode Seconds")) {
3432                 snaptype = SnapToTimecodeSeconds;
3433         } else if (choice == _("Timecode Minutes")) {
3434                 snaptype = SnapToTimecodeMinutes;
3435         } else if (choice == _("Seconds")) {
3436                 snaptype = SnapToSeconds;
3437         } else if (choice == _("Minutes")) {
3438                 snaptype = SnapToMinutes;
3439         }
3440
3441         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3442         if (ract) {
3443                 ract->set_active ();
3444         }
3445 }
3446
3447 void
3448 Editor::snap_mode_selection_done ()
3449 {
3450         string choice = snap_mode_selector.get_active_text();
3451         SnapMode mode = SnapNormal;
3452
3453         if (choice == _("No Grid")) {
3454                 mode = SnapOff;
3455         } else if (choice == _("Grid")) {
3456                 mode = SnapNormal;
3457         } else if (choice == _("Magnetic")) {
3458                 mode = SnapMagnetic;
3459         }
3460
3461         RefPtr<RadioAction> ract = snap_mode_action (mode);
3462
3463         if (ract) {
3464                 ract->set_active (true);
3465         }
3466 }
3467
3468 void
3469 Editor::cycle_edit_point (bool with_marker)
3470 {
3471         switch (_edit_point) {
3472         case EditAtMouse:
3473                 set_edit_point_preference (EditAtPlayhead);
3474                 break;
3475         case EditAtPlayhead:
3476                 if (with_marker) {
3477                         set_edit_point_preference (EditAtSelectedMarker);
3478                 } else {
3479                         set_edit_point_preference (EditAtMouse);
3480                 }
3481                 break;
3482         case EditAtSelectedMarker:
3483                 set_edit_point_preference (EditAtMouse);
3484                 break;
3485         }
3486 }
3487
3488 void
3489 Editor::edit_point_selection_done ()
3490 {
3491         string choice = edit_point_selector.get_active_text();
3492         EditPoint ep = EditAtSelectedMarker;
3493
3494         if (choice == _("Marker")) {
3495                 set_edit_point_preference (EditAtSelectedMarker);
3496         } else if (choice == _("Playhead")) {
3497                 set_edit_point_preference (EditAtPlayhead);
3498         } else {
3499                 set_edit_point_preference (EditAtMouse);
3500         }
3501
3502         RefPtr<RadioAction> ract = edit_point_action (ep);
3503
3504         if (ract) {
3505                 ract->set_active (true);
3506         }
3507 }
3508
3509 void
3510 Editor::zoom_focus_selection_done ()
3511 {
3512         string choice = zoom_focus_selector.get_active_text();
3513         ZoomFocus focus_type = ZoomFocusLeft;
3514
3515         if (choice == _("Left")) {
3516                 focus_type = ZoomFocusLeft;
3517         } else if (choice == _("Right")) {
3518                 focus_type = ZoomFocusRight;
3519         } else if (choice == _("Center")) {
3520                 focus_type = ZoomFocusCenter;
3521         } else if (choice == _("Playhead")) {
3522                 focus_type = ZoomFocusPlayhead;
3523         } else if (choice == _("Mouse")) {
3524                 focus_type = ZoomFocusMouse;
3525         } else if (choice == _("Edit point")) {
3526                 focus_type = ZoomFocusEdit;
3527         }
3528
3529         RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3530
3531         if (ract) {
3532                 ract->set_active ();
3533         }
3534 }
3535
3536 gint
3537 Editor::edit_controls_button_release (GdkEventButton* ev)
3538 {
3539         if (Keyboard::is_context_menu_event (ev)) {
3540                 ARDOUR_UI::instance()->add_route (this);
3541         }
3542         return TRUE;
3543 }
3544
3545 gint
3546 Editor::mouse_select_button_release (GdkEventButton* ev)
3547 {
3548         /* this handles just right-clicks */
3549
3550         if (ev->button != 3) {
3551                 return false;
3552         }
3553
3554         return true;
3555 }
3556
3557 void
3558 Editor::set_zoom_focus (ZoomFocus f)
3559 {
3560         string str = zoom_focus_strings[(int)f];
3561
3562         if (str != zoom_focus_selector.get_active_text()) {
3563                 zoom_focus_selector.set_active_text (str);
3564         }
3565
3566         if (zoom_focus != f) {
3567                 zoom_focus = f;
3568
3569                 ZoomFocusChanged (); /* EMIT_SIGNAL */
3570
3571                 instant_save ();
3572         }
3573 }
3574
3575 void
3576 Editor::ensure_float (Window& win)
3577 {
3578         win.set_transient_for (*this);
3579 }
3580
3581 void
3582 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3583 {
3584         /* recover or initialize pane positions. do this here rather than earlier because
3585            we don't want the positions to change the child allocations, which they seem to do.
3586          */
3587
3588         int pos;
3589         XMLProperty* prop;
3590         char buf[32];
3591         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3592         int width, height;
3593
3594         enum Pane {
3595                 Horizontal = 0x1,
3596                 Vertical = 0x2
3597         };
3598
3599         static Pane done;
3600         
3601         XMLNode* geometry;
3602
3603         width = default_width;
3604         height = default_height;
3605
3606         if ((geometry = find_named_node (*node, "geometry")) != 0) {
3607
3608                 prop = geometry->property ("x-size");
3609                 if (prop) {
3610                         width = atoi (prop->value());
3611                 }
3612                 prop = geometry->property ("y-size");
3613                 if (prop) {
3614                         height = atoi (prop->value());
3615                 }
3616         }
3617
3618         if (which == static_cast<Paned*> (&edit_pane)) {
3619
3620                 if (done & Horizontal) {
3621                         return;
3622                 }
3623
3624                 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3625                         _notebook_shrunk = string_is_affirmative (prop->value ());
3626                 }
3627
3628                 if (geometry && (prop = geometry->property ("pre-maximal-horizontal-pane-position"))) {
3629                         pre_maximal_horizontal_pane_position = atoi (prop->value ());
3630                 }
3631
3632                 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3633                         /* initial allocation is 90% to canvas, 10% to notebook */
3634                         pos = (int) floor (alloc.get_width() * 0.90f);
3635                         snprintf (buf, sizeof(buf), "%d", pos);
3636                 } else {
3637                         pos = atoi (prop->value());
3638                 }
3639
3640                 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3641                         edit_pane.set_position (pos);
3642                         if (pre_maximal_horizontal_pane_position == 0) {
3643                                 pre_maximal_horizontal_pane_position = pos;
3644                         }
3645                 }
3646
3647                 done = (Pane) (done | Horizontal);
3648                 
3649         } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3650
3651                 if (done & Vertical) {
3652                         return;
3653                 }
3654
3655                 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3656                         /* initial allocation is 90% to canvas, 10% to summary */
3657                         pos = (int) floor (alloc.get_height() * 0.90f);
3658                         snprintf (buf, sizeof(buf), "%d", pos);
3659                 } else {
3660                         pos = atoi (prop->value());
3661                 }
3662
3663                 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3664                         editor_summary_pane.set_position (pos);
3665                         pre_maximal_vertical_pane_position = pos;
3666                 }
3667
3668                 done = (Pane) (done | Vertical);
3669         }
3670 }
3671
3672 void
3673 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3674 {
3675         if (_tools_tearoff->torn_off() && _mouse_mode_tearoff->torn_off()) {
3676                 top_hbox.remove (toolbar_frame);
3677         }
3678 }
3679
3680 void
3681 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3682 {
3683         if (toolbar_frame.get_parent() == 0) {
3684                 top_hbox.pack_end (toolbar_frame);
3685         }
3686 }
3687
3688 void
3689 Editor::set_show_measures (bool yn)
3690 {
3691         if (_show_measures != yn) {
3692                 hide_measures ();
3693
3694                 if ((_show_measures = yn) == true) {
3695                         if (tempo_lines)
3696                                 tempo_lines->show();
3697                         draw_measures ();
3698                 }
3699                 instant_save ();
3700         }
3701 }
3702
3703 void
3704 Editor::toggle_follow_playhead ()
3705 {
3706         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3707         if (act) {
3708                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3709                 set_follow_playhead (tact->get_active());
3710         }
3711 }
3712
3713 /** @param yn true to follow playhead, otherwise false.
3714  *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3715  */
3716 void
3717 Editor::set_follow_playhead (bool yn, bool catch_up)
3718 {
3719         if (_follow_playhead != yn) {
3720                 if ((_follow_playhead = yn) == true && catch_up) {
3721                         /* catch up */
3722                         reset_x_origin_to_follow_playhead ();
3723                 }
3724                 instant_save ();
3725         }
3726 }
3727
3728 void
3729 Editor::toggle_stationary_playhead ()
3730 {
3731         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3732         if (act) {
3733                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3734                 set_stationary_playhead (tact->get_active());
3735         }
3736 }
3737
3738 void
3739 Editor::set_stationary_playhead (bool yn)
3740 {
3741         if (_stationary_playhead != yn) {
3742                 if ((_stationary_playhead = yn) == true) {
3743                         /* catch up */
3744                         // FIXME need a 3.0 equivalent of this 2.X call
3745                         // update_current_screen ();
3746                 }
3747                 instant_save ();
3748         }
3749 }
3750
3751 void
3752 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3753 {
3754         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3755         if (xfade) {
3756                 xfade->set_active (!xfade->active());
3757         }
3758 }
3759
3760 void
3761 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3762 {
3763         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3764         if (xfade) {
3765                 xfade->set_follow_overlap (!xfade->following_overlap());
3766         }
3767 }
3768
3769 void
3770 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3771 {
3772         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3773
3774         if (!xfade) {
3775                 return;
3776         }
3777
3778         CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3779
3780         ensure_float (cew);
3781
3782         switch (cew.run ()) {
3783         case RESPONSE_ACCEPT:
3784                 break;
3785         default:
3786                 return;
3787         }
3788
3789         cew.apply ();
3790         PropertyChange all_crossfade_properties;
3791         all_crossfade_properties.add (ARDOUR::Properties::active);
3792         all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3793         xfade->PropertyChanged (all_crossfade_properties);
3794 }
3795
3796 PlaylistSelector&
3797 Editor::playlist_selector () const
3798 {
3799         return *_playlist_selector;
3800 }
3801
3802 Evoral::MusicalTime
3803 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3804 {
3805         success = true;
3806
3807         switch (_snap_type) {
3808         case SnapToBeat:
3809                 return 1.0;
3810                 break;
3811
3812         case SnapToBeatDiv32:
3813                 return 1.0/32.0;
3814                 break;
3815         case SnapToBeatDiv28:
3816                 return 1.0/28.0;
3817                 break;
3818         case SnapToBeatDiv24:
3819                 return 1.0/24.0;
3820                 break;
3821         case SnapToBeatDiv20:
3822                 return 1.0/20.0;
3823                 break;
3824         case SnapToBeatDiv16:
3825                 return 1.0/16.0;
3826                 break;
3827         case SnapToBeatDiv14:
3828                 return 1.0/14.0;
3829                 break;
3830         case SnapToBeatDiv12:
3831                 return 1.0/12.0;
3832                 break;
3833         case SnapToBeatDiv10:
3834                 return 1.0/10.0;
3835                 break;
3836         case SnapToBeatDiv8:
3837                 return 1.0/8.0;
3838                 break;
3839         case SnapToBeatDiv7:
3840                 return 1.0/7.0;
3841                 break;
3842         case SnapToBeatDiv6:
3843                 return 1.0/6.0;
3844                 break;
3845         case SnapToBeatDiv5:
3846                 return 1.0/5.0;
3847                 break;
3848         case SnapToBeatDiv4:
3849                 return 1.0/4.0;
3850                 break;
3851         case SnapToBeatDiv3:
3852                 return 1.0/3.0;
3853                 break;
3854         case SnapToBeatDiv2:
3855                 return 1.0/2.0;
3856                 break;
3857
3858         case SnapToBar:
3859                 if (_session) {
3860                         return _session->tempo_map().meter_at (position).beats_per_bar();
3861                 }
3862                 break;
3863
3864         case SnapToCDFrame:
3865         case SnapToTimecodeFrame:
3866         case SnapToTimecodeSeconds:
3867         case SnapToTimecodeMinutes:
3868         case SnapToSeconds:
3869         case SnapToMinutes:
3870         case SnapToRegionStart:
3871         case SnapToRegionEnd:
3872         case SnapToRegionSync:
3873         case SnapToRegionBoundary:
3874         default:
3875                 success = false;
3876                 break;
3877         }
3878
3879         return 0.0;
3880 }
3881
3882 framecnt_t
3883 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3884 {
3885         framecnt_t ret;
3886
3887         ret = nudge_clock.current_duration (pos);
3888         next = ret + 1; /* XXXX fix me */
3889
3890         return ret;
3891 }
3892
3893 int
3894 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3895 {
3896         ArdourDialog dialog (_("Playlist Deletion"));
3897         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
3898                                         "If left alone, no audio files used by it will be cleaned.\n"
3899                                         "If deleted, audio files used by it alone by will cleaned."),
3900                                       pl->name()));
3901
3902         dialog.set_position (WIN_POS_CENTER);
3903         dialog.get_vbox()->pack_start (label);
3904
3905         label.show ();
3906
3907         dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3908         dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3909         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3910
3911         switch (dialog.run ()) {
3912         case RESPONSE_ACCEPT:
3913                 /* delete the playlist */
3914                 return 0;
3915                 break;
3916
3917         case RESPONSE_REJECT:
3918                 /* keep the playlist */
3919                 return 1;
3920                 break;
3921
3922         default:
3923                 break;
3924         }
3925
3926         return -1;
3927 }
3928
3929 bool
3930 Editor::audio_region_selection_covers (framepos_t where)
3931 {
3932         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3933                 if ((*a)->region()->covers (where)) {
3934                         return true;
3935                 }
3936         }
3937
3938         return false;
3939 }
3940
3941 void
3942 Editor::prepare_for_cleanup ()
3943 {
3944         cut_buffer->clear_regions ();
3945         cut_buffer->clear_playlists ();
3946
3947         selection->clear_regions ();
3948         selection->clear_playlists ();
3949
3950         _regions->suspend_redisplay ();
3951 }
3952
3953 void
3954 Editor::finish_cleanup ()
3955 {
3956         _regions->resume_redisplay ();
3957 }
3958
3959 Location*
3960 Editor::transport_loop_location()
3961 {
3962         if (_session) {
3963                 return _session->locations()->auto_loop_location();
3964         } else {
3965                 return 0;
3966         }
3967 }
3968
3969 Location*
3970 Editor::transport_punch_location()
3971 {
3972         if (_session) {
3973                 return _session->locations()->auto_punch_location();
3974         } else {
3975                 return 0;
3976         }
3977 }
3978
3979 bool
3980 Editor::control_layout_scroll (GdkEventScroll* ev)
3981 {
3982         if (Keyboard::some_magic_widget_has_focus()) {
3983                 return false;
3984         }
3985
3986         switch (ev->direction) {
3987         case GDK_SCROLL_UP:
3988                 scroll_tracks_up_line ();
3989                 return true;
3990                 break;
3991
3992         case GDK_SCROLL_DOWN:
3993                 scroll_tracks_down_line ();
3994                 return true;
3995
3996         default:
3997                 /* no left/right handling yet */
3998                 break;
3999         }
4000
4001         return false;
4002 }
4003
4004 void
4005 Editor::session_state_saved (string)
4006 {
4007         update_title ();        
4008         _snapshots->redisplay ();
4009 }
4010
4011 void
4012 Editor::maximise_editing_space ()
4013 {
4014         _mouse_mode_tearoff->set_visible (false);
4015         _tools_tearoff->set_visible (false);
4016         _zoom_tearoff->set_visible (false);
4017
4018         pre_maximal_horizontal_pane_position = edit_pane.get_position ();
4019         pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
4020         pre_maximal_editor_width = this->get_width ();
4021         pre_maximal_editor_height = this->get_height ();
4022
4023         if (post_maximal_horizontal_pane_position == 0) {
4024                 post_maximal_horizontal_pane_position = edit_pane.get_width();
4025         }
4026
4027         if (post_maximal_vertical_pane_position == 0) {
4028                 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
4029         }
4030         
4031         fullscreen ();
4032
4033         if (post_maximal_editor_width) {
4034                 edit_pane.set_position (post_maximal_horizontal_pane_position -
4035                         abs(post_maximal_editor_width - pre_maximal_editor_width));
4036         } else {
4037                 edit_pane.set_position (post_maximal_horizontal_pane_position);
4038         }
4039
4040         if (post_maximal_editor_height) {
4041                 editor_summary_pane.set_position (post_maximal_vertical_pane_position -
4042                         abs(post_maximal_editor_height - pre_maximal_editor_height));
4043         } else {
4044                 editor_summary_pane.set_position (post_maximal_vertical_pane_position);
4045         }
4046
4047         if (Config->get_keep_tearoffs()) {
4048                 _mouse_mode_tearoff->set_visible (true);
4049                 _tools_tearoff->set_visible (true);
4050                 if (Config->get_show_zoom_tools ()) {
4051                         _zoom_tearoff->set_visible (true);
4052                 }
4053         }
4054
4055 }
4056
4057 void
4058 Editor::restore_editing_space ()
4059 {
4060         // user changed width/height of panes during fullscreen
4061
4062         if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
4063                 post_maximal_horizontal_pane_position = edit_pane.get_position();
4064         }
4065
4066         if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
4067                 post_maximal_vertical_pane_position = editor_summary_pane.get_position();
4068         }
4069         
4070         unfullscreen();
4071
4072         _mouse_mode_tearoff->set_visible (true);
4073         _tools_tearoff->set_visible (true);
4074         if (Config->get_show_zoom_tools ()) {
4075                 _zoom_tearoff->set_visible (true);
4076         }
4077         post_maximal_editor_width = this->get_width();
4078         post_maximal_editor_height = this->get_height();
4079
4080         edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
4081         editor_summary_pane.set_position (pre_maximal_vertical_pane_position + abs(this->get_height() - pre_maximal_editor_height));
4082 }
4083
4084 /**
4085  *  Make new playlists for a given track and also any others that belong
4086  *  to the same active route group with the `edit' property.
4087  *  @param v Track.
4088  */
4089
4090 void
4091 Editor::new_playlists (TimeAxisView* v)
4092 {
4093         begin_reversible_command (_("new playlists"));
4094         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4095         _session->playlists->get (playlists);
4096         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4097         commit_reversible_command ();
4098 }
4099
4100 /**
4101  *  Use a copy of the current playlist for a given track and also any others that belong
4102  *  to the same active route group with the `edit' property.
4103  *  @param v Track.
4104  */
4105
4106 void
4107 Editor::copy_playlists (TimeAxisView* v)
4108 {
4109         begin_reversible_command (_("copy playlists"));
4110         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4111         _session->playlists->get (playlists);
4112         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4113         commit_reversible_command ();
4114 }
4115
4116 /** Clear the current playlist for a given track and also any others that belong
4117  *  to the same active route group with the `edit' property.
4118  *  @param v Track.
4119  */
4120
4121 void
4122 Editor::clear_playlists (TimeAxisView* v)
4123 {
4124         begin_reversible_command (_("clear playlists"));
4125         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4126         _session->playlists->get (playlists);
4127         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4128         commit_reversible_command ();
4129 }
4130
4131 void
4132 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4133 {
4134         atv.use_new_playlist (sz > 1 ? false : true, playlists);
4135 }
4136
4137 void
4138 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4139 {
4140         atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4141 }
4142
4143 void
4144 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4145 {
4146         atv.clear_playlist ();
4147 }
4148
4149 bool
4150 Editor::on_key_press_event (GdkEventKey* ev)
4151 {
4152         return key_press_focus_accelerator_handler (*this, ev);
4153 }
4154
4155 bool
4156 Editor::on_key_release_event (GdkEventKey* ev)
4157 {
4158         return Gtk::Window::on_key_release_event (ev);
4159         // return key_press_focus_accelerator_handler (*this, ev);
4160 }
4161
4162 /** Queue up a change to the viewport x origin.
4163  *  @param frame New x origin.
4164  */
4165 void
4166 Editor::reset_x_origin (framepos_t frame)
4167 {
4168         queue_visual_change (frame);
4169 }
4170
4171 void
4172 Editor::reset_y_origin (double y)
4173 {
4174         queue_visual_change_y (y);
4175 }
4176
4177 void
4178 Editor::reset_zoom (double fpu)
4179 {
4180         queue_visual_change (fpu);
4181 }
4182
4183 void
4184 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4185 {
4186         reset_x_origin (frame);
4187         reset_zoom (fpu);
4188
4189         if (!no_save_visual) {
4190                 undo_visual_stack.push_back (current_visual_state(false));
4191         }
4192 }
4193
4194 Editor::VisualState*
4195 Editor::current_visual_state (bool with_tracks)
4196 {
4197         VisualState* vs = new VisualState;
4198         vs->y_position = vertical_adjustment.get_value();
4199         vs->frames_per_unit = frames_per_unit;
4200         vs->leftmost_frame = leftmost_frame;
4201         vs->zoom_focus = zoom_focus;
4202
4203         if (with_tracks) {
4204                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4205                         vs->track_states.push_back (TAVState ((*i), &(*i)->get_state()));
4206                 }
4207         }
4208
4209         return vs;
4210 }
4211
4212 void
4213 Editor::undo_visual_state ()
4214 {
4215         if (undo_visual_stack.empty()) {
4216                 return;
4217         }
4218
4219         redo_visual_stack.push_back (current_visual_state());
4220
4221         VisualState* vs = undo_visual_stack.back();
4222         undo_visual_stack.pop_back();
4223         use_visual_state (*vs);
4224 }
4225
4226 void
4227 Editor::redo_visual_state ()
4228 {
4229         if (redo_visual_stack.empty()) {
4230                 return;
4231         }
4232
4233         undo_visual_stack.push_back (current_visual_state());
4234
4235         VisualState* vs = redo_visual_stack.back();
4236         redo_visual_stack.pop_back();
4237         use_visual_state (*vs);
4238 }
4239
4240 void
4241 Editor::swap_visual_state ()
4242 {
4243         if (undo_visual_stack.empty()) {
4244                 redo_visual_state ();
4245         } else {
4246                 undo_visual_state ();
4247         }
4248 }
4249
4250 void
4251 Editor::use_visual_state (VisualState& vs)
4252 {
4253         no_save_visual = true;
4254
4255         _routes->suspend_redisplay ();
4256
4257         vertical_adjustment.set_value (vs.y_position);
4258
4259         set_zoom_focus (vs.zoom_focus);
4260         reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4261
4262         for (list<TAVState>::iterator i = vs.track_states.begin(); i != vs.track_states.end(); ++i) {
4263                 TrackViewList::iterator t;
4264
4265                 /* check if the track still exists - it could have been deleted */
4266
4267                 if ((t = find (track_views.begin(), track_views.end(), i->first)) != track_views.end()) {
4268                         (*t)->set_state (*(i->second), Stateful::loading_state_version);
4269                 }
4270         }
4271
4272
4273         if (!vs.track_states.empty()) {
4274                 _routes->update_visibility ();
4275         }
4276
4277         _routes->resume_redisplay ();
4278
4279         no_save_visual = false;
4280 }
4281
4282 void
4283 Editor::set_frames_per_unit (double fpu)
4284 {
4285         /* this is the core function that controls the zoom level of the canvas. it is called
4286            whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4287         */
4288
4289         if (fpu == frames_per_unit) {
4290                 return;
4291         }
4292
4293         if (fpu < 2.0) {
4294                 fpu = 2.0;
4295         }
4296
4297
4298         /* don't allow zooms that fit more than the maximum number
4299            of frames into an 800 pixel wide space.
4300         */
4301
4302         if (max_framepos / fpu < 800.0) {
4303                 return;
4304         }
4305
4306         if (tempo_lines)
4307                 tempo_lines->tempo_map_changed();
4308
4309         frames_per_unit = fpu;
4310         post_zoom ();
4311 }
4312
4313 void
4314 Editor::post_zoom ()
4315 {
4316         // convert fpu to frame count
4317
4318         framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4319
4320         if (frames_per_unit != zoom_range_clock.current_duration()) {
4321                 zoom_range_clock.set (frames);
4322         }
4323
4324         if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4325                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4326                         (*i)->reshow_selection (selection->time);
4327                 }
4328         }
4329
4330         ZoomChanged (); /* EMIT_SIGNAL */
4331
4332         //reset_scrolling_region ();
4333
4334         if (playhead_cursor) {
4335                 playhead_cursor->set_position (playhead_cursor->current_frame);
4336         }
4337
4338         refresh_location_display();
4339         _summary->set_overlays_dirty ();
4340
4341         update_marker_labels ();
4342
4343         instant_save ();
4344 }
4345
4346 void
4347 Editor::queue_visual_change (framepos_t where)
4348 {
4349         pending_visual_change.add (VisualChange::TimeOrigin);
4350         pending_visual_change.time_origin = where;
4351         ensure_visual_change_idle_handler ();
4352 }
4353
4354 void
4355 Editor::queue_visual_change (double fpu)
4356 {
4357         pending_visual_change.add (VisualChange::ZoomLevel);
4358         pending_visual_change.frames_per_unit = fpu;
4359
4360         ensure_visual_change_idle_handler ();
4361 }
4362
4363 void
4364 Editor::queue_visual_change_y (double y)
4365 {
4366         pending_visual_change.add (VisualChange::YOrigin);
4367         pending_visual_change.y_origin = y;
4368
4369         ensure_visual_change_idle_handler ();
4370 }
4371
4372 void
4373 Editor::ensure_visual_change_idle_handler ()
4374 {
4375         if (pending_visual_change.idle_handler_id < 0) {
4376                 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4377         }
4378 }
4379
4380 int
4381 Editor::_idle_visual_changer (void* arg)
4382 {
4383         return static_cast<Editor*>(arg)->idle_visual_changer ();
4384 }
4385
4386 int
4387 Editor::idle_visual_changer ()
4388 {
4389         VisualChange::Type p = pending_visual_change.pending;
4390         pending_visual_change.pending = (VisualChange::Type) 0;
4391
4392         double const last_time_origin = horizontal_position ();
4393
4394         if (p & VisualChange::TimeOrigin) {
4395                 /* This is a bit of a hack, but set_frames_per_unit
4396                    below will (if called) end up with the
4397                    CrossfadeViews looking at Editor::leftmost_frame,
4398                    and if we're changing origin and zoom in the same
4399                    operation it will be the wrong value unless we
4400                    update it here.
4401                 */
4402
4403                 leftmost_frame = pending_visual_change.time_origin;
4404         }
4405
4406         if (p & VisualChange::ZoomLevel) {
4407                 set_frames_per_unit (pending_visual_change.frames_per_unit);
4408
4409                 compute_fixed_ruler_scale ();
4410                 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4411                 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4412                 update_tempo_based_rulers ();
4413         }
4414         if (p & VisualChange::TimeOrigin) {
4415                 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4416         }
4417         if (p & VisualChange::YOrigin) {
4418                 vertical_adjustment.set_value (pending_visual_change.y_origin);
4419         }
4420
4421         if (last_time_origin == horizontal_position ()) {
4422                 /* changed signal not emitted */
4423                 update_fixed_rulers ();
4424                 redisplay_tempo (true);
4425         }
4426
4427         _summary->set_overlays_dirty ();
4428
4429         pending_visual_change.idle_handler_id = -1;
4430         return 0; /* this is always a one-shot call */
4431 }
4432
4433 struct EditorOrderTimeAxisSorter {
4434     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4435             return a->order () < b->order ();
4436     }
4437 };
4438
4439 void
4440 Editor::sort_track_selection (TrackViewList* sel)
4441 {
4442         EditorOrderTimeAxisSorter cmp;
4443
4444         if (sel) {
4445                 sel->sort (cmp);
4446         } else {
4447                 selection->tracks.sort (cmp);
4448         }
4449 }
4450
4451 framepos_t
4452 Editor::get_preferred_edit_position (bool ignore_playhead)
4453 {
4454         bool ignored;
4455         framepos_t where = 0;
4456         EditPoint ep = _edit_point;
4457
4458         if (entered_marker) {
4459                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4460                 return entered_marker->position();
4461         }
4462
4463         if (ignore_playhead && ep == EditAtPlayhead) {
4464                 ep = EditAtSelectedMarker;
4465         }
4466
4467         switch (ep) {
4468         case EditAtPlayhead:
4469                 where = _session->audible_frame();
4470                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4471                 break;
4472
4473         case EditAtSelectedMarker:
4474                 if (!selection->markers.empty()) {
4475                         bool is_start;
4476                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4477                         if (loc) {
4478                                 if (is_start) {
4479                                         where =  loc->start();
4480                                 } else {
4481                                         where = loc->end();
4482                                 }
4483                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4484                                 break;
4485                         }
4486                 }
4487                 /* fallthru */
4488
4489         default:
4490         case EditAtMouse:
4491                 if (!mouse_frame (where, ignored)) {
4492                         /* XXX not right but what can we do ? */
4493                         return 0;
4494                 }
4495                 snap_to (where);
4496                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4497                 break;
4498         }
4499
4500         return where;
4501 }
4502
4503 void
4504 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4505 {
4506         if (!_session) return;
4507
4508         begin_reversible_command (cmd);
4509
4510         Location* tll;
4511
4512         if ((tll = transport_loop_location()) == 0) {
4513                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4514                 XMLNode &before = _session->locations()->get_state();
4515                 _session->locations()->add (loc, true);
4516                 _session->set_auto_loop_location (loc);
4517                 XMLNode &after = _session->locations()->get_state();
4518                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4519         } else {
4520                 XMLNode &before = tll->get_state();
4521                 tll->set_hidden (false, this);
4522                 tll->set (start, end);
4523                 XMLNode &after = tll->get_state();
4524                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4525         }
4526
4527         commit_reversible_command ();
4528 }
4529
4530 void
4531 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4532 {
4533         if (!_session) return;
4534
4535         begin_reversible_command (cmd);
4536
4537         Location* tpl;
4538
4539         if ((tpl = transport_punch_location()) == 0) {
4540                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoPunch);
4541                 XMLNode &before = _session->locations()->get_state();
4542                 _session->locations()->add (loc, true);
4543                 _session->set_auto_loop_location (loc);
4544                 XMLNode &after = _session->locations()->get_state();
4545                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4546         }
4547         else {
4548                 XMLNode &before = tpl->get_state();
4549                 tpl->set_hidden (false, this);
4550                 tpl->set (start, end);
4551                 XMLNode &after = tpl->get_state();
4552                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4553         }
4554
4555         commit_reversible_command ();
4556 }
4557
4558 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4559  *  @param rs List to which found regions are added.
4560  *  @param where Time to look at.
4561  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4562  */
4563 void
4564 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4565 {
4566         const TrackViewList* tracks;
4567
4568         if (ts.empty()) {
4569                 tracks = &track_views;
4570         } else {
4571                 tracks = &ts;
4572         }
4573
4574         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4575
4576                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4577
4578                 if (rtv) {
4579                         boost::shared_ptr<Track> tr;
4580                         boost::shared_ptr<Playlist> pl;
4581
4582                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4583
4584                                 Playlist::RegionList* regions = pl->regions_at (
4585                                                 (framepos_t) floor ( (double) where * tr->speed()));
4586
4587                                 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4588                                         RegionView* rv = rtv->view()->find_view (*i);
4589                                         if (rv) {
4590                                                 rs.add (rv);
4591                                         }
4592                                 }
4593
4594                                 delete regions;
4595                         }
4596                 }
4597         }
4598 }
4599
4600 void
4601 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4602 {
4603         const TrackViewList* tracks;
4604
4605         if (ts.empty()) {
4606                 tracks = &track_views;
4607         } else {
4608                 tracks = &ts;
4609         }
4610
4611         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4612                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4613                 if (rtv) {
4614                         boost::shared_ptr<Track> tr;
4615                         boost::shared_ptr<Playlist> pl;
4616
4617                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4618
4619                                 Playlist::RegionList* regions = pl->regions_touched (
4620                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4621
4622                                 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4623
4624                                         RegionView* rv = rtv->view()->find_view (*i);
4625
4626                                         if (rv) {
4627                                                 rs.push_back (rv);
4628                                         }
4629                                 }
4630
4631                                 delete regions;
4632                         }
4633                 }
4634         }
4635 }
4636
4637 /** Start with regions that are selected.  Then add equivalent regions
4638  *  on tracks in the same active edit-enabled route group as any of
4639  *  the regions that we started with.
4640  */
4641
4642 RegionSelection
4643 Editor::get_regions_from_selection ()
4644 {
4645         return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4646 }
4647
4648 /** Get regions using the following method:
4649  *
4650  *  Make an initial region list using the selected regions, unless
4651  *  the edit point is `mouse' and the mouse is over an unselected
4652  *  region.  In this case, start with just that region.
4653  *
4654  *  Then, make an initial track list of the tracks that these
4655  *  regions are on, and if the edit point is not `mouse', add the
4656  *  selected tracks.
4657  *
4658  *  Look at this track list and add any other tracks that are on the
4659  *  same active edit-enabled route group as one of the initial tracks.
4660  *
4661  *  Finally take the initial region list and add any regions that are
4662  *  under the edit point on one of the tracks on the track list to get
4663  *  the returned region list.
4664  *
4665  *  The rationale here is that the mouse edit point is special in that
4666  *  its position describes both a time and a track; the other edit
4667  *  modes only describe a time.  Hence if the edit point is `mouse' we
4668  *  ignore selected tracks, as we assume the user means something by
4669  *  pointing at a particular track.  Also in this case we take note of
4670  *  the region directly under the edit point, as there is always just one
4671  *  (rather than possibly several with non-mouse edit points).
4672  */
4673
4674 RegionSelection
4675 Editor::get_regions_from_selection_and_edit_point ()
4676 {
4677         RegionSelection regions;
4678         
4679         if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4680                 regions.add (entered_regionview);
4681         } else {
4682                 regions = selection->regions;
4683         }
4684
4685         TrackViewList tracks;
4686
4687         if (_edit_point != EditAtMouse) {
4688                 tracks = selection->tracks;
4689         }
4690
4691         /* Add any other tracks that have regions that are in the same
4692            edit-activated route group as one of our regions.
4693          */
4694         for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4695                 
4696                 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4697                 
4698                 if (g && g->is_active() && g->is_edit()) {
4699                         tracks.add (axis_views_from_routes (g->route_list()));
4700                 }
4701         }
4702         
4703         if (!tracks.empty()) {
4704                 /* now find regions that are at the edit position on those tracks */
4705                 framepos_t const where = get_preferred_edit_position ();
4706                 get_regions_at (regions, where, tracks);
4707         }
4708
4709         return regions;
4710 }
4711
4712 /** Start with regions that are selected, or the entered regionview if none are selected.
4713  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4714  *  of the regions that we started with.
4715  */
4716
4717 RegionSelection
4718 Editor::get_regions_from_selection_and_entered ()
4719 {
4720         RegionSelection regions = selection->regions;
4721         
4722         if (regions.empty() && entered_regionview) {
4723                 regions.add (entered_regionview);
4724         }
4725
4726         return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4727 }
4728
4729 void
4730 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4731 {
4732         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4733
4734                 RouteTimeAxisView* tatv;
4735
4736                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4737
4738                         boost::shared_ptr<Playlist> pl;
4739                         vector<boost::shared_ptr<Region> > results;
4740                         RegionView* marv;
4741                         boost::shared_ptr<Track> tr;
4742
4743                         if ((tr = tatv->track()) == 0) {
4744                                 /* bus */
4745                                 continue;
4746                         }
4747
4748                         if ((pl = (tr->playlist())) != 0) {
4749                                 pl->get_region_list_equivalent_regions (region, results);
4750                         }
4751
4752                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4753                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4754                                         regions.push_back (marv);
4755                                 }
4756                         }
4757
4758                 }
4759         }
4760 }
4761
4762 void
4763 Editor::show_rhythm_ferret ()
4764 {
4765         if (rhythm_ferret == 0) {
4766                 rhythm_ferret = new RhythmFerret(*this);
4767         }
4768
4769         rhythm_ferret->set_session (_session);
4770         rhythm_ferret->show ();
4771         rhythm_ferret->present ();
4772 }
4773
4774 void
4775 Editor::first_idle ()
4776 {
4777         MessageDialog* dialog = 0;
4778
4779         if (track_views.size() > 1) {
4780                 dialog = new MessageDialog (*this,
4781                                             string_compose (_("Please wait while %1 loads visual data"), PROGRAM_NAME),
4782                                             true,
4783                                             Gtk::MESSAGE_INFO,
4784                                             Gtk::BUTTONS_NONE);
4785                 dialog->present ();
4786                 ARDOUR_UI::instance()->flush_pending ();
4787         }
4788
4789         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4790                 (*t)->first_idle();
4791         }
4792
4793         // first idle adds route children (automation tracks), so we need to redisplay here
4794         _routes->redisplay ();
4795
4796         delete dialog;
4797
4798         _have_idled = true;
4799 }
4800
4801 gboolean
4802 Editor::_idle_resize (gpointer arg)
4803 {
4804         return ((Editor*)arg)->idle_resize ();
4805 }
4806
4807 void
4808 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4809 {
4810         if (resize_idle_id < 0) {
4811                 resize_idle_id = g_idle_add (_idle_resize, this);
4812                 _pending_resize_amount = 0;
4813         }
4814
4815         /* make a note of the smallest resulting height, so that we can clamp the
4816            lower limit at TimeAxisView::hSmall */
4817
4818         int32_t min_resulting = INT32_MAX;
4819
4820         _pending_resize_amount += h;
4821         _pending_resize_view = view;
4822
4823         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4824
4825         if (selection->tracks.contains (_pending_resize_view)) {
4826                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4827                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4828                 }
4829         }
4830
4831         if (min_resulting < 0) {
4832                 min_resulting = 0;
4833         }
4834
4835         /* clamp */
4836         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4837                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4838         }
4839 }
4840
4841 /** Handle pending resizing of tracks */
4842 bool
4843 Editor::idle_resize ()
4844 {
4845         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4846
4847         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4848             selection->tracks.contains (_pending_resize_view)) {
4849
4850                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4851                         if (*i != _pending_resize_view) {
4852                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4853                         }
4854                 }
4855         }
4856
4857         _pending_resize_amount = 0;
4858         flush_canvas ();
4859         _group_tabs->set_dirty ();
4860         resize_idle_id = -1;
4861
4862         return false;
4863 }
4864
4865 void
4866 Editor::located ()
4867 {
4868         ENSURE_GUI_THREAD (*this, &Editor::located);
4869
4870         playhead_cursor->set_position (_session->audible_frame ());
4871         if (_follow_playhead && !_pending_initial_locate) {
4872                 reset_x_origin_to_follow_playhead ();
4873         }
4874
4875         _pending_locate_request = false;
4876         _pending_initial_locate = false;
4877 }
4878
4879 void
4880 Editor::region_view_added (RegionView *)
4881 {
4882         _summary->set_dirty ();
4883 }
4884
4885 void
4886 Editor::region_view_removed ()
4887 {
4888         _summary->set_dirty ();
4889 }
4890
4891 TimeAxisView*
4892 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4893 {
4894         TrackViewList::const_iterator j = track_views.begin ();
4895         while (j != track_views.end()) {
4896                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4897                 if (rtv && rtv->route() == r) {
4898                         return rtv;
4899                 }
4900                 ++j;
4901         }
4902
4903         return 0;
4904 }
4905
4906
4907 TrackViewList
4908 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4909 {
4910         TrackViewList t;
4911
4912         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4913                 TimeAxisView* tv = axis_view_from_route (*i);
4914                 if (tv) {
4915                         t.push_back (tv);
4916                 }
4917         }
4918
4919         return t;
4920 }
4921
4922
4923 void
4924 Editor::handle_new_route (RouteList& routes)
4925 {
4926         ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4927
4928         RouteTimeAxisView *rtv;
4929         list<RouteTimeAxisView*> new_views;
4930
4931         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4932                 boost::shared_ptr<Route> route = (*x);
4933
4934                 if (route->is_hidden() || route->is_monitor()) {
4935                         continue;
4936                 }
4937
4938                 DataType dt = route->input()->default_type();
4939
4940                 if (dt == ARDOUR::DataType::AUDIO) {
4941                         rtv = new AudioTimeAxisView (*this, _session, route, *track_canvas);
4942                 } else if (dt == ARDOUR::DataType::MIDI) {
4943                         rtv = new MidiTimeAxisView (*this, _session, route, *track_canvas);
4944                 } else {
4945                         throw unknown_type();
4946                 }
4947
4948                 new_views.push_back (rtv);
4949                 track_views.push_back (rtv);
4950
4951                 rtv->effective_gain_display ();
4952
4953                 if (internal_editing()) {
4954                         rtv->enter_internal_edit_mode ();
4955                 } else {
4956                         rtv->leave_internal_edit_mode ();
4957                 }
4958
4959                 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4960                 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4961         }
4962
4963         _routes->routes_added (new_views);
4964         _summary->routes_added (new_views);
4965
4966         if (show_editor_mixer_when_tracks_arrive) {
4967                 show_editor_mixer (true);
4968         }
4969
4970         editor_list_button.set_sensitive (true);
4971 }
4972
4973 void
4974 Editor::timeaxisview_deleted (TimeAxisView *tv)
4975 {
4976         if (_session && _session->deletion_in_progress()) {
4977                 /* the situation is under control */
4978                 return;
4979         }
4980
4981         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4982
4983         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4984         
4985         _routes->route_removed (tv);
4986
4987         if (tv == entered_track) {
4988                 entered_track = 0;
4989         }
4990
4991         TimeAxisView::Children c = tv->get_child_list ();
4992         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4993                 if (entered_track == i->get()) {
4994                         entered_track = 0;
4995                 }
4996         }
4997
4998         /* remove it from the list of track views */
4999
5000         TrackViewList::iterator i;
5001
5002         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5003                 i = track_views.erase (i);
5004         }
5005
5006         /* update whatever the current mixer strip is displaying, if revelant */
5007
5008         boost::shared_ptr<Route> route;
5009
5010         if (rtav) {
5011                 route = rtav->route ();
5012         } 
5013
5014         if (current_mixer_strip && current_mixer_strip->route() == route) {
5015
5016                 TimeAxisView* next_tv;
5017
5018                 if (track_views.empty()) {
5019                         next_tv = 0;
5020                 } else if (i == track_views.end()) {
5021                         next_tv = track_views.front();
5022                 } else {
5023                         next_tv = (*i);
5024                 }
5025                 
5026                 
5027                 if (next_tv) {
5028                         set_selected_mixer_strip (*next_tv);
5029                 } else {
5030                         /* make the editor mixer strip go away setting the
5031                          * button to inactive (which also unticks the menu option)
5032                          */
5033                         
5034                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5035                 }
5036         } 
5037 }
5038
5039 void
5040 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5041 {
5042         if (apply_to_selection) {
5043                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5044
5045                         TrackSelection::iterator j = i;
5046                         ++j;
5047                         
5048                         hide_track_in_display (*i, false);
5049                         
5050                         i = j;
5051                 }
5052         } else {
5053                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5054                 
5055                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5056                         // this will hide the mixer strip
5057                         set_selected_mixer_strip (*tv);
5058                 }
5059                 
5060                 _routes->hide_track_in_display (*tv);
5061         }
5062 }
5063
5064 bool
5065 Editor::sync_track_view_list_and_routes ()
5066 {
5067         track_views = TrackViewList (_routes->views ());
5068
5069         _summary->set_dirty ();
5070         _group_tabs->set_dirty ();
5071
5072         return false; // do not call again (until needed)
5073 }
5074
5075 void
5076 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5077 {
5078         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5079                 theslot (**i);
5080         }
5081 }
5082
5083 /** Find a RouteTimeAxisView by the ID of its route */
5084 RouteTimeAxisView*
5085 Editor::get_route_view_by_route_id (PBD::ID& id) const
5086 {
5087         RouteTimeAxisView* v;
5088
5089         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5090                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5091                         if(v->route()->id() == id) {
5092                                 return v;
5093                         }
5094                 }
5095         }
5096
5097         return 0;
5098 }
5099
5100 void
5101 Editor::fit_route_group (RouteGroup *g)
5102 {
5103         TrackViewList ts = axis_views_from_routes (g->route_list ());
5104         fit_tracks (ts);
5105 }
5106
5107 void
5108 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5109 {
5110         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5111
5112         if (r == 0) {
5113                 _session->cancel_audition ();
5114                 return;
5115         }
5116
5117         if (_session->is_auditioning()) {
5118                 _session->cancel_audition ();
5119                 if (r == last_audition_region) {
5120                         return;
5121                 }
5122         }
5123
5124         _session->audition_region (r);
5125         last_audition_region = r;
5126 }
5127
5128
5129 void
5130 Editor::hide_a_region (boost::shared_ptr<Region> r)
5131 {
5132         r->set_hidden (true);
5133 }
5134
5135 void
5136 Editor::show_a_region (boost::shared_ptr<Region> r)
5137 {
5138         r->set_hidden (false);
5139 }
5140
5141 void
5142 Editor::audition_region_from_region_list ()
5143 {
5144         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5145 }
5146
5147 void
5148 Editor::hide_region_from_region_list ()
5149 {
5150         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5151 }
5152
5153 void
5154 Editor::show_region_in_region_list ()
5155 {
5156         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5157 }
5158
5159 void
5160 Editor::step_edit_status_change (bool yn)
5161 {
5162         if (yn) {
5163                 start_step_editing ();
5164         } else {
5165                 stop_step_editing ();
5166         }
5167 }
5168
5169 void
5170 Editor::start_step_editing ()
5171 {
5172         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5173 }
5174
5175 void
5176 Editor::stop_step_editing ()
5177 {
5178         step_edit_connection.disconnect ();
5179 }
5180
5181 bool
5182 Editor::check_step_edit ()
5183 {
5184         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5185                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5186                 if (mtv) {
5187                         mtv->check_step_edit ();
5188                 }
5189         }
5190
5191         return true; // do it again, till we stop
5192 }
5193
5194 bool
5195 Editor::scroll_press (Direction dir)
5196 {
5197         ++_scroll_callbacks;
5198         
5199         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5200                 /* delay the first auto-repeat */
5201                 return true;
5202         }
5203
5204         switch (dir) {
5205         case LEFT:
5206                 scroll_backward (1);
5207                 break;
5208
5209         case RIGHT:
5210                 scroll_forward (1);
5211                 break;
5212
5213         case UP:
5214                 scroll_tracks_up_line ();
5215                 break;
5216
5217         case DOWN:
5218                 scroll_tracks_down_line ();
5219                 break;
5220         }
5221
5222         /* do hacky auto-repeat */
5223         if (!_scroll_connection.connected ()) {
5224
5225                 _scroll_connection = Glib::signal_timeout().connect (
5226                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5227                         );
5228                 
5229                 _scroll_callbacks = 0;
5230         }
5231
5232         return true;
5233 }
5234
5235 void
5236 Editor::scroll_release ()
5237 {
5238         _scroll_connection.disconnect ();
5239 }
5240
5241 /** Queue a change for the Editor viewport x origin to follow the playhead */
5242 void
5243 Editor::reset_x_origin_to_follow_playhead ()
5244 {
5245         framepos_t const frame = playhead_cursor->current_frame;
5246
5247         if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5248
5249                 if (_session->transport_speed() < 0) {
5250                         
5251                         if (frame > (current_page_frames() / 2)) {
5252                                 center_screen (frame-(current_page_frames()/2));
5253                         } else {
5254                                 center_screen (current_page_frames()/2);
5255                         }
5256                         
5257                 } else {
5258                                                 
5259                         if (frame < leftmost_frame) {
5260                                 /* moving left */
5261                                 framepos_t l = 0;
5262                                 if (_session->transport_rolling()) {
5263                                         /* rolling; end up with the playhead at the right of the page */
5264                                         l = frame - current_page_frames ();
5265                                 } else {
5266                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5267                                         l = frame - (3 * current_page_frames() / 4);
5268                                 }
5269                                 
5270                                 if (l < 0) {
5271                                         l = 0;
5272                                 }
5273                                 
5274                                 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5275                         } else {
5276                                 /* moving right */
5277                                 if (_session->transport_rolling()) {
5278                                         /* rolling: end up with the playhead on the left of the page */
5279                                         center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ());
5280                                 } else {
5281                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5282                                         center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ());
5283                                 }
5284                         }
5285                 }
5286         }
5287 }
5288
5289 void
5290 Editor::super_rapid_screen_update ()
5291 {
5292         if (!_session || !_session->engine().running()) {
5293                 return;
5294         }
5295
5296         /* METERING / MIXER STRIPS */
5297
5298         /* update track meters, if required */
5299         if (is_mapped() && meters_running) {
5300                 RouteTimeAxisView* rtv;
5301                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5302                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5303                                 rtv->fast_update ();
5304                         }
5305                 }
5306         }
5307
5308         /* and any current mixer strip */
5309         if (current_mixer_strip) {
5310                 current_mixer_strip->fast_update ();
5311         }
5312
5313         /* PLAYHEAD AND VIEWPORT */
5314
5315         framepos_t const frame = _session->audible_frame();
5316
5317         /* There are a few reasons why we might not update the playhead / viewport stuff:
5318          *
5319          * 1.  we don't update things when there's a pending locate request, otherwise
5320          *     when the editor requests a locate there is a chance that this method
5321          *     will move the playhead before the locate request is processed, causing
5322          *     a visual glitch.
5323          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5324          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5325          */
5326
5327         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5328
5329                 last_update_frame = frame;
5330
5331                 if (!_dragging_playhead) {
5332                         playhead_cursor->set_position (frame);
5333                 }
5334
5335                 if (!_stationary_playhead) {
5336
5337                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5338                                 reset_x_origin_to_follow_playhead ();
5339                         }
5340
5341                 } else {
5342                         
5343                         /* don't do continuous scroll till the new position is in the rightmost quarter of the
5344                            editor canvas
5345                         */
5346 #if 0                        
5347                         // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code                         
5348                         double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5349                         if (target <= 0.0) {
5350                                 target = 0.0;
5351                         }
5352                         if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5353                                 target = (target * 0.15) + (current * 0.85);
5354                         } else {
5355                                 /* relax */
5356                         }
5357                         
5358                         current = target;
5359                         set_horizontal_position (current);
5360 #endif
5361                 }
5362                 
5363         }
5364 }
5365
5366
5367 void
5368 Editor::session_going_away ()
5369 {
5370         _have_idled = false;
5371
5372         _session_connections.drop_connections ();
5373
5374         super_rapid_screen_update_connection.disconnect ();
5375         
5376         selection->clear ();
5377         cut_buffer->clear ();
5378
5379         clicked_regionview = 0;
5380         clicked_axisview = 0;
5381         clicked_routeview = 0;
5382         clicked_crossfadeview = 0;
5383         entered_regionview = 0;
5384         entered_track = 0;
5385         last_update_frame = 0;
5386         _drags->abort ();
5387
5388         playhead_cursor->canvas_item.hide ();
5389
5390         /* rip everything out of the list displays */
5391
5392         _regions->clear ();
5393         _routes->clear ();
5394         _route_groups->clear ();
5395
5396         /* do this first so that deleting a track doesn't reset cms to null
5397            and thus cause a leak.
5398         */
5399
5400         if (current_mixer_strip) {
5401                 if (current_mixer_strip->get_parent() != 0) {
5402                         global_hpacker.remove (*current_mixer_strip);
5403                 }
5404                 delete current_mixer_strip;
5405                 current_mixer_strip = 0;
5406         }
5407
5408         /* delete all trackviews */
5409
5410         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5411                 delete *i;
5412         }
5413         track_views.clear ();
5414
5415         zoom_range_clock.set_session (0);
5416         nudge_clock.set_session (0);
5417
5418         editor_list_button.set_active(false);
5419         editor_list_button.set_sensitive(false);
5420
5421         /* clear tempo/meter rulers */
5422         remove_metric_marks ();
5423         hide_measures ();
5424         clear_marker_display ();
5425
5426         delete current_bbt_points;
5427         current_bbt_points = 0;
5428
5429         /* get rid of any existing editor mixer strip */
5430
5431         WindowTitle title(Glib::get_application_name());
5432         title += _("Editor");
5433
5434         set_title (title.get_string());
5435
5436         SessionHandlePtr::session_going_away ();
5437 }
5438
5439
5440 void
5441 Editor::show_editor_list (bool yn)
5442 {
5443         if (yn) {
5444                 _the_notebook.show ();
5445         } else {
5446                 _the_notebook.hide ();
5447         }
5448 }
5449
5450 void
5451 Editor::change_region_layering_order ()
5452 {
5453         framepos_t const position = get_preferred_edit_position ();
5454         
5455         if (!clicked_routeview) {
5456                 if (layering_order_editor) {
5457                         layering_order_editor->hide ();
5458                 }
5459                 return;
5460         }
5461
5462         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5463
5464         if (!track) {
5465                 return;
5466         }
5467
5468         boost::shared_ptr<Playlist> pl = track->playlist();
5469
5470         if (!pl) {
5471                 return;
5472         }
5473                 
5474         if (layering_order_editor == 0) {
5475                 layering_order_editor = new RegionLayeringOrderEditor(*this);
5476         }
5477
5478         layering_order_editor->set_context (clicked_routeview->name(), _session, pl, position);
5479         layering_order_editor->maybe_present ();
5480 }
5481
5482 void
5483 Editor::update_region_layering_order_editor ()
5484 {
5485         if (layering_order_editor && layering_order_editor->is_visible ()) {
5486                 change_region_layering_order ();
5487         }
5488 }
5489
5490 void
5491 Editor::setup_fade_images ()
5492 {
5493         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5494         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5495         _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5496         _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5497         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5498
5499         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5500         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5501         _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5502         _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5503         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5504 }
5505
5506
5507 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5508 Gtk::MenuItem&
5509 Editor::action_menu_item (std::string const & name)
5510 {
5511         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5512         assert (a);
5513         
5514         return *manage (a->create_menu_item ());
5515 }
5516
5517 void
5518 Editor::resize_text_widgets ()
5519 {
5520         set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_FUDGE+10, 15);
5521         set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_FUDGE+10, 15);
5522         set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_FUDGE+10, 15);
5523         set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_FUDGE+10, 15);
5524         set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_FUDGE+10, 15);
5525 }
5526         
5527 void
5528 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5529 {
5530         EventBox* b = manage (new EventBox);
5531         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5532         Label* l = manage (new Label (name));
5533         l->set_angle (-90);
5534         b->add (*l);
5535         b->show_all ();
5536         _the_notebook.append_page (widget, *b);
5537 }
5538
5539 bool
5540 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5541 {
5542         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5543                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5544         }
5545
5546         if (ev->type == GDK_2BUTTON_PRESS) {
5547
5548                 /* double-click on a notebook tab shrinks or expands the notebook */
5549
5550                 if (_notebook_shrunk) {
5551                         edit_pane.set_position (pre_maximal_horizontal_pane_position);
5552                         _notebook_shrunk = false;
5553                 } else {
5554                         pre_maximal_horizontal_pane_position = edit_pane.get_position ();
5555                         edit_pane.set_position (edit_pane.get_position() + page->get_width());
5556                         _notebook_shrunk = true;
5557                 }
5558         }
5559
5560         return true;
5561 }
5562