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