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