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