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