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 playhead_cursor->canvas_item.show ();
1218 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1219 Config->map_parameters (pc);
1220 _session->config.map_parameters (pc);
1222 restore_ruler_visibility ();
1223 //tempo_map_changed (PropertyChange (0));
1224 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1226 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1227 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1230 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1231 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1234 switch (_snap_type) {
1235 case SnapToRegionStart:
1236 case SnapToRegionEnd:
1237 case SnapToRegionSync:
1238 case SnapToRegionBoundary:
1239 build_region_boundary_cache ();
1246 /* register for undo history */
1247 _session->register_with_memento_command_factory(id(), this);
1249 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1251 start_updating_meters ();
1255 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1257 if (a->get_name() == "RegionMenu") {
1258 /* When the main menu's region menu is opened, we setup the actions so that they look right
1259 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1260 so we resensitize all region actions when the entered regionview or the region selection
1261 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1262 happens after the region context menu is opened. So we set a flag here, too.
1266 sensitize_the_right_region_actions ();
1267 _last_region_menu_was_main = true;
1271 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1273 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1275 using namespace Menu_Helpers;
1276 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1279 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1283 MenuList& items (fade_context_menu.items());
1287 switch (item_type) {
1289 case FadeInHandleItem:
1290 if (arv->audio_region()->fade_in_active()) {
1291 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1293 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1296 items.push_back (SeparatorElem());
1298 if (Profile->get_sae()) {
1300 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1301 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1308 *_fade_in_images[FadeLinear],
1309 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1313 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1318 *_fade_in_images[FadeFast],
1319 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1322 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1327 *_fade_in_images[FadeLogB],
1328 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1331 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1336 *_fade_in_images[FadeLogA],
1337 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1340 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1345 *_fade_in_images[FadeSlow],
1346 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1349 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1355 case FadeOutHandleItem:
1356 if (arv->audio_region()->fade_out_active()) {
1357 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1359 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1362 items.push_back (SeparatorElem());
1364 if (Profile->get_sae()) {
1365 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1366 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1372 *_fade_out_images[FadeLinear],
1373 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1377 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1382 *_fade_out_images[FadeFast],
1383 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1386 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1391 *_fade_out_images[FadeLogB],
1392 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1395 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1400 *_fade_out_images[FadeLogA],
1401 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1404 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1409 *_fade_out_images[FadeSlow],
1410 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1413 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1419 fatal << _("programming error: ")
1420 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1425 fade_context_menu.popup (button, time);
1429 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1431 using namespace Menu_Helpers;
1432 Menu* (Editor::*build_menu_function)();
1435 switch (item_type) {
1437 case RegionViewName:
1438 case RegionViewNameHighlight:
1439 case LeftFrameHandle:
1440 case RightFrameHandle:
1441 if (with_selection) {
1442 build_menu_function = &Editor::build_track_selection_context_menu;
1444 build_menu_function = &Editor::build_track_region_context_menu;
1449 if (with_selection) {
1450 build_menu_function = &Editor::build_track_selection_context_menu;
1452 build_menu_function = &Editor::build_track_context_menu;
1456 case CrossfadeViewItem:
1457 build_menu_function = &Editor::build_track_crossfade_context_menu;
1461 if (clicked_routeview->track()) {
1462 build_menu_function = &Editor::build_track_context_menu;
1464 build_menu_function = &Editor::build_track_bus_context_menu;
1469 /* probably shouldn't happen but if it does, we don't care */
1473 menu = (this->*build_menu_function)();
1474 menu->set_name ("ArdourContextMenu");
1476 /* now handle specific situations */
1478 switch (item_type) {
1480 case RegionViewName:
1481 case RegionViewNameHighlight:
1482 case LeftFrameHandle:
1483 case RightFrameHandle:
1484 if (!with_selection) {
1485 if (region_edit_menu_split_item) {
1486 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1487 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1489 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1492 if (region_edit_menu_split_multichannel_item) {
1493 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1494 region_edit_menu_split_multichannel_item->set_sensitive (true);
1496 region_edit_menu_split_multichannel_item->set_sensitive (false);
1505 case CrossfadeViewItem:
1512 /* probably shouldn't happen but if it does, we don't care */
1516 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1518 /* Bounce to disk */
1520 using namespace Menu_Helpers;
1521 MenuList& edit_items = menu->items();
1523 edit_items.push_back (SeparatorElem());
1525 switch (clicked_routeview->audio_track()->freeze_state()) {
1526 case AudioTrack::NoFreeze:
1527 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1530 case AudioTrack::Frozen:
1531 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1534 case AudioTrack::UnFrozen:
1535 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1541 if (item_type == StreamItem && clicked_routeview) {
1542 clicked_routeview->build_underlay_menu(menu);
1545 /* When the region menu is opened, we setup the actions so that they look right
1548 sensitize_the_right_region_actions ();
1549 _last_region_menu_was_main = false;
1551 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1552 menu->popup (button, time);
1556 Editor::build_track_context_menu ()
1558 using namespace Menu_Helpers;
1560 MenuList& edit_items = track_context_menu.items();
1563 add_dstream_context_items (edit_items);
1564 return &track_context_menu;
1568 Editor::build_track_bus_context_menu ()
1570 using namespace Menu_Helpers;
1572 MenuList& edit_items = track_context_menu.items();
1575 add_bus_context_items (edit_items);
1576 return &track_context_menu;
1580 Editor::build_track_region_context_menu ()
1582 using namespace Menu_Helpers;
1583 MenuList& edit_items = track_region_context_menu.items();
1586 /* we've just cleared the track region context menu, so the menu that these
1587 two items were on will have disappeared; stop them dangling.
1589 region_edit_menu_split_item = 0;
1590 region_edit_menu_split_multichannel_item = 0;
1592 /* we might try to use items that are currently attached to a crossfade menu,
1595 track_crossfade_context_menu.items().clear ();
1597 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1600 boost::shared_ptr<Track> tr;
1601 boost::shared_ptr<Playlist> pl;
1603 if ((tr = rtv->track())) {
1604 add_region_context_items (edit_items, tr);
1608 add_dstream_context_items (edit_items);
1610 return &track_region_context_menu;
1614 Editor::build_track_crossfade_context_menu ()
1616 using namespace Menu_Helpers;
1617 MenuList& edit_items = track_crossfade_context_menu.items();
1618 edit_items.clear ();
1620 /* we might try to use items that are currently attached to a crossfade menu,
1623 track_region_context_menu.items().clear ();
1625 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1628 boost::shared_ptr<Track> tr;
1629 boost::shared_ptr<Playlist> pl;
1630 boost::shared_ptr<AudioPlaylist> apl;
1632 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1634 AudioPlaylist::Crossfades xfades;
1638 /* The xfade menu is a bit of a special case, as we always use the mouse position
1639 to decide whether or not to display it (rather than the edit point). No particularly
1640 strong reasons for this, other than it is a bit surprising to right-click on a xfade
1643 mouse_frame (where, ignored);
1644 apl->crossfades_at (where, xfades);
1646 bool const many = xfades.size() > 1;
1648 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1649 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1652 add_region_context_items (edit_items, tr);
1656 add_dstream_context_items (edit_items);
1658 return &track_crossfade_context_menu;
1662 Editor::analyze_region_selection ()
1664 if (analysis_window == 0) {
1665 analysis_window = new AnalysisWindow();
1668 analysis_window->set_session(_session);
1670 analysis_window->show_all();
1673 analysis_window->set_regionmode();
1674 analysis_window->analyze();
1676 analysis_window->present();
1680 Editor::analyze_range_selection()
1682 if (analysis_window == 0) {
1683 analysis_window = new AnalysisWindow();
1686 analysis_window->set_session(_session);
1688 analysis_window->show_all();
1691 analysis_window->set_rangemode();
1692 analysis_window->analyze();
1694 analysis_window->present();
1698 Editor::build_track_selection_context_menu ()
1700 using namespace Menu_Helpers;
1701 MenuList& edit_items = track_selection_context_menu.items();
1702 edit_items.clear ();
1704 add_selection_context_items (edit_items);
1705 // edit_items.push_back (SeparatorElem());
1706 // add_dstream_context_items (edit_items);
1708 return &track_selection_context_menu;
1711 /** Add context menu items relevant to crossfades.
1712 * @param edit_items List to add the items to.
1715 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1717 using namespace Menu_Helpers;
1718 Menu *xfade_menu = manage (new Menu);
1719 MenuList& items = xfade_menu->items();
1720 xfade_menu->set_name ("ArdourContextMenu");
1723 if (xfade->active()) {
1730 MenuElem (str, sigc::bind (sigc::mem_fun (*this, &Editor::toggle_xfade_active), &view->trackview(), boost::weak_ptr<Crossfade> (xfade)))
1734 MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade)))
1737 if (xfade->can_follow_overlap()) {
1739 if (xfade->following_overlap()) {
1740 str = _("Convert to Short");
1742 str = _("Convert to Full");
1746 MenuElem (str, sigc::bind (sigc::mem_fun (*this, &Editor::toggle_xfade_length), &view->trackview(), xfade))
1751 str = xfade->out()->name();
1753 str += xfade->in()->name();
1755 str = _("Crossfade");
1758 edit_items.push_back (MenuElem (str, *xfade_menu));
1759 edit_items.push_back (SeparatorElem());
1763 Editor::xfade_edit_left_region ()
1765 if (clicked_crossfadeview) {
1766 clicked_crossfadeview->left_view.show_region_editor ();
1771 Editor::xfade_edit_right_region ()
1773 if (clicked_crossfadeview) {
1774 clicked_crossfadeview->right_view.show_region_editor ();
1779 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1781 using namespace Menu_Helpers;
1783 /* OK, stick the region submenu at the top of the list, and then add
1787 RegionSelection rs = get_regions_from_selection_and_entered ();
1789 string::size_type pos = 0;
1790 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1792 /* we have to hack up the region name because "_" has a special
1793 meaning for menu titles.
1796 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1797 menu_item_name.replace (pos, 1, "__");
1801 if (_popup_region_menu_item == 0) {
1802 _popup_region_menu_item = new MenuItem (menu_item_name);
1803 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1804 _popup_region_menu_item->show ();
1806 _popup_region_menu_item->set_label (menu_item_name);
1809 const framepos_t position = get_preferred_edit_position (false, true);
1811 edit_items.push_back (*_popup_region_menu_item);
1812 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1813 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1815 edit_items.push_back (SeparatorElem());
1818 /** Add context menu items relevant to selection ranges.
1819 * @param edit_items List to add the items to.
1822 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1824 using namespace Menu_Helpers;
1826 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1827 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1829 edit_items.push_back (SeparatorElem());
1830 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1832 edit_items.push_back (SeparatorElem());
1834 edit_items.push_back (
1836 _("Move Range Start to Previous Region Boundary"),
1837 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1841 edit_items.push_back (
1843 _("Move Range Start to Next Region Boundary"),
1844 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1848 edit_items.push_back (
1850 _("Move Range End to Previous Region Boundary"),
1851 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1855 edit_items.push_back (
1857 _("Move Range End to Next Region Boundary"),
1858 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1862 edit_items.push_back (SeparatorElem());
1863 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1864 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1866 edit_items.push_back (SeparatorElem());
1867 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1869 edit_items.push_back (SeparatorElem());
1870 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1871 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1873 edit_items.push_back (SeparatorElem());
1874 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1876 edit_items.push_back (SeparatorElem());
1877 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1878 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1879 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1881 edit_items.push_back (SeparatorElem());
1882 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1883 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1884 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1885 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1886 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1891 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1893 using namespace Menu_Helpers;
1897 Menu *play_menu = manage (new Menu);
1898 MenuList& play_items = play_menu->items();
1899 play_menu->set_name ("ArdourContextMenu");
1901 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1902 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1903 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1904 play_items.push_back (SeparatorElem());
1905 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1907 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1911 Menu *select_menu = manage (new Menu);
1912 MenuList& select_items = select_menu->items();
1913 select_menu->set_name ("ArdourContextMenu");
1915 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1916 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1917 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1918 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1919 select_items.push_back (SeparatorElem());
1920 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1921 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1922 select_items.push_back (SeparatorElem());
1923 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1924 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1925 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1926 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1927 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1928 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1929 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1931 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1935 Menu *cutnpaste_menu = manage (new Menu);
1936 MenuList& cutnpaste_items = cutnpaste_menu->items();
1937 cutnpaste_menu->set_name ("ArdourContextMenu");
1939 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1940 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1941 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1943 cutnpaste_items.push_back (SeparatorElem());
1945 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1946 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1948 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1950 /* Adding new material */
1952 edit_items.push_back (SeparatorElem());
1953 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1954 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1958 Menu *nudge_menu = manage (new Menu());
1959 MenuList& nudge_items = nudge_menu->items();
1960 nudge_menu->set_name ("ArdourContextMenu");
1962 edit_items.push_back (SeparatorElem());
1963 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1964 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1965 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1966 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1968 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1972 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1974 using namespace Menu_Helpers;
1978 Menu *play_menu = manage (new Menu);
1979 MenuList& play_items = play_menu->items();
1980 play_menu->set_name ("ArdourContextMenu");
1982 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1983 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1984 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1988 Menu *select_menu = manage (new Menu);
1989 MenuList& select_items = select_menu->items();
1990 select_menu->set_name ("ArdourContextMenu");
1992 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1993 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1994 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1995 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1996 select_items.push_back (SeparatorElem());
1997 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1998 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1999 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2000 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2002 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2006 Menu *cutnpaste_menu = manage (new Menu);
2007 MenuList& cutnpaste_items = cutnpaste_menu->items();
2008 cutnpaste_menu->set_name ("ArdourContextMenu");
2010 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2011 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2012 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2014 Menu *nudge_menu = manage (new Menu());
2015 MenuList& nudge_items = nudge_menu->items();
2016 nudge_menu->set_name ("ArdourContextMenu");
2018 edit_items.push_back (SeparatorElem());
2019 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2020 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2021 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2022 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2024 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2028 Editor::snap_type() const
2034 Editor::snap_mode() const
2040 Editor::set_snap_to (SnapType st)
2042 unsigned int snap_ind = (unsigned int)st;
2046 if (snap_ind > snap_type_strings.size() - 1) {
2048 _snap_type = (SnapType)snap_ind;
2051 string str = snap_type_strings[snap_ind];
2053 if (str != snap_type_selector.get_active_text()) {
2054 snap_type_selector.set_active_text (str);
2059 switch (_snap_type) {
2060 case SnapToBeatDiv128:
2061 case SnapToBeatDiv64:
2062 case SnapToBeatDiv32:
2063 case SnapToBeatDiv28:
2064 case SnapToBeatDiv24:
2065 case SnapToBeatDiv20:
2066 case SnapToBeatDiv16:
2067 case SnapToBeatDiv14:
2068 case SnapToBeatDiv12:
2069 case SnapToBeatDiv10:
2070 case SnapToBeatDiv8:
2071 case SnapToBeatDiv7:
2072 case SnapToBeatDiv6:
2073 case SnapToBeatDiv5:
2074 case SnapToBeatDiv4:
2075 case SnapToBeatDiv3:
2076 case SnapToBeatDiv2:
2077 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2078 update_tempo_based_rulers ();
2081 case SnapToRegionStart:
2082 case SnapToRegionEnd:
2083 case SnapToRegionSync:
2084 case SnapToRegionBoundary:
2085 build_region_boundary_cache ();
2093 SnapChanged (); /* EMIT SIGNAL */
2097 Editor::set_snap_mode (SnapMode mode)
2100 string str = snap_mode_strings[(int)mode];
2102 if (str != snap_mode_selector.get_active_text ()) {
2103 snap_mode_selector.set_active_text (str);
2109 Editor::set_edit_point_preference (EditPoint ep, bool force)
2111 bool changed = (_edit_point != ep);
2114 string str = edit_point_strings[(int)ep];
2116 if (str != edit_point_selector.get_active_text ()) {
2117 edit_point_selector.set_active_text (str);
2120 set_canvas_cursor ();
2122 if (!force && !changed) {
2126 const char* action=NULL;
2128 switch (_edit_point) {
2129 case EditAtPlayhead:
2130 action = "edit-at-playhead";
2132 case EditAtSelectedMarker:
2133 action = "edit-at-marker";
2136 action = "edit-at-mouse";
2140 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2142 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2146 bool in_track_canvas;
2148 if (!mouse_frame (foo, in_track_canvas)) {
2149 in_track_canvas = false;
2152 reset_canvas_action_sensitivity (in_track_canvas);
2158 Editor::set_state (const XMLNode& node, int /*version*/)
2160 const XMLProperty* prop;
2167 g.base_width = default_width;
2168 g.base_height = default_height;
2172 if ((geometry = find_named_node (node, "geometry")) != 0) {
2176 if ((prop = geometry->property("x_size")) == 0) {
2177 prop = geometry->property ("x-size");
2180 g.base_width = atoi(prop->value());
2182 if ((prop = geometry->property("y_size")) == 0) {
2183 prop = geometry->property ("y-size");
2186 g.base_height = atoi(prop->value());
2189 if ((prop = geometry->property ("x_pos")) == 0) {
2190 prop = geometry->property ("x-pos");
2193 x = atoi (prop->value());
2196 if ((prop = geometry->property ("y_pos")) == 0) {
2197 prop = geometry->property ("y-pos");
2200 y = atoi (prop->value());
2204 set_default_size (g.base_width, g.base_height);
2207 if (_session && (prop = node.property ("playhead"))) {
2209 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2210 playhead_cursor->set_position (pos);
2212 playhead_cursor->set_position (0);
2215 if ((prop = node.property ("mixer-width"))) {
2216 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2219 if ((prop = node.property ("zoom-focus"))) {
2220 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2223 if ((prop = node.property ("zoom"))) {
2224 reset_zoom (PBD::atof (prop->value()));
2226 reset_zoom (frames_per_unit);
2229 if ((prop = node.property ("snap-to"))) {
2230 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2233 if ((prop = node.property ("snap-mode"))) {
2234 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2237 if ((prop = node.property ("internal-snap-to"))) {
2238 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2241 if ((prop = node.property ("internal-snap-mode"))) {
2242 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2245 if ((prop = node.property ("pre-internal-snap-to"))) {
2246 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2249 if ((prop = node.property ("pre-internal-snap-mode"))) {
2250 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2253 if ((prop = node.property ("mouse-mode"))) {
2254 MouseMode m = str2mousemode(prop->value());
2255 set_mouse_mode (m, true);
2257 set_mouse_mode (MouseObject, true);
2260 if ((prop = node.property ("left-frame")) != 0) {
2262 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2266 reset_x_origin (pos);
2270 if ((prop = node.property ("y-origin")) != 0) {
2271 reset_y_origin (atof (prop->value ()));
2274 if ((prop = node.property ("internal-edit"))) {
2275 bool yn = string_is_affirmative (prop->value());
2276 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2278 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2279 tact->set_active (!yn);
2280 tact->set_active (yn);
2284 if ((prop = node.property ("join-object-range"))) {
2285 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2288 if ((prop = node.property ("edit-point"))) {
2289 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2292 if ((prop = node.property ("show-measures"))) {
2293 bool yn = string_is_affirmative (prop->value());
2294 _show_measures = yn;
2295 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2297 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2298 /* do it twice to force the change */
2299 tact->set_active (!yn);
2300 tact->set_active (yn);
2304 if ((prop = node.property ("follow-playhead"))) {
2305 bool yn = string_is_affirmative (prop->value());
2306 set_follow_playhead (yn);
2307 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2309 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2310 if (tact->get_active() != yn) {
2311 tact->set_active (yn);
2316 if ((prop = node.property ("stationary-playhead"))) {
2317 bool yn = string_is_affirmative (prop->value());
2318 set_stationary_playhead (yn);
2319 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2321 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2322 if (tact->get_active() != yn) {
2323 tact->set_active (yn);
2328 if ((prop = node.property ("region-list-sort-type"))) {
2329 RegionListSortType st;
2330 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2333 if ((prop = node.property ("xfades-visible"))) {
2334 bool yn = string_is_affirmative (prop->value());
2335 _xfade_visibility = !yn;
2336 // set_xfade_visibility (yn);
2339 if ((prop = node.property ("show-editor-mixer"))) {
2341 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2344 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2345 bool yn = string_is_affirmative (prop->value());
2347 /* do it twice to force the change */
2349 tact->set_active (!yn);
2350 tact->set_active (yn);
2353 if ((prop = node.property ("show-editor-list"))) {
2355 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
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 (X_("editor-list-page")))) {
2368 _the_notebook.set_current_page (atoi (prop->value ()));
2371 if ((prop = node.property (X_("show-marker-lines")))) {
2372 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2374 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2375 bool yn = string_is_affirmative (prop->value ());
2377 tact->set_active (!yn);
2378 tact->set_active (yn);
2381 XMLNodeList children = node.children ();
2382 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2383 selection->set_state (**i, Stateful::current_state_version);
2384 _regions->set_state (**i);
2387 if ((prop = node.property ("maximised"))) {
2388 bool yn = string_is_affirmative (prop->value());
2390 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2394 if ((prop = node.property ("nudge-clock-value"))) {
2396 sscanf (prop->value().c_str(), "%" PRId64, &f);
2397 nudge_clock->set (f);
2399 nudge_clock->set_mode (AudioClock::Timecode);
2400 nudge_clock->set (_session->frame_rate() * 5, true);
2407 Editor::get_state ()
2409 XMLNode* node = new XMLNode ("Editor");
2412 id().print (buf, sizeof (buf));
2413 node->add_property ("id", buf);
2415 if (is_realized()) {
2416 Glib::RefPtr<Gdk::Window> win = get_window();
2418 int x, y, width, height;
2419 win->get_root_origin(x, y);
2420 win->get_size(width, height);
2422 XMLNode* geometry = new XMLNode ("geometry");
2424 snprintf(buf, sizeof(buf), "%d", width);
2425 geometry->add_property("x-size", string(buf));
2426 snprintf(buf, sizeof(buf), "%d", height);
2427 geometry->add_property("y-size", string(buf));
2428 snprintf(buf, sizeof(buf), "%d", x);
2429 geometry->add_property("x-pos", string(buf));
2430 snprintf(buf, sizeof(buf), "%d", y);
2431 geometry->add_property("y-pos", string(buf));
2432 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2433 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2434 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2435 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2436 geometry->add_property("edit-vertical-pane-pos", string(buf));
2438 node->add_child_nocopy (*geometry);
2441 maybe_add_mixer_strip_width (*node);
2443 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2444 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2445 node->add_property ("zoom", buf);
2446 node->add_property ("snap-to", enum_2_string (_snap_type));
2447 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2448 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2449 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2450 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2451 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2452 node->add_property ("edit-point", enum_2_string (_edit_point));
2454 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2455 node->add_property ("playhead", buf);
2456 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2457 node->add_property ("left-frame", buf);
2458 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2459 node->add_property ("y-origin", buf);
2461 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2462 node->add_property ("maximised", _maximised ? "yes" : "no");
2463 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2464 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2465 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2466 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2467 node->add_property ("mouse-mode", enum2str(mouse_mode));
2468 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2469 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2471 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2473 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2474 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2477 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2479 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2480 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2483 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2484 node->add_property (X_("editor-list-page"), buf);
2486 if (button_bindings) {
2487 XMLNode* bb = new XMLNode (X_("Buttons"));
2488 button_bindings->save (*bb);
2489 node->add_child_nocopy (*bb);
2492 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2494 node->add_child_nocopy (selection->get_state ());
2495 node->add_child_nocopy (_regions->get_state ());
2497 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2498 node->add_property ("nudge-clock-value", buf);
2505 /** @param y y offset from the top of all trackviews.
2506 * @return pair: TimeAxisView that y is over, layer index.
2507 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2508 * in stacked or expanded region display mode, otherwise 0.
2510 std::pair<TimeAxisView *, double>
2511 Editor::trackview_by_y_position (double y)
2513 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2515 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2521 return std::make_pair ( (TimeAxisView *) 0, 0);
2524 /** Snap a position to the grid, if appropriate, taking into account current
2525 * grid settings and also the state of any snap modifier keys that may be pressed.
2526 * @param start Position to snap.
2527 * @param event Event to get current key modifier information from, or 0.
2530 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2532 if (!_session || !event) {
2536 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2537 if (_snap_mode == SnapOff) {
2538 snap_to_internal (start, direction, for_mark);
2541 if (_snap_mode != SnapOff) {
2542 snap_to_internal (start, direction, for_mark);
2548 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2550 if (!_session || _snap_mode == SnapOff) {
2554 snap_to_internal (start, direction, for_mark);
2558 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2560 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2561 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2563 switch (_snap_type) {
2564 case SnapToTimecodeFrame:
2565 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2566 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2568 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2572 case SnapToTimecodeSeconds:
2573 if (_session->config.get_timecode_offset_negative()) {
2574 start += _session->config.get_timecode_offset ();
2576 start -= _session->config.get_timecode_offset ();
2578 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2579 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2581 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2584 if (_session->config.get_timecode_offset_negative()) {
2585 start -= _session->config.get_timecode_offset ();
2587 start += _session->config.get_timecode_offset ();
2591 case SnapToTimecodeMinutes:
2592 if (_session->config.get_timecode_offset_negative()) {
2593 start += _session->config.get_timecode_offset ();
2595 start -= _session->config.get_timecode_offset ();
2597 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2598 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2600 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2602 if (_session->config.get_timecode_offset_negative()) {
2603 start -= _session->config.get_timecode_offset ();
2605 start += _session->config.get_timecode_offset ();
2609 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2615 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2617 const framepos_t one_second = _session->frame_rate();
2618 const framepos_t one_minute = _session->frame_rate() * 60;
2619 framepos_t presnap = start;
2623 switch (_snap_type) {
2624 case SnapToTimecodeFrame:
2625 case SnapToTimecodeSeconds:
2626 case SnapToTimecodeMinutes:
2627 return timecode_snap_to_internal (start, direction, for_mark);
2630 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2631 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2633 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2638 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2639 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2641 start = (framepos_t) floor ((double) start / one_second) * one_second;
2646 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2647 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2649 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2654 start = _session->tempo_map().round_to_bar (start, direction);
2658 start = _session->tempo_map().round_to_beat (start, direction);
2661 case SnapToBeatDiv128:
2662 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2664 case SnapToBeatDiv64:
2665 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2667 case SnapToBeatDiv32:
2668 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2670 case SnapToBeatDiv28:
2671 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2673 case SnapToBeatDiv24:
2674 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2676 case SnapToBeatDiv20:
2677 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2679 case SnapToBeatDiv16:
2680 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2682 case SnapToBeatDiv14:
2683 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2685 case SnapToBeatDiv12:
2686 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2688 case SnapToBeatDiv10:
2689 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2691 case SnapToBeatDiv8:
2692 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2694 case SnapToBeatDiv7:
2695 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2697 case SnapToBeatDiv6:
2698 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2700 case SnapToBeatDiv5:
2701 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2703 case SnapToBeatDiv4:
2704 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2706 case SnapToBeatDiv3:
2707 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2709 case SnapToBeatDiv2:
2710 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2718 _session->locations()->marks_either_side (start, before, after);
2720 if (before == max_framepos) {
2722 } else if (after == max_framepos) {
2724 } else if (before != max_framepos && after != max_framepos) {
2725 /* have before and after */
2726 if ((start - before) < (after - start)) {
2735 case SnapToRegionStart:
2736 case SnapToRegionEnd:
2737 case SnapToRegionSync:
2738 case SnapToRegionBoundary:
2739 if (!region_boundary_cache.empty()) {
2741 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2742 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2744 if (direction > 0) {
2745 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2747 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2750 if (next != region_boundary_cache.begin ()) {
2755 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2756 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2758 if (start > (p + n) / 2) {
2767 switch (_snap_mode) {
2773 if (presnap > start) {
2774 if (presnap > (start + unit_to_frame(snap_threshold))) {
2778 } else if (presnap < start) {
2779 if (presnap < (start - unit_to_frame(snap_threshold))) {
2785 /* handled at entry */
2793 Editor::setup_toolbar ()
2795 HBox* mode_box = manage(new HBox);
2796 mode_box->set_border_width (2);
2797 mode_box->set_spacing(4);
2799 HBox* mouse_mode_box = manage (new HBox);
2800 HBox* mouse_mode_hbox1 = manage (new HBox);
2801 HBox* mouse_mode_hbox2 = manage (new HBox);
2802 VBox* mouse_mode_vbox1 = manage (new VBox);
2803 VBox* mouse_mode_vbox2 = manage (new VBox);
2804 Alignment* mouse_mode_align1 = manage (new Alignment);
2805 Alignment* mouse_mode_align2 = manage (new Alignment);
2807 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2808 mouse_mode_size_group->add_widget (mouse_move_button);
2809 mouse_mode_size_group->add_widget (mouse_select_button);
2810 mouse_mode_size_group->add_widget (mouse_zoom_button);
2811 mouse_mode_size_group->add_widget (mouse_gain_button);
2812 mouse_mode_size_group->add_widget (mouse_timefx_button);
2813 mouse_mode_size_group->add_widget (mouse_audition_button);
2814 mouse_mode_size_group->add_widget (mouse_draw_button);
2815 mouse_mode_size_group->add_widget (internal_edit_button);
2817 /* make them just a bit bigger */
2818 mouse_move_button.set_size_request (-1, 25);
2820 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button, true));
2821 smart_mode_joiner->set_related_action (smart_mode_action);
2823 mouse_mode_hbox2->set_spacing (2);
2824 mouse_mode_box->set_spacing (2);
2826 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2827 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2828 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2829 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2830 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2831 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2832 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2834 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2835 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2837 mouse_mode_align1->add (*mouse_mode_vbox1);
2838 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2839 mouse_mode_align2->add (*mouse_mode_vbox2);
2840 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2842 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2843 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2845 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2846 if (!Profile->get_sae()) {
2847 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2849 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2851 edit_mode_selector.set_name ("EditModeSelector");
2852 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2853 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2855 mode_box->pack_start (edit_mode_selector, false, false);
2856 mode_box->pack_start (*mouse_mode_box, false, false);
2858 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2859 _mouse_mode_tearoff->set_name ("MouseModeBase");
2860 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2862 if (Profile->get_sae()) {
2863 _mouse_mode_tearoff->set_can_be_torn_off (false);
2866 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2867 &_mouse_mode_tearoff->tearoff_window()));
2868 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2869 &_mouse_mode_tearoff->tearoff_window(), 1));
2870 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2871 &_mouse_mode_tearoff->tearoff_window()));
2872 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2873 &_mouse_mode_tearoff->tearoff_window(), 1));
2877 _zoom_box.set_spacing (2);
2878 _zoom_box.set_border_width (2);
2882 zoom_in_button.set_name ("zoom button");
2883 zoom_in_button.set_image (::get_icon ("zoom_in"));
2884 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2885 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2886 zoom_in_button.set_related_action (act);
2888 zoom_out_button.set_name ("zoom button");
2889 zoom_out_button.set_image (::get_icon ("zoom_out"));
2890 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2891 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2892 zoom_out_button.set_related_action (act);
2894 zoom_out_full_button.set_name ("zoom button");
2895 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2896 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2897 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2898 zoom_out_full_button.set_related_action (act);
2900 zoom_focus_selector.set_name ("ZoomFocusSelector");
2901 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2902 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2904 _zoom_box.pack_start (zoom_out_button, false, false);
2905 _zoom_box.pack_start (zoom_in_button, false, false);
2906 _zoom_box.pack_start (zoom_out_full_button, false, false);
2908 _zoom_box.pack_start (zoom_focus_selector, false, false);
2910 /* Track zoom buttons */
2911 tav_expand_button.set_name ("TrackHeightButton");
2912 tav_expand_button.set_size_request (-1, 20);
2913 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2914 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2915 act->connect_proxy (tav_expand_button);
2917 tav_shrink_button.set_name ("TrackHeightButton");
2918 tav_shrink_button.set_size_request (-1, 20);
2919 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2920 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2921 act->connect_proxy (tav_shrink_button);
2923 _zoom_box.pack_start (tav_shrink_button);
2924 _zoom_box.pack_start (tav_expand_button);
2926 _zoom_tearoff = manage (new TearOff (_zoom_box));
2928 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2929 &_zoom_tearoff->tearoff_window()));
2930 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2931 &_zoom_tearoff->tearoff_window(), 0));
2932 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2933 &_zoom_tearoff->tearoff_window()));
2934 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2935 &_zoom_tearoff->tearoff_window(), 0));
2937 snap_box.set_spacing (1);
2938 snap_box.set_border_width (2);
2940 snap_type_selector.set_name ("SnapTypeSelector");
2941 set_popdown_strings (snap_type_selector, snap_type_strings);
2942 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2944 snap_mode_selector.set_name ("SnapModeSelector");
2945 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2946 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2948 edit_point_selector.set_name ("EditPointSelector");
2949 set_popdown_strings (edit_point_selector, edit_point_strings);
2950 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2952 snap_box.pack_start (snap_mode_selector, false, false);
2953 snap_box.pack_start (snap_type_selector, false, false);
2954 snap_box.pack_start (edit_point_selector, false, false);
2958 HBox *nudge_box = manage (new HBox);
2959 nudge_box->set_spacing (2);
2960 nudge_box->set_border_width (2);
2962 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2963 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2965 nudge_box->pack_start (nudge_backward_button, false, false);
2966 nudge_box->pack_start (nudge_forward_button, false, false);
2967 nudge_box->pack_start (*nudge_clock, false, false);
2970 /* Pack everything in... */
2972 HBox* hbox = manage (new HBox);
2973 hbox->set_spacing(10);
2975 _tools_tearoff = manage (new TearOff (*hbox));
2976 _tools_tearoff->set_name ("MouseModeBase");
2977 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2979 if (Profile->get_sae()) {
2980 _tools_tearoff->set_can_be_torn_off (false);
2983 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2984 &_tools_tearoff->tearoff_window()));
2985 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2986 &_tools_tearoff->tearoff_window(), 0));
2987 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2988 &_tools_tearoff->tearoff_window()));
2989 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2990 &_tools_tearoff->tearoff_window(), 0));
2992 toolbar_hbox.set_spacing (10);
2993 toolbar_hbox.set_border_width (1);
2995 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2996 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2997 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2999 hbox->pack_start (snap_box, false, false);
3000 if (!Profile->get_small_screen()) {
3001 hbox->pack_start (*nudge_box, false, false);
3003 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3005 hbox->pack_start (panic_box, false, false);
3009 toolbar_base.set_name ("ToolBarBase");
3010 toolbar_base.add (toolbar_hbox);
3012 _toolbar_viewport.add (toolbar_base);
3013 /* stick to the required height but allow width to vary if there's not enough room */
3014 _toolbar_viewport.set_size_request (1, -1);
3016 toolbar_frame.set_shadow_type (SHADOW_OUT);
3017 toolbar_frame.set_name ("BaseFrame");
3018 toolbar_frame.add (_toolbar_viewport);
3022 Editor::setup_tooltips ()
3024 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3025 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
3026 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3027 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3028 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3029 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3030 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3031 ARDOUR_UI::instance()->set_tip (smart_mode_joiner, _("Smart Mode (Select/Move Objects + Ranges)"));
3032 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3033 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3034 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
3035 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
3036 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3037 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3038 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3039 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3040 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3041 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3042 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3043 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3044 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3045 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3046 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3050 Editor::convert_drop_to_paths (
3051 vector<string>& paths,
3052 const RefPtr<Gdk::DragContext>& /*context*/,
3055 const SelectionData& data,
3059 if (_session == 0) {
3063 vector<string> uris = data.get_uris();
3067 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3068 are actually URI lists. So do it by hand.
3071 if (data.get_target() != "text/plain") {
3075 /* Parse the "uri-list" format that Nautilus provides,
3076 where each pathname is delimited by \r\n.
3078 THERE MAY BE NO NULL TERMINATING CHAR!!!
3081 string txt = data.get_text();
3085 p = (const char *) malloc (txt.length() + 1);
3086 txt.copy ((char *) p, txt.length(), 0);
3087 ((char*)p)[txt.length()] = '\0';
3093 while (g_ascii_isspace (*p))
3097 while (*q && (*q != '\n') && (*q != '\r')) {
3104 while (q > p && g_ascii_isspace (*q))
3109 uris.push_back (string (p, q - p + 1));
3113 p = strchr (p, '\n');
3125 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3127 if ((*i).substr (0,7) == "file://") {
3129 string const p = PBD::url_decode (*i);
3131 // scan forward past three slashes
3133 string::size_type slashcnt = 0;
3134 string::size_type n = 0;
3135 string::const_iterator x = p.begin();
3137 while (slashcnt < 3 && x != p.end()) {
3140 } else if (slashcnt == 3) {
3147 if (slashcnt != 3 || x == p.end()) {
3148 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3152 paths.push_back (p.substr (n - 1));
3160 Editor::new_tempo_section ()
3166 Editor::map_transport_state ()
3168 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3170 if (_session && _session->transport_stopped()) {
3171 have_pending_keyboard_selection = false;
3174 update_loop_range_view (true);
3180 Editor::begin_reversible_command (string name)
3183 _session->begin_reversible_command (name);
3188 Editor::begin_reversible_command (GQuark q)
3191 _session->begin_reversible_command (q);
3196 Editor::commit_reversible_command ()
3199 _session->commit_reversible_command ();
3204 Editor::history_changed ()
3208 if (undo_action && _session) {
3209 if (_session->undo_depth() == 0) {
3210 label = S_("Command|Undo");
3212 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3214 undo_action->property_label() = label;
3217 if (redo_action && _session) {
3218 if (_session->redo_depth() == 0) {
3221 label = string_compose(_("Redo (%1)"), _session->next_redo());
3223 redo_action->property_label() = label;
3228 Editor::duplicate_dialog (bool with_dialog)
3232 if (mouse_mode == MouseRange) {
3233 if (selection->time.length() == 0) {
3238 RegionSelection rs = get_regions_from_selection_and_entered ();
3240 if (mouse_mode != MouseRange && rs.empty()) {
3246 ArdourDialog win (_("Duplicate"));
3247 Label label (_("Number of duplications:"));
3248 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3249 SpinButton spinner (adjustment, 0.0, 1);
3252 win.get_vbox()->set_spacing (12);
3253 win.get_vbox()->pack_start (hbox);
3254 hbox.set_border_width (6);
3255 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3257 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3258 place, visually. so do this by hand.
3261 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3262 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3263 spinner.grab_focus();
3269 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3270 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3271 win.set_default_response (RESPONSE_ACCEPT);
3273 win.set_position (WIN_POS_MOUSE);
3275 spinner.grab_focus ();
3277 switch (win.run ()) {
3278 case RESPONSE_ACCEPT:
3284 times = adjustment.get_value();
3287 if (mouse_mode == MouseRange) {
3288 duplicate_selection (times);
3290 duplicate_some_regions (rs, times);
3295 Editor::set_edit_mode (EditMode m)
3297 Config->set_edit_mode (m);
3301 Editor::cycle_edit_mode ()
3303 switch (Config->get_edit_mode()) {
3305 if (Profile->get_sae()) {
3306 Config->set_edit_mode (Lock);
3308 Config->set_edit_mode (Splice);
3312 Config->set_edit_mode (Lock);
3315 Config->set_edit_mode (Slide);
3321 Editor::edit_mode_selection_done ()
3323 string s = edit_mode_selector.get_active_text ();
3326 Config->set_edit_mode (string_to_edit_mode (s));
3331 Editor::snap_type_selection_done ()
3333 string choice = snap_type_selector.get_active_text();
3334 SnapType snaptype = SnapToBeat;
3336 if (choice == _("Beats/2")) {
3337 snaptype = SnapToBeatDiv2;
3338 } else if (choice == _("Beats/3")) {
3339 snaptype = SnapToBeatDiv3;
3340 } else if (choice == _("Beats/4")) {
3341 snaptype = SnapToBeatDiv4;
3342 } else if (choice == _("Beats/5")) {
3343 snaptype = SnapToBeatDiv5;
3344 } else if (choice == _("Beats/6")) {
3345 snaptype = SnapToBeatDiv6;
3346 } else if (choice == _("Beats/7")) {
3347 snaptype = SnapToBeatDiv7;
3348 } else if (choice == _("Beats/8")) {
3349 snaptype = SnapToBeatDiv8;
3350 } else if (choice == _("Beats/10")) {
3351 snaptype = SnapToBeatDiv10;
3352 } else if (choice == _("Beats/12")) {
3353 snaptype = SnapToBeatDiv12;
3354 } else if (choice == _("Beats/14")) {
3355 snaptype = SnapToBeatDiv14;
3356 } else if (choice == _("Beats/16")) {
3357 snaptype = SnapToBeatDiv16;
3358 } else if (choice == _("Beats/20")) {
3359 snaptype = SnapToBeatDiv20;
3360 } else if (choice == _("Beats/24")) {
3361 snaptype = SnapToBeatDiv24;
3362 } else if (choice == _("Beats/28")) {
3363 snaptype = SnapToBeatDiv28;
3364 } else if (choice == _("Beats/32")) {
3365 snaptype = SnapToBeatDiv32;
3366 } else if (choice == _("Beats/64")) {
3367 snaptype = SnapToBeatDiv64;
3368 } else if (choice == _("Beats/128")) {
3369 snaptype = SnapToBeatDiv128;
3370 } else if (choice == _("Beats")) {
3371 snaptype = SnapToBeat;
3372 } else if (choice == _("Bars")) {
3373 snaptype = SnapToBar;
3374 } else if (choice == _("Marks")) {
3375 snaptype = SnapToMark;
3376 } else if (choice == _("Region starts")) {
3377 snaptype = SnapToRegionStart;
3378 } else if (choice == _("Region ends")) {
3379 snaptype = SnapToRegionEnd;
3380 } else if (choice == _("Region bounds")) {
3381 snaptype = SnapToRegionBoundary;
3382 } else if (choice == _("Region syncs")) {
3383 snaptype = SnapToRegionSync;
3384 } else if (choice == _("CD Frames")) {
3385 snaptype = SnapToCDFrame;
3386 } else if (choice == _("Timecode Frames")) {
3387 snaptype = SnapToTimecodeFrame;
3388 } else if (choice == _("Timecode Seconds")) {
3389 snaptype = SnapToTimecodeSeconds;
3390 } else if (choice == _("Timecode Minutes")) {
3391 snaptype = SnapToTimecodeMinutes;
3392 } else if (choice == _("Seconds")) {
3393 snaptype = SnapToSeconds;
3394 } else if (choice == _("Minutes")) {
3395 snaptype = SnapToMinutes;
3398 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3400 ract->set_active ();
3405 Editor::snap_mode_selection_done ()
3407 string choice = snap_mode_selector.get_active_text();
3408 SnapMode mode = SnapNormal;
3410 if (choice == _("No Grid")) {
3412 } else if (choice == _("Grid")) {
3414 } else if (choice == _("Magnetic")) {
3415 mode = SnapMagnetic;
3418 RefPtr<RadioAction> ract = snap_mode_action (mode);
3421 ract->set_active (true);
3426 Editor::cycle_edit_point (bool with_marker)
3428 switch (_edit_point) {
3430 set_edit_point_preference (EditAtPlayhead);
3432 case EditAtPlayhead:
3434 set_edit_point_preference (EditAtSelectedMarker);
3436 set_edit_point_preference (EditAtMouse);
3439 case EditAtSelectedMarker:
3440 set_edit_point_preference (EditAtMouse);
3446 Editor::edit_point_selection_done ()
3448 string choice = edit_point_selector.get_active_text();
3449 EditPoint ep = EditAtSelectedMarker;
3451 if (choice == _("Marker")) {
3452 set_edit_point_preference (EditAtSelectedMarker);
3453 } else if (choice == _("Playhead")) {
3454 set_edit_point_preference (EditAtPlayhead);
3456 set_edit_point_preference (EditAtMouse);
3459 RefPtr<RadioAction> ract = edit_point_action (ep);
3462 ract->set_active (true);
3467 Editor::zoom_focus_selection_done ()
3469 string choice = zoom_focus_selector.get_active_text();
3470 ZoomFocus focus_type = ZoomFocusLeft;
3472 if (choice == _("Left")) {
3473 focus_type = ZoomFocusLeft;
3474 } else if (choice == _("Right")) {
3475 focus_type = ZoomFocusRight;
3476 } else if (choice == _("Center")) {
3477 focus_type = ZoomFocusCenter;
3478 } else if (choice == _("Playhead")) {
3479 focus_type = ZoomFocusPlayhead;
3480 } else if (choice == _("Mouse")) {
3481 focus_type = ZoomFocusMouse;
3482 } else if (choice == _("Edit point")) {
3483 focus_type = ZoomFocusEdit;
3486 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3489 ract->set_active ();
3494 Editor::edit_controls_button_release (GdkEventButton* ev)
3496 if (Keyboard::is_context_menu_event (ev)) {
3497 ARDOUR_UI::instance()->add_route (this);
3498 } else if (ev->button == 1) {
3499 selection->clear_tracks ();
3506 Editor::mouse_select_button_release (GdkEventButton* ev)
3508 /* this handles just right-clicks */
3510 if (ev->button != 3) {
3518 Editor::set_zoom_focus (ZoomFocus f)
3520 string str = zoom_focus_strings[(int)f];
3522 if (str != zoom_focus_selector.get_active_text()) {
3523 zoom_focus_selector.set_active_text (str);
3526 if (zoom_focus != f) {
3533 Editor::ensure_float (Window& win)
3535 win.set_transient_for (*this);
3539 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3541 /* recover or initialize pane positions. do this here rather than earlier because
3542 we don't want the positions to change the child allocations, which they seem to do.
3548 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3557 XMLNode* geometry = find_named_node (*node, "geometry");
3559 if (which == static_cast<Paned*> (&edit_pane)) {
3561 if (done & Horizontal) {
3565 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3566 _notebook_shrunk = string_is_affirmative (prop->value ());
3569 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3570 /* initial allocation is 90% to canvas, 10% to notebook */
3571 pos = (int) floor (alloc.get_width() * 0.90f);
3572 snprintf (buf, sizeof(buf), "%d", pos);
3574 pos = atoi (prop->value());
3577 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3578 edit_pane.set_position (pos);
3581 done = (Pane) (done | Horizontal);
3583 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3585 if (done & Vertical) {
3589 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3590 /* initial allocation is 90% to canvas, 10% to summary */
3591 pos = (int) floor (alloc.get_height() * 0.90f);
3592 snprintf (buf, sizeof(buf), "%d", pos);
3595 pos = atoi (prop->value());
3598 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3599 editor_summary_pane.set_position (pos);
3602 done = (Pane) (done | Vertical);
3607 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3609 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3610 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3611 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3612 top_hbox.remove (toolbar_frame);
3617 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3619 if (toolbar_frame.get_parent() == 0) {
3620 top_hbox.pack_end (toolbar_frame);
3625 Editor::set_show_measures (bool yn)
3627 if (_show_measures != yn) {
3630 if ((_show_measures = yn) == true) {
3632 tempo_lines->show();
3640 Editor::toggle_follow_playhead ()
3642 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3644 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3645 set_follow_playhead (tact->get_active());
3649 /** @param yn true to follow playhead, otherwise false.
3650 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3653 Editor::set_follow_playhead (bool yn, bool catch_up)
3655 if (_follow_playhead != yn) {
3656 if ((_follow_playhead = yn) == true && catch_up) {
3658 reset_x_origin_to_follow_playhead ();
3665 Editor::toggle_stationary_playhead ()
3667 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3669 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3670 set_stationary_playhead (tact->get_active());
3675 Editor::set_stationary_playhead (bool yn)
3677 if (_stationary_playhead != yn) {
3678 if ((_stationary_playhead = yn) == true) {
3680 // FIXME need a 3.0 equivalent of this 2.X call
3681 // update_current_screen ();
3688 Editor::toggle_xfade_active (RouteTimeAxisView* tv, boost::weak_ptr<Crossfade> wxfade)
3690 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3695 vector<boost::shared_ptr<Crossfade> > all = get_equivalent_crossfades (*tv, xfade, ARDOUR::Properties::edit.property_id);
3697 _session->begin_reversible_command (_("Change crossfade active state"));
3699 for (vector<boost::shared_ptr<Crossfade> >::iterator i = all.begin(); i != all.end(); ++i) {
3700 (*i)->clear_changes ();
3701 (*i)->set_active (!(*i)->active());
3702 _session->add_command (new StatefulDiffCommand (*i));
3705 _session->commit_reversible_command ();
3709 Editor::toggle_xfade_length (RouteTimeAxisView* tv, boost::weak_ptr<Crossfade> wxfade)
3711 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3716 vector<boost::shared_ptr<Crossfade> > all = get_equivalent_crossfades (*tv, xfade, ARDOUR::Properties::edit.property_id);
3718 /* This can't be a StatefulDiffCommand as the fade shapes are not
3719 managed by the Stateful properties system.
3721 _session->begin_reversible_command (_("Change crossfade length"));
3723 for (vector<boost::shared_ptr<Crossfade> >::iterator i = all.begin(); i != all.end(); ++i) {
3724 XMLNode& before = (*i)->get_state ();
3725 (*i)->set_follow_overlap (!(*i)->following_overlap());
3726 XMLNode& after = (*i)->get_state ();
3728 _session->add_command (new MementoCommand<Crossfade> (*i->get(), &before, &after));
3731 _session->commit_reversible_command ();
3735 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3737 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3743 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3747 switch (cew.run ()) {
3748 case RESPONSE_ACCEPT:
3755 PropertyChange all_crossfade_properties;
3756 all_crossfade_properties.add (ARDOUR::Properties::active);
3757 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3758 xfade->PropertyChanged (all_crossfade_properties);
3762 Editor::playlist_selector () const
3764 return *_playlist_selector;
3768 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3772 switch (_snap_type) {
3777 case SnapToBeatDiv128:
3780 case SnapToBeatDiv64:
3783 case SnapToBeatDiv32:
3786 case SnapToBeatDiv28:
3789 case SnapToBeatDiv24:
3792 case SnapToBeatDiv20:
3795 case SnapToBeatDiv16:
3798 case SnapToBeatDiv14:
3801 case SnapToBeatDiv12:
3804 case SnapToBeatDiv10:
3807 case SnapToBeatDiv8:
3810 case SnapToBeatDiv7:
3813 case SnapToBeatDiv6:
3816 case SnapToBeatDiv5:
3819 case SnapToBeatDiv4:
3822 case SnapToBeatDiv3:
3825 case SnapToBeatDiv2:
3831 return _session->tempo_map().meter_at (position).divisions_per_bar();
3836 case SnapToTimecodeFrame:
3837 case SnapToTimecodeSeconds:
3838 case SnapToTimecodeMinutes:
3841 case SnapToRegionStart:
3842 case SnapToRegionEnd:
3843 case SnapToRegionSync:
3844 case SnapToRegionBoundary:
3854 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3858 ret = nudge_clock->current_duration (pos);
3859 next = ret + 1; /* XXXX fix me */
3865 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3867 ArdourDialog dialog (_("Playlist Deletion"));
3868 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3869 "If it is kept, its audio files will not be cleaned.\n"
3870 "If it is deleted, audio files used by it alone will be cleaned."),
3873 dialog.set_position (WIN_POS_CENTER);
3874 dialog.get_vbox()->pack_start (label);
3878 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3879 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3880 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3882 switch (dialog.run ()) {
3883 case RESPONSE_ACCEPT:
3884 /* delete the playlist */
3888 case RESPONSE_REJECT:
3889 /* keep the playlist */
3901 Editor::audio_region_selection_covers (framepos_t where)
3903 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3904 if ((*a)->region()->covers (where)) {
3913 Editor::prepare_for_cleanup ()
3915 cut_buffer->clear_regions ();
3916 cut_buffer->clear_playlists ();
3918 selection->clear_regions ();
3919 selection->clear_playlists ();
3921 _regions->suspend_redisplay ();
3925 Editor::finish_cleanup ()
3927 _regions->resume_redisplay ();
3931 Editor::transport_loop_location()
3934 return _session->locations()->auto_loop_location();
3941 Editor::transport_punch_location()
3944 return _session->locations()->auto_punch_location();
3951 Editor::control_layout_scroll (GdkEventScroll* ev)
3953 if (Keyboard::some_magic_widget_has_focus()) {
3957 switch (ev->direction) {
3959 scroll_tracks_up_line ();
3963 case GDK_SCROLL_DOWN:
3964 scroll_tracks_down_line ();
3968 /* no left/right handling yet */
3976 Editor::session_state_saved (string)
3979 _snapshots->redisplay ();
3983 Editor::maximise_editing_space ()
3991 if (!Config->get_keep_tearoffs()) {
3992 /* these calls will leave each tearoff visible *if* it is torn off,
3993 but invisible otherwise.
3995 _mouse_mode_tearoff->set_visible (false);
3996 _tools_tearoff->set_visible (false);
3997 _zoom_tearoff->set_visible (false);
4004 Editor::restore_editing_space ()
4012 if (!Config->get_keep_tearoffs()) {
4013 _mouse_mode_tearoff->set_visible (true);
4014 _tools_tearoff->set_visible (true);
4015 _zoom_tearoff->set_visible (true);
4022 * Make new playlists for a given track and also any others that belong
4023 * to the same active route group with the `edit' property.
4028 Editor::new_playlists (TimeAxisView* v)
4030 begin_reversible_command (_("new playlists"));
4031 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4032 _session->playlists->get (playlists);
4033 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4034 commit_reversible_command ();
4038 * Use a copy of the current playlist for a given track and also any others that belong
4039 * to the same active route group with the `edit' property.
4044 Editor::copy_playlists (TimeAxisView* v)
4046 begin_reversible_command (_("copy playlists"));
4047 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4048 _session->playlists->get (playlists);
4049 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4050 commit_reversible_command ();
4053 /** Clear the current playlist for a given track and also any others that belong
4054 * to the same active route group with the `edit' property.
4059 Editor::clear_playlists (TimeAxisView* v)
4061 begin_reversible_command (_("clear playlists"));
4062 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4063 _session->playlists->get (playlists);
4064 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4065 commit_reversible_command ();
4069 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4071 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4075 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4077 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4081 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4083 atv.clear_playlist ();
4087 Editor::on_key_press_event (GdkEventKey* ev)
4089 return key_press_focus_accelerator_handler (*this, ev);
4093 Editor::on_key_release_event (GdkEventKey* ev)
4095 return Gtk::Window::on_key_release_event (ev);
4096 // return key_press_focus_accelerator_handler (*this, ev);
4099 /** Queue up a change to the viewport x origin.
4100 * @param frame New x origin.
4103 Editor::reset_x_origin (framepos_t frame)
4105 queue_visual_change (frame);
4109 Editor::reset_y_origin (double y)
4111 queue_visual_change_y (y);
4115 Editor::reset_zoom (double fpu)
4117 queue_visual_change (fpu);
4121 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4123 reset_x_origin (frame);
4126 if (!no_save_visual) {
4127 undo_visual_stack.push_back (current_visual_state(false));
4131 Editor::VisualState::VisualState (bool with_tracks)
4132 : gui_state (with_tracks ? new GUIObjectState : 0)
4136 Editor::VisualState::~VisualState ()
4141 Editor::VisualState*
4142 Editor::current_visual_state (bool with_tracks)
4144 VisualState* vs = new VisualState (with_tracks);
4145 vs->y_position = vertical_adjustment.get_value();
4146 vs->frames_per_unit = frames_per_unit;
4147 vs->leftmost_frame = leftmost_frame;
4148 vs->zoom_focus = zoom_focus;
4151 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4158 Editor::undo_visual_state ()
4160 if (undo_visual_stack.empty()) {
4164 VisualState* vs = undo_visual_stack.back();
4165 undo_visual_stack.pop_back();
4168 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4170 use_visual_state (*vs);
4174 Editor::redo_visual_state ()
4176 if (redo_visual_stack.empty()) {
4180 VisualState* vs = redo_visual_stack.back();
4181 redo_visual_stack.pop_back();
4183 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4185 use_visual_state (*vs);
4189 Editor::swap_visual_state ()
4191 if (undo_visual_stack.empty()) {
4192 redo_visual_state ();
4194 undo_visual_state ();
4199 Editor::use_visual_state (VisualState& vs)
4201 PBD::Unwinder<bool> nsv (no_save_visual, true);
4203 _routes->suspend_redisplay ();
4205 vertical_adjustment.set_value (vs.y_position);
4207 set_zoom_focus (vs.zoom_focus);
4208 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4211 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4213 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4214 (*i)->reset_visual_state ();
4218 _routes->update_visibility ();
4219 _routes->resume_redisplay ();
4223 Editor::set_frames_per_unit (double fpu)
4225 /* this is the core function that controls the zoom level of the canvas. it is called
4226 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4229 if (fpu == frames_per_unit) {
4238 /* don't allow zooms that fit more than the maximum number
4239 of frames into an 800 pixel wide space.
4242 if (max_framepos / fpu < 800.0) {
4247 tempo_lines->tempo_map_changed();
4249 frames_per_unit = fpu;
4254 Editor::post_zoom ()
4256 // convert fpu to frame count
4258 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4260 if (frames_per_unit != zoom_range_clock->current_duration()) {
4261 zoom_range_clock->set (frames);
4264 bool const showing_time_selection =
4265 mouse_mode == MouseRange ||
4266 (mouse_mode == MouseObject && _join_object_range_state != JOIN_OBJECT_RANGE_NONE);
4268 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4269 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4270 (*i)->reshow_selection (selection->time);
4274 ZoomChanged (); /* EMIT_SIGNAL */
4276 //reset_scrolling_region ();
4278 if (playhead_cursor) {
4279 playhead_cursor->set_position (playhead_cursor->current_frame);
4282 refresh_location_display();
4283 _summary->set_overlays_dirty ();
4285 update_marker_labels ();
4291 Editor::queue_visual_change (framepos_t where)
4293 pending_visual_change.add (VisualChange::TimeOrigin);
4294 pending_visual_change.time_origin = where;
4295 ensure_visual_change_idle_handler ();
4299 Editor::queue_visual_change (double fpu)
4301 pending_visual_change.add (VisualChange::ZoomLevel);
4302 pending_visual_change.frames_per_unit = fpu;
4304 ensure_visual_change_idle_handler ();
4308 Editor::queue_visual_change_y (double y)
4310 pending_visual_change.add (VisualChange::YOrigin);
4311 pending_visual_change.y_origin = y;
4313 ensure_visual_change_idle_handler ();
4317 Editor::ensure_visual_change_idle_handler ()
4319 if (pending_visual_change.idle_handler_id < 0) {
4320 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4325 Editor::_idle_visual_changer (void* arg)
4327 return static_cast<Editor*>(arg)->idle_visual_changer ();
4331 Editor::idle_visual_changer ()
4333 VisualChange::Type p = pending_visual_change.pending;
4334 pending_visual_change.pending = (VisualChange::Type) 0;
4336 double const last_time_origin = horizontal_position ();
4338 if (p & VisualChange::TimeOrigin) {
4339 /* This is a bit of a hack, but set_frames_per_unit
4340 below will (if called) end up with the
4341 CrossfadeViews looking at Editor::leftmost_frame,
4342 and if we're changing origin and zoom in the same
4343 operation it will be the wrong value unless we
4347 leftmost_frame = pending_visual_change.time_origin;
4348 assert (leftmost_frame >= 0);
4351 if (p & VisualChange::ZoomLevel) {
4352 set_frames_per_unit (pending_visual_change.frames_per_unit);
4354 compute_fixed_ruler_scale ();
4355 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4356 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4357 update_tempo_based_rulers ();
4359 if (p & VisualChange::TimeOrigin) {
4360 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4362 if (p & VisualChange::YOrigin) {
4363 vertical_adjustment.set_value (pending_visual_change.y_origin);
4366 if (last_time_origin == horizontal_position ()) {
4367 /* changed signal not emitted */
4368 update_fixed_rulers ();
4369 redisplay_tempo (true);
4372 _summary->set_overlays_dirty ();
4374 pending_visual_change.idle_handler_id = -1;
4375 return 0; /* this is always a one-shot call */
4378 struct EditorOrderTimeAxisSorter {
4379 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4380 return a->order () < b->order ();
4385 Editor::sort_track_selection (TrackViewList& sel)
4387 EditorOrderTimeAxisSorter cmp;
4392 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4395 framepos_t where = 0;
4396 EditPoint ep = _edit_point;
4398 if (from_context_menu && (ep == EditAtMouse)) {
4399 return event_frame (&context_click_event, 0, 0);
4402 if (entered_marker) {
4403 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4404 return entered_marker->position();
4407 if (ignore_playhead && ep == EditAtPlayhead) {
4408 ep = EditAtSelectedMarker;
4412 case EditAtPlayhead:
4413 where = _session->audible_frame();
4414 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4417 case EditAtSelectedMarker:
4418 if (!selection->markers.empty()) {
4420 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4423 where = loc->start();
4427 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4435 if (!mouse_frame (where, ignored)) {
4436 /* XXX not right but what can we do ? */
4440 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4448 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4450 if (!_session) return;
4452 begin_reversible_command (cmd);
4456 if ((tll = transport_loop_location()) == 0) {
4457 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4458 XMLNode &before = _session->locations()->get_state();
4459 _session->locations()->add (loc, true);
4460 _session->set_auto_loop_location (loc);
4461 XMLNode &after = _session->locations()->get_state();
4462 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4464 XMLNode &before = tll->get_state();
4465 tll->set_hidden (false, this);
4466 tll->set (start, end);
4467 XMLNode &after = tll->get_state();
4468 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4471 commit_reversible_command ();
4475 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4477 if (!_session) return;
4479 begin_reversible_command (cmd);
4483 if ((tpl = transport_punch_location()) == 0) {
4484 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4485 XMLNode &before = _session->locations()->get_state();
4486 _session->locations()->add (loc, true);
4487 _session->set_auto_loop_location (loc);
4488 XMLNode &after = _session->locations()->get_state();
4489 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4492 XMLNode &before = tpl->get_state();
4493 tpl->set_hidden (false, this);
4494 tpl->set (start, end);
4495 XMLNode &after = tpl->get_state();
4496 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4499 commit_reversible_command ();
4502 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4503 * @param rs List to which found regions are added.
4504 * @param where Time to look at.
4505 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4508 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4510 const TrackViewList* tracks;
4513 tracks = &track_views;
4518 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4520 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4523 boost::shared_ptr<Track> tr;
4524 boost::shared_ptr<Playlist> pl;
4526 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4528 boost::shared_ptr<RegionList> regions = pl->regions_at (
4529 (framepos_t) floor ( (double) where * tr->speed()));
4531 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4532 RegionView* rv = rtv->view()->find_view (*i);
4543 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4545 const TrackViewList* tracks;
4548 tracks = &track_views;
4553 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4554 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4556 boost::shared_ptr<Track> tr;
4557 boost::shared_ptr<Playlist> pl;
4559 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4561 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4562 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4564 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4566 RegionView* rv = rtv->view()->find_view (*i);
4577 /** Start with regions that are selected. Then add equivalent regions
4578 * on tracks in the same active edit-enabled route group as any of
4579 * the regions that we started with.
4583 Editor::get_regions_from_selection ()
4585 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4588 /** Get regions using the following method:
4590 * Make an initial region list using the selected regions, unless
4591 * the edit point is `mouse' and the mouse is over an unselected
4592 * region. In this case, start with just that region.
4594 * Then, make an initial track list of the tracks that these
4595 * regions are on, and if the edit point is not `mouse', add the
4598 * Look at this track list and add any other tracks that are on the
4599 * same active edit-enabled route group as one of the initial tracks.
4601 * Finally take the initial region list and add any regions that are
4602 * under the edit point on one of the tracks on the track list to get
4603 * the returned region list.
4605 * The rationale here is that the mouse edit point is special in that
4606 * its position describes both a time and a track; the other edit
4607 * modes only describe a time. Hence if the edit point is `mouse' we
4608 * ignore selected tracks, as we assume the user means something by
4609 * pointing at a particular track. Also in this case we take note of
4610 * the region directly under the edit point, as there is always just one
4611 * (rather than possibly several with non-mouse edit points).
4615 Editor::get_regions_from_selection_and_edit_point ()
4617 RegionSelection regions;
4619 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4620 regions.add (entered_regionview);
4622 regions = selection->regions;
4625 TrackViewList tracks;
4627 if (_edit_point != EditAtMouse) {
4628 tracks = selection->tracks;
4631 /* Add any other tracks that have regions that are in the same
4632 edit-activated route group as one of our regions.
4634 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4636 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4638 if (g && g->is_active() && g->is_edit()) {
4639 tracks.add (axis_views_from_routes (g->route_list()));
4643 if (!tracks.empty()) {
4644 /* now find regions that are at the edit position on those tracks */
4645 framepos_t const where = get_preferred_edit_position ();
4646 get_regions_at (regions, where, tracks);
4652 /** Start with regions that are selected, or the entered regionview if none are selected.
4653 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4654 * of the regions that we started with.
4658 Editor::get_regions_from_selection_and_entered ()
4660 RegionSelection regions = selection->regions;
4662 if (regions.empty() && entered_regionview) {
4663 regions.add (entered_regionview);
4666 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4670 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4672 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4674 RouteTimeAxisView* tatv;
4676 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4678 boost::shared_ptr<Playlist> pl;
4679 vector<boost::shared_ptr<Region> > results;
4681 boost::shared_ptr<Track> tr;
4683 if ((tr = tatv->track()) == 0) {
4688 if ((pl = (tr->playlist())) != 0) {
4689 pl->get_region_list_equivalent_regions (region, results);
4692 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4693 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4694 regions.push_back (marv);
4703 Editor::show_rhythm_ferret ()
4705 if (rhythm_ferret == 0) {
4706 rhythm_ferret = new RhythmFerret(*this);
4709 rhythm_ferret->set_session (_session);
4710 rhythm_ferret->show ();
4711 rhythm_ferret->present ();
4715 Editor::first_idle ()
4717 MessageDialog* dialog = 0;
4719 if (track_views.size() > 1) {
4720 dialog = new MessageDialog (
4722 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4726 ARDOUR_UI::instance()->flush_pending ();
4729 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4733 // first idle adds route children (automation tracks), so we need to redisplay here
4734 _routes->redisplay ();
4741 Editor::_idle_resize (gpointer arg)
4743 return ((Editor*)arg)->idle_resize ();
4747 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4749 if (resize_idle_id < 0) {
4750 resize_idle_id = g_idle_add (_idle_resize, this);
4751 _pending_resize_amount = 0;
4754 /* make a note of the smallest resulting height, so that we can clamp the
4755 lower limit at TimeAxisView::hSmall */
4757 int32_t min_resulting = INT32_MAX;
4759 _pending_resize_amount += h;
4760 _pending_resize_view = view;
4762 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4764 if (selection->tracks.contains (_pending_resize_view)) {
4765 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4766 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4770 if (min_resulting < 0) {
4775 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4776 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4780 /** Handle pending resizing of tracks */
4782 Editor::idle_resize ()
4784 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4786 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4787 selection->tracks.contains (_pending_resize_view)) {
4789 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4790 if (*i != _pending_resize_view) {
4791 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4796 _pending_resize_amount = 0;
4798 _group_tabs->set_dirty ();
4799 resize_idle_id = -1;
4807 ENSURE_GUI_THREAD (*this, &Editor::located);
4809 playhead_cursor->set_position (_session->audible_frame ());
4810 if (_follow_playhead && !_pending_initial_locate) {
4811 reset_x_origin_to_follow_playhead ();
4814 _pending_locate_request = false;
4815 _pending_initial_locate = false;
4819 Editor::region_view_added (RegionView *)
4821 _summary->set_dirty ();
4825 Editor::region_view_removed ()
4827 _summary->set_dirty ();
4831 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4833 TrackViewList::const_iterator j = track_views.begin ();
4834 while (j != track_views.end()) {
4835 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4836 if (rtv && rtv->route() == r) {
4847 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4851 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4852 TimeAxisView* tv = axis_view_from_route (*i);
4863 Editor::handle_new_route (RouteList& routes)
4865 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4867 RouteTimeAxisView *rtv;
4868 list<RouteTimeAxisView*> new_views;
4870 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4871 boost::shared_ptr<Route> route = (*x);
4873 if (route->is_hidden() || route->is_monitor()) {
4877 DataType dt = route->input()->default_type();
4879 if (dt == ARDOUR::DataType::AUDIO) {
4880 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4881 rtv->set_route (route);
4882 } else if (dt == ARDOUR::DataType::MIDI) {
4883 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4884 rtv->set_route (route);
4886 throw unknown_type();
4889 new_views.push_back (rtv);
4890 track_views.push_back (rtv);
4892 rtv->effective_gain_display ();
4894 if (internal_editing()) {
4895 rtv->enter_internal_edit_mode ();
4897 rtv->leave_internal_edit_mode ();
4900 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4901 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4904 _routes->routes_added (new_views);
4905 _summary->routes_added (new_views);
4907 if (show_editor_mixer_when_tracks_arrive) {
4908 show_editor_mixer (true);
4911 editor_list_button.set_sensitive (true);
4915 Editor::timeaxisview_deleted (TimeAxisView *tv)
4917 if (_session && _session->deletion_in_progress()) {
4918 /* the situation is under control */
4922 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4924 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4926 _routes->route_removed (tv);
4928 if (tv == entered_track) {
4932 TimeAxisView::Children c = tv->get_child_list ();
4933 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4934 if (entered_track == i->get()) {
4939 /* remove it from the list of track views */
4941 TrackViewList::iterator i;
4943 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4944 i = track_views.erase (i);
4947 /* update whatever the current mixer strip is displaying, if revelant */
4949 boost::shared_ptr<Route> route;
4952 route = rtav->route ();
4955 if (current_mixer_strip && current_mixer_strip->route() == route) {
4957 TimeAxisView* next_tv;
4959 if (track_views.empty()) {
4961 } else if (i == track_views.end()) {
4962 next_tv = track_views.front();
4969 set_selected_mixer_strip (*next_tv);
4971 /* make the editor mixer strip go away setting the
4972 * button to inactive (which also unticks the menu option)
4975 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4981 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4983 if (apply_to_selection) {
4984 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4986 TrackSelection::iterator j = i;
4989 hide_track_in_display (*i, false);
4994 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4996 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4997 // this will hide the mixer strip
4998 set_selected_mixer_strip (*tv);
5001 _routes->hide_track_in_display (*tv);
5006 Editor::sync_track_view_list_and_routes ()
5008 track_views = TrackViewList (_routes->views ());
5010 _summary->set_dirty ();
5011 _group_tabs->set_dirty ();
5013 return false; // do not call again (until needed)
5017 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5019 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5024 /** Find a RouteTimeAxisView by the ID of its route */
5026 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5028 RouteTimeAxisView* v;
5030 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5031 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5032 if(v->route()->id() == id) {
5042 Editor::fit_route_group (RouteGroup *g)
5044 TrackViewList ts = axis_views_from_routes (g->route_list ());
5049 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5051 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5054 _session->cancel_audition ();
5058 if (_session->is_auditioning()) {
5059 _session->cancel_audition ();
5060 if (r == last_audition_region) {
5065 _session->audition_region (r);
5066 last_audition_region = r;
5071 Editor::hide_a_region (boost::shared_ptr<Region> r)
5073 r->set_hidden (true);
5077 Editor::show_a_region (boost::shared_ptr<Region> r)
5079 r->set_hidden (false);
5083 Editor::audition_region_from_region_list ()
5085 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5089 Editor::hide_region_from_region_list ()
5091 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5095 Editor::show_region_in_region_list ()
5097 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5101 Editor::step_edit_status_change (bool yn)
5104 start_step_editing ();
5106 stop_step_editing ();
5111 Editor::start_step_editing ()
5113 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5117 Editor::stop_step_editing ()
5119 step_edit_connection.disconnect ();
5123 Editor::check_step_edit ()
5125 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5126 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5128 mtv->check_step_edit ();
5132 return true; // do it again, till we stop
5136 Editor::scroll_press (Direction dir)
5138 ++_scroll_callbacks;
5140 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5141 /* delay the first auto-repeat */
5147 scroll_backward (1);
5155 scroll_tracks_up_line ();
5159 scroll_tracks_down_line ();
5163 /* do hacky auto-repeat */
5164 if (!_scroll_connection.connected ()) {
5166 _scroll_connection = Glib::signal_timeout().connect (
5167 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5170 _scroll_callbacks = 0;
5177 Editor::scroll_release ()
5179 _scroll_connection.disconnect ();
5182 /** Queue a change for the Editor viewport x origin to follow the playhead */
5184 Editor::reset_x_origin_to_follow_playhead ()
5186 framepos_t const frame = playhead_cursor->current_frame;
5188 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5190 if (_session->transport_speed() < 0) {
5192 if (frame > (current_page_frames() / 2)) {
5193 center_screen (frame-(current_page_frames()/2));
5195 center_screen (current_page_frames()/2);
5202 if (frame < leftmost_frame) {
5204 if (_session->transport_rolling()) {
5205 /* rolling; end up with the playhead at the right of the page */
5206 l = frame - current_page_frames ();
5208 /* not rolling: end up with the playhead 1/4 of the way along the page */
5209 l = frame - current_page_frames() / 4;
5213 if (_session->transport_rolling()) {
5214 /* rolling: end up with the playhead on the left of the page */
5217 /* not rolling: end up with the playhead 3/4 of the way along the page */
5218 l = frame - 3 * current_page_frames() / 4;
5226 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5232 Editor::super_rapid_screen_update ()
5234 if (!_session || !_session->engine().running()) {
5238 /* METERING / MIXER STRIPS */
5240 /* update track meters, if required */
5241 if (is_mapped() && meters_running) {
5242 RouteTimeAxisView* rtv;
5243 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5244 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5245 rtv->fast_update ();
5250 /* and any current mixer strip */
5251 if (current_mixer_strip) {
5252 current_mixer_strip->fast_update ();
5255 /* PLAYHEAD AND VIEWPORT */
5257 framepos_t const frame = _session->audible_frame();
5259 /* There are a few reasons why we might not update the playhead / viewport stuff:
5261 * 1. we don't update things when there's a pending locate request, otherwise
5262 * when the editor requests a locate there is a chance that this method
5263 * will move the playhead before the locate request is processed, causing
5265 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5266 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5269 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5271 last_update_frame = frame;
5273 if (!_dragging_playhead) {
5274 playhead_cursor->set_position (frame);
5277 if (!_stationary_playhead) {
5279 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5280 reset_x_origin_to_follow_playhead ();
5285 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5289 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5290 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5291 if (target <= 0.0) {
5294 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5295 target = (target * 0.15) + (current * 0.85);
5301 set_horizontal_position (current);
5310 Editor::session_going_away ()
5312 _have_idled = false;
5314 _session_connections.drop_connections ();
5316 super_rapid_screen_update_connection.disconnect ();
5318 selection->clear ();
5319 cut_buffer->clear ();
5321 clicked_regionview = 0;
5322 clicked_axisview = 0;
5323 clicked_routeview = 0;
5324 clicked_crossfadeview = 0;
5325 entered_regionview = 0;
5327 last_update_frame = 0;
5330 playhead_cursor->canvas_item.hide ();
5332 /* rip everything out of the list displays */
5336 _route_groups->clear ();
5338 /* do this first so that deleting a track doesn't reset cms to null
5339 and thus cause a leak.
5342 if (current_mixer_strip) {
5343 if (current_mixer_strip->get_parent() != 0) {
5344 global_hpacker.remove (*current_mixer_strip);
5346 delete current_mixer_strip;
5347 current_mixer_strip = 0;
5350 /* delete all trackviews */
5352 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5355 track_views.clear ();
5357 zoom_range_clock->set_session (0);
5358 nudge_clock->set_session (0);
5360 editor_list_button.set_active(false);
5361 editor_list_button.set_sensitive(false);
5363 /* clear tempo/meter rulers */
5364 remove_metric_marks ();
5366 clear_marker_display ();
5368 current_bbt_points_begin = current_bbt_points_end;
5370 /* get rid of any existing editor mixer strip */
5372 WindowTitle title(Glib::get_application_name());
5373 title += _("Editor");
5375 set_title (title.get_string());
5377 SessionHandlePtr::session_going_away ();
5382 Editor::show_editor_list (bool yn)
5385 _the_notebook.show ();
5387 _the_notebook.hide ();
5392 Editor::change_region_layering_order (bool from_context_menu)
5394 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5396 if (!clicked_routeview) {
5397 if (layering_order_editor) {
5398 layering_order_editor->hide ();
5403 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5409 boost::shared_ptr<Playlist> pl = track->playlist();
5415 if (layering_order_editor == 0) {
5416 layering_order_editor = new RegionLayeringOrderEditor (*this);
5417 layering_order_editor->set_position (WIN_POS_MOUSE);
5420 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5421 layering_order_editor->maybe_present ();
5425 Editor::update_region_layering_order_editor ()
5427 if (layering_order_editor && layering_order_editor->is_visible ()) {
5428 change_region_layering_order (true);
5433 Editor::setup_fade_images ()
5435 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5436 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5437 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5438 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5439 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5441 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5442 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5443 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5444 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5445 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5449 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5451 Editor::action_menu_item (std::string const & name)
5453 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5456 return *manage (a->create_menu_item ());
5460 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5462 EventBox* b = manage (new EventBox);
5463 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5464 Label* l = manage (new Label (name));
5468 _the_notebook.append_page (widget, *b);
5472 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5474 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5475 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5478 if (ev->type == GDK_2BUTTON_PRESS) {
5480 /* double-click on a notebook tab shrinks or expands the notebook */
5482 if (_notebook_shrunk) {
5483 if (pre_notebook_shrink_pane_width) {
5484 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5486 _notebook_shrunk = false;
5488 pre_notebook_shrink_pane_width = edit_pane.get_position();
5490 /* this expands the LHS of the edit pane to cover the notebook
5491 PAGE but leaves the tabs visible.
5493 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5494 _notebook_shrunk = true;
5502 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5504 using namespace Menu_Helpers;
5506 MenuList& items = _control_point_context_menu.items ();
5509 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5510 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5511 if (!can_remove_control_point (item)) {
5512 items.back().set_sensitive (false);
5515 _control_point_context_menu.popup (event->button.button, event->button.time);