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