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/audioplaylist.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/midi_region.h"
67 #include "ardour/plugin_manager.h"
68 #include "ardour/profile.h"
69 #include "ardour/route_group.h"
70 #include "ardour/session_directory.h"
71 #include "ardour/session_route.h"
72 #include "ardour/session_state_utils.h"
73 #include "ardour/tempo.h"
74 #include "ardour/utils.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/audioengine.h"
78 #include "control_protocol/control_protocol.h"
82 #include "analysis_window.h"
83 #include "audio_clock.h"
84 #include "audio_region_view.h"
85 #include "audio_streamview.h"
86 #include "audio_time_axis.h"
87 #include "automation_time_axis.h"
88 #include "bundle_manager.h"
89 #include "button_joiner.h"
90 #include "canvas-noevent-text.h"
91 #include "canvas_impl.h"
92 #include "crossfade_edit.h"
93 #include "crossfade_view.h"
97 #include "editor_cursors.h"
98 #include "editor_drag.h"
99 #include "editor_group_tabs.h"
100 #include "editor_locations.h"
101 #include "editor_regions.h"
102 #include "editor_route_groups.h"
103 #include "editor_routes.h"
104 #include "editor_snapshots.h"
105 #include "editor_summary.h"
106 #include "global_port_matrix.h"
107 #include "gui_object.h"
108 #include "gui_thread.h"
109 #include "keyboard.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "playlist_selector.h"
116 #include "public_editor.h"
117 #include "region_layering_order_editor.h"
118 #include "rgb_macros.h"
119 #include "rhythm_ferret.h"
120 #include "selection.h"
122 #include "simpleline.h"
123 #include "tempo_lines.h"
124 #include "time_axis_view.h"
130 #include "imageframe_socket_handler.h"
134 using namespace ARDOUR;
137 using namespace Glib;
138 using namespace Gtkmm2ext;
139 using namespace Editing;
141 using PBD::internationalize;
143 using Gtkmm2ext::Keyboard;
145 const double Editor::timebar_height = 15.0;
147 static const gchar *_snap_type_strings[] = {
149 N_("Timecode Frames"),
150 N_("Timecode Seconds"),
151 N_("Timecode Minutes"),
181 static const gchar *_snap_mode_strings[] = {
188 static const gchar *_edit_point_strings[] = {
195 static const gchar *_zoom_focus_strings[] = {
205 #ifdef USE_RUBBERBAND
206 static const gchar *_rb_opt_strings[] = {
209 N_("Balanced multitimbral mixture"),
210 N_("Unpitched percussion with stable notes"),
211 N_("Crisp monophonic instrumental"),
212 N_("Unpitched solo percussion"),
213 N_("Resample without preserving pitch"),
219 show_me_the_size (Requisition* r, const char* what)
221 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
226 pane_size_watcher (Paned* pane)
228 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
229 it is no longer accessible. so stop that. this doesn't happen on X11,
230 just the quartz backend.
235 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
237 gint pos = pane->get_position ();
239 if (pos > max_width_of_lhs) {
240 pane->set_position (max_width_of_lhs);
246 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
248 /* time display buttons */
249 , minsec_label (_("Mins:Secs"))
250 , bbt_label (_("Bars:Beats"))
251 , timecode_label (_("Timecode"))
252 , samples_label (_("Samples"))
253 , tempo_label (_("Tempo"))
254 , meter_label (_("Meter"))
255 , mark_label (_("Location Markers"))
256 , range_mark_label (_("Range Markers"))
257 , transport_mark_label (_("Loop/Punch Ranges"))
258 , cd_mark_label (_("CD Markers"))
259 , edit_packer (4, 4, true)
261 /* the values here don't matter: layout widgets
262 reset them as needed.
265 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
267 /* tool bar related */
269 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
271 , toolbar_selection_clock_table (2,3)
273 , automation_mode_button (_("mode"))
275 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
278 , image_socket_listener(0)
283 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
284 , meters_running(false)
285 , _pending_locate_request (false)
286 , _pending_initial_locate (false)
287 , _last_cut_copy_source_track (0)
289 , _region_selection_change_updates_region_list (true)
290 , _following_mixer_selection (false)
294 /* we are a singleton */
296 PublicEditor::_instance = this;
300 selection = new Selection (this);
301 cut_buffer = new Selection (this);
303 clicked_regionview = 0;
304 clicked_axisview = 0;
305 clicked_routeview = 0;
306 clicked_crossfadeview = 0;
307 clicked_control_point = 0;
308 last_update_frame = 0;
309 pre_press_cursor = 0;
310 _drags = new DragManager (this);
311 current_mixer_strip = 0;
314 snap_type_strings = I18N (_snap_type_strings);
315 snap_mode_strings = I18N (_snap_mode_strings);
316 zoom_focus_strings = I18N (_zoom_focus_strings);
317 edit_point_strings = I18N (_edit_point_strings);
318 #ifdef USE_RUBBERBAND
319 rb_opt_strings = I18N (_rb_opt_strings);
323 snap_threshold = 5.0;
324 bbt_beat_subdivision = 4;
327 last_autoscroll_x = 0;
328 last_autoscroll_y = 0;
329 autoscroll_active = false;
330 autoscroll_timeout_tag = -1;
335 current_interthread_info = 0;
336 _show_measures = true;
338 show_gain_after_trim = false;
340 have_pending_keyboard_selection = false;
341 _follow_playhead = true;
342 _stationary_playhead = false;
343 _xfade_visibility = true;
344 editor_ruler_menu = 0;
345 no_ruler_shown_update = false;
347 range_marker_menu = 0;
348 marker_menu_item = 0;
349 tempo_or_meter_marker_menu = 0;
350 transport_marker_menu = 0;
351 new_transport_marker_menu = 0;
352 editor_mixer_strip_width = Wide;
353 show_editor_mixer_when_tracks_arrive = false;
354 region_edit_menu_split_multichannel_item = 0;
355 region_edit_menu_split_item = 0;
358 current_stepping_trackview = 0;
360 entered_regionview = 0;
362 clear_entered_track = false;
365 button_release_can_deselect = true;
366 _dragging_playhead = false;
367 _dragging_edit_point = false;
368 select_new_marker = false;
370 layering_order_editor = 0;
371 no_save_visual = false;
373 within_track_canvas = false;
375 scrubbing_direction = 0;
379 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
380 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
381 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
382 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
383 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
385 _edit_point = EditAtMouse;
386 _internal_editing = false;
387 current_canvas_cursor = 0;
389 frames_per_unit = 2048; /* too early to use reset_zoom () */
391 _scroll_callbacks = 0;
393 zoom_focus = ZoomFocusLeft;
394 set_zoom_focus (ZoomFocusLeft);
395 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
397 bbt_label.set_name ("EditorTimeButton");
398 bbt_label.set_size_request (-1, (int)timebar_height);
399 bbt_label.set_alignment (1.0, 0.5);
400 bbt_label.set_padding (5,0);
402 bbt_label.set_no_show_all();
403 minsec_label.set_name ("EditorTimeButton");
404 minsec_label.set_size_request (-1, (int)timebar_height);
405 minsec_label.set_alignment (1.0, 0.5);
406 minsec_label.set_padding (5,0);
407 minsec_label.hide ();
408 minsec_label.set_no_show_all();
409 timecode_label.set_name ("EditorTimeButton");
410 timecode_label.set_size_request (-1, (int)timebar_height);
411 timecode_label.set_alignment (1.0, 0.5);
412 timecode_label.set_padding (5,0);
413 timecode_label.hide ();
414 timecode_label.set_no_show_all();
415 samples_label.set_name ("EditorTimeButton");
416 samples_label.set_size_request (-1, (int)timebar_height);
417 samples_label.set_alignment (1.0, 0.5);
418 samples_label.set_padding (5,0);
419 samples_label.hide ();
420 samples_label.set_no_show_all();
422 tempo_label.set_name ("EditorTimeButton");
423 tempo_label.set_size_request (-1, (int)timebar_height);
424 tempo_label.set_alignment (1.0, 0.5);
425 tempo_label.set_padding (5,0);
427 tempo_label.set_no_show_all();
429 meter_label.set_name ("EditorTimeButton");
430 meter_label.set_size_request (-1, (int)timebar_height);
431 meter_label.set_alignment (1.0, 0.5);
432 meter_label.set_padding (5,0);
434 meter_label.set_no_show_all();
436 mark_label.set_name ("EditorTimeButton");
437 mark_label.set_size_request (-1, (int)timebar_height);
438 mark_label.set_alignment (1.0, 0.5);
439 mark_label.set_padding (5,0);
441 mark_label.set_no_show_all();
443 cd_mark_label.set_name ("EditorTimeButton");
444 cd_mark_label.set_size_request (-1, (int)timebar_height);
445 cd_mark_label.set_alignment (1.0, 0.5);
446 cd_mark_label.set_padding (5,0);
447 cd_mark_label.hide();
448 cd_mark_label.set_no_show_all();
450 range_mark_label.set_name ("EditorTimeButton");
451 range_mark_label.set_size_request (-1, (int)timebar_height);
452 range_mark_label.set_alignment (1.0, 0.5);
453 range_mark_label.set_padding (5,0);
454 range_mark_label.hide();
455 range_mark_label.set_no_show_all();
457 transport_mark_label.set_name ("EditorTimeButton");
458 transport_mark_label.set_size_request (-1, (int)timebar_height);
459 transport_mark_label.set_alignment (1.0, 0.5);
460 transport_mark_label.set_padding (5,0);
461 transport_mark_label.hide();
462 transport_mark_label.set_no_show_all();
464 initialize_rulers ();
465 initialize_canvas ();
467 _summary = new EditorSummary (this);
469 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
470 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
472 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
474 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
475 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
477 edit_controls_vbox.set_spacing (0);
478 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
479 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
481 HBox* h = manage (new HBox);
482 _group_tabs = new EditorGroupTabs (this);
483 h->pack_start (*_group_tabs, PACK_SHRINK);
484 h->pack_start (edit_controls_vbox);
485 controls_layout.add (*h);
487 controls_layout.set_name ("EditControlsBase");
488 controls_layout.add_events (Gdk::SCROLL_MASK);
489 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
491 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
492 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
494 _cursors = new MouseCursors;
496 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
497 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
498 0.0, 1.0, 100.0, 1.0));
500 pad_line_1->property_color_rgba() = 0xFF0000FF;
505 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
506 time_canvas_vbox.set_size_request (-1, -1);
508 ruler_label_event_box.add (ruler_label_vbox);
509 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
510 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
512 time_button_event_box.add (time_button_vbox);
513 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
514 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
516 /* these enable us to have a dedicated window (for cursor setting, etc.)
517 for the canvas areas.
520 track_canvas_event_box.add (*track_canvas);
522 time_canvas_event_box.add (time_canvas_vbox);
523 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
525 edit_packer.set_col_spacings (0);
526 edit_packer.set_row_spacings (0);
527 edit_packer.set_homogeneous (false);
528 edit_packer.set_border_width (0);
529 edit_packer.set_name ("EditorWindow");
531 /* labels for the rulers */
532 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
533 /* labels for the marker "tracks" */
534 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
536 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
538 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
540 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
542 bottom_hbox.set_border_width (2);
543 bottom_hbox.set_spacing (3);
545 _route_groups = new EditorRouteGroups (this);
546 _routes = new EditorRoutes (this);
547 _regions = new EditorRegions (this);
548 _snapshots = new EditorSnapshots (this);
549 _locations = new EditorLocations (this);
551 add_notebook_page (_("Regions"), _regions->widget ());
552 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
553 add_notebook_page (_("Snapshots"), _snapshots->widget ());
554 add_notebook_page (_("Route Groups"), _route_groups->widget ());
555 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
557 _the_notebook.set_show_tabs (true);
558 _the_notebook.set_scrollable (true);
559 _the_notebook.popup_disable ();
560 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
561 _the_notebook.show_all ();
563 _notebook_shrunk = false;
565 editor_summary_pane.pack1(edit_packer);
567 Button* summary_arrows_left_left = manage (new Button);
568 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
569 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
570 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
572 Button* summary_arrows_left_right = manage (new Button);
573 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
574 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
575 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
577 VBox* summary_arrows_left = manage (new VBox);
578 summary_arrows_left->pack_start (*summary_arrows_left_left);
579 summary_arrows_left->pack_start (*summary_arrows_left_right);
581 Button* summary_arrows_right_up = manage (new Button);
582 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
583 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
584 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
586 Button* summary_arrows_right_down = manage (new Button);
587 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
588 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
589 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
591 VBox* summary_arrows_right = manage (new VBox);
592 summary_arrows_right->pack_start (*summary_arrows_right_up);
593 summary_arrows_right->pack_start (*summary_arrows_right_down);
595 Frame* summary_frame = manage (new Frame);
596 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
598 summary_frame->add (*_summary);
599 summary_frame->show ();
601 _summary_hbox.pack_start (*summary_arrows_left, false, false);
602 _summary_hbox.pack_start (*summary_frame, true, true);
603 _summary_hbox.pack_start (*summary_arrows_right, false, false);
605 editor_summary_pane.pack2 (_summary_hbox);
607 edit_pane.pack1 (editor_summary_pane, true, true);
608 edit_pane.pack2 (_the_notebook, false, true);
610 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
612 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
614 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
616 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
617 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
619 top_hbox.pack_start (toolbar_frame);
621 HBox *hbox = manage (new HBox);
622 hbox->pack_start (edit_pane, true, true);
624 global_vpacker.pack_start (top_hbox, false, false);
625 global_vpacker.pack_start (*hbox, true, true);
627 global_hpacker.pack_start (global_vpacker, true, true);
629 set_name ("EditorWindow");
630 add_accel_group (ActionManager::ui_manager->get_accel_group());
632 status_bar_hpacker.show ();
634 vpacker.pack_end (status_bar_hpacker, false, false);
635 vpacker.pack_end (global_hpacker, true, true);
637 /* register actions now so that set_state() can find them and set toggles/checks etc */
640 /* when we start using our own keybinding system for the editor, this
641 * will be uncommented
647 _snap_type = SnapToBeat;
648 set_snap_to (_snap_type);
649 _snap_mode = SnapOff;
650 set_snap_mode (_snap_mode);
651 set_mouse_mode (MouseObject, true);
652 pre_internal_mouse_mode = MouseObject;
653 pre_internal_snap_type = _snap_type;
654 pre_internal_snap_mode = _snap_mode;
655 internal_snap_type = _snap_type;
656 internal_snap_mode = _snap_mode;
657 set_edit_point_preference (EditAtMouse, true);
659 _playlist_selector = new PlaylistSelector();
660 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
662 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
666 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
667 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
669 nudge_forward_button.set_name ("TransportButton");
670 nudge_backward_button.set_name ("TransportButton");
672 fade_context_menu.set_name ("ArdourContextMenu");
674 /* icons, titles, WM stuff */
676 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
677 Glib::RefPtr<Gdk::Pixbuf> icon;
679 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
680 window_icons.push_back (icon);
682 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
683 window_icons.push_back (icon);
685 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
686 window_icons.push_back (icon);
688 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
689 window_icons.push_back (icon);
691 if (!window_icons.empty()) {
692 // set_icon_list (window_icons);
693 set_default_icon_list (window_icons);
696 WindowTitle title(Glib::get_application_name());
697 title += _("Editor");
698 set_title (title.get_string());
699 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
702 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
704 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
705 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
707 /* allow external control surfaces/protocols to do various things */
709 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
710 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
711 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
712 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
713 ControlProtocol::SelectByRID.connect (*this, invalidator (*this), ui_bind (&Editor::control_select, this, _1), gui_context());
714 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
716 /* problematic: has to return a value and thus cannot be x-thread */
718 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
720 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
722 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
724 _ignore_region_action = false;
725 _last_region_menu_was_main = false;
726 _popup_region_menu_item = 0;
728 _show_marker_lines = false;
729 _over_region_trim_target = false;
731 /* Button bindings */
733 button_bindings = new Bindings;
735 XMLNode* node = button_settings();
737 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
738 button_bindings->load (**i);
745 setup_fade_images ();
751 if(image_socket_listener) {
752 if(image_socket_listener->is_connected())
754 image_socket_listener->close_connection() ;
757 delete image_socket_listener ;
758 image_socket_listener = 0 ;
762 delete button_bindings;
764 delete _route_groups;
770 Editor::button_settings () const
772 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
773 XMLNode* node = find_named_node (*settings, X_("Buttons"));
776 cerr << "new empty Button node\n";
777 node = new XMLNode (X_("Buttons"));
784 Editor::add_toplevel_controls (Container& cont)
786 vpacker.pack_start (cont, false, false);
791 Editor::catch_vanishing_regionview (RegionView *rv)
793 /* note: the selection will take care of the vanishing
794 audioregionview by itself.
797 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
801 if (clicked_regionview == rv) {
802 clicked_regionview = 0;
805 if (entered_regionview == rv) {
806 set_entered_regionview (0);
809 if (!_all_region_actions_sensitized) {
810 sensitize_all_region_actions (true);
813 _over_region_trim_target = false;
817 Editor::set_entered_regionview (RegionView* rv)
819 if (rv == entered_regionview) {
823 if (entered_regionview) {
824 entered_regionview->exited ();
827 if ((entered_regionview = rv) != 0) {
828 entered_regionview->entered (internal_editing ());
831 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
832 /* This RegionView entry might have changed what region actions
833 are allowed, so sensitize them all in case a key is pressed.
835 sensitize_all_region_actions (true);
840 Editor::set_entered_track (TimeAxisView* tav)
843 entered_track->exited ();
846 if ((entered_track = tav) != 0) {
847 entered_track->entered ();
852 Editor::show_window ()
854 if (!is_visible ()) {
857 /* XXX: this is a bit unfortunate; it would probably
858 be nicer if we could just call show () above rather
859 than needing the show_all ()
862 /* re-hide stuff if necessary */
863 editor_list_button_toggled ();
864 parameter_changed ("show-summary");
865 parameter_changed ("show-group-tabs");
866 parameter_changed ("show-zoom-tools");
868 /* now reset all audio_time_axis heights, because widgets might need
874 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
875 tv = (static_cast<TimeAxisView*>(*i));
879 if (current_mixer_strip) {
880 current_mixer_strip->hide_things ();
881 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
889 Editor::instant_save ()
891 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
896 _session->add_instant_xml(get_state());
898 Config->add_instant_xml(get_state());
903 Editor::zoom_adjustment_changed ()
909 double fpu = zoom_range_clock->current_duration() / _canvas_width;
913 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
914 } else if (fpu > _session->current_end_frame() / _canvas_width) {
915 fpu = _session->current_end_frame() / _canvas_width;
916 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
923 Editor::control_select (uint32_t rid)
925 /* handles the (static) signal from the ControlProtocol class that
926 * requests setting the selected track to a given RID
933 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
939 TimeAxisView* tav = axis_view_from_route (r);
942 selection->set (tav);
944 selection->clear_tracks ();
949 Editor::control_scroll (float fraction)
951 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
957 double step = fraction * current_page_frames();
960 _control_scroll_target is an optional<T>
962 it acts like a pointer to an framepos_t, with
963 a operator conversion to boolean to check
964 that it has a value could possibly use
965 playhead_cursor->current_frame to store the
966 value and a boolean in the class to know
967 when it's out of date
970 if (!_control_scroll_target) {
971 _control_scroll_target = _session->transport_frame();
972 _dragging_playhead = true;
975 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
976 *_control_scroll_target = 0;
977 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
978 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
980 *_control_scroll_target += (framepos_t) floor (step);
983 /* move visuals, we'll catch up with it later */
985 playhead_cursor->set_position (*_control_scroll_target);
986 UpdateAllTransportClocks (*_control_scroll_target);
988 if (*_control_scroll_target > (current_page_frames() / 2)) {
989 /* try to center PH in window */
990 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
996 Now we do a timeout to actually bring the session to the right place
997 according to the playhead. This is to avoid reading disk buffers on every
998 call to control_scroll, which is driven by ScrollTimeline and therefore
999 probably by a control surface wheel which can generate lots of events.
1001 /* cancel the existing timeout */
1003 control_scroll_connection.disconnect ();
1005 /* add the next timeout */
1007 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1011 Editor::deferred_control_scroll (framepos_t /*target*/)
1013 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1014 // reset for next stream
1015 _control_scroll_target = boost::none;
1016 _dragging_playhead = false;
1021 Editor::access_action (std::string action_group, std::string action_item)
1027 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1030 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1038 Editor::on_realize ()
1040 Window::on_realize ();
1045 Editor::map_position_change (framepos_t frame)
1047 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1049 if (_session == 0) {
1053 if (_follow_playhead) {
1054 center_screen (frame);
1057 playhead_cursor->set_position (frame);
1061 Editor::center_screen (framepos_t frame)
1063 double page = _canvas_width * frames_per_unit;
1065 /* if we're off the page, then scroll.
1068 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1069 center_screen_internal (frame, page);
1074 Editor::center_screen_internal (framepos_t frame, float page)
1079 frame -= (framepos_t) page;
1084 reset_x_origin (frame);
1089 Editor::update_title ()
1091 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1094 bool dirty = _session->dirty();
1096 string session_name;
1098 if (_session->snap_name() != _session->name()) {
1099 session_name = _session->snap_name();
1101 session_name = _session->name();
1105 session_name = "*" + session_name;
1108 WindowTitle title(session_name);
1109 title += Glib::get_application_name();
1110 set_title (title.get_string());
1115 Editor::set_session (Session *t)
1117 SessionHandlePtr::set_session (t);
1123 zoom_range_clock->set_session (_session);
1124 _playlist_selector->set_session (_session);
1125 nudge_clock->set_session (_session);
1126 _summary->set_session (_session);
1127 _group_tabs->set_session (_session);
1128 _route_groups->set_session (_session);
1129 _regions->set_session (_session);
1130 _snapshots->set_session (_session);
1131 _routes->set_session (_session);
1132 _locations->set_session (_session);
1134 if (rhythm_ferret) {
1135 rhythm_ferret->set_session (_session);
1138 if (analysis_window) {
1139 analysis_window->set_session (_session);
1143 sfbrowser->set_session (_session);
1146 compute_fixed_ruler_scale ();
1148 /* Make sure we have auto loop and auto punch ranges */
1150 Location* loc = _session->locations()->auto_loop_location();
1152 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1154 if (loc->start() == loc->end()) {
1155 loc->set_end (loc->start() + 1);
1158 _session->locations()->add (loc, false);
1159 _session->set_auto_loop_location (loc);
1162 loc->set_name (_("Loop"));
1165 loc = _session->locations()->auto_punch_location();
1168 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1170 if (loc->start() == loc->end()) {
1171 loc->set_end (loc->start() + 1);
1174 _session->locations()->add (loc, false);
1175 _session->set_auto_punch_location (loc);
1178 loc->set_name (_("Punch"));
1181 refresh_location_display ();
1183 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1184 the selected Marker; this needs the LocationMarker list to be available.
1186 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1187 set_state (*node, Stateful::loading_state_version);
1189 /* catch up with the playhead */
1191 _session->request_locate (playhead_cursor->current_frame);
1192 _pending_initial_locate = true;
1196 /* These signals can all be emitted by a non-GUI thread. Therefore the
1197 handlers for them must not attempt to directly interact with the GUI,
1198 but use Gtkmm2ext::UI::instance()->call_slot();
1201 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1202 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1203 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1204 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1205 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1206 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1207 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1208 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1209 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1210 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1211 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1212 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1213 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display, this), gui_context());
1214 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1216 if (Profile->get_sae()) {
1217 Timecode::BBT_Time bbt;
1221 framepos_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1222 nudge_clock->set_mode(AudioClock::BBT);
1223 nudge_clock->set (pos, true);
1226 nudge_clock->set_mode (AudioClock::Timecode);
1227 nudge_clock->set (_session->frame_rate() * 5, true);
1230 playhead_cursor->canvas_item.show ();
1232 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1233 Config->map_parameters (pc);
1234 _session->config.map_parameters (pc);
1236 restore_ruler_visibility ();
1237 //tempo_map_changed (PropertyChange (0));
1238 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1240 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1241 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1244 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1245 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1248 switch (_snap_type) {
1249 case SnapToRegionStart:
1250 case SnapToRegionEnd:
1251 case SnapToRegionSync:
1252 case SnapToRegionBoundary:
1253 build_region_boundary_cache ();
1260 /* register for undo history */
1261 _session->register_with_memento_command_factory(id(), this);
1263 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1265 start_updating_meters ();
1269 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1271 if (a->get_name() == "RegionMenu") {
1272 /* When the main menu's region menu is opened, we setup the actions so that they look right
1273 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1274 so we resensitize all region actions when the entered regionview or the region selection
1275 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1276 happens after the region context menu is opened. So we set a flag here, too.
1280 sensitize_the_right_region_actions ();
1281 _last_region_menu_was_main = true;
1285 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1287 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1289 using namespace Menu_Helpers;
1290 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1293 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1297 MenuList& items (fade_context_menu.items());
1301 switch (item_type) {
1303 case FadeInHandleItem:
1304 if (arv->audio_region()->fade_in_active()) {
1305 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1307 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1310 items.push_back (SeparatorElem());
1312 if (Profile->get_sae()) {
1314 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1315 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1322 *_fade_in_images[FadeLinear],
1323 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1327 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1332 *_fade_in_images[FadeFast],
1333 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1336 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1341 *_fade_in_images[FadeLogB],
1342 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1345 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1350 *_fade_in_images[FadeLogA],
1351 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1354 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1359 *_fade_in_images[FadeSlow],
1360 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1363 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1369 case FadeOutHandleItem:
1370 if (arv->audio_region()->fade_out_active()) {
1371 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1373 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1376 items.push_back (SeparatorElem());
1378 if (Profile->get_sae()) {
1379 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1380 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1386 *_fade_out_images[FadeLinear],
1387 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1391 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1396 *_fade_out_images[FadeFast],
1397 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1400 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1405 *_fade_out_images[FadeLogB],
1406 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1409 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1414 *_fade_out_images[FadeLogA],
1415 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1418 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1423 *_fade_out_images[FadeSlow],
1424 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1427 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1433 fatal << _("programming error: ")
1434 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1439 fade_context_menu.popup (button, time);
1443 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1445 using namespace Menu_Helpers;
1446 Menu* (Editor::*build_menu_function)();
1449 switch (item_type) {
1451 case RegionViewName:
1452 case RegionViewNameHighlight:
1453 case LeftFrameHandle:
1454 case RightFrameHandle:
1455 if (with_selection) {
1456 build_menu_function = &Editor::build_track_selection_context_menu;
1458 build_menu_function = &Editor::build_track_region_context_menu;
1463 if (with_selection) {
1464 build_menu_function = &Editor::build_track_selection_context_menu;
1466 build_menu_function = &Editor::build_track_context_menu;
1470 case CrossfadeViewItem:
1471 build_menu_function = &Editor::build_track_crossfade_context_menu;
1475 if (clicked_routeview->track()) {
1476 build_menu_function = &Editor::build_track_context_menu;
1478 build_menu_function = &Editor::build_track_bus_context_menu;
1483 /* probably shouldn't happen but if it does, we don't care */
1487 menu = (this->*build_menu_function)();
1488 menu->set_name ("ArdourContextMenu");
1490 /* now handle specific situations */
1492 switch (item_type) {
1494 case RegionViewName:
1495 case RegionViewNameHighlight:
1496 case LeftFrameHandle:
1497 case RightFrameHandle:
1498 if (!with_selection) {
1499 if (region_edit_menu_split_item) {
1500 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1501 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1503 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1506 if (region_edit_menu_split_multichannel_item) {
1507 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1508 region_edit_menu_split_multichannel_item->set_sensitive (true);
1510 region_edit_menu_split_multichannel_item->set_sensitive (false);
1519 case CrossfadeViewItem:
1526 /* probably shouldn't happen but if it does, we don't care */
1530 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1532 /* Bounce to disk */
1534 using namespace Menu_Helpers;
1535 MenuList& edit_items = menu->items();
1537 edit_items.push_back (SeparatorElem());
1539 switch (clicked_routeview->audio_track()->freeze_state()) {
1540 case AudioTrack::NoFreeze:
1541 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1544 case AudioTrack::Frozen:
1545 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1548 case AudioTrack::UnFrozen:
1549 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1555 if (item_type == StreamItem && clicked_routeview) {
1556 clicked_routeview->build_underlay_menu(menu);
1559 /* When the region menu is opened, we setup the actions so that they look right
1562 sensitize_the_right_region_actions ();
1563 _last_region_menu_was_main = false;
1565 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1566 menu->popup (button, time);
1570 Editor::build_track_context_menu ()
1572 using namespace Menu_Helpers;
1574 MenuList& edit_items = track_context_menu.items();
1577 add_dstream_context_items (edit_items);
1578 return &track_context_menu;
1582 Editor::build_track_bus_context_menu ()
1584 using namespace Menu_Helpers;
1586 MenuList& edit_items = track_context_menu.items();
1589 add_bus_context_items (edit_items);
1590 return &track_context_menu;
1594 Editor::build_track_region_context_menu ()
1596 using namespace Menu_Helpers;
1597 MenuList& edit_items = track_region_context_menu.items();
1600 /* we've just cleared the track region context menu, so the menu that these
1601 two items were on will have disappeared; stop them dangling.
1603 region_edit_menu_split_item = 0;
1604 region_edit_menu_split_multichannel_item = 0;
1606 /* we might try to use items that are currently attached to a crossfade menu,
1609 track_crossfade_context_menu.items().clear ();
1611 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1614 boost::shared_ptr<Track> tr;
1615 boost::shared_ptr<Playlist> pl;
1617 if ((tr = rtv->track())) {
1618 add_region_context_items (edit_items, tr);
1622 add_dstream_context_items (edit_items);
1624 return &track_region_context_menu;
1628 Editor::build_track_crossfade_context_menu ()
1630 using namespace Menu_Helpers;
1631 MenuList& edit_items = track_crossfade_context_menu.items();
1632 edit_items.clear ();
1634 /* we might try to use items that are currently attached to a crossfade menu,
1637 track_region_context_menu.items().clear ();
1639 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1642 boost::shared_ptr<Track> tr;
1643 boost::shared_ptr<Playlist> pl;
1644 boost::shared_ptr<AudioPlaylist> apl;
1646 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1648 AudioPlaylist::Crossfades xfades;
1652 /* The xfade menu is a bit of a special case, as we always use the mouse position
1653 to decide whether or not to display it (rather than the edit point). No particularly
1654 strong reasons for this, other than it is a bit surprising to right-click on a xfade
1657 mouse_frame (where, ignored);
1658 apl->crossfades_at (where, xfades);
1660 bool const many = xfades.size() > 1;
1662 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1663 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1666 add_region_context_items (edit_items, tr);
1670 add_dstream_context_items (edit_items);
1672 return &track_crossfade_context_menu;
1676 Editor::analyze_region_selection ()
1678 if (analysis_window == 0) {
1679 analysis_window = new AnalysisWindow();
1682 analysis_window->set_session(_session);
1684 analysis_window->show_all();
1687 analysis_window->set_regionmode();
1688 analysis_window->analyze();
1690 analysis_window->present();
1694 Editor::analyze_range_selection()
1696 if (analysis_window == 0) {
1697 analysis_window = new AnalysisWindow();
1700 analysis_window->set_session(_session);
1702 analysis_window->show_all();
1705 analysis_window->set_rangemode();
1706 analysis_window->analyze();
1708 analysis_window->present();
1712 Editor::build_track_selection_context_menu ()
1714 using namespace Menu_Helpers;
1715 MenuList& edit_items = track_selection_context_menu.items();
1716 edit_items.clear ();
1718 add_selection_context_items (edit_items);
1719 // edit_items.push_back (SeparatorElem());
1720 // add_dstream_context_items (edit_items);
1722 return &track_selection_context_menu;
1725 /** Add context menu items relevant to crossfades.
1726 * @param edit_items List to add the items to.
1729 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1731 using namespace Menu_Helpers;
1732 Menu *xfade_menu = manage (new Menu);
1733 MenuList& items = xfade_menu->items();
1734 xfade_menu->set_name ("ArdourContextMenu");
1737 if (xfade->active()) {
1744 MenuElem (str, sigc::bind (sigc::mem_fun (*this, &Editor::toggle_xfade_active), &view->trackview(), boost::weak_ptr<Crossfade> (xfade)))
1748 MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade)))
1751 if (xfade->can_follow_overlap()) {
1753 if (xfade->following_overlap()) {
1754 str = _("Convert to Short");
1756 str = _("Convert to Full");
1760 MenuElem (str, sigc::bind (sigc::mem_fun (*this, &Editor::toggle_xfade_length), &view->trackview(), xfade))
1765 str = xfade->out()->name();
1767 str += xfade->in()->name();
1769 str = _("Crossfade");
1772 edit_items.push_back (MenuElem (str, *xfade_menu));
1773 edit_items.push_back (SeparatorElem());
1777 Editor::xfade_edit_left_region ()
1779 if (clicked_crossfadeview) {
1780 clicked_crossfadeview->left_view.show_region_editor ();
1785 Editor::xfade_edit_right_region ()
1787 if (clicked_crossfadeview) {
1788 clicked_crossfadeview->right_view.show_region_editor ();
1793 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1795 using namespace Menu_Helpers;
1797 /* OK, stick the region submenu at the top of the list, and then add
1801 RegionSelection rs = get_regions_from_selection_and_entered ();
1803 string::size_type pos = 0;
1804 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1806 /* we have to hack up the region name because "_" has a special
1807 meaning for menu titles.
1810 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1811 menu_item_name.replace (pos, 1, "__");
1815 if (_popup_region_menu_item == 0) {
1816 _popup_region_menu_item = new MenuItem (menu_item_name);
1817 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1818 _popup_region_menu_item->show ();
1820 _popup_region_menu_item->set_label (menu_item_name);
1823 const framepos_t position = get_preferred_edit_position (false, true);
1825 edit_items.push_back (*_popup_region_menu_item);
1826 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1827 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1829 edit_items.push_back (SeparatorElem());
1832 /** Add context menu items relevant to selection ranges.
1833 * @param edit_items List to add the items to.
1836 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1838 using namespace Menu_Helpers;
1840 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1841 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1843 edit_items.push_back (SeparatorElem());
1844 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1846 edit_items.push_back (SeparatorElem());
1848 edit_items.push_back (
1850 _("Move Range Start to Previous Region Boundary"),
1851 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1855 edit_items.push_back (
1857 _("Move Range Start to Next Region Boundary"),
1858 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1862 edit_items.push_back (
1864 _("Move Range End to Previous Region Boundary"),
1865 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1869 edit_items.push_back (
1871 _("Move Range End to Next Region Boundary"),
1872 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1876 edit_items.push_back (SeparatorElem());
1877 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1878 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1880 edit_items.push_back (SeparatorElem());
1881 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1883 edit_items.push_back (SeparatorElem());
1884 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1885 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1887 edit_items.push_back (SeparatorElem());
1888 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1890 edit_items.push_back (SeparatorElem());
1891 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1892 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1893 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1895 edit_items.push_back (SeparatorElem());
1896 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1897 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1898 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1899 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1900 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1905 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1907 using namespace Menu_Helpers;
1911 Menu *play_menu = manage (new Menu);
1912 MenuList& play_items = play_menu->items();
1913 play_menu->set_name ("ArdourContextMenu");
1915 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1916 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1917 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1918 play_items.push_back (SeparatorElem());
1919 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1921 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1925 Menu *select_menu = manage (new Menu);
1926 MenuList& select_items = select_menu->items();
1927 select_menu->set_name ("ArdourContextMenu");
1929 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1930 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1931 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1932 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1933 select_items.push_back (SeparatorElem());
1934 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1935 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1936 select_items.push_back (SeparatorElem());
1937 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1938 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1939 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1940 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1941 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1942 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1943 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1945 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1949 Menu *cutnpaste_menu = manage (new Menu);
1950 MenuList& cutnpaste_items = cutnpaste_menu->items();
1951 cutnpaste_menu->set_name ("ArdourContextMenu");
1953 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1954 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1955 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1957 cutnpaste_items.push_back (SeparatorElem());
1959 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1960 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1962 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1964 /* Adding new material */
1966 edit_items.push_back (SeparatorElem());
1967 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1968 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1972 Menu *nudge_menu = manage (new Menu());
1973 MenuList& nudge_items = nudge_menu->items();
1974 nudge_menu->set_name ("ArdourContextMenu");
1976 edit_items.push_back (SeparatorElem());
1977 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1978 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1979 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1980 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1982 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1986 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1988 using namespace Menu_Helpers;
1992 Menu *play_menu = manage (new Menu);
1993 MenuList& play_items = play_menu->items();
1994 play_menu->set_name ("ArdourContextMenu");
1996 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1997 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1998 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2002 Menu *select_menu = manage (new Menu);
2003 MenuList& select_items = select_menu->items();
2004 select_menu->set_name ("ArdourContextMenu");
2006 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2007 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2008 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2009 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2010 select_items.push_back (SeparatorElem());
2011 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2012 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2013 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2014 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2016 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2020 Menu *cutnpaste_menu = manage (new Menu);
2021 MenuList& cutnpaste_items = cutnpaste_menu->items();
2022 cutnpaste_menu->set_name ("ArdourContextMenu");
2024 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2025 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2026 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2028 Menu *nudge_menu = manage (new Menu());
2029 MenuList& nudge_items = nudge_menu->items();
2030 nudge_menu->set_name ("ArdourContextMenu");
2032 edit_items.push_back (SeparatorElem());
2033 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2034 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2035 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2036 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2038 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2042 Editor::snap_type() const
2048 Editor::snap_mode() const
2054 Editor::set_snap_to (SnapType st)
2056 unsigned int snap_ind = (unsigned int)st;
2060 if (snap_ind > snap_type_strings.size() - 1) {
2062 _snap_type = (SnapType)snap_ind;
2065 string str = snap_type_strings[snap_ind];
2067 if (str != snap_type_selector.get_active_text()) {
2068 snap_type_selector.set_active_text (str);
2073 switch (_snap_type) {
2074 case SnapToBeatDiv128:
2075 case SnapToBeatDiv64:
2076 case SnapToBeatDiv32:
2077 case SnapToBeatDiv28:
2078 case SnapToBeatDiv24:
2079 case SnapToBeatDiv20:
2080 case SnapToBeatDiv16:
2081 case SnapToBeatDiv14:
2082 case SnapToBeatDiv12:
2083 case SnapToBeatDiv10:
2084 case SnapToBeatDiv8:
2085 case SnapToBeatDiv7:
2086 case SnapToBeatDiv6:
2087 case SnapToBeatDiv5:
2088 case SnapToBeatDiv4:
2089 case SnapToBeatDiv3:
2090 case SnapToBeatDiv2:
2091 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2092 update_tempo_based_rulers ();
2095 case SnapToRegionStart:
2096 case SnapToRegionEnd:
2097 case SnapToRegionSync:
2098 case SnapToRegionBoundary:
2099 build_region_boundary_cache ();
2107 SnapChanged (); /* EMIT SIGNAL */
2111 Editor::set_snap_mode (SnapMode mode)
2114 string str = snap_mode_strings[(int)mode];
2116 if (str != snap_mode_selector.get_active_text ()) {
2117 snap_mode_selector.set_active_text (str);
2123 Editor::set_edit_point_preference (EditPoint ep, bool force)
2125 bool changed = (_edit_point != ep);
2128 string str = edit_point_strings[(int)ep];
2130 if (str != edit_point_selector.get_active_text ()) {
2131 edit_point_selector.set_active_text (str);
2134 set_canvas_cursor ();
2136 if (!force && !changed) {
2140 const char* action=NULL;
2142 switch (_edit_point) {
2143 case EditAtPlayhead:
2144 action = "edit-at-playhead";
2146 case EditAtSelectedMarker:
2147 action = "edit-at-marker";
2150 action = "edit-at-mouse";
2154 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2156 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2160 bool in_track_canvas;
2162 if (!mouse_frame (foo, in_track_canvas)) {
2163 in_track_canvas = false;
2166 reset_canvas_action_sensitivity (in_track_canvas);
2172 Editor::set_state (const XMLNode& node, int /*version*/)
2174 const XMLProperty* prop;
2181 g.base_width = default_width;
2182 g.base_height = default_height;
2186 if ((geometry = find_named_node (node, "geometry")) != 0) {
2190 if ((prop = geometry->property("x_size")) == 0) {
2191 prop = geometry->property ("x-size");
2194 g.base_width = atoi(prop->value());
2196 if ((prop = geometry->property("y_size")) == 0) {
2197 prop = geometry->property ("y-size");
2200 g.base_height = atoi(prop->value());
2203 if ((prop = geometry->property ("x_pos")) == 0) {
2204 prop = geometry->property ("x-pos");
2207 x = atoi (prop->value());
2210 if ((prop = geometry->property ("y_pos")) == 0) {
2211 prop = geometry->property ("y-pos");
2214 y = atoi (prop->value());
2218 set_default_size (g.base_width, g.base_height);
2221 if (_session && (prop = node.property ("playhead"))) {
2223 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2224 playhead_cursor->set_position (pos);
2226 playhead_cursor->set_position (0);
2229 if ((prop = node.property ("mixer-width"))) {
2230 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2233 if ((prop = node.property ("zoom-focus"))) {
2234 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2237 if ((prop = node.property ("zoom"))) {
2238 reset_zoom (PBD::atof (prop->value()));
2240 reset_zoom (frames_per_unit);
2243 if ((prop = node.property ("snap-to"))) {
2244 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2247 if ((prop = node.property ("snap-mode"))) {
2248 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2251 if ((prop = node.property ("internal-snap-to"))) {
2252 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2255 if ((prop = node.property ("internal-snap-mode"))) {
2256 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2259 if ((prop = node.property ("pre-internal-snap-to"))) {
2260 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2263 if ((prop = node.property ("pre-internal-snap-mode"))) {
2264 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2267 if ((prop = node.property ("mouse-mode"))) {
2268 MouseMode m = str2mousemode(prop->value());
2269 set_mouse_mode (m, true);
2271 set_mouse_mode (MouseObject, true);
2274 if ((prop = node.property ("left-frame")) != 0) {
2276 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2280 reset_x_origin (pos);
2284 if ((prop = node.property ("y-origin")) != 0) {
2285 reset_y_origin (atof (prop->value ()));
2288 if ((prop = node.property ("internal-edit"))) {
2289 bool yn = string_is_affirmative (prop->value());
2290 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2292 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2293 tact->set_active (!yn);
2294 tact->set_active (yn);
2298 if ((prop = node.property ("join-object-range"))) {
2299 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2302 if ((prop = node.property ("edit-point"))) {
2303 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2306 if ((prop = node.property ("show-measures"))) {
2307 bool yn = string_is_affirmative (prop->value());
2308 _show_measures = yn;
2309 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2311 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2312 /* do it twice to force the change */
2313 tact->set_active (!yn);
2314 tact->set_active (yn);
2318 if ((prop = node.property ("follow-playhead"))) {
2319 bool yn = string_is_affirmative (prop->value());
2320 set_follow_playhead (yn);
2321 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2323 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2324 if (tact->get_active() != yn) {
2325 tact->set_active (yn);
2330 if ((prop = node.property ("stationary-playhead"))) {
2331 bool yn = string_is_affirmative (prop->value());
2332 set_stationary_playhead (yn);
2333 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2335 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2336 if (tact->get_active() != yn) {
2337 tact->set_active (yn);
2342 if ((prop = node.property ("region-list-sort-type"))) {
2343 RegionListSortType st;
2344 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2347 if ((prop = node.property ("xfades-visible"))) {
2348 bool yn = string_is_affirmative (prop->value());
2349 _xfade_visibility = !yn;
2350 // set_xfade_visibility (yn);
2353 if ((prop = node.property ("show-editor-mixer"))) {
2355 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2358 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2359 bool yn = string_is_affirmative (prop->value());
2361 /* do it twice to force the change */
2363 tact->set_active (!yn);
2364 tact->set_active (yn);
2367 if ((prop = node.property ("show-editor-list"))) {
2369 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2372 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2373 bool yn = string_is_affirmative (prop->value());
2375 /* do it twice to force the change */
2377 tact->set_active (!yn);
2378 tact->set_active (yn);
2381 if ((prop = node.property (X_("editor-list-page")))) {
2382 _the_notebook.set_current_page (atoi (prop->value ()));
2385 if ((prop = node.property (X_("show-marker-lines")))) {
2386 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2388 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2389 bool yn = string_is_affirmative (prop->value ());
2391 tact->set_active (!yn);
2392 tact->set_active (yn);
2395 XMLNodeList children = node.children ();
2396 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2397 selection->set_state (**i, Stateful::current_state_version);
2398 _regions->set_state (**i);
2401 if ((prop = node.property ("maximised"))) {
2402 bool yn = string_is_affirmative (prop->value());
2404 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2412 Editor::get_state ()
2414 XMLNode* node = new XMLNode ("Editor");
2417 id().print (buf, sizeof (buf));
2418 node->add_property ("id", buf);
2420 if (is_realized()) {
2421 Glib::RefPtr<Gdk::Window> win = get_window();
2423 int x, y, width, height;
2424 win->get_root_origin(x, y);
2425 win->get_size(width, height);
2427 XMLNode* geometry = new XMLNode ("geometry");
2429 snprintf(buf, sizeof(buf), "%d", width);
2430 geometry->add_property("x-size", string(buf));
2431 snprintf(buf, sizeof(buf), "%d", height);
2432 geometry->add_property("y-size", string(buf));
2433 snprintf(buf, sizeof(buf), "%d", x);
2434 geometry->add_property("x-pos", string(buf));
2435 snprintf(buf, sizeof(buf), "%d", y);
2436 geometry->add_property("y-pos", string(buf));
2437 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2438 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2439 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2440 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2441 geometry->add_property("edit-vertical-pane-pos", string(buf));
2443 node->add_child_nocopy (*geometry);
2446 maybe_add_mixer_strip_width (*node);
2448 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2449 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2450 node->add_property ("zoom", buf);
2451 node->add_property ("snap-to", enum_2_string (_snap_type));
2452 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2453 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2454 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2455 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2456 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2457 node->add_property ("edit-point", enum_2_string (_edit_point));
2459 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2460 node->add_property ("playhead", buf);
2461 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2462 node->add_property ("left-frame", buf);
2463 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2464 node->add_property ("y-origin", buf);
2466 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2467 node->add_property ("maximised", _maximised ? "yes" : "no");
2468 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2469 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2470 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2471 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2472 node->add_property ("mouse-mode", enum2str(mouse_mode));
2473 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2474 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2476 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2478 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2479 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2482 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2484 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2485 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2488 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2489 node->add_property (X_("editor-list-page"), buf);
2491 if (button_bindings) {
2492 XMLNode* bb = new XMLNode (X_("Buttons"));
2493 button_bindings->save (*bb);
2494 node->add_child_nocopy (*bb);
2497 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2499 node->add_child_nocopy (selection->get_state ());
2500 node->add_child_nocopy (_regions->get_state ());
2507 /** @param y y offset from the top of all trackviews.
2508 * @return pair: TimeAxisView that y is over, layer index.
2509 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2510 * in stacked or expanded region display mode, otherwise 0.
2512 std::pair<TimeAxisView *, double>
2513 Editor::trackview_by_y_position (double y)
2515 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2517 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2523 return std::make_pair ( (TimeAxisView *) 0, 0);
2526 /** Snap a position to the grid, if appropriate, taking into account current
2527 * grid settings and also the state of any snap modifier keys that may be pressed.
2528 * @param start Position to snap.
2529 * @param event Event to get current key modifier information from, or 0.
2532 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2534 if (!_session || !event) {
2538 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2539 if (_snap_mode == SnapOff) {
2540 snap_to_internal (start, direction, for_mark);
2543 if (_snap_mode != SnapOff) {
2544 snap_to_internal (start, direction, for_mark);
2550 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2552 if (!_session || _snap_mode == SnapOff) {
2556 snap_to_internal (start, direction, for_mark);
2560 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2562 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2563 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2565 switch (_snap_type) {
2566 case SnapToTimecodeFrame:
2567 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2568 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2570 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2574 case SnapToTimecodeSeconds:
2575 if (_session->config.get_timecode_offset_negative()) {
2576 start += _session->config.get_timecode_offset ();
2578 start -= _session->config.get_timecode_offset ();
2580 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2581 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2583 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2586 if (_session->config.get_timecode_offset_negative()) {
2587 start -= _session->config.get_timecode_offset ();
2589 start += _session->config.get_timecode_offset ();
2593 case SnapToTimecodeMinutes:
2594 if (_session->config.get_timecode_offset_negative()) {
2595 start += _session->config.get_timecode_offset ();
2597 start -= _session->config.get_timecode_offset ();
2599 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2600 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2602 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2604 if (_session->config.get_timecode_offset_negative()) {
2605 start -= _session->config.get_timecode_offset ();
2607 start += _session->config.get_timecode_offset ();
2611 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2617 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2619 const framepos_t one_second = _session->frame_rate();
2620 const framepos_t one_minute = _session->frame_rate() * 60;
2621 framepos_t presnap = start;
2625 switch (_snap_type) {
2626 case SnapToTimecodeFrame:
2627 case SnapToTimecodeSeconds:
2628 case SnapToTimecodeMinutes:
2629 return timecode_snap_to_internal (start, direction, for_mark);
2632 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2633 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2635 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2640 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2641 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2643 start = (framepos_t) floor ((double) start / one_second) * one_second;
2648 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2649 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2651 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2656 start = _session->tempo_map().round_to_bar (start, direction);
2660 start = _session->tempo_map().round_to_beat (start, direction);
2663 case SnapToBeatDiv128:
2664 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2666 case SnapToBeatDiv64:
2667 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2669 case SnapToBeatDiv32:
2670 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2672 case SnapToBeatDiv28:
2673 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2675 case SnapToBeatDiv24:
2676 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2678 case SnapToBeatDiv20:
2679 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2681 case SnapToBeatDiv16:
2682 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2684 case SnapToBeatDiv14:
2685 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2687 case SnapToBeatDiv12:
2688 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2690 case SnapToBeatDiv10:
2691 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2693 case SnapToBeatDiv8:
2694 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2696 case SnapToBeatDiv7:
2697 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2699 case SnapToBeatDiv6:
2700 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2702 case SnapToBeatDiv5:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2705 case SnapToBeatDiv4:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2708 case SnapToBeatDiv3:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2711 case SnapToBeatDiv2:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2720 _session->locations()->marks_either_side (start, before, after);
2722 if (before == max_framepos) {
2724 } else if (after == max_framepos) {
2726 } else if (before != max_framepos && after != max_framepos) {
2727 /* have before and after */
2728 if ((start - before) < (after - start)) {
2737 case SnapToRegionStart:
2738 case SnapToRegionEnd:
2739 case SnapToRegionSync:
2740 case SnapToRegionBoundary:
2741 if (!region_boundary_cache.empty()) {
2743 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2744 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2746 if (direction > 0) {
2747 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2749 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2752 if (next != region_boundary_cache.begin ()) {
2757 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2758 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2760 if (start > (p + n) / 2) {
2769 switch (_snap_mode) {
2775 if (presnap > start) {
2776 if (presnap > (start + unit_to_frame(snap_threshold))) {
2780 } else if (presnap < start) {
2781 if (presnap < (start - unit_to_frame(snap_threshold))) {
2787 /* handled at entry */
2795 Editor::setup_toolbar ()
2797 HBox* mode_box = manage(new HBox);
2798 mode_box->set_border_width (2);
2799 mode_box->set_spacing(4);
2801 HBox* mouse_mode_box = manage (new HBox);
2802 HBox* mouse_mode_hbox1 = manage (new HBox);
2803 HBox* mouse_mode_hbox2 = manage (new HBox);
2804 VBox* mouse_mode_vbox1 = manage (new VBox);
2805 VBox* mouse_mode_vbox2 = manage (new VBox);
2806 Alignment* mouse_mode_align1 = manage (new Alignment);
2807 Alignment* mouse_mode_align2 = manage (new Alignment);
2809 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2810 mouse_mode_size_group->add_widget (mouse_move_button);
2811 mouse_mode_size_group->add_widget (mouse_select_button);
2812 mouse_mode_size_group->add_widget (mouse_zoom_button);
2813 mouse_mode_size_group->add_widget (mouse_gain_button);
2814 mouse_mode_size_group->add_widget (mouse_timefx_button);
2815 mouse_mode_size_group->add_widget (mouse_audition_button);
2816 mouse_mode_size_group->add_widget (mouse_draw_button);
2817 mouse_mode_size_group->add_widget (internal_edit_button);
2819 /* make them just a bit bigger */
2820 mouse_move_button.set_size_request (-1, 25);
2822 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button));
2823 smart_mode_joiner->set_related_action (smart_mode_action);
2825 mouse_move_button.set_elements (ArdourButton::Element (ArdourButton::Body|ArdourButton::Text));
2826 mouse_select_button.set_elements (ArdourButton::Element (ArdourButton::Body|ArdourButton::Text));
2828 mouse_move_button.set_rounded_corner_mask (0x1); // upper left only
2829 mouse_select_button.set_rounded_corner_mask (0x2); // upper right only
2831 mouse_mode_hbox2->set_spacing (2);
2832 mouse_mode_box->set_spacing (2);
2834 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2835 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2836 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2837 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2838 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2839 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2840 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2842 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2843 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2845 mouse_mode_align1->add (*mouse_mode_vbox1);
2846 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2847 mouse_mode_align2->add (*mouse_mode_vbox2);
2848 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2850 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2851 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2853 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2854 if (!Profile->get_sae()) {
2855 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2857 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2859 edit_mode_selector.set_name ("EditModeSelector");
2860 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2861 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2863 mode_box->pack_start (edit_mode_selector, false, false);
2864 mode_box->pack_start (*mouse_mode_box, false, false);
2866 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2867 _mouse_mode_tearoff->set_name ("MouseModeBase");
2868 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2870 if (Profile->get_sae()) {
2871 _mouse_mode_tearoff->set_can_be_torn_off (false);
2874 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2875 &_mouse_mode_tearoff->tearoff_window()));
2876 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2877 &_mouse_mode_tearoff->tearoff_window(), 1));
2878 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2879 &_mouse_mode_tearoff->tearoff_window()));
2880 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2881 &_mouse_mode_tearoff->tearoff_window(), 1));
2885 _zoom_box.set_spacing (2);
2886 _zoom_box.set_border_width (2);
2890 zoom_in_button.set_name ("zoom button");
2891 zoom_in_button.set_image (::get_icon ("zoom_in"));
2892 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2893 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2894 zoom_in_button.set_related_action (act);
2896 zoom_out_button.set_name ("zoom button");
2897 zoom_out_button.set_image (::get_icon ("zoom_out"));
2898 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2899 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2900 zoom_out_button.set_related_action (act);
2902 zoom_out_full_button.set_name ("zoom button");
2903 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2904 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2905 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2906 zoom_out_full_button.set_related_action (act);
2908 zoom_focus_selector.set_name ("ZoomFocusSelector");
2909 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2910 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2912 _zoom_box.pack_start (zoom_out_button, false, false);
2913 _zoom_box.pack_start (zoom_in_button, false, false);
2914 _zoom_box.pack_start (zoom_out_full_button, false, false);
2916 _zoom_box.pack_start (zoom_focus_selector, false, false);
2918 /* Track zoom buttons */
2919 tav_expand_button.set_name ("TrackHeightButton");
2920 tav_expand_button.set_size_request (-1, 20);
2921 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2922 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2923 act->connect_proxy (tav_expand_button);
2925 tav_shrink_button.set_name ("TrackHeightButton");
2926 tav_shrink_button.set_size_request (-1, 20);
2927 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2928 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2929 act->connect_proxy (tav_shrink_button);
2931 _zoom_box.pack_start (tav_shrink_button);
2932 _zoom_box.pack_start (tav_expand_button);
2934 _zoom_tearoff = manage (new TearOff (_zoom_box));
2936 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2937 &_zoom_tearoff->tearoff_window()));
2938 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2939 &_zoom_tearoff->tearoff_window(), 0));
2940 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2941 &_zoom_tearoff->tearoff_window()));
2942 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2943 &_zoom_tearoff->tearoff_window(), 0));
2945 snap_box.set_spacing (1);
2946 snap_box.set_border_width (2);
2948 snap_type_selector.set_name ("SnapTypeSelector");
2949 set_popdown_strings (snap_type_selector, snap_type_strings);
2950 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2952 snap_mode_selector.set_name ("SnapModeSelector");
2953 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2954 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2956 edit_point_selector.set_name ("EditPointSelector");
2957 set_popdown_strings (edit_point_selector, edit_point_strings);
2958 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2960 snap_box.pack_start (snap_mode_selector, false, false);
2961 snap_box.pack_start (snap_type_selector, false, false);
2962 snap_box.pack_start (edit_point_selector, false, false);
2966 HBox *nudge_box = manage (new HBox);
2967 nudge_box->set_spacing (2);
2968 nudge_box->set_border_width (2);
2970 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2971 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2973 nudge_box->pack_start (nudge_backward_button, false, false);
2974 nudge_box->pack_start (nudge_forward_button, false, false);
2975 nudge_box->pack_start (*nudge_clock, false, false);
2978 /* Pack everything in... */
2980 HBox* hbox = manage (new HBox);
2981 hbox->set_spacing(10);
2983 _tools_tearoff = manage (new TearOff (*hbox));
2984 _tools_tearoff->set_name ("MouseModeBase");
2985 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2987 if (Profile->get_sae()) {
2988 _tools_tearoff->set_can_be_torn_off (false);
2991 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2992 &_tools_tearoff->tearoff_window()));
2993 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2994 &_tools_tearoff->tearoff_window(), 0));
2995 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2996 &_tools_tearoff->tearoff_window()));
2997 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2998 &_tools_tearoff->tearoff_window(), 0));
3000 toolbar_hbox.set_spacing (10);
3001 toolbar_hbox.set_border_width (1);
3003 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3004 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3005 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3007 hbox->pack_start (snap_box, false, false);
3008 if (!Profile->get_small_screen()) {
3009 hbox->pack_start (*nudge_box, false, false);
3011 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3013 hbox->pack_start (panic_box, false, false);
3017 toolbar_base.set_name ("ToolBarBase");
3018 toolbar_base.add (toolbar_hbox);
3020 _toolbar_viewport.add (toolbar_base);
3021 /* stick to the required height but allow width to vary if there's not enough room */
3022 _toolbar_viewport.set_size_request (1, -1);
3024 toolbar_frame.set_shadow_type (SHADOW_OUT);
3025 toolbar_frame.set_name ("BaseFrame");
3026 toolbar_frame.add (_toolbar_viewport);
3030 Editor::setup_tooltips ()
3032 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3033 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
3034 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3035 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3036 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3037 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3038 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3039 ARDOUR_UI::instance()->set_tip (smart_mode_joiner, _("Smart Mode (Select/Move Objects + Ranges)"));
3040 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3041 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3042 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
3043 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
3044 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3045 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3046 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3047 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3048 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3049 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3050 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3051 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3052 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3053 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3054 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3058 Editor::convert_drop_to_paths (
3059 vector<string>& paths,
3060 const RefPtr<Gdk::DragContext>& /*context*/,
3063 const SelectionData& data,
3067 if (_session == 0) {
3071 vector<string> uris = data.get_uris();
3075 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3076 are actually URI lists. So do it by hand.
3079 if (data.get_target() != "text/plain") {
3083 /* Parse the "uri-list" format that Nautilus provides,
3084 where each pathname is delimited by \r\n.
3086 THERE MAY BE NO NULL TERMINATING CHAR!!!
3089 string txt = data.get_text();
3093 p = (const char *) malloc (txt.length() + 1);
3094 txt.copy ((char *) p, txt.length(), 0);
3095 ((char*)p)[txt.length()] = '\0';
3101 while (g_ascii_isspace (*p))
3105 while (*q && (*q != '\n') && (*q != '\r')) {
3112 while (q > p && g_ascii_isspace (*q))
3117 uris.push_back (string (p, q - p + 1));
3121 p = strchr (p, '\n');
3133 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3135 if ((*i).substr (0,7) == "file://") {
3138 PBD::url_decode (p);
3140 // scan forward past three slashes
3142 string::size_type slashcnt = 0;
3143 string::size_type n = 0;
3144 string::iterator x = p.begin();
3146 while (slashcnt < 3 && x != p.end()) {
3149 } else if (slashcnt == 3) {
3156 if (slashcnt != 3 || x == p.end()) {
3157 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3161 paths.push_back (p.substr (n - 1));
3169 Editor::new_tempo_section ()
3175 Editor::map_transport_state ()
3177 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3179 if (_session && _session->transport_stopped()) {
3180 have_pending_keyboard_selection = false;
3183 update_loop_range_view (true);
3188 Editor::State::State (PublicEditor const * e)
3190 selection = new Selection (e);
3193 Editor::State::~State ()
3199 Editor::begin_reversible_command (string name)
3202 _session->begin_reversible_command (name);
3207 Editor::begin_reversible_command (GQuark q)
3210 _session->begin_reversible_command (q);
3215 Editor::commit_reversible_command ()
3218 _session->commit_reversible_command ();
3223 Editor::history_changed ()
3227 if (undo_action && _session) {
3228 if (_session->undo_depth() == 0) {
3229 label = S_("Command|Undo");
3231 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3233 undo_action->property_label() = label;
3236 if (redo_action && _session) {
3237 if (_session->redo_depth() == 0) {
3240 label = string_compose(_("Redo (%1)"), _session->next_redo());
3242 redo_action->property_label() = label;
3247 Editor::duplicate_dialog (bool with_dialog)
3251 if (mouse_mode == MouseRange) {
3252 if (selection->time.length() == 0) {
3257 RegionSelection rs = get_regions_from_selection_and_entered ();
3259 if (mouse_mode != MouseRange && rs.empty()) {
3265 ArdourDialog win (_("Duplicate"));
3266 Label label (_("Number of duplications:"));
3267 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3268 SpinButton spinner (adjustment, 0.0, 1);
3271 win.get_vbox()->set_spacing (12);
3272 win.get_vbox()->pack_start (hbox);
3273 hbox.set_border_width (6);
3274 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3276 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3277 place, visually. so do this by hand.
3280 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3281 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3282 spinner.grab_focus();
3288 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3289 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3290 win.set_default_response (RESPONSE_ACCEPT);
3292 win.set_position (WIN_POS_MOUSE);
3294 spinner.grab_focus ();
3296 switch (win.run ()) {
3297 case RESPONSE_ACCEPT:
3303 times = adjustment.get_value();
3306 if (mouse_mode == MouseRange) {
3307 duplicate_selection (times);
3309 duplicate_some_regions (rs, times);
3314 Editor::set_edit_mode (EditMode m)
3316 Config->set_edit_mode (m);
3320 Editor::cycle_edit_mode ()
3322 switch (Config->get_edit_mode()) {
3324 if (Profile->get_sae()) {
3325 Config->set_edit_mode (Lock);
3327 Config->set_edit_mode (Splice);
3331 Config->set_edit_mode (Lock);
3334 Config->set_edit_mode (Slide);
3340 Editor::edit_mode_selection_done ()
3342 string s = edit_mode_selector.get_active_text ();
3345 Config->set_edit_mode (string_to_edit_mode (s));
3350 Editor::snap_type_selection_done ()
3352 string choice = snap_type_selector.get_active_text();
3353 SnapType snaptype = SnapToBeat;
3355 if (choice == _("Beats/2")) {
3356 snaptype = SnapToBeatDiv2;
3357 } else if (choice == _("Beats/3")) {
3358 snaptype = SnapToBeatDiv3;
3359 } else if (choice == _("Beats/4")) {
3360 snaptype = SnapToBeatDiv4;
3361 } else if (choice == _("Beats/5")) {
3362 snaptype = SnapToBeatDiv5;
3363 } else if (choice == _("Beats/6")) {
3364 snaptype = SnapToBeatDiv6;
3365 } else if (choice == _("Beats/7")) {
3366 snaptype = SnapToBeatDiv7;
3367 } else if (choice == _("Beats/8")) {
3368 snaptype = SnapToBeatDiv8;
3369 } else if (choice == _("Beats/10")) {
3370 snaptype = SnapToBeatDiv10;
3371 } else if (choice == _("Beats/12")) {
3372 snaptype = SnapToBeatDiv12;
3373 } else if (choice == _("Beats/14")) {
3374 snaptype = SnapToBeatDiv14;
3375 } else if (choice == _("Beats/16")) {
3376 snaptype = SnapToBeatDiv16;
3377 } else if (choice == _("Beats/20")) {
3378 snaptype = SnapToBeatDiv20;
3379 } else if (choice == _("Beats/24")) {
3380 snaptype = SnapToBeatDiv24;
3381 } else if (choice == _("Beats/28")) {
3382 snaptype = SnapToBeatDiv28;
3383 } else if (choice == _("Beats/32")) {
3384 snaptype = SnapToBeatDiv32;
3385 } else if (choice == _("Beats/64")) {
3386 snaptype = SnapToBeatDiv64;
3387 } else if (choice == _("Beats/128")) {
3388 snaptype = SnapToBeatDiv128;
3389 } else if (choice == _("Beats")) {
3390 snaptype = SnapToBeat;
3391 } else if (choice == _("Bars")) {
3392 snaptype = SnapToBar;
3393 } else if (choice == _("Marks")) {
3394 snaptype = SnapToMark;
3395 } else if (choice == _("Region starts")) {
3396 snaptype = SnapToRegionStart;
3397 } else if (choice == _("Region ends")) {
3398 snaptype = SnapToRegionEnd;
3399 } else if (choice == _("Region bounds")) {
3400 snaptype = SnapToRegionBoundary;
3401 } else if (choice == _("Region syncs")) {
3402 snaptype = SnapToRegionSync;
3403 } else if (choice == _("CD Frames")) {
3404 snaptype = SnapToCDFrame;
3405 } else if (choice == _("Timecode Frames")) {
3406 snaptype = SnapToTimecodeFrame;
3407 } else if (choice == _("Timecode Seconds")) {
3408 snaptype = SnapToTimecodeSeconds;
3409 } else if (choice == _("Timecode Minutes")) {
3410 snaptype = SnapToTimecodeMinutes;
3411 } else if (choice == _("Seconds")) {
3412 snaptype = SnapToSeconds;
3413 } else if (choice == _("Minutes")) {
3414 snaptype = SnapToMinutes;
3417 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3419 ract->set_active ();
3424 Editor::snap_mode_selection_done ()
3426 string choice = snap_mode_selector.get_active_text();
3427 SnapMode mode = SnapNormal;
3429 if (choice == _("No Grid")) {
3431 } else if (choice == _("Grid")) {
3433 } else if (choice == _("Magnetic")) {
3434 mode = SnapMagnetic;
3437 RefPtr<RadioAction> ract = snap_mode_action (mode);
3440 ract->set_active (true);
3445 Editor::cycle_edit_point (bool with_marker)
3447 switch (_edit_point) {
3449 set_edit_point_preference (EditAtPlayhead);
3451 case EditAtPlayhead:
3453 set_edit_point_preference (EditAtSelectedMarker);
3455 set_edit_point_preference (EditAtMouse);
3458 case EditAtSelectedMarker:
3459 set_edit_point_preference (EditAtMouse);
3465 Editor::edit_point_selection_done ()
3467 string choice = edit_point_selector.get_active_text();
3468 EditPoint ep = EditAtSelectedMarker;
3470 if (choice == _("Marker")) {
3471 set_edit_point_preference (EditAtSelectedMarker);
3472 } else if (choice == _("Playhead")) {
3473 set_edit_point_preference (EditAtPlayhead);
3475 set_edit_point_preference (EditAtMouse);
3478 RefPtr<RadioAction> ract = edit_point_action (ep);
3481 ract->set_active (true);
3486 Editor::zoom_focus_selection_done ()
3488 string choice = zoom_focus_selector.get_active_text();
3489 ZoomFocus focus_type = ZoomFocusLeft;
3491 if (choice == _("Left")) {
3492 focus_type = ZoomFocusLeft;
3493 } else if (choice == _("Right")) {
3494 focus_type = ZoomFocusRight;
3495 } else if (choice == _("Center")) {
3496 focus_type = ZoomFocusCenter;
3497 } else if (choice == _("Playhead")) {
3498 focus_type = ZoomFocusPlayhead;
3499 } else if (choice == _("Mouse")) {
3500 focus_type = ZoomFocusMouse;
3501 } else if (choice == _("Edit point")) {
3502 focus_type = ZoomFocusEdit;
3505 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3508 ract->set_active ();
3513 Editor::edit_controls_button_release (GdkEventButton* ev)
3515 if (Keyboard::is_context_menu_event (ev)) {
3516 ARDOUR_UI::instance()->add_route (this);
3517 } else if (ev->button == 1) {
3518 selection->clear_tracks ();
3525 Editor::mouse_select_button_release (GdkEventButton* ev)
3527 /* this handles just right-clicks */
3529 if (ev->button != 3) {
3537 Editor::set_zoom_focus (ZoomFocus f)
3539 string str = zoom_focus_strings[(int)f];
3541 if (str != zoom_focus_selector.get_active_text()) {
3542 zoom_focus_selector.set_active_text (str);
3545 if (zoom_focus != f) {
3552 Editor::ensure_float (Window& win)
3554 win.set_transient_for (*this);
3558 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3560 /* recover or initialize pane positions. do this here rather than earlier because
3561 we don't want the positions to change the child allocations, which they seem to do.
3567 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3576 XMLNode* geometry = find_named_node (*node, "geometry");
3578 if (which == static_cast<Paned*> (&edit_pane)) {
3580 if (done & Horizontal) {
3584 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3585 _notebook_shrunk = string_is_affirmative (prop->value ());
3588 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3589 /* initial allocation is 90% to canvas, 10% to notebook */
3590 pos = (int) floor (alloc.get_width() * 0.90f);
3591 snprintf (buf, sizeof(buf), "%d", pos);
3593 pos = atoi (prop->value());
3596 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3597 edit_pane.set_position (pos);
3600 done = (Pane) (done | Horizontal);
3602 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3604 if (done & Vertical) {
3608 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3609 /* initial allocation is 90% to canvas, 10% to summary */
3610 pos = (int) floor (alloc.get_height() * 0.90f);
3611 snprintf (buf, sizeof(buf), "%d", pos);
3614 pos = atoi (prop->value());
3617 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3618 editor_summary_pane.set_position (pos);
3621 done = (Pane) (done | Vertical);
3626 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3628 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3629 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3630 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3631 top_hbox.remove (toolbar_frame);
3636 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3638 if (toolbar_frame.get_parent() == 0) {
3639 top_hbox.pack_end (toolbar_frame);
3644 Editor::set_show_measures (bool yn)
3646 if (_show_measures != yn) {
3649 if ((_show_measures = yn) == true) {
3651 tempo_lines->show();
3659 Editor::toggle_follow_playhead ()
3661 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3663 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3664 set_follow_playhead (tact->get_active());
3668 /** @param yn true to follow playhead, otherwise false.
3669 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3672 Editor::set_follow_playhead (bool yn, bool catch_up)
3674 if (_follow_playhead != yn) {
3675 if ((_follow_playhead = yn) == true && catch_up) {
3677 reset_x_origin_to_follow_playhead ();
3684 Editor::toggle_stationary_playhead ()
3686 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3688 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3689 set_stationary_playhead (tact->get_active());
3694 Editor::set_stationary_playhead (bool yn)
3696 if (_stationary_playhead != yn) {
3697 if ((_stationary_playhead = yn) == true) {
3699 // FIXME need a 3.0 equivalent of this 2.X call
3700 // update_current_screen ();
3707 Editor::toggle_xfade_active (RouteTimeAxisView* tv, boost::weak_ptr<Crossfade> wxfade)
3709 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3714 vector<boost::shared_ptr<Crossfade> > all = get_equivalent_crossfades (*tv, xfade, ARDOUR::Properties::edit.property_id);
3716 _session->begin_reversible_command (_("Change crossfade active state"));
3718 for (vector<boost::shared_ptr<Crossfade> >::iterator i = all.begin(); i != all.end(); ++i) {
3719 (*i)->clear_changes ();
3720 (*i)->set_active (!(*i)->active());
3721 _session->add_command (new StatefulDiffCommand (*i));
3724 _session->commit_reversible_command ();
3728 Editor::toggle_xfade_length (RouteTimeAxisView* tv, boost::weak_ptr<Crossfade> wxfade)
3730 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3735 vector<boost::shared_ptr<Crossfade> > all = get_equivalent_crossfades (*tv, xfade, ARDOUR::Properties::edit.property_id);
3737 /* This can't be a StatefulDiffCommand as the fade shapes are not
3738 managed by the Stateful properties system.
3740 _session->begin_reversible_command (_("Change crossfade length"));
3742 for (vector<boost::shared_ptr<Crossfade> >::iterator i = all.begin(); i != all.end(); ++i) {
3743 XMLNode& before = (*i)->get_state ();
3744 (*i)->set_follow_overlap (!(*i)->following_overlap());
3745 XMLNode& after = (*i)->get_state ();
3747 _session->add_command (new MementoCommand<Crossfade> (*i->get(), &before, &after));
3750 _session->commit_reversible_command ();
3754 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3756 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3762 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3766 switch (cew.run ()) {
3767 case RESPONSE_ACCEPT:
3774 PropertyChange all_crossfade_properties;
3775 all_crossfade_properties.add (ARDOUR::Properties::active);
3776 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3777 xfade->PropertyChanged (all_crossfade_properties);
3781 Editor::playlist_selector () const
3783 return *_playlist_selector;
3787 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3791 switch (_snap_type) {
3796 case SnapToBeatDiv128:
3799 case SnapToBeatDiv64:
3802 case SnapToBeatDiv32:
3805 case SnapToBeatDiv28:
3808 case SnapToBeatDiv24:
3811 case SnapToBeatDiv20:
3814 case SnapToBeatDiv16:
3817 case SnapToBeatDiv14:
3820 case SnapToBeatDiv12:
3823 case SnapToBeatDiv10:
3826 case SnapToBeatDiv8:
3829 case SnapToBeatDiv7:
3832 case SnapToBeatDiv6:
3835 case SnapToBeatDiv5:
3838 case SnapToBeatDiv4:
3841 case SnapToBeatDiv3:
3844 case SnapToBeatDiv2:
3850 return _session->tempo_map().meter_at (position).divisions_per_bar();
3855 case SnapToTimecodeFrame:
3856 case SnapToTimecodeSeconds:
3857 case SnapToTimecodeMinutes:
3860 case SnapToRegionStart:
3861 case SnapToRegionEnd:
3862 case SnapToRegionSync:
3863 case SnapToRegionBoundary:
3873 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3877 ret = nudge_clock->current_duration (pos);
3878 next = ret + 1; /* XXXX fix me */
3884 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3886 ArdourDialog dialog (_("Playlist Deletion"));
3887 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3888 "If it is kept, its audio files will not be cleaned.\n"
3889 "If it is deleted, audio files used by it alone will be cleaned."),
3892 dialog.set_position (WIN_POS_CENTER);
3893 dialog.get_vbox()->pack_start (label);
3897 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3898 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3899 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3901 switch (dialog.run ()) {
3902 case RESPONSE_ACCEPT:
3903 /* delete the playlist */
3907 case RESPONSE_REJECT:
3908 /* keep the playlist */
3920 Editor::audio_region_selection_covers (framepos_t where)
3922 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3923 if ((*a)->region()->covers (where)) {
3932 Editor::prepare_for_cleanup ()
3934 cut_buffer->clear_regions ();
3935 cut_buffer->clear_playlists ();
3937 selection->clear_regions ();
3938 selection->clear_playlists ();
3940 _regions->suspend_redisplay ();
3944 Editor::finish_cleanup ()
3946 _regions->resume_redisplay ();
3950 Editor::transport_loop_location()
3953 return _session->locations()->auto_loop_location();
3960 Editor::transport_punch_location()
3963 return _session->locations()->auto_punch_location();
3970 Editor::control_layout_scroll (GdkEventScroll* ev)
3972 if (Keyboard::some_magic_widget_has_focus()) {
3976 switch (ev->direction) {
3978 scroll_tracks_up_line ();
3982 case GDK_SCROLL_DOWN:
3983 scroll_tracks_down_line ();
3987 /* no left/right handling yet */
3995 Editor::session_state_saved (string)
3998 _snapshots->redisplay ();
4002 Editor::maximise_editing_space ()
4010 if (!Config->get_keep_tearoffs()) {
4011 /* these calls will leave each tearoff visible *if* it is torn off,
4012 but invisible otherwise.
4014 _mouse_mode_tearoff->set_visible (false);
4015 _tools_tearoff->set_visible (false);
4016 _zoom_tearoff->set_visible (false);
4023 Editor::restore_editing_space ()
4031 if (!Config->get_keep_tearoffs()) {
4032 _mouse_mode_tearoff->set_visible (true);
4033 _tools_tearoff->set_visible (true);
4034 _zoom_tearoff->set_visible (true);
4041 * Make new playlists for a given track and also any others that belong
4042 * to the same active route group with the `edit' property.
4047 Editor::new_playlists (TimeAxisView* v)
4049 begin_reversible_command (_("new playlists"));
4050 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4051 _session->playlists->get (playlists);
4052 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4053 commit_reversible_command ();
4057 * Use a copy of the current playlist for a given track and also any others that belong
4058 * to the same active route group with the `edit' property.
4063 Editor::copy_playlists (TimeAxisView* v)
4065 begin_reversible_command (_("copy playlists"));
4066 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4067 _session->playlists->get (playlists);
4068 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4069 commit_reversible_command ();
4072 /** Clear the current playlist for a given track and also any others that belong
4073 * to the same active route group with the `edit' property.
4078 Editor::clear_playlists (TimeAxisView* v)
4080 begin_reversible_command (_("clear playlists"));
4081 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4082 _session->playlists->get (playlists);
4083 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4084 commit_reversible_command ();
4088 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4090 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4094 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4096 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4100 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4102 atv.clear_playlist ();
4106 Editor::on_key_press_event (GdkEventKey* ev)
4108 return key_press_focus_accelerator_handler (*this, ev);
4112 Editor::on_key_release_event (GdkEventKey* ev)
4114 return Gtk::Window::on_key_release_event (ev);
4115 // return key_press_focus_accelerator_handler (*this, ev);
4118 /** Queue up a change to the viewport x origin.
4119 * @param frame New x origin.
4122 Editor::reset_x_origin (framepos_t frame)
4124 queue_visual_change (frame);
4128 Editor::reset_y_origin (double y)
4130 queue_visual_change_y (y);
4134 Editor::reset_zoom (double fpu)
4136 queue_visual_change (fpu);
4140 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4142 reset_x_origin (frame);
4145 if (!no_save_visual) {
4146 undo_visual_stack.push_back (current_visual_state(false));
4150 Editor::VisualState::VisualState (bool with_tracks)
4151 : gui_state (with_tracks ? new GUIObjectState : 0)
4155 Editor::VisualState::~VisualState ()
4160 Editor::VisualState*
4161 Editor::current_visual_state (bool with_tracks)
4163 VisualState* vs = new VisualState (with_tracks);
4164 vs->y_position = vertical_adjustment.get_value();
4165 vs->frames_per_unit = frames_per_unit;
4166 vs->leftmost_frame = leftmost_frame;
4167 vs->zoom_focus = zoom_focus;
4170 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4177 Editor::undo_visual_state ()
4179 if (undo_visual_stack.empty()) {
4183 VisualState* vs = undo_visual_stack.back();
4184 undo_visual_stack.pop_back();
4187 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4189 use_visual_state (*vs);
4193 Editor::redo_visual_state ()
4195 if (redo_visual_stack.empty()) {
4199 VisualState* vs = redo_visual_stack.back();
4200 redo_visual_stack.pop_back();
4202 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4204 use_visual_state (*vs);
4208 Editor::swap_visual_state ()
4210 if (undo_visual_stack.empty()) {
4211 redo_visual_state ();
4213 undo_visual_state ();
4218 Editor::use_visual_state (VisualState& vs)
4220 PBD::Unwinder<bool> nsv (no_save_visual, true);
4222 _routes->suspend_redisplay ();
4224 vertical_adjustment.set_value (vs.y_position);
4226 set_zoom_focus (vs.zoom_focus);
4227 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4230 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4232 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4233 (*i)->reset_visual_state ();
4237 _routes->update_visibility ();
4238 _routes->resume_redisplay ();
4242 Editor::set_frames_per_unit (double fpu)
4244 /* this is the core function that controls the zoom level of the canvas. it is called
4245 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4248 if (fpu == frames_per_unit) {
4257 /* don't allow zooms that fit more than the maximum number
4258 of frames into an 800 pixel wide space.
4261 if (max_framepos / fpu < 800.0) {
4266 tempo_lines->tempo_map_changed();
4268 frames_per_unit = fpu;
4273 Editor::post_zoom ()
4275 // convert fpu to frame count
4277 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4279 if (frames_per_unit != zoom_range_clock->current_duration()) {
4280 zoom_range_clock->set (frames);
4283 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4284 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4285 (*i)->reshow_selection (selection->time);
4289 ZoomChanged (); /* EMIT_SIGNAL */
4291 //reset_scrolling_region ();
4293 if (playhead_cursor) {
4294 playhead_cursor->set_position (playhead_cursor->current_frame);
4297 refresh_location_display();
4298 _summary->set_overlays_dirty ();
4300 update_marker_labels ();
4306 Editor::queue_visual_change (framepos_t where)
4308 pending_visual_change.add (VisualChange::TimeOrigin);
4309 pending_visual_change.time_origin = where;
4310 ensure_visual_change_idle_handler ();
4314 Editor::queue_visual_change (double fpu)
4316 pending_visual_change.add (VisualChange::ZoomLevel);
4317 pending_visual_change.frames_per_unit = fpu;
4319 ensure_visual_change_idle_handler ();
4323 Editor::queue_visual_change_y (double y)
4325 pending_visual_change.add (VisualChange::YOrigin);
4326 pending_visual_change.y_origin = y;
4328 ensure_visual_change_idle_handler ();
4332 Editor::ensure_visual_change_idle_handler ()
4334 if (pending_visual_change.idle_handler_id < 0) {
4335 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4340 Editor::_idle_visual_changer (void* arg)
4342 return static_cast<Editor*>(arg)->idle_visual_changer ();
4346 Editor::idle_visual_changer ()
4348 VisualChange::Type p = pending_visual_change.pending;
4349 pending_visual_change.pending = (VisualChange::Type) 0;
4351 double const last_time_origin = horizontal_position ();
4353 if (p & VisualChange::TimeOrigin) {
4354 /* This is a bit of a hack, but set_frames_per_unit
4355 below will (if called) end up with the
4356 CrossfadeViews looking at Editor::leftmost_frame,
4357 and if we're changing origin and zoom in the same
4358 operation it will be the wrong value unless we
4362 leftmost_frame = pending_visual_change.time_origin;
4363 assert (leftmost_frame >= 0);
4366 if (p & VisualChange::ZoomLevel) {
4367 set_frames_per_unit (pending_visual_change.frames_per_unit);
4369 compute_fixed_ruler_scale ();
4370 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4371 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4372 update_tempo_based_rulers ();
4374 if (p & VisualChange::TimeOrigin) {
4375 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4377 if (p & VisualChange::YOrigin) {
4378 vertical_adjustment.set_value (pending_visual_change.y_origin);
4381 if (last_time_origin == horizontal_position ()) {
4382 /* changed signal not emitted */
4383 update_fixed_rulers ();
4384 redisplay_tempo (true);
4387 _summary->set_overlays_dirty ();
4389 pending_visual_change.idle_handler_id = -1;
4390 return 0; /* this is always a one-shot call */
4393 struct EditorOrderTimeAxisSorter {
4394 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4395 return a->order () < b->order ();
4400 Editor::sort_track_selection (TrackViewList& sel)
4402 EditorOrderTimeAxisSorter cmp;
4407 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4410 framepos_t where = 0;
4411 EditPoint ep = _edit_point;
4413 if (from_context_menu && (ep == EditAtMouse)) {
4414 return event_frame (&context_click_event, 0, 0);
4417 if (entered_marker) {
4418 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4419 return entered_marker->position();
4422 if (ignore_playhead && ep == EditAtPlayhead) {
4423 ep = EditAtSelectedMarker;
4427 case EditAtPlayhead:
4428 where = _session->audible_frame();
4429 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4432 case EditAtSelectedMarker:
4433 if (!selection->markers.empty()) {
4435 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4438 where = loc->start();
4442 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4450 if (!mouse_frame (where, ignored)) {
4451 /* XXX not right but what can we do ? */
4455 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4463 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4465 if (!_session) return;
4467 begin_reversible_command (cmd);
4471 if ((tll = transport_loop_location()) == 0) {
4472 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4473 XMLNode &before = _session->locations()->get_state();
4474 _session->locations()->add (loc, true);
4475 _session->set_auto_loop_location (loc);
4476 XMLNode &after = _session->locations()->get_state();
4477 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4479 XMLNode &before = tll->get_state();
4480 tll->set_hidden (false, this);
4481 tll->set (start, end);
4482 XMLNode &after = tll->get_state();
4483 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4486 commit_reversible_command ();
4490 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4492 if (!_session) return;
4494 begin_reversible_command (cmd);
4498 if ((tpl = transport_punch_location()) == 0) {
4499 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4500 XMLNode &before = _session->locations()->get_state();
4501 _session->locations()->add (loc, true);
4502 _session->set_auto_loop_location (loc);
4503 XMLNode &after = _session->locations()->get_state();
4504 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4507 XMLNode &before = tpl->get_state();
4508 tpl->set_hidden (false, this);
4509 tpl->set (start, end);
4510 XMLNode &after = tpl->get_state();
4511 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4514 commit_reversible_command ();
4517 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4518 * @param rs List to which found regions are added.
4519 * @param where Time to look at.
4520 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4523 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4525 const TrackViewList* tracks;
4528 tracks = &track_views;
4533 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4535 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4538 boost::shared_ptr<Track> tr;
4539 boost::shared_ptr<Playlist> pl;
4541 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4543 boost::shared_ptr<RegionList> regions = pl->regions_at (
4544 (framepos_t) floor ( (double) where * tr->speed()));
4546 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4547 RegionView* rv = rtv->view()->find_view (*i);
4558 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4560 const TrackViewList* tracks;
4563 tracks = &track_views;
4568 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4569 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4571 boost::shared_ptr<Track> tr;
4572 boost::shared_ptr<Playlist> pl;
4574 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4576 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4577 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4579 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4581 RegionView* rv = rtv->view()->find_view (*i);
4592 /** Start with regions that are selected. Then add equivalent regions
4593 * on tracks in the same active edit-enabled route group as any of
4594 * the regions that we started with.
4598 Editor::get_regions_from_selection ()
4600 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4603 /** Get regions using the following method:
4605 * Make an initial region list using the selected regions, unless
4606 * the edit point is `mouse' and the mouse is over an unselected
4607 * region. In this case, start with just that region.
4609 * Then, make an initial track list of the tracks that these
4610 * regions are on, and if the edit point is not `mouse', add the
4613 * Look at this track list and add any other tracks that are on the
4614 * same active edit-enabled route group as one of the initial tracks.
4616 * Finally take the initial region list and add any regions that are
4617 * under the edit point on one of the tracks on the track list to get
4618 * the returned region list.
4620 * The rationale here is that the mouse edit point is special in that
4621 * its position describes both a time and a track; the other edit
4622 * modes only describe a time. Hence if the edit point is `mouse' we
4623 * ignore selected tracks, as we assume the user means something by
4624 * pointing at a particular track. Also in this case we take note of
4625 * the region directly under the edit point, as there is always just one
4626 * (rather than possibly several with non-mouse edit points).
4630 Editor::get_regions_from_selection_and_edit_point ()
4632 RegionSelection regions;
4634 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4635 regions.add (entered_regionview);
4637 regions = selection->regions;
4640 TrackViewList tracks;
4642 if (_edit_point != EditAtMouse) {
4643 tracks = selection->tracks;
4646 /* Add any other tracks that have regions that are in the same
4647 edit-activated route group as one of our regions.
4649 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4651 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4653 if (g && g->is_active() && g->is_edit()) {
4654 tracks.add (axis_views_from_routes (g->route_list()));
4658 if (!tracks.empty()) {
4659 /* now find regions that are at the edit position on those tracks */
4660 framepos_t const where = get_preferred_edit_position ();
4661 get_regions_at (regions, where, tracks);
4667 /** Start with regions that are selected, or the entered regionview if none are selected.
4668 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4669 * of the regions that we started with.
4673 Editor::get_regions_from_selection_and_entered ()
4675 RegionSelection regions = selection->regions;
4677 if (regions.empty() && entered_regionview) {
4678 regions.add (entered_regionview);
4681 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4685 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4687 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4689 RouteTimeAxisView* tatv;
4691 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4693 boost::shared_ptr<Playlist> pl;
4694 vector<boost::shared_ptr<Region> > results;
4696 boost::shared_ptr<Track> tr;
4698 if ((tr = tatv->track()) == 0) {
4703 if ((pl = (tr->playlist())) != 0) {
4704 pl->get_region_list_equivalent_regions (region, results);
4707 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4708 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4709 regions.push_back (marv);
4718 Editor::show_rhythm_ferret ()
4720 if (rhythm_ferret == 0) {
4721 rhythm_ferret = new RhythmFerret(*this);
4724 rhythm_ferret->set_session (_session);
4725 rhythm_ferret->show ();
4726 rhythm_ferret->present ();
4730 Editor::first_idle ()
4732 MessageDialog* dialog = 0;
4734 if (track_views.size() > 1) {
4735 dialog = new MessageDialog (
4737 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4741 ARDOUR_UI::instance()->flush_pending ();
4744 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4748 // first idle adds route children (automation tracks), so we need to redisplay here
4749 _routes->redisplay ();
4756 Editor::_idle_resize (gpointer arg)
4758 return ((Editor*)arg)->idle_resize ();
4762 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4764 if (resize_idle_id < 0) {
4765 resize_idle_id = g_idle_add (_idle_resize, this);
4766 _pending_resize_amount = 0;
4769 /* make a note of the smallest resulting height, so that we can clamp the
4770 lower limit at TimeAxisView::hSmall */
4772 int32_t min_resulting = INT32_MAX;
4774 _pending_resize_amount += h;
4775 _pending_resize_view = view;
4777 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4779 if (selection->tracks.contains (_pending_resize_view)) {
4780 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4781 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4785 if (min_resulting < 0) {
4790 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4791 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4795 /** Handle pending resizing of tracks */
4797 Editor::idle_resize ()
4799 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4801 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4802 selection->tracks.contains (_pending_resize_view)) {
4804 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4805 if (*i != _pending_resize_view) {
4806 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4811 _pending_resize_amount = 0;
4813 _group_tabs->set_dirty ();
4814 resize_idle_id = -1;
4822 ENSURE_GUI_THREAD (*this, &Editor::located);
4824 playhead_cursor->set_position (_session->audible_frame ());
4825 if (_follow_playhead && !_pending_initial_locate) {
4826 reset_x_origin_to_follow_playhead ();
4829 _pending_locate_request = false;
4830 _pending_initial_locate = false;
4834 Editor::region_view_added (RegionView *)
4836 _summary->set_dirty ();
4840 Editor::region_view_removed ()
4842 _summary->set_dirty ();
4846 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4848 TrackViewList::const_iterator j = track_views.begin ();
4849 while (j != track_views.end()) {
4850 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4851 if (rtv && rtv->route() == r) {
4862 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4866 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4867 TimeAxisView* tv = axis_view_from_route (*i);
4878 Editor::handle_new_route (RouteList& routes)
4880 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4882 RouteTimeAxisView *rtv;
4883 list<RouteTimeAxisView*> new_views;
4885 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4886 boost::shared_ptr<Route> route = (*x);
4888 if (route->is_hidden() || route->is_monitor()) {
4892 DataType dt = route->input()->default_type();
4894 if (dt == ARDOUR::DataType::AUDIO) {
4895 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4896 rtv->set_route (route);
4897 } else if (dt == ARDOUR::DataType::MIDI) {
4898 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4899 rtv->set_route (route);
4901 throw unknown_type();
4904 new_views.push_back (rtv);
4905 track_views.push_back (rtv);
4907 rtv->effective_gain_display ();
4909 if (internal_editing()) {
4910 rtv->enter_internal_edit_mode ();
4912 rtv->leave_internal_edit_mode ();
4915 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4916 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4919 _routes->routes_added (new_views);
4920 _summary->routes_added (new_views);
4922 if (show_editor_mixer_when_tracks_arrive) {
4923 show_editor_mixer (true);
4926 editor_list_button.set_sensitive (true);
4930 Editor::timeaxisview_deleted (TimeAxisView *tv)
4932 if (_session && _session->deletion_in_progress()) {
4933 /* the situation is under control */
4937 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4939 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4941 _routes->route_removed (tv);
4943 if (tv == entered_track) {
4947 TimeAxisView::Children c = tv->get_child_list ();
4948 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4949 if (entered_track == i->get()) {
4954 /* remove it from the list of track views */
4956 TrackViewList::iterator i;
4958 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4959 i = track_views.erase (i);
4962 /* update whatever the current mixer strip is displaying, if revelant */
4964 boost::shared_ptr<Route> route;
4967 route = rtav->route ();
4970 if (current_mixer_strip && current_mixer_strip->route() == route) {
4972 TimeAxisView* next_tv;
4974 if (track_views.empty()) {
4976 } else if (i == track_views.end()) {
4977 next_tv = track_views.front();
4984 set_selected_mixer_strip (*next_tv);
4986 /* make the editor mixer strip go away setting the
4987 * button to inactive (which also unticks the menu option)
4990 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4996 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4998 if (apply_to_selection) {
4999 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5001 TrackSelection::iterator j = i;
5004 hide_track_in_display (*i, false);
5009 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5011 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5012 // this will hide the mixer strip
5013 set_selected_mixer_strip (*tv);
5016 _routes->hide_track_in_display (*tv);
5021 Editor::sync_track_view_list_and_routes ()
5023 track_views = TrackViewList (_routes->views ());
5025 _summary->set_dirty ();
5026 _group_tabs->set_dirty ();
5028 return false; // do not call again (until needed)
5032 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5034 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5039 /** Find a RouteTimeAxisView by the ID of its route */
5041 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5043 RouteTimeAxisView* v;
5045 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5046 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5047 if(v->route()->id() == id) {
5057 Editor::fit_route_group (RouteGroup *g)
5059 TrackViewList ts = axis_views_from_routes (g->route_list ());
5064 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5066 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5069 _session->cancel_audition ();
5073 if (_session->is_auditioning()) {
5074 _session->cancel_audition ();
5075 if (r == last_audition_region) {
5080 _session->audition_region (r);
5081 last_audition_region = r;
5086 Editor::hide_a_region (boost::shared_ptr<Region> r)
5088 r->set_hidden (true);
5092 Editor::show_a_region (boost::shared_ptr<Region> r)
5094 r->set_hidden (false);
5098 Editor::audition_region_from_region_list ()
5100 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5104 Editor::hide_region_from_region_list ()
5106 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5110 Editor::show_region_in_region_list ()
5112 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5116 Editor::step_edit_status_change (bool yn)
5119 start_step_editing ();
5121 stop_step_editing ();
5126 Editor::start_step_editing ()
5128 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5132 Editor::stop_step_editing ()
5134 step_edit_connection.disconnect ();
5138 Editor::check_step_edit ()
5140 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5141 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5143 mtv->check_step_edit ();
5147 return true; // do it again, till we stop
5151 Editor::scroll_press (Direction dir)
5153 ++_scroll_callbacks;
5155 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5156 /* delay the first auto-repeat */
5162 scroll_backward (1);
5170 scroll_tracks_up_line ();
5174 scroll_tracks_down_line ();
5178 /* do hacky auto-repeat */
5179 if (!_scroll_connection.connected ()) {
5181 _scroll_connection = Glib::signal_timeout().connect (
5182 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5185 _scroll_callbacks = 0;
5192 Editor::scroll_release ()
5194 _scroll_connection.disconnect ();
5197 /** Queue a change for the Editor viewport x origin to follow the playhead */
5199 Editor::reset_x_origin_to_follow_playhead ()
5201 framepos_t const frame = playhead_cursor->current_frame;
5203 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5205 if (_session->transport_speed() < 0) {
5207 if (frame > (current_page_frames() / 2)) {
5208 center_screen (frame-(current_page_frames()/2));
5210 center_screen (current_page_frames()/2);
5217 if (frame < leftmost_frame) {
5219 if (_session->transport_rolling()) {
5220 /* rolling; end up with the playhead at the right of the page */
5221 l = frame - current_page_frames ();
5223 /* not rolling: end up with the playhead 1/4 of the way along the page */
5224 l = frame - current_page_frames() / 4;
5228 if (_session->transport_rolling()) {
5229 /* rolling: end up with the playhead on the left of the page */
5232 /* not rolling: end up with the playhead 3/4 of the way along the page */
5233 l = frame - 3 * current_page_frames() / 4;
5241 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5247 Editor::super_rapid_screen_update ()
5249 if (!_session || !_session->engine().running()) {
5253 /* METERING / MIXER STRIPS */
5255 /* update track meters, if required */
5256 if (is_mapped() && meters_running) {
5257 RouteTimeAxisView* rtv;
5258 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5259 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5260 rtv->fast_update ();
5265 /* and any current mixer strip */
5266 if (current_mixer_strip) {
5267 current_mixer_strip->fast_update ();
5270 /* PLAYHEAD AND VIEWPORT */
5272 framepos_t const frame = _session->audible_frame();
5274 /* There are a few reasons why we might not update the playhead / viewport stuff:
5276 * 1. we don't update things when there's a pending locate request, otherwise
5277 * when the editor requests a locate there is a chance that this method
5278 * will move the playhead before the locate request is processed, causing
5280 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5281 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5284 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5286 last_update_frame = frame;
5288 if (!_dragging_playhead) {
5289 playhead_cursor->set_position (frame);
5292 if (!_stationary_playhead) {
5294 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5295 reset_x_origin_to_follow_playhead ();
5300 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5304 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5305 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5306 if (target <= 0.0) {
5309 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5310 target = (target * 0.15) + (current * 0.85);
5316 set_horizontal_position (current);
5325 Editor::session_going_away ()
5327 _have_idled = false;
5329 _session_connections.drop_connections ();
5331 super_rapid_screen_update_connection.disconnect ();
5333 selection->clear ();
5334 cut_buffer->clear ();
5336 clicked_regionview = 0;
5337 clicked_axisview = 0;
5338 clicked_routeview = 0;
5339 clicked_crossfadeview = 0;
5340 entered_regionview = 0;
5342 last_update_frame = 0;
5345 playhead_cursor->canvas_item.hide ();
5347 /* rip everything out of the list displays */
5351 _route_groups->clear ();
5353 /* do this first so that deleting a track doesn't reset cms to null
5354 and thus cause a leak.
5357 if (current_mixer_strip) {
5358 if (current_mixer_strip->get_parent() != 0) {
5359 global_hpacker.remove (*current_mixer_strip);
5361 delete current_mixer_strip;
5362 current_mixer_strip = 0;
5365 /* delete all trackviews */
5367 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5370 track_views.clear ();
5372 zoom_range_clock->set_session (0);
5373 nudge_clock->set_session (0);
5375 editor_list_button.set_active(false);
5376 editor_list_button.set_sensitive(false);
5378 /* clear tempo/meter rulers */
5379 remove_metric_marks ();
5381 clear_marker_display ();
5383 current_bbt_points_begin = current_bbt_points_end;
5385 /* get rid of any existing editor mixer strip */
5387 WindowTitle title(Glib::get_application_name());
5388 title += _("Editor");
5390 set_title (title.get_string());
5392 SessionHandlePtr::session_going_away ();
5397 Editor::show_editor_list (bool yn)
5400 _the_notebook.show ();
5402 _the_notebook.hide ();
5407 Editor::change_region_layering_order (bool from_context_menu)
5409 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5411 if (!clicked_routeview) {
5412 if (layering_order_editor) {
5413 layering_order_editor->hide ();
5418 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5424 boost::shared_ptr<Playlist> pl = track->playlist();
5430 if (layering_order_editor == 0) {
5431 layering_order_editor = new RegionLayeringOrderEditor (*this);
5432 layering_order_editor->set_position (WIN_POS_MOUSE);
5435 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5436 layering_order_editor->maybe_present ();
5440 Editor::update_region_layering_order_editor ()
5442 if (layering_order_editor && layering_order_editor->is_visible ()) {
5443 change_region_layering_order (true);
5448 Editor::setup_fade_images ()
5450 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5451 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5452 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5453 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5454 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5456 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5457 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5458 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5459 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5460 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5464 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5466 Editor::action_menu_item (std::string const & name)
5468 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5471 return *manage (a->create_menu_item ());
5475 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5477 EventBox* b = manage (new EventBox);
5478 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5479 Label* l = manage (new Label (name));
5483 _the_notebook.append_page (widget, *b);
5487 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5489 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5490 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5493 if (ev->type == GDK_2BUTTON_PRESS) {
5495 /* double-click on a notebook tab shrinks or expands the notebook */
5497 if (_notebook_shrunk) {
5498 if (pre_notebook_shrink_pane_width) {
5499 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5501 _notebook_shrunk = false;
5503 pre_notebook_shrink_pane_width = edit_pane.get_position();
5505 /* this expands the LHS of the edit pane to cover the notebook
5506 PAGE but leaves the tabs visible.
5508 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5509 _notebook_shrunk = true;
5517 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5519 using namespace Menu_Helpers;
5521 MenuList& items = _control_point_context_menu.items ();
5524 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5525 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5526 if (!can_remove_control_point (item)) {
5527 items.back().set_sensitive (false);
5530 _control_point_context_menu.popup (event->button.button, event->button.time);