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