2 Copyright (C) 2000-2009 Paul Davis
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.
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.
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.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
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.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
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"
48 #include <glibmm/miscutils.h>
49 #include <gtkmm/image.h>
50 #include <gdkmm/color.h>
51 #include <gdkmm/bitmap.h>
53 #include "gtkmm2ext/bindings.h"
54 #include "gtkmm2ext/grouped_buttons.h"
55 #include "gtkmm2ext/gtk_ui.h"
56 #include "gtkmm2ext/tearoff.h"
57 #include "gtkmm2ext/utils.h"
58 #include "gtkmm2ext/window_title.h"
59 #include "gtkmm2ext/choice.h"
60 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
62 #include "ardour/audio_track.h"
63 #include "ardour/audioengine.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/profile.h"
67 #include "ardour/route_group.h"
68 #include "ardour/session_playlists.h"
69 #include "ardour/tempo.h"
70 #include "ardour/utils.h"
72 #include "control_protocol/control_protocol.h"
76 #include "analysis_window.h"
77 #include "audio_clock.h"
78 #include "audio_region_view.h"
79 #include "audio_streamview.h"
80 #include "audio_time_axis.h"
81 #include "automation_time_axis.h"
82 #include "bundle_manager.h"
83 #include "canvas-noevent-text.h"
84 #include "canvas_impl.h"
85 #include "crossfade_edit.h"
89 #include "editor_cursors.h"
90 #include "editor_drag.h"
91 #include "editor_group_tabs.h"
92 #include "editor_locations.h"
93 #include "editor_regions.h"
94 #include "editor_route_groups.h"
95 #include "editor_routes.h"
96 #include "editor_snapshots.h"
97 #include "editor_summary.h"
98 #include "global_port_matrix.h"
99 #include "gui_object.h"
100 #include "gui_thread.h"
101 #include "keyboard.h"
103 #include "midi_time_axis.h"
104 #include "mixer_strip.h"
105 #include "mixer_ui.h"
106 #include "mouse_cursors.h"
107 #include "playlist_selector.h"
108 #include "public_editor.h"
109 #include "region_layering_order_editor.h"
110 #include "rgb_macros.h"
111 #include "rhythm_ferret.h"
112 #include "selection.h"
114 #include "simpleline.h"
115 #include "tempo_lines.h"
116 #include "time_axis_view.h"
122 #include "imageframe_socket_handler.h"
126 using namespace ARDOUR;
129 using namespace Glib;
130 using namespace Gtkmm2ext;
131 using namespace Editing;
133 using PBD::internationalize;
135 using Gtkmm2ext::Keyboard;
137 const double Editor::timebar_height = 15.0;
139 static const gchar *_snap_type_strings[] = {
141 N_("Timecode Frames"),
142 N_("Timecode Seconds"),
143 N_("Timecode Minutes"),
173 static const gchar *_snap_mode_strings[] = {
180 static const gchar *_edit_point_strings[] = {
187 static const gchar *_zoom_focus_strings[] = {
197 #ifdef USE_RUBBERBAND
198 static const gchar *_rb_opt_strings[] = {
201 N_("Balanced multitimbral mixture"),
202 N_("Unpitched percussion with stable notes"),
203 N_("Crisp monophonic instrumental"),
204 N_("Unpitched solo percussion"),
205 N_("Resample without preserving pitch"),
211 pane_size_watcher (Paned* pane)
213 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
217 Quartz: impossible to access
219 so stop that by preventing it from ever getting too narrow. 35
220 pixels is basically a rough guess at the tab width.
225 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
227 gint pos = pane->get_position ();
229 if (pos > max_width_of_lhs) {
230 pane->set_position (max_width_of_lhs);
235 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
237 /* time display buttons */
238 , minsec_label (_("Mins:Secs"))
239 , bbt_label (_("Bars:Beats"))
240 , timecode_label (_("Timecode"))
241 , samples_label (_("Samples"))
242 , tempo_label (_("Tempo"))
243 , meter_label (_("Meter"))
244 , mark_label (_("Location Markers"))
245 , range_mark_label (_("Range Markers"))
246 , transport_mark_label (_("Loop/Punch Ranges"))
247 , cd_mark_label (_("CD Markers"))
248 , edit_packer (4, 4, true)
250 /* the values here don't matter: layout widgets
251 reset them as needed.
254 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
256 /* tool bar related */
258 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
260 , toolbar_selection_clock_table (2,3)
262 , automation_mode_button (_("mode"))
264 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
267 , image_socket_listener(0)
272 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
273 , meters_running(false)
274 , _pending_locate_request (false)
275 , _pending_initial_locate (false)
276 , _last_cut_copy_source_track (0)
278 , _region_selection_change_updates_region_list (true)
279 , _following_mixer_selection (false)
280 , _control_point_toggled_on_press (false)
281 , _stepping_axis_view (0)
285 /* we are a singleton */
287 PublicEditor::_instance = this;
291 selection = new Selection (this);
292 cut_buffer = new Selection (this);
294 clicked_regionview = 0;
295 clicked_axisview = 0;
296 clicked_routeview = 0;
297 clicked_control_point = 0;
298 last_update_frame = 0;
299 pre_press_cursor = 0;
300 _drags = new DragManager (this);
301 current_mixer_strip = 0;
304 snap_type_strings = I18N (_snap_type_strings);
305 snap_mode_strings = I18N (_snap_mode_strings);
306 zoom_focus_strings = I18N (_zoom_focus_strings);
307 edit_point_strings = I18N (_edit_point_strings);
308 #ifdef USE_RUBBERBAND
309 rb_opt_strings = I18N (_rb_opt_strings);
313 snap_threshold = 5.0;
314 bbt_beat_subdivision = 4;
317 last_autoscroll_x = 0;
318 last_autoscroll_y = 0;
319 autoscroll_active = false;
320 autoscroll_timeout_tag = -1;
325 current_interthread_info = 0;
326 _show_measures = true;
328 show_gain_after_trim = false;
330 have_pending_keyboard_selection = false;
331 _follow_playhead = true;
332 _stationary_playhead = false;
333 editor_ruler_menu = 0;
334 no_ruler_shown_update = false;
336 range_marker_menu = 0;
337 marker_menu_item = 0;
338 tempo_or_meter_marker_menu = 0;
339 transport_marker_menu = 0;
340 new_transport_marker_menu = 0;
341 editor_mixer_strip_width = Wide;
342 show_editor_mixer_when_tracks_arrive = false;
343 region_edit_menu_split_multichannel_item = 0;
344 region_edit_menu_split_item = 0;
347 current_stepping_trackview = 0;
349 entered_regionview = 0;
351 clear_entered_track = false;
354 button_release_can_deselect = true;
355 _dragging_playhead = false;
356 _dragging_edit_point = false;
357 select_new_marker = false;
359 layering_order_editor = 0;
360 no_save_visual = false;
362 within_track_canvas = false;
364 scrubbing_direction = 0;
368 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
369 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
370 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
371 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
372 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
374 _edit_point = EditAtMouse;
375 _internal_editing = false;
376 current_canvas_cursor = 0;
378 frames_per_unit = 2048; /* too early to use reset_zoom () */
380 _scroll_callbacks = 0;
382 zoom_focus = ZoomFocusLeft;
383 set_zoom_focus (ZoomFocusLeft);
384 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
386 bbt_label.set_name ("EditorTimeButton");
387 bbt_label.set_size_request (-1, (int)timebar_height);
388 bbt_label.set_alignment (1.0, 0.5);
389 bbt_label.set_padding (5,0);
391 bbt_label.set_no_show_all();
392 minsec_label.set_name ("EditorTimeButton");
393 minsec_label.set_size_request (-1, (int)timebar_height);
394 minsec_label.set_alignment (1.0, 0.5);
395 minsec_label.set_padding (5,0);
396 minsec_label.hide ();
397 minsec_label.set_no_show_all();
398 timecode_label.set_name ("EditorTimeButton");
399 timecode_label.set_size_request (-1, (int)timebar_height);
400 timecode_label.set_alignment (1.0, 0.5);
401 timecode_label.set_padding (5,0);
402 timecode_label.hide ();
403 timecode_label.set_no_show_all();
404 samples_label.set_name ("EditorTimeButton");
405 samples_label.set_size_request (-1, (int)timebar_height);
406 samples_label.set_alignment (1.0, 0.5);
407 samples_label.set_padding (5,0);
408 samples_label.hide ();
409 samples_label.set_no_show_all();
411 tempo_label.set_name ("EditorTimeButton");
412 tempo_label.set_size_request (-1, (int)timebar_height);
413 tempo_label.set_alignment (1.0, 0.5);
414 tempo_label.set_padding (5,0);
416 tempo_label.set_no_show_all();
418 meter_label.set_name ("EditorTimeButton");
419 meter_label.set_size_request (-1, (int)timebar_height);
420 meter_label.set_alignment (1.0, 0.5);
421 meter_label.set_padding (5,0);
423 meter_label.set_no_show_all();
425 mark_label.set_name ("EditorTimeButton");
426 mark_label.set_size_request (-1, (int)timebar_height);
427 mark_label.set_alignment (1.0, 0.5);
428 mark_label.set_padding (5,0);
430 mark_label.set_no_show_all();
432 cd_mark_label.set_name ("EditorTimeButton");
433 cd_mark_label.set_size_request (-1, (int)timebar_height);
434 cd_mark_label.set_alignment (1.0, 0.5);
435 cd_mark_label.set_padding (5,0);
436 cd_mark_label.hide();
437 cd_mark_label.set_no_show_all();
439 range_mark_label.set_name ("EditorTimeButton");
440 range_mark_label.set_size_request (-1, (int)timebar_height);
441 range_mark_label.set_alignment (1.0, 0.5);
442 range_mark_label.set_padding (5,0);
443 range_mark_label.hide();
444 range_mark_label.set_no_show_all();
446 transport_mark_label.set_name ("EditorTimeButton");
447 transport_mark_label.set_size_request (-1, (int)timebar_height);
448 transport_mark_label.set_alignment (1.0, 0.5);
449 transport_mark_label.set_padding (5,0);
450 transport_mark_label.hide();
451 transport_mark_label.set_no_show_all();
453 initialize_rulers ();
454 initialize_canvas ();
456 _summary = new EditorSummary (this);
458 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
459 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
461 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
463 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
464 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
466 edit_controls_vbox.set_spacing (0);
467 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
468 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
470 HBox* h = manage (new HBox);
471 _group_tabs = new EditorGroupTabs (this);
472 h->pack_start (*_group_tabs, PACK_SHRINK);
473 h->pack_start (edit_controls_vbox);
474 controls_layout.add (*h);
476 controls_layout.set_name ("EditControlsBase");
477 controls_layout.add_events (Gdk::SCROLL_MASK);
478 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
480 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
481 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
483 _cursors = new MouseCursors;
485 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
486 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
487 0.0, 1.0, 100.0, 1.0));
489 pad_line_1->property_color_rgba() = 0xFF0000FF;
494 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
495 time_canvas_vbox.set_size_request (-1, -1);
497 ruler_label_event_box.add (ruler_label_vbox);
498 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
499 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
501 time_button_event_box.add (time_button_vbox);
502 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
503 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
505 /* these enable us to have a dedicated window (for cursor setting, etc.)
506 for the canvas areas.
509 track_canvas_event_box.add (*track_canvas);
511 time_canvas_event_box.add (time_canvas_vbox);
512 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
514 edit_packer.set_col_spacings (0);
515 edit_packer.set_row_spacings (0);
516 edit_packer.set_homogeneous (false);
517 edit_packer.set_border_width (0);
518 edit_packer.set_name ("EditorWindow");
520 /* labels for the rulers */
521 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
522 /* labels for the marker "tracks" */
523 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
525 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
527 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
529 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
531 bottom_hbox.set_border_width (2);
532 bottom_hbox.set_spacing (3);
534 _route_groups = new EditorRouteGroups (this);
535 _routes = new EditorRoutes (this);
536 _regions = new EditorRegions (this);
537 _snapshots = new EditorSnapshots (this);
538 _locations = new EditorLocations (this);
540 add_notebook_page (_("Regions"), _regions->widget ());
541 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
542 add_notebook_page (_("Snapshots"), _snapshots->widget ());
543 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
544 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
546 _the_notebook.set_show_tabs (true);
547 _the_notebook.set_scrollable (true);
548 _the_notebook.popup_disable ();
549 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
550 _the_notebook.show_all ();
552 _notebook_shrunk = false;
554 editor_summary_pane.pack1(edit_packer);
556 Button* summary_arrows_left_left = manage (new Button);
557 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
558 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
559 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
561 Button* summary_arrows_left_right = manage (new Button);
562 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
563 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
564 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
566 VBox* summary_arrows_left = manage (new VBox);
567 summary_arrows_left->pack_start (*summary_arrows_left_left);
568 summary_arrows_left->pack_start (*summary_arrows_left_right);
570 Button* summary_arrows_right_up = manage (new Button);
571 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
572 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
573 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
575 Button* summary_arrows_right_down = manage (new Button);
576 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
577 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
578 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
580 VBox* summary_arrows_right = manage (new VBox);
581 summary_arrows_right->pack_start (*summary_arrows_right_up);
582 summary_arrows_right->pack_start (*summary_arrows_right_down);
584 Frame* summary_frame = manage (new Frame);
585 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
587 summary_frame->add (*_summary);
588 summary_frame->show ();
590 _summary_hbox.pack_start (*summary_arrows_left, false, false);
591 _summary_hbox.pack_start (*summary_frame, true, true);
592 _summary_hbox.pack_start (*summary_arrows_right, false, false);
594 editor_summary_pane.pack2 (_summary_hbox);
596 edit_pane.pack1 (editor_summary_pane, true, true);
597 edit_pane.pack2 (_the_notebook, false, true);
599 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
601 /* XXX: editor_summary_pane might need similar to the edit_pane */
603 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
605 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
606 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
608 top_hbox.pack_start (toolbar_frame);
610 HBox *hbox = manage (new HBox);
611 hbox->pack_start (edit_pane, true, true);
613 global_vpacker.pack_start (top_hbox, false, false);
614 global_vpacker.pack_start (*hbox, true, true);
616 global_hpacker.pack_start (global_vpacker, true, true);
618 set_name ("EditorWindow");
619 add_accel_group (ActionManager::ui_manager->get_accel_group());
621 status_bar_hpacker.show ();
623 vpacker.pack_end (status_bar_hpacker, false, false);
624 vpacker.pack_end (global_hpacker, true, true);
626 /* register actions now so that set_state() can find them and set toggles/checks etc */
629 /* when we start using our own keybinding system for the editor, this
630 * will be uncommented
636 _snap_type = SnapToBeat;
637 set_snap_to (_snap_type);
638 _snap_mode = SnapOff;
639 set_snap_mode (_snap_mode);
640 set_mouse_mode (MouseObject, true);
641 pre_internal_mouse_mode = MouseObject;
642 pre_internal_snap_type = _snap_type;
643 pre_internal_snap_mode = _snap_mode;
644 internal_snap_type = _snap_type;
645 internal_snap_mode = _snap_mode;
646 set_edit_point_preference (EditAtMouse, true);
648 _playlist_selector = new PlaylistSelector();
649 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
651 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
655 nudge_forward_button.set_name ("zoom button");
656 nudge_forward_button.add_elements (ArdourButton::FlatFace);
657 nudge_forward_button.set_image(::get_icon("nudge_right"));
659 nudge_backward_button.set_name ("zoom button");
660 nudge_backward_button.add_elements (ArdourButton::FlatFace);
661 nudge_backward_button.set_image(::get_icon("nudge_left"));
663 fade_context_menu.set_name ("ArdourContextMenu");
665 /* icons, titles, WM stuff */
667 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
668 Glib::RefPtr<Gdk::Pixbuf> icon;
670 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
671 window_icons.push_back (icon);
673 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
674 window_icons.push_back (icon);
676 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
677 window_icons.push_back (icon);
679 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
680 window_icons.push_back (icon);
682 if (!window_icons.empty()) {
683 // set_icon_list (window_icons);
684 set_default_icon_list (window_icons);
687 WindowTitle title(Glib::get_application_name());
688 title += _("Editor");
689 set_title (title.get_string());
690 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
693 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
695 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
696 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
698 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
700 /* allow external control surfaces/protocols to do various things */
702 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
703 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
704 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
705 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
706 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
707 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
708 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
709 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
710 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
711 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
712 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
713 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
714 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
715 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
717 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
718 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
719 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
720 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
721 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
723 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
725 /* problematic: has to return a value and thus cannot be x-thread */
727 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
729 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
731 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
733 _ignore_region_action = false;
734 _last_region_menu_was_main = false;
735 _popup_region_menu_item = 0;
737 _show_marker_lines = false;
738 _over_region_trim_target = false;
740 /* Button bindings */
742 button_bindings = new Bindings;
744 XMLNode* node = button_settings();
746 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
747 button_bindings->load (**i);
754 setup_fade_images ();
760 if(image_socket_listener) {
761 if(image_socket_listener->is_connected())
763 image_socket_listener->close_connection() ;
766 delete image_socket_listener ;
767 image_socket_listener = 0 ;
771 delete button_bindings;
773 delete _route_groups;
779 Editor::button_settings () const
781 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
782 XMLNode* node = find_named_node (*settings, X_("Buttons"));
785 node = new XMLNode (X_("Buttons"));
792 Editor::add_toplevel_controls (Container& cont)
794 vpacker.pack_start (cont, false, false);
799 Editor::get_smart_mode () const
801 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
805 Editor::catch_vanishing_regionview (RegionView *rv)
807 /* note: the selection will take care of the vanishing
808 audioregionview by itself.
811 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
815 if (clicked_regionview == rv) {
816 clicked_regionview = 0;
819 if (entered_regionview == rv) {
820 set_entered_regionview (0);
823 if (!_all_region_actions_sensitized) {
824 sensitize_all_region_actions (true);
827 _over_region_trim_target = false;
831 Editor::set_entered_regionview (RegionView* rv)
833 if (rv == entered_regionview) {
837 if (entered_regionview) {
838 entered_regionview->exited ();
841 if ((entered_regionview = rv) != 0) {
842 entered_regionview->entered (internal_editing ());
845 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
846 /* This RegionView entry might have changed what region actions
847 are allowed, so sensitize them all in case a key is pressed.
849 sensitize_all_region_actions (true);
854 Editor::set_entered_track (TimeAxisView* tav)
857 entered_track->exited ();
860 if ((entered_track = tav) != 0) {
861 entered_track->entered ();
866 Editor::show_window ()
868 if (!is_visible ()) {
871 /* XXX: this is a bit unfortunate; it would probably
872 be nicer if we could just call show () above rather
873 than needing the show_all ()
876 /* re-hide stuff if necessary */
877 editor_list_button_toggled ();
878 parameter_changed ("show-summary");
879 parameter_changed ("show-group-tabs");
880 parameter_changed ("show-zoom-tools");
882 /* now reset all audio_time_axis heights, because widgets might need
888 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
889 tv = (static_cast<TimeAxisView*>(*i));
893 if (current_mixer_strip) {
894 current_mixer_strip->hide_things ();
895 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
903 Editor::instant_save ()
905 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
910 _session->add_instant_xml(get_state());
912 Config->add_instant_xml(get_state());
917 Editor::zoom_adjustment_changed ()
923 double fpu = zoom_range_clock->current_duration() / _canvas_width;
924 bool clamped = clamp_frames_per_unit (fpu);
927 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
934 Editor::control_vertical_zoom_in_all ()
936 tav_zoom_smooth (false, true);
940 Editor::control_vertical_zoom_out_all ()
942 tav_zoom_smooth (true, true);
946 Editor::control_vertical_zoom_in_selected ()
948 tav_zoom_smooth (false, false);
952 Editor::control_vertical_zoom_out_selected ()
954 tav_zoom_smooth (true, false);
958 Editor::control_view (uint32_t view)
960 goto_visual_state (view);
964 Editor::control_unselect ()
966 selection->clear_tracks ();
970 Editor::control_select (uint32_t rid, Selection::Operation op)
972 /* handles the (static) signal from the ControlProtocol class that
973 * requests setting the selected track to a given RID
980 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
986 TimeAxisView* tav = axis_view_from_route (r);
991 selection->add (tav);
993 case Selection::Toggle:
994 selection->toggle (tav);
996 case Selection::Extend:
999 selection->set (tav);
1003 selection->clear_tracks ();
1008 Editor::control_step_tracks_up ()
1010 scroll_tracks_up_line ();
1014 Editor::control_step_tracks_down ()
1016 scroll_tracks_down_line ();
1020 Editor::control_scroll (float fraction)
1022 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1028 double step = fraction * current_page_frames();
1031 _control_scroll_target is an optional<T>
1033 it acts like a pointer to an framepos_t, with
1034 a operator conversion to boolean to check
1035 that it has a value could possibly use
1036 playhead_cursor->current_frame to store the
1037 value and a boolean in the class to know
1038 when it's out of date
1041 if (!_control_scroll_target) {
1042 _control_scroll_target = _session->transport_frame();
1043 _dragging_playhead = true;
1046 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1047 *_control_scroll_target = 0;
1048 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1049 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1051 *_control_scroll_target += (framepos_t) floor (step);
1054 /* move visuals, we'll catch up with it later */
1056 playhead_cursor->set_position (*_control_scroll_target);
1057 UpdateAllTransportClocks (*_control_scroll_target);
1059 if (*_control_scroll_target > (current_page_frames() / 2)) {
1060 /* try to center PH in window */
1061 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1067 Now we do a timeout to actually bring the session to the right place
1068 according to the playhead. This is to avoid reading disk buffers on every
1069 call to control_scroll, which is driven by ScrollTimeline and therefore
1070 probably by a control surface wheel which can generate lots of events.
1072 /* cancel the existing timeout */
1074 control_scroll_connection.disconnect ();
1076 /* add the next timeout */
1078 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1082 Editor::deferred_control_scroll (framepos_t /*target*/)
1084 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1085 // reset for next stream
1086 _control_scroll_target = boost::none;
1087 _dragging_playhead = false;
1092 Editor::access_action (std::string action_group, std::string action_item)
1098 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1101 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1109 Editor::on_realize ()
1111 Window::on_realize ();
1116 Editor::map_position_change (framepos_t frame)
1118 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1120 if (_session == 0) {
1124 if (_follow_playhead) {
1125 center_screen (frame);
1128 playhead_cursor->set_position (frame);
1132 Editor::center_screen (framepos_t frame)
1134 double page = _canvas_width * frames_per_unit;
1136 /* if we're off the page, then scroll.
1139 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1140 center_screen_internal (frame, page);
1145 Editor::center_screen_internal (framepos_t frame, float page)
1150 frame -= (framepos_t) page;
1155 reset_x_origin (frame);
1160 Editor::update_title ()
1162 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1165 bool dirty = _session->dirty();
1167 string session_name;
1169 if (_session->snap_name() != _session->name()) {
1170 session_name = _session->snap_name();
1172 session_name = _session->name();
1176 session_name = "*" + session_name;
1179 WindowTitle title(session_name);
1180 title += Glib::get_application_name();
1181 set_title (title.get_string());
1183 /* ::session_going_away() will have taken care of it */
1188 Editor::set_session (Session *t)
1190 SessionHandlePtr::set_session (t);
1196 zoom_range_clock->set_session (_session);
1197 _playlist_selector->set_session (_session);
1198 nudge_clock->set_session (_session);
1199 _summary->set_session (_session);
1200 _group_tabs->set_session (_session);
1201 _route_groups->set_session (_session);
1202 _regions->set_session (_session);
1203 _snapshots->set_session (_session);
1204 _routes->set_session (_session);
1205 _locations->set_session (_session);
1207 if (rhythm_ferret) {
1208 rhythm_ferret->set_session (_session);
1211 if (analysis_window) {
1212 analysis_window->set_session (_session);
1216 sfbrowser->set_session (_session);
1219 compute_fixed_ruler_scale ();
1221 /* Make sure we have auto loop and auto punch ranges */
1223 Location* loc = _session->locations()->auto_loop_location();
1225 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1227 if (loc->start() == loc->end()) {
1228 loc->set_end (loc->start() + 1);
1231 _session->locations()->add (loc, false);
1232 _session->set_auto_loop_location (loc);
1235 loc->set_name (_("Loop"));
1238 loc = _session->locations()->auto_punch_location();
1241 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1243 if (loc->start() == loc->end()) {
1244 loc->set_end (loc->start() + 1);
1247 _session->locations()->add (loc, false);
1248 _session->set_auto_punch_location (loc);
1251 loc->set_name (_("Punch"));
1254 refresh_location_display ();
1256 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1257 the selected Marker; this needs the LocationMarker list to be available.
1259 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1260 set_state (*node, Stateful::loading_state_version);
1262 /* catch up with the playhead */
1264 _session->request_locate (playhead_cursor->current_frame);
1265 _pending_initial_locate = true;
1269 /* These signals can all be emitted by a non-GUI thread. Therefore the
1270 handlers for them must not attempt to directly interact with the GUI,
1271 but use Gtkmm2ext::UI::instance()->call_slot();
1274 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1275 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1276 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1277 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1278 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1279 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1280 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1281 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1282 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1283 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1284 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1285 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1286 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1287 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1289 playhead_cursor->canvas_item.show ();
1291 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1292 Config->map_parameters (pc);
1293 _session->config.map_parameters (pc);
1295 restore_ruler_visibility ();
1296 //tempo_map_changed (PropertyChange (0));
1297 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1299 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1300 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1303 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1304 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1307 switch (_snap_type) {
1308 case SnapToRegionStart:
1309 case SnapToRegionEnd:
1310 case SnapToRegionSync:
1311 case SnapToRegionBoundary:
1312 build_region_boundary_cache ();
1319 /* register for undo history */
1320 _session->register_with_memento_command_factory(id(), this);
1322 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1324 start_updating_meters ();
1328 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1330 if (a->get_name() == "RegionMenu") {
1331 /* When the main menu's region menu is opened, we setup the actions so that they look right
1332 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1333 so we resensitize all region actions when the entered regionview or the region selection
1334 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1335 happens after the region context menu is opened. So we set a flag here, too.
1339 sensitize_the_right_region_actions ();
1340 _last_region_menu_was_main = true;
1345 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1347 using namespace Menu_Helpers;
1349 void (Editor::*emf)(FadeShape);
1350 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1353 images = &_xfade_in_images;
1354 emf = &Editor::set_fade_in_shape;
1356 images = &_xfade_out_images;
1357 emf = &Editor::set_fade_out_shape;
1362 _("Linear (for highly correlated material)"),
1363 *(*images)[FadeLinear],
1364 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1368 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1373 *(*images)[FadeConstantPower],
1374 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1377 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1382 *(*images)[FadeSymmetric],
1383 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1387 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1392 *(*images)[FadeSlow],
1393 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1396 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1401 *(*images)[FadeFast],
1402 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1405 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1408 /** Pop up a context menu for when the user clicks on a start crossfade */
1410 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1412 using namespace Menu_Helpers;
1414 MenuList& items (xfade_in_context_menu.items());
1416 if (items.empty()) {
1417 fill_xfade_menu (items, true);
1420 xfade_in_context_menu.popup (button, time);
1423 /** Pop up a context menu for when the user clicks on an end crossfade */
1425 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1427 using namespace Menu_Helpers;
1429 MenuList& items (xfade_out_context_menu.items());
1431 if (items.empty()) {
1432 fill_xfade_menu (items, false);
1435 xfade_out_context_menu.popup (button, time);
1439 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1441 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1443 using namespace Menu_Helpers;
1444 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1447 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1451 MenuList& items (fade_context_menu.items());
1454 switch (item_type) {
1456 case FadeInHandleItem:
1457 if (arv->audio_region()->fade_in_active()) {
1458 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1460 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1463 items.push_back (SeparatorElem());
1465 if (Profile->get_sae()) {
1467 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1468 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1475 *_fade_in_images[FadeLinear],
1476 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1480 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 *_fade_in_images[FadeSlow],
1486 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1489 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1494 *_fade_in_images[FadeFast],
1495 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1498 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1503 *_fade_in_images[FadeSymmetric],
1504 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1509 _("Constant Power"),
1510 *_fade_in_images[FadeConstantPower],
1511 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1514 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1520 case FadeOutHandleItem:
1521 if (arv->audio_region()->fade_out_active()) {
1522 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1524 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1527 items.push_back (SeparatorElem());
1529 if (Profile->get_sae()) {
1530 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1531 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1537 *_fade_out_images[FadeLinear],
1538 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1542 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1547 *_fade_out_images[FadeSlow],
1548 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1551 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1556 *_fade_out_images[FadeFast],
1557 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1560 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1565 *_fade_out_images[FadeSymmetric],
1566 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1571 _("Constant Power"),
1572 *_fade_out_images[FadeConstantPower],
1573 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1576 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1582 fatal << _("programming error: ")
1583 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1588 fade_context_menu.popup (button, time);
1592 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1594 using namespace Menu_Helpers;
1595 Menu* (Editor::*build_menu_function)();
1598 switch (item_type) {
1600 case RegionViewName:
1601 case RegionViewNameHighlight:
1602 case LeftFrameHandle:
1603 case RightFrameHandle:
1604 if (with_selection) {
1605 build_menu_function = &Editor::build_track_selection_context_menu;
1607 build_menu_function = &Editor::build_track_region_context_menu;
1612 if (with_selection) {
1613 build_menu_function = &Editor::build_track_selection_context_menu;
1615 build_menu_function = &Editor::build_track_context_menu;
1620 if (clicked_routeview->track()) {
1621 build_menu_function = &Editor::build_track_context_menu;
1623 build_menu_function = &Editor::build_track_bus_context_menu;
1628 /* probably shouldn't happen but if it does, we don't care */
1632 menu = (this->*build_menu_function)();
1633 menu->set_name ("ArdourContextMenu");
1635 /* now handle specific situations */
1637 switch (item_type) {
1639 case RegionViewName:
1640 case RegionViewNameHighlight:
1641 case LeftFrameHandle:
1642 case RightFrameHandle:
1643 if (!with_selection) {
1644 if (region_edit_menu_split_item) {
1645 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1646 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1648 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1651 if (region_edit_menu_split_multichannel_item) {
1652 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1653 region_edit_menu_split_multichannel_item->set_sensitive (true);
1655 region_edit_menu_split_multichannel_item->set_sensitive (false);
1668 /* probably shouldn't happen but if it does, we don't care */
1672 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1674 /* Bounce to disk */
1676 using namespace Menu_Helpers;
1677 MenuList& edit_items = menu->items();
1679 edit_items.push_back (SeparatorElem());
1681 switch (clicked_routeview->audio_track()->freeze_state()) {
1682 case AudioTrack::NoFreeze:
1683 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1686 case AudioTrack::Frozen:
1687 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1690 case AudioTrack::UnFrozen:
1691 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1697 if (item_type == StreamItem && clicked_routeview) {
1698 clicked_routeview->build_underlay_menu(menu);
1701 /* When the region menu is opened, we setup the actions so that they look right
1704 sensitize_the_right_region_actions ();
1705 _last_region_menu_was_main = false;
1707 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1708 menu->popup (button, time);
1712 Editor::build_track_context_menu ()
1714 using namespace Menu_Helpers;
1716 MenuList& edit_items = track_context_menu.items();
1719 add_dstream_context_items (edit_items);
1720 return &track_context_menu;
1724 Editor::build_track_bus_context_menu ()
1726 using namespace Menu_Helpers;
1728 MenuList& edit_items = track_context_menu.items();
1731 add_bus_context_items (edit_items);
1732 return &track_context_menu;
1736 Editor::build_track_region_context_menu ()
1738 using namespace Menu_Helpers;
1739 MenuList& edit_items = track_region_context_menu.items();
1742 /* we've just cleared the track region context menu, so the menu that these
1743 two items were on will have disappeared; stop them dangling.
1745 region_edit_menu_split_item = 0;
1746 region_edit_menu_split_multichannel_item = 0;
1748 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1751 boost::shared_ptr<Track> tr;
1752 boost::shared_ptr<Playlist> pl;
1754 if ((tr = rtv->track())) {
1755 add_region_context_items (edit_items, tr);
1759 add_dstream_context_items (edit_items);
1761 return &track_region_context_menu;
1765 Editor::analyze_region_selection ()
1767 if (analysis_window == 0) {
1768 analysis_window = new AnalysisWindow();
1771 analysis_window->set_session(_session);
1773 analysis_window->show_all();
1776 analysis_window->set_regionmode();
1777 analysis_window->analyze();
1779 analysis_window->present();
1783 Editor::analyze_range_selection()
1785 if (analysis_window == 0) {
1786 analysis_window = new AnalysisWindow();
1789 analysis_window->set_session(_session);
1791 analysis_window->show_all();
1794 analysis_window->set_rangemode();
1795 analysis_window->analyze();
1797 analysis_window->present();
1801 Editor::build_track_selection_context_menu ()
1803 using namespace Menu_Helpers;
1804 MenuList& edit_items = track_selection_context_menu.items();
1805 edit_items.clear ();
1807 add_selection_context_items (edit_items);
1808 // edit_items.push_back (SeparatorElem());
1809 // add_dstream_context_items (edit_items);
1811 return &track_selection_context_menu;
1815 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1817 using namespace Menu_Helpers;
1819 /* OK, stick the region submenu at the top of the list, and then add
1823 RegionSelection rs = get_regions_from_selection_and_entered ();
1825 string::size_type pos = 0;
1826 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1828 /* we have to hack up the region name because "_" has a special
1829 meaning for menu titles.
1832 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1833 menu_item_name.replace (pos, 1, "__");
1837 if (_popup_region_menu_item == 0) {
1838 _popup_region_menu_item = new MenuItem (menu_item_name);
1839 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1840 _popup_region_menu_item->show ();
1842 _popup_region_menu_item->set_label (menu_item_name);
1845 const framepos_t position = get_preferred_edit_position (false, true);
1847 edit_items.push_back (*_popup_region_menu_item);
1848 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1849 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1851 edit_items.push_back (SeparatorElem());
1854 /** Add context menu items relevant to selection ranges.
1855 * @param edit_items List to add the items to.
1858 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1860 using namespace Menu_Helpers;
1862 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1863 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1865 edit_items.push_back (SeparatorElem());
1866 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1868 edit_items.push_back (SeparatorElem());
1870 edit_items.push_back (
1872 _("Move Range Start to Previous Region Boundary"),
1873 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1877 edit_items.push_back (
1879 _("Move Range Start to Next Region Boundary"),
1880 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1884 edit_items.push_back (
1886 _("Move Range End to Previous Region Boundary"),
1887 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1891 edit_items.push_back (
1893 _("Move Range End to Next Region Boundary"),
1894 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1898 edit_items.push_back (SeparatorElem());
1899 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1900 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1902 edit_items.push_back (SeparatorElem());
1903 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1905 edit_items.push_back (SeparatorElem());
1906 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1907 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1909 edit_items.push_back (SeparatorElem());
1910 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1912 edit_items.push_back (SeparatorElem());
1913 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1914 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1915 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1917 edit_items.push_back (SeparatorElem());
1918 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1919 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1920 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1921 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1922 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1927 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1929 using namespace Menu_Helpers;
1933 Menu *play_menu = manage (new Menu);
1934 MenuList& play_items = play_menu->items();
1935 play_menu->set_name ("ArdourContextMenu");
1937 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1938 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1939 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1940 play_items.push_back (SeparatorElem());
1941 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1943 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1947 Menu *select_menu = manage (new Menu);
1948 MenuList& select_items = select_menu->items();
1949 select_menu->set_name ("ArdourContextMenu");
1951 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1952 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1953 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1954 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1955 select_items.push_back (SeparatorElem());
1956 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1957 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1958 select_items.push_back (SeparatorElem());
1959 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1960 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1961 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1962 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1963 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1964 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1965 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1967 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1971 Menu *cutnpaste_menu = manage (new Menu);
1972 MenuList& cutnpaste_items = cutnpaste_menu->items();
1973 cutnpaste_menu->set_name ("ArdourContextMenu");
1975 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1976 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1977 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1979 cutnpaste_items.push_back (SeparatorElem());
1981 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1982 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1984 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1986 /* Adding new material */
1988 edit_items.push_back (SeparatorElem());
1989 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1990 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1994 Menu *nudge_menu = manage (new Menu());
1995 MenuList& nudge_items = nudge_menu->items();
1996 nudge_menu->set_name ("ArdourContextMenu");
1998 edit_items.push_back (SeparatorElem());
1999 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2000 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2001 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2002 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2004 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2008 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2010 using namespace Menu_Helpers;
2014 Menu *play_menu = manage (new Menu);
2015 MenuList& play_items = play_menu->items();
2016 play_menu->set_name ("ArdourContextMenu");
2018 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2019 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2020 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2024 Menu *select_menu = manage (new Menu);
2025 MenuList& select_items = select_menu->items();
2026 select_menu->set_name ("ArdourContextMenu");
2028 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2029 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2030 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2031 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2032 select_items.push_back (SeparatorElem());
2033 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2034 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2035 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2036 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 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2042 Menu *cutnpaste_menu = manage (new Menu);
2043 MenuList& cutnpaste_items = cutnpaste_menu->items();
2044 cutnpaste_menu->set_name ("ArdourContextMenu");
2046 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2047 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2048 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2050 Menu *nudge_menu = manage (new Menu());
2051 MenuList& nudge_items = nudge_menu->items();
2052 nudge_menu->set_name ("ArdourContextMenu");
2054 edit_items.push_back (SeparatorElem());
2055 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2056 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2057 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2058 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2060 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2064 Editor::snap_type() const
2070 Editor::snap_mode() const
2076 Editor::set_snap_to (SnapType st)
2078 unsigned int snap_ind = (unsigned int)st;
2082 if (snap_ind > snap_type_strings.size() - 1) {
2084 _snap_type = (SnapType)snap_ind;
2087 string str = snap_type_strings[snap_ind];
2089 if (str != snap_type_selector.get_active_text()) {
2090 snap_type_selector.set_active_text (str);
2095 switch (_snap_type) {
2096 case SnapToBeatDiv128:
2097 case SnapToBeatDiv64:
2098 case SnapToBeatDiv32:
2099 case SnapToBeatDiv28:
2100 case SnapToBeatDiv24:
2101 case SnapToBeatDiv20:
2102 case SnapToBeatDiv16:
2103 case SnapToBeatDiv14:
2104 case SnapToBeatDiv12:
2105 case SnapToBeatDiv10:
2106 case SnapToBeatDiv8:
2107 case SnapToBeatDiv7:
2108 case SnapToBeatDiv6:
2109 case SnapToBeatDiv5:
2110 case SnapToBeatDiv4:
2111 case SnapToBeatDiv3:
2112 case SnapToBeatDiv2: {
2113 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2114 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2116 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2117 current_bbt_points_begin, current_bbt_points_end);
2118 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2119 current_bbt_points_begin, current_bbt_points_end);
2120 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2124 case SnapToRegionStart:
2125 case SnapToRegionEnd:
2126 case SnapToRegionSync:
2127 case SnapToRegionBoundary:
2128 build_region_boundary_cache ();
2136 SnapChanged (); /* EMIT SIGNAL */
2140 Editor::set_snap_mode (SnapMode mode)
2143 string str = snap_mode_strings[(int)mode];
2145 if (str != snap_mode_selector.get_active_text ()) {
2146 snap_mode_selector.set_active_text (str);
2152 Editor::set_edit_point_preference (EditPoint ep, bool force)
2154 bool changed = (_edit_point != ep);
2157 string str = edit_point_strings[(int)ep];
2159 if (str != edit_point_selector.get_active_text ()) {
2160 edit_point_selector.set_active_text (str);
2163 set_canvas_cursor ();
2165 if (!force && !changed) {
2169 const char* action=NULL;
2171 switch (_edit_point) {
2172 case EditAtPlayhead:
2173 action = "edit-at-playhead";
2175 case EditAtSelectedMarker:
2176 action = "edit-at-marker";
2179 action = "edit-at-mouse";
2183 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2185 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2189 bool in_track_canvas;
2191 if (!mouse_frame (foo, in_track_canvas)) {
2192 in_track_canvas = false;
2195 reset_canvas_action_sensitivity (in_track_canvas);
2201 Editor::set_state (const XMLNode& node, int /*version*/)
2203 const XMLProperty* prop;
2210 g.base_width = default_width;
2211 g.base_height = default_height;
2215 if ((geometry = find_named_node (node, "geometry")) != 0) {
2219 if ((prop = geometry->property("x_size")) == 0) {
2220 prop = geometry->property ("x-size");
2223 g.base_width = atoi(prop->value());
2225 if ((prop = geometry->property("y_size")) == 0) {
2226 prop = geometry->property ("y-size");
2229 g.base_height = atoi(prop->value());
2232 if ((prop = geometry->property ("x_pos")) == 0) {
2233 prop = geometry->property ("x-pos");
2236 x = atoi (prop->value());
2239 if ((prop = geometry->property ("y_pos")) == 0) {
2240 prop = geometry->property ("y-pos");
2243 y = atoi (prop->value());
2247 set_default_size (g.base_width, g.base_height);
2250 if (_session && (prop = node.property ("playhead"))) {
2252 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2253 playhead_cursor->set_position (pos);
2255 playhead_cursor->set_position (0);
2258 if ((prop = node.property ("mixer-width"))) {
2259 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2262 if ((prop = node.property ("zoom-focus"))) {
2263 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2266 if ((prop = node.property ("zoom"))) {
2267 reset_zoom (PBD::atof (prop->value()));
2269 reset_zoom (frames_per_unit);
2272 if ((prop = node.property ("snap-to"))) {
2273 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2276 if ((prop = node.property ("snap-mode"))) {
2277 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2280 if ((prop = node.property ("internal-snap-to"))) {
2281 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2284 if ((prop = node.property ("internal-snap-mode"))) {
2285 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2288 if ((prop = node.property ("pre-internal-snap-to"))) {
2289 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2292 if ((prop = node.property ("pre-internal-snap-mode"))) {
2293 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2296 if ((prop = node.property ("mouse-mode"))) {
2297 MouseMode m = str2mousemode(prop->value());
2298 set_mouse_mode (m, true);
2300 set_mouse_mode (MouseObject, true);
2303 if ((prop = node.property ("left-frame")) != 0) {
2305 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2309 reset_x_origin (pos);
2313 if ((prop = node.property ("y-origin")) != 0) {
2314 reset_y_origin (atof (prop->value ()));
2317 if ((prop = node.property ("internal-edit"))) {
2318 bool yn = string_is_affirmative (prop->value());
2319 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2321 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2322 tact->set_active (!yn);
2323 tact->set_active (yn);
2327 if ((prop = node.property ("join-object-range"))) {
2328 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2329 bool yn = string_is_affirmative (prop->value());
2331 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2332 tact->set_active (!yn);
2333 tact->set_active (yn);
2335 set_mouse_mode(mouse_mode, true);
2338 if ((prop = node.property ("edit-point"))) {
2339 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2342 if ((prop = node.property ("show-measures"))) {
2343 bool yn = string_is_affirmative (prop->value());
2344 _show_measures = yn;
2345 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2347 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2348 /* do it twice to force the change */
2349 tact->set_active (!yn);
2350 tact->set_active (yn);
2354 if ((prop = node.property ("follow-playhead"))) {
2355 bool yn = string_is_affirmative (prop->value());
2356 set_follow_playhead (yn);
2357 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2359 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2360 if (tact->get_active() != yn) {
2361 tact->set_active (yn);
2366 if ((prop = node.property ("stationary-playhead"))) {
2367 bool yn = string_is_affirmative (prop->value());
2368 set_stationary_playhead (yn);
2369 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2371 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2372 if (tact->get_active() != yn) {
2373 tact->set_active (yn);
2378 if ((prop = node.property ("region-list-sort-type"))) {
2379 RegionListSortType st;
2380 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2383 if ((prop = node.property ("show-editor-mixer"))) {
2385 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2388 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2389 bool yn = string_is_affirmative (prop->value());
2391 /* do it twice to force the change */
2393 tact->set_active (!yn);
2394 tact->set_active (yn);
2397 if ((prop = node.property ("show-editor-list"))) {
2399 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2402 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2403 bool yn = string_is_affirmative (prop->value());
2405 /* do it twice to force the change */
2407 tact->set_active (!yn);
2408 tact->set_active (yn);
2411 if ((prop = node.property (X_("editor-list-page")))) {
2412 _the_notebook.set_current_page (atoi (prop->value ()));
2415 if ((prop = node.property (X_("show-marker-lines")))) {
2416 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2418 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2419 bool yn = string_is_affirmative (prop->value ());
2421 tact->set_active (!yn);
2422 tact->set_active (yn);
2425 XMLNodeList children = node.children ();
2426 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2427 selection->set_state (**i, Stateful::current_state_version);
2428 _regions->set_state (**i);
2431 if ((prop = node.property ("maximised"))) {
2432 bool yn = string_is_affirmative (prop->value());
2434 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2438 if ((prop = node.property ("nudge-clock-value"))) {
2440 sscanf (prop->value().c_str(), "%" PRId64, &f);
2441 nudge_clock->set (f);
2443 nudge_clock->set_mode (AudioClock::Timecode);
2444 nudge_clock->set (_session->frame_rate() * 5, true);
2451 Editor::get_state ()
2453 XMLNode* node = new XMLNode ("Editor");
2456 id().print (buf, sizeof (buf));
2457 node->add_property ("id", buf);
2459 if (is_realized()) {
2460 Glib::RefPtr<Gdk::Window> win = get_window();
2462 int x, y, width, height;
2463 win->get_root_origin(x, y);
2464 win->get_size(width, height);
2466 XMLNode* geometry = new XMLNode ("geometry");
2468 snprintf(buf, sizeof(buf), "%d", width);
2469 geometry->add_property("x-size", string(buf));
2470 snprintf(buf, sizeof(buf), "%d", height);
2471 geometry->add_property("y-size", string(buf));
2472 snprintf(buf, sizeof(buf), "%d", x);
2473 geometry->add_property("x-pos", string(buf));
2474 snprintf(buf, sizeof(buf), "%d", y);
2475 geometry->add_property("y-pos", string(buf));
2476 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2477 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2478 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2479 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2480 geometry->add_property("edit-vertical-pane-pos", string(buf));
2482 node->add_child_nocopy (*geometry);
2485 maybe_add_mixer_strip_width (*node);
2487 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2488 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2489 node->add_property ("zoom", buf);
2490 node->add_property ("snap-to", enum_2_string (_snap_type));
2491 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2492 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2493 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2494 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2495 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2496 node->add_property ("edit-point", enum_2_string (_edit_point));
2498 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2499 node->add_property ("playhead", buf);
2500 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2501 node->add_property ("left-frame", buf);
2502 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2503 node->add_property ("y-origin", buf);
2505 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2506 node->add_property ("maximised", _maximised ? "yes" : "no");
2507 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2508 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2509 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2510 node->add_property ("mouse-mode", enum2str(mouse_mode));
2511 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2512 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2514 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2516 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2517 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2520 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2522 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2523 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2526 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2527 node->add_property (X_("editor-list-page"), buf);
2529 if (button_bindings) {
2530 XMLNode* bb = new XMLNode (X_("Buttons"));
2531 button_bindings->save (*bb);
2532 node->add_child_nocopy (*bb);
2535 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2537 node->add_child_nocopy (selection->get_state ());
2538 node->add_child_nocopy (_regions->get_state ());
2540 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2541 node->add_property ("nudge-clock-value", buf);
2548 /** @param y y offset from the top of all trackviews.
2549 * @return pair: TimeAxisView that y is over, layer index.
2550 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2551 * in stacked or expanded region display mode, otherwise 0.
2553 std::pair<TimeAxisView *, double>
2554 Editor::trackview_by_y_position (double y)
2556 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2558 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2564 return std::make_pair ( (TimeAxisView *) 0, 0);
2567 /** Snap a position to the grid, if appropriate, taking into account current
2568 * grid settings and also the state of any snap modifier keys that may be pressed.
2569 * @param start Position to snap.
2570 * @param event Event to get current key modifier information from, or 0.
2573 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2575 if (!_session || !event) {
2579 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2580 if (_snap_mode == SnapOff) {
2581 snap_to_internal (start, direction, for_mark);
2584 if (_snap_mode != SnapOff) {
2585 snap_to_internal (start, direction, for_mark);
2591 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2593 if (!_session || _snap_mode == SnapOff) {
2597 snap_to_internal (start, direction, for_mark);
2601 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2603 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2604 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2606 switch (_snap_type) {
2607 case SnapToTimecodeFrame:
2608 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2609 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2611 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2615 case SnapToTimecodeSeconds:
2616 if (_session->config.get_timecode_offset_negative()) {
2617 start += _session->config.get_timecode_offset ();
2619 start -= _session->config.get_timecode_offset ();
2621 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2622 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2624 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2627 if (_session->config.get_timecode_offset_negative()) {
2628 start -= _session->config.get_timecode_offset ();
2630 start += _session->config.get_timecode_offset ();
2634 case SnapToTimecodeMinutes:
2635 if (_session->config.get_timecode_offset_negative()) {
2636 start += _session->config.get_timecode_offset ();
2638 start -= _session->config.get_timecode_offset ();
2640 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2641 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2643 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2645 if (_session->config.get_timecode_offset_negative()) {
2646 start -= _session->config.get_timecode_offset ();
2648 start += _session->config.get_timecode_offset ();
2652 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2658 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2660 const framepos_t one_second = _session->frame_rate();
2661 const framepos_t one_minute = _session->frame_rate() * 60;
2662 framepos_t presnap = start;
2666 switch (_snap_type) {
2667 case SnapToTimecodeFrame:
2668 case SnapToTimecodeSeconds:
2669 case SnapToTimecodeMinutes:
2670 return timecode_snap_to_internal (start, direction, for_mark);
2673 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2674 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2676 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2681 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2682 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2684 start = (framepos_t) floor ((double) start / one_second) * one_second;
2689 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2690 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2692 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2697 start = _session->tempo_map().round_to_bar (start, direction);
2701 start = _session->tempo_map().round_to_beat (start, direction);
2704 case SnapToBeatDiv128:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2707 case SnapToBeatDiv64:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2710 case SnapToBeatDiv32:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2713 case SnapToBeatDiv28:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2716 case SnapToBeatDiv24:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2719 case SnapToBeatDiv20:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2722 case SnapToBeatDiv16:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2725 case SnapToBeatDiv14:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2728 case SnapToBeatDiv12:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2731 case SnapToBeatDiv10:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2734 case SnapToBeatDiv8:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2737 case SnapToBeatDiv7:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2740 case SnapToBeatDiv6:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2743 case SnapToBeatDiv5:
2744 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2746 case SnapToBeatDiv4:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2749 case SnapToBeatDiv3:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2752 case SnapToBeatDiv2:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2761 _session->locations()->marks_either_side (start, before, after);
2763 if (before == max_framepos && after == max_framepos) {
2764 /* No marks to snap to, so just don't snap */
2766 } else if (before == max_framepos) {
2768 } else if (after == max_framepos) {
2770 } else if (before != max_framepos && after != max_framepos) {
2771 /* have before and after */
2772 if ((start - before) < (after - start)) {
2781 case SnapToRegionStart:
2782 case SnapToRegionEnd:
2783 case SnapToRegionSync:
2784 case SnapToRegionBoundary:
2785 if (!region_boundary_cache.empty()) {
2787 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2788 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2790 if (direction > 0) {
2791 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2793 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2796 if (next != region_boundary_cache.begin ()) {
2801 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2802 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2804 if (start > (p + n) / 2) {
2813 switch (_snap_mode) {
2819 if (presnap > start) {
2820 if (presnap > (start + unit_to_frame(snap_threshold))) {
2824 } else if (presnap < start) {
2825 if (presnap < (start - unit_to_frame(snap_threshold))) {
2831 /* handled at entry */
2839 Editor::setup_toolbar ()
2841 HBox* mode_box = manage(new HBox);
2842 mode_box->set_border_width (2);
2843 mode_box->set_spacing(4);
2845 HBox* mouse_mode_box = manage (new HBox);
2846 HBox* mouse_mode_hbox = manage (new HBox);
2847 VBox* mouse_mode_vbox = manage (new VBox);
2848 Alignment* mouse_mode_align = manage (new Alignment);
2850 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2851 // mouse_mode_size_group->add_widget (smart_mode_button);
2852 mouse_mode_size_group->add_widget (mouse_move_button);
2853 mouse_mode_size_group->add_widget (mouse_select_button);
2854 mouse_mode_size_group->add_widget (mouse_zoom_button);
2855 mouse_mode_size_group->add_widget (mouse_gain_button);
2856 mouse_mode_size_group->add_widget (mouse_timefx_button);
2857 mouse_mode_size_group->add_widget (mouse_audition_button);
2858 mouse_mode_size_group->add_widget (mouse_draw_button);
2859 mouse_mode_size_group->add_widget (internal_edit_button);
2861 /* make them just a bit bigger */
2862 mouse_move_button.set_size_request (-1, 30);
2864 mouse_mode_hbox->set_spacing (2);
2866 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2867 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2868 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2869 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2870 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2871 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2872 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2873 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2874 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2876 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2878 mouse_mode_align->add (*mouse_mode_vbox);
2879 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2881 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2883 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2884 if (!Profile->get_sae()) {
2885 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2887 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2889 edit_mode_selector.set_name ("EditModeSelector");
2890 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2891 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2893 mode_box->pack_start (edit_mode_selector, false, false);
2894 mode_box->pack_start (*mouse_mode_box, false, false);
2896 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2897 _mouse_mode_tearoff->set_name ("MouseModeBase");
2898 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2900 if (Profile->get_sae()) {
2901 _mouse_mode_tearoff->set_can_be_torn_off (false);
2904 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2905 &_mouse_mode_tearoff->tearoff_window()));
2906 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2907 &_mouse_mode_tearoff->tearoff_window(), 1));
2908 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2909 &_mouse_mode_tearoff->tearoff_window()));
2910 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2911 &_mouse_mode_tearoff->tearoff_window(), 1));
2915 _zoom_box.set_spacing (2);
2916 _zoom_box.set_border_width (2);
2920 zoom_in_button.set_name ("zoom button");
2921 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2922 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2923 zoom_in_button.set_image(::get_icon ("zoom_in"));
2924 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2925 zoom_in_button.set_related_action (act);
2927 zoom_out_button.set_name ("zoom button");
2928 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2929 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2930 zoom_out_button.set_image(::get_icon ("zoom_out"));
2931 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2932 zoom_out_button.set_related_action (act);
2934 zoom_out_full_button.set_name ("zoom button");
2935 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2936 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2937 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2938 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2939 zoom_out_full_button.set_related_action (act);
2941 zoom_focus_selector.set_name ("ZoomFocusSelector");
2942 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2943 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2945 _zoom_box.pack_start (zoom_out_button, false, false);
2946 _zoom_box.pack_start (zoom_in_button, false, false);
2947 _zoom_box.pack_start (zoom_out_full_button, false, false);
2949 _zoom_box.pack_start (zoom_focus_selector, false, false);
2951 /* Track zoom buttons */
2952 tav_expand_button.set_name ("zoom button");
2953 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2954 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2955 tav_expand_button.set_size_request (-1, 20);
2956 tav_expand_button.set_image(::get_icon ("tav_exp"));
2957 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2958 tav_expand_button.set_related_action (act);
2960 tav_shrink_button.set_name ("zoom button");
2961 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2962 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2963 tav_shrink_button.set_size_request (-1, 20);
2964 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2965 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2966 tav_shrink_button.set_related_action (act);
2968 _zoom_box.pack_start (tav_shrink_button);
2969 _zoom_box.pack_start (tav_expand_button);
2971 _zoom_tearoff = manage (new TearOff (_zoom_box));
2973 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2974 &_zoom_tearoff->tearoff_window()));
2975 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2976 &_zoom_tearoff->tearoff_window(), 0));
2977 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2978 &_zoom_tearoff->tearoff_window()));
2979 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2980 &_zoom_tearoff->tearoff_window(), 0));
2982 snap_box.set_spacing (2);
2983 snap_box.set_border_width (2);
2985 snap_type_selector.set_name ("SnapTypeSelector");
2986 set_popdown_strings (snap_type_selector, snap_type_strings);
2987 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2989 snap_mode_selector.set_name ("SnapModeSelector");
2990 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2991 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2993 edit_point_selector.set_name ("EditPointSelector");
2994 set_popdown_strings (edit_point_selector, edit_point_strings);
2995 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2997 snap_box.pack_start (snap_mode_selector, false, false);
2998 snap_box.pack_start (snap_type_selector, false, false);
2999 snap_box.pack_start (edit_point_selector, false, false);
3003 HBox *nudge_box = manage (new HBox);
3004 nudge_box->set_spacing (2);
3005 nudge_box->set_border_width (2);
3007 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3008 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3010 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3011 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3013 nudge_box->pack_start (nudge_backward_button, false, false);
3014 nudge_box->pack_start (nudge_forward_button, false, false);
3015 nudge_box->pack_start (*nudge_clock, false, false);
3018 /* Pack everything in... */
3020 HBox* hbox = manage (new HBox);
3021 hbox->set_spacing(10);
3023 _tools_tearoff = manage (new TearOff (*hbox));
3024 _tools_tearoff->set_name ("MouseModeBase");
3025 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3027 if (Profile->get_sae()) {
3028 _tools_tearoff->set_can_be_torn_off (false);
3031 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3032 &_tools_tearoff->tearoff_window()));
3033 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3034 &_tools_tearoff->tearoff_window(), 0));
3035 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3036 &_tools_tearoff->tearoff_window()));
3037 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3038 &_tools_tearoff->tearoff_window(), 0));
3040 toolbar_hbox.set_spacing (10);
3041 toolbar_hbox.set_border_width (1);
3043 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3044 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3045 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3047 hbox->pack_start (snap_box, false, false);
3048 if (!Profile->get_small_screen()) {
3049 hbox->pack_start (*nudge_box, false, false);
3051 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3053 hbox->pack_start (panic_box, false, false);
3057 toolbar_base.set_name ("ToolBarBase");
3058 toolbar_base.add (toolbar_hbox);
3060 _toolbar_viewport.add (toolbar_base);
3061 /* stick to the required height but allow width to vary if there's not enough room */
3062 _toolbar_viewport.set_size_request (1, -1);
3064 toolbar_frame.set_shadow_type (SHADOW_OUT);
3065 toolbar_frame.set_name ("BaseFrame");
3066 toolbar_frame.add (_toolbar_viewport);
3070 Editor::setup_tooltips ()
3072 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3073 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3074 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3075 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3076 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3077 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3078 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3079 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3080 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3081 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3082 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3083 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3084 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3085 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3086 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3087 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3088 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3089 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3090 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3091 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3092 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3093 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3094 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3098 Editor::convert_drop_to_paths (
3099 vector<string>& paths,
3100 const RefPtr<Gdk::DragContext>& /*context*/,
3103 const SelectionData& data,
3107 if (_session == 0) {
3111 vector<string> uris = data.get_uris();
3115 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3116 are actually URI lists. So do it by hand.
3119 if (data.get_target() != "text/plain") {
3123 /* Parse the "uri-list" format that Nautilus provides,
3124 where each pathname is delimited by \r\n.
3126 THERE MAY BE NO NULL TERMINATING CHAR!!!
3129 string txt = data.get_text();
3133 p = (const char *) malloc (txt.length() + 1);
3134 txt.copy (const_cast<char *> (p), txt.length(), 0);
3135 const_cast<char*>(p)[txt.length()] = '\0';
3141 while (g_ascii_isspace (*p))
3145 while (*q && (*q != '\n') && (*q != '\r')) {
3152 while (q > p && g_ascii_isspace (*q))
3157 uris.push_back (string (p, q - p + 1));
3161 p = strchr (p, '\n');
3173 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3175 if ((*i).substr (0,7) == "file://") {
3177 string const p = PBD::url_decode (*i);
3179 // scan forward past three slashes
3181 string::size_type slashcnt = 0;
3182 string::size_type n = 0;
3183 string::const_iterator x = p.begin();
3185 while (slashcnt < 3 && x != p.end()) {
3188 } else if (slashcnt == 3) {
3195 if (slashcnt != 3 || x == p.end()) {
3196 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3200 paths.push_back (p.substr (n - 1));
3208 Editor::new_tempo_section ()
3214 Editor::map_transport_state ()
3216 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3218 if (_session && _session->transport_stopped()) {
3219 have_pending_keyboard_selection = false;
3222 update_loop_range_view (true);
3228 Editor::begin_reversible_command (string name)
3231 _session->begin_reversible_command (name);
3236 Editor::begin_reversible_command (GQuark q)
3239 _session->begin_reversible_command (q);
3244 Editor::commit_reversible_command ()
3247 _session->commit_reversible_command ();
3252 Editor::history_changed ()
3256 if (undo_action && _session) {
3257 if (_session->undo_depth() == 0) {
3258 label = S_("Command|Undo");
3260 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3262 undo_action->property_label() = label;
3265 if (redo_action && _session) {
3266 if (_session->redo_depth() == 0) {
3269 label = string_compose(_("Redo (%1)"), _session->next_redo());
3271 redo_action->property_label() = label;
3276 Editor::duplicate_range (bool with_dialog)
3280 RegionSelection rs = get_regions_from_selection_and_entered ();
3282 if ( selection->time.length() == 0 && rs.empty()) {
3288 ArdourDialog win (_("Duplicate"));
3289 Label label (_("Number of duplications:"));
3290 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3291 SpinButton spinner (adjustment, 0.0, 1);
3294 win.get_vbox()->set_spacing (12);
3295 win.get_vbox()->pack_start (hbox);
3296 hbox.set_border_width (6);
3297 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3299 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3300 place, visually. so do this by hand.
3303 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3304 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3305 spinner.grab_focus();
3311 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3312 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3313 win.set_default_response (RESPONSE_ACCEPT);
3315 win.set_position (WIN_POS_MOUSE);
3317 spinner.grab_focus ();
3319 switch (win.run ()) {
3320 case RESPONSE_ACCEPT:
3326 times = adjustment.get_value();
3329 if ((current_mouse_mode() == Editing::MouseRange)) {
3330 if (selection->time.length()) {
3331 duplicate_selection (times);
3333 } else if (get_smart_mode()) {
3334 if (selection->time.length()) {
3335 duplicate_selection (times);
3337 duplicate_some_regions (rs, times);
3339 duplicate_some_regions (rs, times);
3344 Editor::set_edit_mode (EditMode m)
3346 Config->set_edit_mode (m);
3350 Editor::cycle_edit_mode ()
3352 switch (Config->get_edit_mode()) {
3354 if (Profile->get_sae()) {
3355 Config->set_edit_mode (Lock);
3357 Config->set_edit_mode (Splice);
3361 Config->set_edit_mode (Lock);
3364 Config->set_edit_mode (Slide);
3370 Editor::edit_mode_selection_done ()
3372 string s = edit_mode_selector.get_active_text ();
3375 Config->set_edit_mode (string_to_edit_mode (s));
3380 Editor::snap_type_selection_done ()
3382 string choice = snap_type_selector.get_active_text();
3383 SnapType snaptype = SnapToBeat;
3385 if (choice == _("Beats/2")) {
3386 snaptype = SnapToBeatDiv2;
3387 } else if (choice == _("Beats/3")) {
3388 snaptype = SnapToBeatDiv3;
3389 } else if (choice == _("Beats/4")) {
3390 snaptype = SnapToBeatDiv4;
3391 } else if (choice == _("Beats/5")) {
3392 snaptype = SnapToBeatDiv5;
3393 } else if (choice == _("Beats/6")) {
3394 snaptype = SnapToBeatDiv6;
3395 } else if (choice == _("Beats/7")) {
3396 snaptype = SnapToBeatDiv7;
3397 } else if (choice == _("Beats/8")) {
3398 snaptype = SnapToBeatDiv8;
3399 } else if (choice == _("Beats/10")) {
3400 snaptype = SnapToBeatDiv10;
3401 } else if (choice == _("Beats/12")) {
3402 snaptype = SnapToBeatDiv12;
3403 } else if (choice == _("Beats/14")) {
3404 snaptype = SnapToBeatDiv14;
3405 } else if (choice == _("Beats/16")) {
3406 snaptype = SnapToBeatDiv16;
3407 } else if (choice == _("Beats/20")) {
3408 snaptype = SnapToBeatDiv20;
3409 } else if (choice == _("Beats/24")) {
3410 snaptype = SnapToBeatDiv24;
3411 } else if (choice == _("Beats/28")) {
3412 snaptype = SnapToBeatDiv28;
3413 } else if (choice == _("Beats/32")) {
3414 snaptype = SnapToBeatDiv32;
3415 } else if (choice == _("Beats/64")) {
3416 snaptype = SnapToBeatDiv64;
3417 } else if (choice == _("Beats/128")) {
3418 snaptype = SnapToBeatDiv128;
3419 } else if (choice == _("Beats")) {
3420 snaptype = SnapToBeat;
3421 } else if (choice == _("Bars")) {
3422 snaptype = SnapToBar;
3423 } else if (choice == _("Marks")) {
3424 snaptype = SnapToMark;
3425 } else if (choice == _("Region starts")) {
3426 snaptype = SnapToRegionStart;
3427 } else if (choice == _("Region ends")) {
3428 snaptype = SnapToRegionEnd;
3429 } else if (choice == _("Region bounds")) {
3430 snaptype = SnapToRegionBoundary;
3431 } else if (choice == _("Region syncs")) {
3432 snaptype = SnapToRegionSync;
3433 } else if (choice == _("CD Frames")) {
3434 snaptype = SnapToCDFrame;
3435 } else if (choice == _("Timecode Frames")) {
3436 snaptype = SnapToTimecodeFrame;
3437 } else if (choice == _("Timecode Seconds")) {
3438 snaptype = SnapToTimecodeSeconds;
3439 } else if (choice == _("Timecode Minutes")) {
3440 snaptype = SnapToTimecodeMinutes;
3441 } else if (choice == _("Seconds")) {
3442 snaptype = SnapToSeconds;
3443 } else if (choice == _("Minutes")) {
3444 snaptype = SnapToMinutes;
3447 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3449 ract->set_active ();
3454 Editor::snap_mode_selection_done ()
3456 string choice = snap_mode_selector.get_active_text();
3457 SnapMode mode = SnapNormal;
3459 if (choice == _("No Grid")) {
3461 } else if (choice == _("Grid")) {
3463 } else if (choice == _("Magnetic")) {
3464 mode = SnapMagnetic;
3467 RefPtr<RadioAction> ract = snap_mode_action (mode);
3470 ract->set_active (true);
3475 Editor::cycle_edit_point (bool with_marker)
3477 switch (_edit_point) {
3479 set_edit_point_preference (EditAtPlayhead);
3481 case EditAtPlayhead:
3483 set_edit_point_preference (EditAtSelectedMarker);
3485 set_edit_point_preference (EditAtMouse);
3488 case EditAtSelectedMarker:
3489 set_edit_point_preference (EditAtMouse);
3495 Editor::edit_point_selection_done ()
3497 string choice = edit_point_selector.get_active_text();
3498 EditPoint ep = EditAtSelectedMarker;
3500 if (choice == _("Marker")) {
3501 set_edit_point_preference (EditAtSelectedMarker);
3502 } else if (choice == _("Playhead")) {
3503 set_edit_point_preference (EditAtPlayhead);
3505 set_edit_point_preference (EditAtMouse);
3508 RefPtr<RadioAction> ract = edit_point_action (ep);
3511 ract->set_active (true);
3516 Editor::zoom_focus_selection_done ()
3518 string choice = zoom_focus_selector.get_active_text();
3519 ZoomFocus focus_type = ZoomFocusLeft;
3521 if (choice == _("Left")) {
3522 focus_type = ZoomFocusLeft;
3523 } else if (choice == _("Right")) {
3524 focus_type = ZoomFocusRight;
3525 } else if (choice == _("Center")) {
3526 focus_type = ZoomFocusCenter;
3527 } else if (choice == _("Playhead")) {
3528 focus_type = ZoomFocusPlayhead;
3529 } else if (choice == _("Mouse")) {
3530 focus_type = ZoomFocusMouse;
3531 } else if (choice == _("Edit point")) {
3532 focus_type = ZoomFocusEdit;
3535 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3538 ract->set_active ();
3543 Editor::edit_controls_button_release (GdkEventButton* ev)
3545 if (Keyboard::is_context_menu_event (ev)) {
3546 ARDOUR_UI::instance()->add_route (this);
3547 } else if (ev->button == 1) {
3548 selection->clear_tracks ();
3555 Editor::mouse_select_button_release (GdkEventButton* ev)
3557 /* this handles just right-clicks */
3559 if (ev->button != 3) {
3567 Editor::set_zoom_focus (ZoomFocus f)
3569 string str = zoom_focus_strings[(int)f];
3571 if (str != zoom_focus_selector.get_active_text()) {
3572 zoom_focus_selector.set_active_text (str);
3575 if (zoom_focus != f) {
3582 Editor::cycle_zoom_focus ()
3584 switch (zoom_focus) {
3586 set_zoom_focus (ZoomFocusRight);
3588 case ZoomFocusRight:
3589 set_zoom_focus (ZoomFocusCenter);
3591 case ZoomFocusCenter:
3592 set_zoom_focus (ZoomFocusPlayhead);
3594 case ZoomFocusPlayhead:
3595 set_zoom_focus (ZoomFocusMouse);
3597 case ZoomFocusMouse:
3598 set_zoom_focus (ZoomFocusEdit);
3601 set_zoom_focus (ZoomFocusLeft);
3607 Editor::ensure_float (Window& win)
3609 win.set_transient_for (*this);
3613 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3615 /* recover or initialize pane positions. do this here rather than earlier because
3616 we don't want the positions to change the child allocations, which they seem to do.
3622 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3631 XMLNode* geometry = find_named_node (*node, "geometry");
3633 if (which == static_cast<Paned*> (&edit_pane)) {
3635 if (done & Horizontal) {
3639 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3640 _notebook_shrunk = string_is_affirmative (prop->value ());
3643 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3644 /* initial allocation is 90% to canvas, 10% to notebook */
3645 pos = (int) floor (alloc.get_width() * 0.90f);
3646 snprintf (buf, sizeof(buf), "%d", pos);
3648 pos = atoi (prop->value());
3651 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3652 edit_pane.set_position (pos);
3655 done = (Pane) (done | Horizontal);
3657 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3659 if (done & Vertical) {
3663 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3664 /* initial allocation is 90% to canvas, 10% to summary */
3665 pos = (int) floor (alloc.get_height() * 0.90f);
3666 snprintf (buf, sizeof(buf), "%d", pos);
3669 pos = atoi (prop->value());
3672 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3673 editor_summary_pane.set_position (pos);
3676 done = (Pane) (done | Vertical);
3681 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3683 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3684 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3685 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3686 top_hbox.remove (toolbar_frame);
3691 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3693 if (toolbar_frame.get_parent() == 0) {
3694 top_hbox.pack_end (toolbar_frame);
3699 Editor::set_show_measures (bool yn)
3701 if (_show_measures != yn) {
3704 if ((_show_measures = yn) == true) {
3706 tempo_lines->show();
3708 (void) redraw_measures ();
3715 Editor::toggle_follow_playhead ()
3717 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3719 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3720 set_follow_playhead (tact->get_active());
3724 /** @param yn true to follow playhead, otherwise false.
3725 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3728 Editor::set_follow_playhead (bool yn, bool catch_up)
3730 if (_follow_playhead != yn) {
3731 if ((_follow_playhead = yn) == true && catch_up) {
3733 reset_x_origin_to_follow_playhead ();
3740 Editor::toggle_stationary_playhead ()
3742 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3744 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3745 set_stationary_playhead (tact->get_active());
3750 Editor::set_stationary_playhead (bool yn)
3752 if (_stationary_playhead != yn) {
3753 if ((_stationary_playhead = yn) == true) {
3755 // FIXME need a 3.0 equivalent of this 2.X call
3756 // update_current_screen ();
3763 Editor::playlist_selector () const
3765 return *_playlist_selector;
3769 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3773 switch (_snap_type) {
3778 case SnapToBeatDiv128:
3781 case SnapToBeatDiv64:
3784 case SnapToBeatDiv32:
3787 case SnapToBeatDiv28:
3790 case SnapToBeatDiv24:
3793 case SnapToBeatDiv20:
3796 case SnapToBeatDiv16:
3799 case SnapToBeatDiv14:
3802 case SnapToBeatDiv12:
3805 case SnapToBeatDiv10:
3808 case SnapToBeatDiv8:
3811 case SnapToBeatDiv7:
3814 case SnapToBeatDiv6:
3817 case SnapToBeatDiv5:
3820 case SnapToBeatDiv4:
3823 case SnapToBeatDiv3:
3826 case SnapToBeatDiv2:
3832 return _session->tempo_map().meter_at (position).divisions_per_bar();
3837 case SnapToTimecodeFrame:
3838 case SnapToTimecodeSeconds:
3839 case SnapToTimecodeMinutes:
3842 case SnapToRegionStart:
3843 case SnapToRegionEnd:
3844 case SnapToRegionSync:
3845 case SnapToRegionBoundary:
3855 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3859 ret = nudge_clock->current_duration (pos);
3860 next = ret + 1; /* XXXX fix me */
3866 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3868 ArdourDialog dialog (_("Playlist Deletion"));
3869 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3870 "If it is kept, its audio files will not be cleaned.\n"
3871 "If it is deleted, audio files used by it alone will be cleaned."),
3874 dialog.set_position (WIN_POS_CENTER);
3875 dialog.get_vbox()->pack_start (label);
3879 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3880 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3881 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3883 switch (dialog.run ()) {
3884 case RESPONSE_ACCEPT:
3885 /* delete the playlist */
3889 case RESPONSE_REJECT:
3890 /* keep the playlist */
3902 Editor::audio_region_selection_covers (framepos_t where)
3904 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3905 if ((*a)->region()->covers (where)) {
3914 Editor::prepare_for_cleanup ()
3916 cut_buffer->clear_regions ();
3917 cut_buffer->clear_playlists ();
3919 selection->clear_regions ();
3920 selection->clear_playlists ();
3922 _regions->suspend_redisplay ();
3926 Editor::finish_cleanup ()
3928 _regions->resume_redisplay ();
3932 Editor::transport_loop_location()
3935 return _session->locations()->auto_loop_location();
3942 Editor::transport_punch_location()
3945 return _session->locations()->auto_punch_location();
3952 Editor::control_layout_scroll (GdkEventScroll* ev)
3954 if (Keyboard::some_magic_widget_has_focus()) {
3958 switch (ev->direction) {
3960 scroll_tracks_up_line ();
3964 case GDK_SCROLL_DOWN:
3965 scroll_tracks_down_line ();
3969 /* no left/right handling yet */
3977 Editor::session_state_saved (string)
3980 _snapshots->redisplay ();
3984 Editor::update_tearoff_visibility()
3986 bool visible = Config->get_keep_tearoffs();
3987 _mouse_mode_tearoff->set_visible (visible);
3988 _tools_tearoff->set_visible (visible);
3989 _zoom_tearoff->set_visible (visible);
3993 Editor::maximise_editing_space ()
4005 Editor::restore_editing_space ()
4017 * Make new playlists for a given track and also any others that belong
4018 * to the same active route group with the `edit' property.
4023 Editor::new_playlists (TimeAxisView* v)
4025 begin_reversible_command (_("new playlists"));
4026 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4027 _session->playlists->get (playlists);
4028 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4029 commit_reversible_command ();
4033 * Use a copy of the current playlist for a given track and also any others that belong
4034 * to the same active route group with the `edit' property.
4039 Editor::copy_playlists (TimeAxisView* v)
4041 begin_reversible_command (_("copy playlists"));
4042 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4043 _session->playlists->get (playlists);
4044 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4045 commit_reversible_command ();
4048 /** Clear the current playlist for a given track and also any others that belong
4049 * to the same active route group with the `edit' property.
4054 Editor::clear_playlists (TimeAxisView* v)
4056 begin_reversible_command (_("clear playlists"));
4057 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4058 _session->playlists->get (playlists);
4059 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4060 commit_reversible_command ();
4064 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4066 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4070 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4072 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4076 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4078 atv.clear_playlist ();
4082 Editor::on_key_press_event (GdkEventKey* ev)
4084 return key_press_focus_accelerator_handler (*this, ev);
4088 Editor::on_key_release_event (GdkEventKey* ev)
4090 return Gtk::Window::on_key_release_event (ev);
4091 // return key_press_focus_accelerator_handler (*this, ev);
4094 /** Queue up a change to the viewport x origin.
4095 * @param frame New x origin.
4098 Editor::reset_x_origin (framepos_t frame)
4100 pending_visual_change.add (VisualChange::TimeOrigin);
4101 pending_visual_change.time_origin = frame;
4102 ensure_visual_change_idle_handler ();
4106 Editor::reset_y_origin (double y)
4108 pending_visual_change.add (VisualChange::YOrigin);
4109 pending_visual_change.y_origin = y;
4110 ensure_visual_change_idle_handler ();
4114 Editor::reset_zoom (double fpu)
4116 clamp_frames_per_unit (fpu);
4118 if (fpu == frames_per_unit) {
4122 pending_visual_change.add (VisualChange::ZoomLevel);
4123 pending_visual_change.frames_per_unit = fpu;
4124 ensure_visual_change_idle_handler ();
4128 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4130 reset_x_origin (frame);
4133 if (!no_save_visual) {
4134 undo_visual_stack.push_back (current_visual_state(false));
4138 Editor::VisualState::VisualState (bool with_tracks)
4139 : gui_state (with_tracks ? new GUIObjectState : 0)
4143 Editor::VisualState::~VisualState ()
4148 Editor::VisualState*
4149 Editor::current_visual_state (bool with_tracks)
4151 VisualState* vs = new VisualState (with_tracks);
4152 vs->y_position = vertical_adjustment.get_value();
4153 vs->frames_per_unit = frames_per_unit;
4154 vs->leftmost_frame = leftmost_frame;
4155 vs->zoom_focus = zoom_focus;
4158 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4165 Editor::undo_visual_state ()
4167 if (undo_visual_stack.empty()) {
4171 VisualState* vs = undo_visual_stack.back();
4172 undo_visual_stack.pop_back();
4175 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4177 use_visual_state (*vs);
4181 Editor::redo_visual_state ()
4183 if (redo_visual_stack.empty()) {
4187 VisualState* vs = redo_visual_stack.back();
4188 redo_visual_stack.pop_back();
4190 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4192 use_visual_state (*vs);
4196 Editor::swap_visual_state ()
4198 if (undo_visual_stack.empty()) {
4199 redo_visual_state ();
4201 undo_visual_state ();
4206 Editor::use_visual_state (VisualState& vs)
4208 PBD::Unwinder<bool> nsv (no_save_visual, true);
4210 _routes->suspend_redisplay ();
4212 vertical_adjustment.set_value (vs.y_position);
4214 set_zoom_focus (vs.zoom_focus);
4215 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4218 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4220 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4221 (*i)->reset_visual_state ();
4225 _routes->update_visibility ();
4226 _routes->resume_redisplay ();
4229 /** This is the core function that controls the zoom level of the canvas. It is called
4230 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4231 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4234 Editor::set_frames_per_unit (double fpu)
4237 tempo_lines->tempo_map_changed();
4240 frames_per_unit = fpu;
4242 /* convert fpu to frame count */
4244 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4246 if (frames_per_unit != zoom_range_clock->current_duration()) {
4247 zoom_range_clock->set (frames);
4250 bool const showing_time_selection = selection->time.length() > 0;
4252 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4253 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4254 (*i)->reshow_selection (selection->time);
4258 ZoomChanged (); /* EMIT_SIGNAL */
4260 //reset_scrolling_region ();
4262 if (playhead_cursor) {
4263 playhead_cursor->set_position (playhead_cursor->current_frame);
4266 refresh_location_display();
4267 _summary->set_overlays_dirty ();
4269 update_marker_labels ();
4275 Editor::ensure_visual_change_idle_handler ()
4277 if (pending_visual_change.idle_handler_id < 0) {
4278 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4283 Editor::_idle_visual_changer (void* arg)
4285 return static_cast<Editor*>(arg)->idle_visual_changer ();
4289 Editor::idle_visual_changer ()
4291 /* set_horizontal_position() below (and maybe other calls) call
4292 gtk_main_iteration(), so it's possible that a signal will be handled
4293 half-way through this method. If this signal wants an
4294 idle_visual_changer we must schedule another one after this one, so
4295 mark the idle_handler_id as -1 here to allow that. Also make a note
4296 that we are doing the visual change, so that changes in response to
4297 super-rapid-screen-update can be dropped if we are still processing
4301 pending_visual_change.idle_handler_id = -1;
4302 pending_visual_change.being_handled = true;
4304 VisualChange::Type p = pending_visual_change.pending;
4305 pending_visual_change.pending = (VisualChange::Type) 0;
4307 double const last_time_origin = horizontal_position ();
4309 if (p & VisualChange::ZoomLevel) {
4310 set_frames_per_unit (pending_visual_change.frames_per_unit);
4312 compute_fixed_ruler_scale ();
4314 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4315 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4317 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4318 current_bbt_points_begin, current_bbt_points_end);
4319 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4320 current_bbt_points_begin, current_bbt_points_end);
4321 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4323 if (p & VisualChange::TimeOrigin) {
4324 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4326 if (p & VisualChange::YOrigin) {
4327 vertical_adjustment.set_value (pending_visual_change.y_origin);
4330 if (last_time_origin == horizontal_position ()) {
4331 /* changed signal not emitted */
4332 update_fixed_rulers ();
4333 redisplay_tempo (true);
4336 _summary->set_overlays_dirty ();
4338 pending_visual_change.being_handled = false;
4339 return 0; /* this is always a one-shot call */
4342 struct EditorOrderTimeAxisSorter {
4343 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4344 return a->order () < b->order ();
4349 Editor::sort_track_selection (TrackViewList& sel)
4351 EditorOrderTimeAxisSorter cmp;
4356 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4359 framepos_t where = 0;
4360 EditPoint ep = _edit_point;
4362 if (from_context_menu && (ep == EditAtMouse)) {
4363 return event_frame (&context_click_event, 0, 0);
4366 if (entered_marker) {
4367 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4368 return entered_marker->position();
4371 if (ignore_playhead && ep == EditAtPlayhead) {
4372 ep = EditAtSelectedMarker;
4376 case EditAtPlayhead:
4377 where = _session->audible_frame();
4378 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4381 case EditAtSelectedMarker:
4382 if (!selection->markers.empty()) {
4384 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4387 where = loc->start();
4391 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4399 if (!mouse_frame (where, ignored)) {
4400 /* XXX not right but what can we do ? */
4404 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4412 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4414 if (!_session) return;
4416 begin_reversible_command (cmd);
4420 if ((tll = transport_loop_location()) == 0) {
4421 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4422 XMLNode &before = _session->locations()->get_state();
4423 _session->locations()->add (loc, true);
4424 _session->set_auto_loop_location (loc);
4425 XMLNode &after = _session->locations()->get_state();
4426 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4428 XMLNode &before = tll->get_state();
4429 tll->set_hidden (false, this);
4430 tll->set (start, end);
4431 XMLNode &after = tll->get_state();
4432 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4435 commit_reversible_command ();
4439 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4441 if (!_session) return;
4443 begin_reversible_command (cmd);
4447 if ((tpl = transport_punch_location()) == 0) {
4448 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4449 XMLNode &before = _session->locations()->get_state();
4450 _session->locations()->add (loc, true);
4451 _session->set_auto_loop_location (loc);
4452 XMLNode &after = _session->locations()->get_state();
4453 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4456 XMLNode &before = tpl->get_state();
4457 tpl->set_hidden (false, this);
4458 tpl->set (start, end);
4459 XMLNode &after = tpl->get_state();
4460 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4463 commit_reversible_command ();
4466 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4467 * @param rs List to which found regions are added.
4468 * @param where Time to look at.
4469 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4472 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4474 const TrackViewList* tracks;
4477 tracks = &track_views;
4482 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4484 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4487 boost::shared_ptr<Track> tr;
4488 boost::shared_ptr<Playlist> pl;
4490 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4492 boost::shared_ptr<RegionList> regions = pl->regions_at (
4493 (framepos_t) floor ( (double) where * tr->speed()));
4495 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4496 RegionView* rv = rtv->view()->find_view (*i);
4507 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4509 const TrackViewList* tracks;
4512 tracks = &track_views;
4517 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4518 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4520 boost::shared_ptr<Track> tr;
4521 boost::shared_ptr<Playlist> pl;
4523 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4525 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4526 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4528 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4530 RegionView* rv = rtv->view()->find_view (*i);
4541 /** Start with regions that are selected. Then add equivalent regions
4542 * on tracks in the same active edit-enabled route group as any of
4543 * the regions that we started with.
4547 Editor::get_regions_from_selection ()
4549 return get_equivalent_regions (selection->regions, ARDOUR::Properties::select.property_id);
4552 /** Get regions using the following method:
4554 * Make an initial region list using the selected regions, unless
4555 * the edit point is `mouse' and the mouse is over an unselected
4556 * region. In this case, start with just that region.
4558 * Then, add equivalent regions in active edit groups to the region list.
4560 * Then, search the list of selected tracks to find any selected tracks which
4561 * do not contain regions already in the region list. If there are no selected
4562 * tracks and 'No Selection = All Tracks' is active, search all tracks rather
4563 * than just the selected.
4565 * Add any regions that are under the edit point on these tracks to get the
4566 * returned region list.
4568 * The rationale here is that the mouse edit point is special in that
4569 * its position describes both a time and a track; the other edit
4570 * modes only describe a time. Hence if the edit point is `mouse' we
4571 * ignore selected tracks, as we assume the user means something by
4572 * pointing at a particular track. Also in this case we take note of
4573 * the region directly under the edit point, as there is always just one
4574 * (rather than possibly several with non-mouse edit points).
4578 Editor::get_regions_from_selection_and_edit_point ()
4580 RegionSelection regions;
4582 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4583 regions.add (entered_regionview);
4585 regions = selection->regions;
4588 TrackViewList tracks;
4590 if (_edit_point != EditAtMouse) {
4591 tracks = selection->tracks;
4594 /* Add any other regions that are in the same
4595 edit-activated route group as one of our regions.
4597 regions = get_equivalent_regions (regions, ARDOUR::Properties::select.property_id);
4598 framepos_t const where = get_preferred_edit_position ();
4600 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4601 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4602 * is enabled, so consider all tracks
4604 tracks = track_views;
4607 if (!tracks.empty()) {
4608 /* now search the selected tracks for tracks which don't
4609 already contain regions to be acted upon, and get regions at
4610 the edit point on those tracks too.
4612 TrackViewList tracks_without_relevant_regions;
4614 for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) {
4615 if (!regions.involves (**t)) {
4616 /* there are no equivalent regions on this track */
4617 tracks_without_relevant_regions.push_back (*t);
4621 if (!tracks_without_relevant_regions.empty()) {
4622 /* there are some selected tracks with neither selected
4623 * regions or their equivalents: act upon all regions in
4626 get_regions_at (regions, where, tracks_without_relevant_regions);
4633 /** Start with regions that are selected, or the entered regionview if none are selected.
4634 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4635 * of the regions that we started with.
4639 Editor::get_regions_from_selection_and_entered ()
4641 RegionSelection regions = selection->regions;
4643 if (regions.empty() && entered_regionview) {
4644 regions.add (entered_regionview);
4647 return get_equivalent_regions (regions, ARDOUR::Properties::select.property_id);
4651 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4653 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4655 RouteTimeAxisView* tatv;
4657 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4659 boost::shared_ptr<Playlist> pl;
4660 vector<boost::shared_ptr<Region> > results;
4662 boost::shared_ptr<Track> tr;
4664 if ((tr = tatv->track()) == 0) {
4669 if ((pl = (tr->playlist())) != 0) {
4670 pl->get_region_list_equivalent_regions (region, results);
4673 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4674 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4675 regions.push_back (marv);
4684 Editor::show_rhythm_ferret ()
4686 if (rhythm_ferret == 0) {
4687 rhythm_ferret = new RhythmFerret(*this);
4690 rhythm_ferret->set_session (_session);
4691 rhythm_ferret->show ();
4692 rhythm_ferret->present ();
4696 Editor::first_idle ()
4698 MessageDialog* dialog = 0;
4700 if (track_views.size() > 1) {
4701 dialog = new MessageDialog (
4703 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4707 ARDOUR_UI::instance()->flush_pending ();
4710 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4714 // first idle adds route children (automation tracks), so we need to redisplay here
4715 _routes->redisplay ();
4722 Editor::_idle_resize (gpointer arg)
4724 return ((Editor*)arg)->idle_resize ();
4728 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4730 if (resize_idle_id < 0) {
4731 resize_idle_id = g_idle_add (_idle_resize, this);
4732 _pending_resize_amount = 0;
4735 /* make a note of the smallest resulting height, so that we can clamp the
4736 lower limit at TimeAxisView::hSmall */
4738 int32_t min_resulting = INT32_MAX;
4740 _pending_resize_amount += h;
4741 _pending_resize_view = view;
4743 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4745 if (selection->tracks.contains (_pending_resize_view)) {
4746 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4747 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4751 if (min_resulting < 0) {
4756 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4757 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4761 /** Handle pending resizing of tracks */
4763 Editor::idle_resize ()
4765 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4767 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4768 selection->tracks.contains (_pending_resize_view)) {
4770 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4771 if (*i != _pending_resize_view) {
4772 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4777 _pending_resize_amount = 0;
4779 _group_tabs->set_dirty ();
4780 resize_idle_id = -1;
4788 ENSURE_GUI_THREAD (*this, &Editor::located);
4791 playhead_cursor->set_position (_session->audible_frame ());
4792 if (_follow_playhead && !_pending_initial_locate) {
4793 reset_x_origin_to_follow_playhead ();
4797 _pending_locate_request = false;
4798 _pending_initial_locate = false;
4802 Editor::region_view_added (RegionView *)
4804 _summary->set_dirty ();
4808 Editor::region_view_removed ()
4810 _summary->set_dirty ();
4814 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4816 TrackViewList::const_iterator j = track_views.begin ();
4817 while (j != track_views.end()) {
4818 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4819 if (rtv && rtv->route() == r) {
4830 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4834 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4835 TimeAxisView* tv = axis_view_from_route (*i);
4845 Editor::add_routes (RouteList& routes)
4847 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4849 RouteTimeAxisView *rtv;
4850 list<RouteTimeAxisView*> new_views;
4852 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4853 boost::shared_ptr<Route> route = (*x);
4855 if (route->is_hidden() || route->is_monitor()) {
4859 DataType dt = route->input()->default_type();
4861 if (dt == ARDOUR::DataType::AUDIO) {
4862 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4863 rtv->set_route (route);
4864 } else if (dt == ARDOUR::DataType::MIDI) {
4865 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4866 rtv->set_route (route);
4868 throw unknown_type();
4871 new_views.push_back (rtv);
4872 track_views.push_back (rtv);
4874 rtv->effective_gain_display ();
4876 if (internal_editing()) {
4877 rtv->enter_internal_edit_mode ();
4879 rtv->leave_internal_edit_mode ();
4882 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4883 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4886 _routes->routes_added (new_views);
4887 _summary->routes_added (new_views);
4889 if (show_editor_mixer_when_tracks_arrive) {
4890 show_editor_mixer (true);
4893 editor_list_button.set_sensitive (true);
4897 Editor::timeaxisview_deleted (TimeAxisView *tv)
4899 if (_session && _session->deletion_in_progress()) {
4900 /* the situation is under control */
4904 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4906 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4908 _routes->route_removed (tv);
4910 if (tv == entered_track) {
4914 TimeAxisView::Children c = tv->get_child_list ();
4915 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4916 if (entered_track == i->get()) {
4921 /* remove it from the list of track views */
4923 TrackViewList::iterator i;
4925 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4926 i = track_views.erase (i);
4929 /* update whatever the current mixer strip is displaying, if revelant */
4931 boost::shared_ptr<Route> route;
4934 route = rtav->route ();
4937 if (current_mixer_strip && current_mixer_strip->route() == route) {
4939 TimeAxisView* next_tv;
4941 if (track_views.empty()) {
4943 } else if (i == track_views.end()) {
4944 next_tv = track_views.front();
4951 set_selected_mixer_strip (*next_tv);
4953 /* make the editor mixer strip go away setting the
4954 * button to inactive (which also unticks the menu option)
4957 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4963 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4965 if (apply_to_selection) {
4966 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4968 TrackSelection::iterator j = i;
4971 hide_track_in_display (*i, false);
4976 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4978 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4979 // this will hide the mixer strip
4980 set_selected_mixer_strip (*tv);
4983 _routes->hide_track_in_display (*tv);
4988 Editor::sync_track_view_list_and_routes ()
4990 track_views = TrackViewList (_routes->views ());
4992 _summary->set_dirty ();
4993 _group_tabs->set_dirty ();
4995 return false; // do not call again (until needed)
4999 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5001 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5006 /** Find a RouteTimeAxisView by the ID of its route */
5008 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5010 RouteTimeAxisView* v;
5012 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5013 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5014 if(v->route()->id() == id) {
5024 Editor::fit_route_group (RouteGroup *g)
5026 TrackViewList ts = axis_views_from_routes (g->route_list ());
5031 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5033 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5036 _session->cancel_audition ();
5040 if (_session->is_auditioning()) {
5041 _session->cancel_audition ();
5042 if (r == last_audition_region) {
5047 _session->audition_region (r);
5048 last_audition_region = r;
5053 Editor::hide_a_region (boost::shared_ptr<Region> r)
5055 r->set_hidden (true);
5059 Editor::show_a_region (boost::shared_ptr<Region> r)
5061 r->set_hidden (false);
5065 Editor::audition_region_from_region_list ()
5067 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5071 Editor::hide_region_from_region_list ()
5073 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5077 Editor::show_region_in_region_list ()
5079 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5083 Editor::step_edit_status_change (bool yn)
5086 start_step_editing ();
5088 stop_step_editing ();
5093 Editor::start_step_editing ()
5095 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5099 Editor::stop_step_editing ()
5101 step_edit_connection.disconnect ();
5105 Editor::check_step_edit ()
5107 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5108 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5110 mtv->check_step_edit ();
5114 return true; // do it again, till we stop
5118 Editor::scroll_press (Direction dir)
5120 ++_scroll_callbacks;
5122 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5123 /* delay the first auto-repeat */
5129 scroll_backward (1);
5137 scroll_tracks_up_line ();
5141 scroll_tracks_down_line ();
5145 /* do hacky auto-repeat */
5146 if (!_scroll_connection.connected ()) {
5148 _scroll_connection = Glib::signal_timeout().connect (
5149 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5152 _scroll_callbacks = 0;
5159 Editor::scroll_release ()
5161 _scroll_connection.disconnect ();
5164 /** Queue a change for the Editor viewport x origin to follow the playhead */
5166 Editor::reset_x_origin_to_follow_playhead ()
5168 framepos_t const frame = playhead_cursor->current_frame;
5170 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5172 if (_session->transport_speed() < 0) {
5174 if (frame > (current_page_frames() / 2)) {
5175 center_screen (frame-(current_page_frames()/2));
5177 center_screen (current_page_frames()/2);
5184 if (frame < leftmost_frame) {
5186 if (_session->transport_rolling()) {
5187 /* rolling; end up with the playhead at the right of the page */
5188 l = frame - current_page_frames ();
5190 /* not rolling: end up with the playhead 1/4 of the way along the page */
5191 l = frame - current_page_frames() / 4;
5195 if (_session->transport_rolling()) {
5196 /* rolling: end up with the playhead on the left of the page */
5199 /* not rolling: end up with the playhead 3/4 of the way along the page */
5200 l = frame - 3 * current_page_frames() / 4;
5208 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5214 Editor::super_rapid_screen_update ()
5216 if (!_session || !_session->engine().running()) {
5220 /* METERING / MIXER STRIPS */
5222 /* update track meters, if required */
5223 if (is_mapped() && meters_running) {
5224 RouteTimeAxisView* rtv;
5225 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5226 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5227 rtv->fast_update ();
5232 /* and any current mixer strip */
5233 if (current_mixer_strip) {
5234 current_mixer_strip->fast_update ();
5237 /* PLAYHEAD AND VIEWPORT */
5239 framepos_t const frame = _session->audible_frame();
5241 /* There are a few reasons why we might not update the playhead / viewport stuff:
5243 * 1. we don't update things when there's a pending locate request, otherwise
5244 * when the editor requests a locate there is a chance that this method
5245 * will move the playhead before the locate request is processed, causing
5247 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5248 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5251 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5253 last_update_frame = frame;
5255 if (!_dragging_playhead) {
5256 playhead_cursor->set_position (frame);
5259 if (!_stationary_playhead) {
5261 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5262 /* We only do this if we aren't already
5263 handling a visual change (ie if
5264 pending_visual_change.being_handled is
5265 false) so that these requests don't stack
5266 up there are too many of them to handle in
5269 reset_x_origin_to_follow_playhead ();
5274 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5278 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5279 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5280 if (target <= 0.0) {
5283 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5284 target = (target * 0.15) + (current * 0.85);
5290 set_horizontal_position (current);
5299 Editor::session_going_away ()
5301 _have_idled = false;
5303 _session_connections.drop_connections ();
5305 super_rapid_screen_update_connection.disconnect ();
5307 selection->clear ();
5308 cut_buffer->clear ();
5310 clicked_regionview = 0;
5311 clicked_axisview = 0;
5312 clicked_routeview = 0;
5313 entered_regionview = 0;
5315 last_update_frame = 0;
5318 playhead_cursor->canvas_item.hide ();
5320 /* rip everything out of the list displays */
5324 _route_groups->clear ();
5326 /* do this first so that deleting a track doesn't reset cms to null
5327 and thus cause a leak.
5330 if (current_mixer_strip) {
5331 if (current_mixer_strip->get_parent() != 0) {
5332 global_hpacker.remove (*current_mixer_strip);
5334 delete current_mixer_strip;
5335 current_mixer_strip = 0;
5338 /* delete all trackviews */
5340 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5343 track_views.clear ();
5345 zoom_range_clock->set_session (0);
5346 nudge_clock->set_session (0);
5348 editor_list_button.set_active(false);
5349 editor_list_button.set_sensitive(false);
5351 /* clear tempo/meter rulers */
5352 remove_metric_marks ();
5354 clear_marker_display ();
5356 stop_step_editing ();
5358 /* get rid of any existing editor mixer strip */
5360 WindowTitle title(Glib::get_application_name());
5361 title += _("Editor");
5363 set_title (title.get_string());
5365 SessionHandlePtr::session_going_away ();
5370 Editor::show_editor_list (bool yn)
5373 _the_notebook.show ();
5375 _the_notebook.hide ();
5380 Editor::change_region_layering_order (bool from_context_menu)
5382 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5384 if (!clicked_routeview) {
5385 if (layering_order_editor) {
5386 layering_order_editor->hide ();
5391 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5397 boost::shared_ptr<Playlist> pl = track->playlist();
5403 if (layering_order_editor == 0) {
5404 layering_order_editor = new RegionLayeringOrderEditor (*this);
5405 layering_order_editor->set_position (WIN_POS_MOUSE);
5408 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5409 layering_order_editor->maybe_present ();
5413 Editor::update_region_layering_order_editor ()
5415 if (layering_order_editor && layering_order_editor->is_visible ()) {
5416 change_region_layering_order (true);
5421 Editor::setup_fade_images ()
5423 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5424 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5425 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5426 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5427 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5429 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5430 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5431 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5432 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5433 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5435 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5436 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5437 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5438 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5439 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5441 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5442 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5443 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5444 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5445 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5449 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5451 Editor::action_menu_item (std::string const & name)
5453 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5456 return *manage (a->create_menu_item ());
5460 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5462 EventBox* b = manage (new EventBox);
5463 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5464 Label* l = manage (new Label (name));
5468 _the_notebook.append_page (widget, *b);
5472 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5474 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5475 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5478 if (ev->type == GDK_2BUTTON_PRESS) {
5480 /* double-click on a notebook tab shrinks or expands the notebook */
5482 if (_notebook_shrunk) {
5483 if (pre_notebook_shrink_pane_width) {
5484 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5486 _notebook_shrunk = false;
5488 pre_notebook_shrink_pane_width = edit_pane.get_position();
5490 /* this expands the LHS of the edit pane to cover the notebook
5491 PAGE but leaves the tabs visible.
5493 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5494 _notebook_shrunk = true;
5502 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5504 using namespace Menu_Helpers;
5506 MenuList& items = _control_point_context_menu.items ();
5509 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5510 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5511 if (!can_remove_control_point (item)) {
5512 items.back().set_sensitive (false);
5515 _control_point_context_menu.popup (event->button.button, event->button.time);
5519 Editor::shift_key_released ()
5521 _stepping_axis_view = 0;