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