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