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