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