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