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/stacktrace.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 "canvas-noevent-text.h"
90 #include "canvas_impl.h"
91 #include "crossfade_edit.h"
92 #include "crossfade_view.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
121 #include "simpleline.h"
122 #include "tempo_lines.h"
123 #include "time_axis_view.h"
129 #include "imageframe_socket_handler.h"
133 using namespace ARDOUR;
136 using namespace Glib;
137 using namespace Gtkmm2ext;
138 using namespace Editing;
140 using PBD::internationalize;
142 using Gtkmm2ext::Keyboard;
144 const double Editor::timebar_height = 15.0;
146 static const gchar *_snap_type_strings[] = {
148 N_("Timecode Frames"),
149 N_("Timecode Seconds"),
150 N_("Timecode Minutes"),
178 static const gchar *_snap_mode_strings[] = {
185 static const gchar *_edit_point_strings[] = {
192 static const gchar *_zoom_focus_strings[] = {
202 #ifdef USE_RUBBERBAND
203 static const gchar *_rb_opt_strings[] = {
206 N_("Balanced multitimbral mixture"),
207 N_("Unpitched percussion with stable notes"),
208 N_("Crisp monophonic instrumental"),
209 N_("Unpitched solo percussion"),
210 N_("Resample without preserving pitch"),
216 show_me_the_size (Requisition* r, const char* what)
218 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
223 pane_size_watcher (Paned* pane)
225 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
226 it is no longer accessible. so stop that. this doesn't happen on X11,
227 just the quartz backend.
232 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
234 gint pos = pane->get_position ();
236 if (pos > max_width_of_lhs) {
237 pane->set_position (max_width_of_lhs);
243 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
245 /* time display buttons */
246 , minsec_label (_("Mins:Secs"))
247 , bbt_label (_("Bars:Beats"))
248 , timecode_label (_("Timecode"))
249 , samples_label (_("Samples"))
250 , tempo_label (_("Tempo"))
251 , meter_label (_("Meter"))
252 , mark_label (_("Location Markers"))
253 , range_mark_label (_("Range Markers"))
254 , transport_mark_label (_("Loop/Punch Ranges"))
255 , cd_mark_label (_("CD Markers"))
256 , edit_packer (4, 4, true)
258 /* the values here don't matter: layout widgets
259 reset them as needed.
262 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
264 /* tool bar related */
266 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
268 , toolbar_selection_clock_table (2,3)
270 , automation_mode_button (_("mode"))
272 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
275 , image_socket_listener(0)
280 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
281 , meters_running(false)
282 , _pending_locate_request (false)
283 , _pending_initial_locate (false)
284 , _last_cut_copy_source_track (0)
286 , _region_selection_change_updates_region_list (true)
287 , _following_mixer_selection (false)
291 /* we are a singleton */
293 PublicEditor::_instance = this;
297 selection = new Selection (this);
298 cut_buffer = new Selection (this);
300 clicked_regionview = 0;
301 clicked_axisview = 0;
302 clicked_routeview = 0;
303 clicked_crossfadeview = 0;
304 clicked_control_point = 0;
305 last_update_frame = 0;
306 pre_press_cursor = 0;
307 _drags = new DragManager (this);
308 current_mixer_strip = 0;
311 snap_type_strings = I18N (_snap_type_strings);
312 snap_mode_strings = I18N (_snap_mode_strings);
313 zoom_focus_strings = I18N (_zoom_focus_strings);
314 edit_point_strings = I18N (_edit_point_strings);
315 #ifdef USE_RUBBERBAND
316 rb_opt_strings = I18N (_rb_opt_strings);
320 snap_threshold = 5.0;
321 bbt_beat_subdivision = 4;
324 last_autoscroll_x = 0;
325 last_autoscroll_y = 0;
326 autoscroll_active = false;
327 autoscroll_timeout_tag = -1;
332 current_interthread_info = 0;
333 _show_measures = true;
335 show_gain_after_trim = false;
337 have_pending_keyboard_selection = false;
338 _follow_playhead = true;
339 _stationary_playhead = false;
340 _xfade_visibility = true;
341 editor_ruler_menu = 0;
342 no_ruler_shown_update = false;
344 range_marker_menu = 0;
345 marker_menu_item = 0;
346 tempo_or_meter_marker_menu = 0;
347 transport_marker_menu = 0;
348 new_transport_marker_menu = 0;
349 editor_mixer_strip_width = Wide;
350 show_editor_mixer_when_tracks_arrive = false;
351 region_edit_menu_split_multichannel_item = 0;
352 region_edit_menu_split_item = 0;
355 current_stepping_trackview = 0;
357 entered_regionview = 0;
359 clear_entered_track = false;
362 button_release_can_deselect = true;
363 _dragging_playhead = false;
364 _dragging_edit_point = false;
365 select_new_marker = false;
367 layering_order_editor = 0;
368 no_save_visual = false;
371 scrubbing_direction = 0;
375 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
376 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
377 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
378 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
379 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
381 _edit_point = EditAtMouse;
382 _internal_editing = false;
383 current_canvas_cursor = 0;
385 frames_per_unit = 2048; /* too early to use reset_zoom () */
387 _scroll_callbacks = 0;
389 zoom_focus = ZoomFocusLeft;
390 set_zoom_focus (ZoomFocusLeft);
391 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
393 bbt_label.set_name ("EditorTimeButton");
394 bbt_label.set_size_request (-1, (int)timebar_height);
395 bbt_label.set_alignment (1.0, 0.5);
396 bbt_label.set_padding (5,0);
398 bbt_label.set_no_show_all();
399 minsec_label.set_name ("EditorTimeButton");
400 minsec_label.set_size_request (-1, (int)timebar_height);
401 minsec_label.set_alignment (1.0, 0.5);
402 minsec_label.set_padding (5,0);
403 minsec_label.hide ();
404 minsec_label.set_no_show_all();
405 timecode_label.set_name ("EditorTimeButton");
406 timecode_label.set_size_request (-1, (int)timebar_height);
407 timecode_label.set_alignment (1.0, 0.5);
408 timecode_label.set_padding (5,0);
409 timecode_label.hide ();
410 timecode_label.set_no_show_all();
411 samples_label.set_name ("EditorTimeButton");
412 samples_label.set_size_request (-1, (int)timebar_height);
413 samples_label.set_alignment (1.0, 0.5);
414 samples_label.set_padding (5,0);
415 samples_label.hide ();
416 samples_label.set_no_show_all();
418 tempo_label.set_name ("EditorTimeButton");
419 tempo_label.set_size_request (-1, (int)timebar_height);
420 tempo_label.set_alignment (1.0, 0.5);
421 tempo_label.set_padding (5,0);
423 tempo_label.set_no_show_all();
425 meter_label.set_name ("EditorTimeButton");
426 meter_label.set_size_request (-1, (int)timebar_height);
427 meter_label.set_alignment (1.0, 0.5);
428 meter_label.set_padding (5,0);
430 meter_label.set_no_show_all();
432 mark_label.set_name ("EditorTimeButton");
433 mark_label.set_size_request (-1, (int)timebar_height);
434 mark_label.set_alignment (1.0, 0.5);
435 mark_label.set_padding (5,0);
437 mark_label.set_no_show_all();
439 cd_mark_label.set_name ("EditorTimeButton");
440 cd_mark_label.set_size_request (-1, (int)timebar_height);
441 cd_mark_label.set_alignment (1.0, 0.5);
442 cd_mark_label.set_padding (5,0);
443 cd_mark_label.hide();
444 cd_mark_label.set_no_show_all();
446 range_mark_label.set_name ("EditorTimeButton");
447 range_mark_label.set_size_request (-1, (int)timebar_height);
448 range_mark_label.set_alignment (1.0, 0.5);
449 range_mark_label.set_padding (5,0);
450 range_mark_label.hide();
451 range_mark_label.set_no_show_all();
453 transport_mark_label.set_name ("EditorTimeButton");
454 transport_mark_label.set_size_request (-1, (int)timebar_height);
455 transport_mark_label.set_alignment (1.0, 0.5);
456 transport_mark_label.set_padding (5,0);
457 transport_mark_label.hide();
458 transport_mark_label.set_no_show_all();
460 initialize_rulers ();
461 initialize_canvas ();
463 _summary = new EditorSummary (this);
465 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
466 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
468 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
470 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
471 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
473 edit_controls_vbox.set_spacing (0);
474 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
475 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
477 HBox* h = manage (new HBox);
478 _group_tabs = new EditorGroupTabs (this);
479 h->pack_start (*_group_tabs, PACK_SHRINK);
480 h->pack_start (edit_controls_vbox);
481 controls_layout.add (*h);
483 controls_layout.set_name ("EditControlsBase");
484 controls_layout.add_events (Gdk::SCROLL_MASK);
485 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
487 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
488 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
490 _cursors = new MouseCursors;
492 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
493 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
494 0.0, 1.0, 100.0, 1.0));
496 pad_line_1->property_color_rgba() = 0xFF0000FF;
501 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
502 time_canvas_vbox.set_size_request (-1, -1);
504 ruler_label_event_box.add (ruler_label_vbox);
505 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
506 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
508 time_button_event_box.add (time_button_vbox);
509 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
510 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
512 /* these enable us to have a dedicated window (for cursor setting, etc.)
513 for the canvas areas.
516 track_canvas_event_box.add (*track_canvas);
518 time_canvas_event_box.add (time_canvas_vbox);
519 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
521 edit_packer.set_col_spacings (0);
522 edit_packer.set_row_spacings (0);
523 edit_packer.set_homogeneous (false);
524 edit_packer.set_border_width (0);
525 edit_packer.set_name ("EditorWindow");
527 /* labels for the rulers */
528 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
529 /* labels for the marker "tracks" */
530 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
532 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
534 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
536 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
538 bottom_hbox.set_border_width (2);
539 bottom_hbox.set_spacing (3);
541 _route_groups = new EditorRouteGroups (this);
542 _routes = new EditorRoutes (this);
543 _regions = new EditorRegions (this);
544 _snapshots = new EditorSnapshots (this);
545 _locations = new EditorLocations (this);
547 add_notebook_page (_("Regions"), _regions->widget ());
548 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
549 add_notebook_page (_("Snapshots"), _snapshots->widget ());
550 add_notebook_page (_("Route Groups"), _route_groups->widget ());
551 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
553 _the_notebook.set_show_tabs (true);
554 _the_notebook.set_scrollable (true);
555 _the_notebook.popup_disable ();
556 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
557 _the_notebook.show_all ();
559 _notebook_shrunk = false;
561 editor_summary_pane.pack1(edit_packer);
563 Button* summary_arrows_left_left = manage (new Button);
564 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
565 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
566 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
568 Button* summary_arrows_left_right = manage (new Button);
569 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
570 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
571 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
573 VBox* summary_arrows_left = manage (new VBox);
574 summary_arrows_left->pack_start (*summary_arrows_left_left);
575 summary_arrows_left->pack_start (*summary_arrows_left_right);
577 Button* summary_arrows_right_up = manage (new Button);
578 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
579 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
580 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
582 Button* summary_arrows_right_down = manage (new Button);
583 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
584 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
585 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
587 VBox* summary_arrows_right = manage (new VBox);
588 summary_arrows_right->pack_start (*summary_arrows_right_up);
589 summary_arrows_right->pack_start (*summary_arrows_right_down);
591 Frame* summary_frame = manage (new Frame);
592 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
594 summary_frame->add (*_summary);
595 summary_frame->show ();
597 _summary_hbox.pack_start (*summary_arrows_left, false, false);
598 _summary_hbox.pack_start (*summary_frame, true, true);
599 _summary_hbox.pack_start (*summary_arrows_right, false, false);
601 editor_summary_pane.pack2 (_summary_hbox);
603 edit_pane.pack1 (editor_summary_pane, true, true);
604 edit_pane.pack2 (_the_notebook, false, true);
606 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
608 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
610 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
612 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
613 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
615 top_hbox.pack_start (toolbar_frame);
617 HBox *hbox = manage (new HBox);
618 hbox->pack_start (edit_pane, true, true);
620 global_vpacker.pack_start (top_hbox, false, false);
621 global_vpacker.pack_start (*hbox, true, true);
623 global_hpacker.pack_start (global_vpacker, true, true);
625 set_name ("EditorWindow");
626 add_accel_group (ActionManager::ui_manager->get_accel_group());
628 status_bar_hpacker.show ();
630 vpacker.pack_end (status_bar_hpacker, false, false);
631 vpacker.pack_end (global_hpacker, true, true);
633 /* register actions now so that set_state() can find them and set toggles/checks etc */
636 /* when we start using our own keybinding system for the editor, this
637 * will be uncommented
643 _snap_type = SnapToBeat;
644 set_snap_to (_snap_type);
645 _snap_mode = SnapOff;
646 set_snap_mode (_snap_mode);
647 set_mouse_mode (MouseObject, true);
648 pre_internal_mouse_mode = MouseObject;
649 set_edit_point_preference (EditAtMouse, true);
651 _playlist_selector = new PlaylistSelector();
652 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
654 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
658 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
659 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
661 nudge_forward_button.set_name ("TransportButton");
662 nudge_backward_button.set_name ("TransportButton");
664 fade_context_menu.set_name ("ArdourContextMenu");
666 /* icons, titles, WM stuff */
668 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
669 Glib::RefPtr<Gdk::Pixbuf> icon;
671 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
672 window_icons.push_back (icon);
674 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
675 window_icons.push_back (icon);
677 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
678 window_icons.push_back (icon);
680 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
681 window_icons.push_back (icon);
683 if (!window_icons.empty()) {
684 // set_icon_list (window_icons);
685 set_default_icon_list (window_icons);
688 WindowTitle title(Glib::get_application_name());
689 title += _("Editor");
690 set_title (title.get_string());
691 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
694 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
696 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
697 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
699 /* allow external control surfaces/protocols to do various things */
701 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
702 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
703 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
704 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
705 ControlProtocol::SelectByRID.connect (*this, invalidator (*this), ui_bind (&Editor::control_select, this, _1), gui_context());
706 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
708 /* problematic: has to return a value and thus cannot be x-thread */
710 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
712 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
714 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
716 _ignore_region_action = false;
717 _last_region_menu_was_main = false;
718 _popup_region_menu_item = 0;
720 _show_marker_lines = false;
721 _over_region_trim_target = false;
723 /* Button bindings */
725 button_bindings = new Bindings;
727 XMLNode* node = button_settings();
729 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
730 button_bindings->load (**i);
737 setup_fade_images ();
743 if(image_socket_listener) {
744 if(image_socket_listener->is_connected())
746 image_socket_listener->close_connection() ;
749 delete image_socket_listener ;
750 image_socket_listener = 0 ;
754 delete button_bindings;
756 delete _route_groups;
762 Editor::button_settings () const
764 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
765 XMLNode* node = find_named_node (*settings, X_("Buttons"));
768 cerr << "new empty Button node\n";
769 node = new XMLNode (X_("Buttons"));
776 Editor::add_toplevel_controls (Container& cont)
778 vpacker.pack_start (cont, false, false);
783 Editor::catch_vanishing_regionview (RegionView *rv)
785 /* note: the selection will take care of the vanishing
786 audioregionview by itself.
789 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
793 if (clicked_regionview == rv) {
794 clicked_regionview = 0;
797 if (entered_regionview == rv) {
798 set_entered_regionview (0);
801 if (!_all_region_actions_sensitized) {
802 sensitize_all_region_actions (true);
805 _over_region_trim_target = false;
809 Editor::set_entered_regionview (RegionView* rv)
811 if (rv == entered_regionview) {
815 if (entered_regionview) {
816 entered_regionview->exited ();
819 if ((entered_regionview = rv) != 0) {
820 entered_regionview->entered (internal_editing ());
823 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
824 /* This RegionView entry might have changed what region actions
825 are allowed, so sensitize them all in case a key is pressed.
827 sensitize_all_region_actions (true);
832 Editor::set_entered_track (TimeAxisView* tav)
835 entered_track->exited ();
838 if ((entered_track = tav) != 0) {
839 entered_track->entered ();
844 Editor::show_window ()
846 if (!is_visible ()) {
849 /* XXX: this is a bit unfortunate; it would probably
850 be nicer if we could just call show () above rather
851 than needing the show_all ()
854 /* re-hide stuff if necessary */
855 editor_list_button_toggled ();
856 parameter_changed ("show-summary");
857 parameter_changed ("show-group-tabs");
858 parameter_changed ("show-zoom-tools");
860 /* now reset all audio_time_axis heights, because widgets might need
866 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
867 tv = (static_cast<TimeAxisView*>(*i));
871 if (current_mixer_strip) {
872 current_mixer_strip->hide_things ();
873 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
881 Editor::instant_save ()
883 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
888 _session->add_instant_xml(get_state());
890 Config->add_instant_xml(get_state());
895 Editor::zoom_adjustment_changed ()
901 double fpu = zoom_range_clock->current_duration() / _canvas_width;
905 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
906 } else if (fpu > _session->current_end_frame() / _canvas_width) {
907 fpu = _session->current_end_frame() / _canvas_width;
908 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
915 Editor::control_select (uint32_t rid)
917 /* handles the (static) signal from the ControlProtocol class that
918 * requests setting the selected track to a given RID
925 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
931 TimeAxisView* tav = axis_view_from_route (r);
934 selection->set (tav);
936 selection->clear_tracks ();
941 Editor::control_scroll (float fraction)
943 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
949 double step = fraction * current_page_frames();
952 _control_scroll_target is an optional<T>
954 it acts like a pointer to an framepos_t, with
955 a operator conversion to boolean to check
956 that it has a value could possibly use
957 playhead_cursor->current_frame to store the
958 value and a boolean in the class to know
959 when it's out of date
962 if (!_control_scroll_target) {
963 _control_scroll_target = _session->transport_frame();
964 _dragging_playhead = true;
967 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
968 *_control_scroll_target = 0;
969 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
970 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
972 *_control_scroll_target += (framepos_t) floor (step);
975 /* move visuals, we'll catch up with it later */
977 playhead_cursor->set_position (*_control_scroll_target);
978 UpdateAllTransportClocks (*_control_scroll_target);
980 if (*_control_scroll_target > (current_page_frames() / 2)) {
981 /* try to center PH in window */
982 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
988 Now we do a timeout to actually bring the session to the right place
989 according to the playhead. This is to avoid reading disk buffers on every
990 call to control_scroll, which is driven by ScrollTimeline and therefore
991 probably by a control surface wheel which can generate lots of events.
993 /* cancel the existing timeout */
995 control_scroll_connection.disconnect ();
997 /* add the next timeout */
999 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1003 Editor::deferred_control_scroll (framepos_t /*target*/)
1005 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1006 // reset for next stream
1007 _control_scroll_target = boost::none;
1008 _dragging_playhead = false;
1013 Editor::access_action (std::string action_group, std::string action_item)
1019 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1022 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1030 Editor::on_realize ()
1032 Window::on_realize ();
1037 Editor::map_position_change (framepos_t frame)
1039 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1041 if (_session == 0) {
1045 if (_follow_playhead) {
1046 center_screen (frame);
1049 playhead_cursor->set_position (frame);
1053 Editor::center_screen (framepos_t frame)
1055 double page = _canvas_width * frames_per_unit;
1057 /* if we're off the page, then scroll.
1060 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1061 center_screen_internal (frame, page);
1066 Editor::center_screen_internal (framepos_t frame, float page)
1071 frame -= (framepos_t) page;
1076 reset_x_origin (frame);
1081 Editor::update_title ()
1083 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1086 bool dirty = _session->dirty();
1088 string session_name;
1090 if (_session->snap_name() != _session->name()) {
1091 session_name = _session->snap_name();
1093 session_name = _session->name();
1097 session_name = "*" + session_name;
1100 WindowTitle title(session_name);
1101 title += Glib::get_application_name();
1102 set_title (title.get_string());
1107 Editor::set_session (Session *t)
1109 SessionHandlePtr::set_session (t);
1115 zoom_range_clock->set_session (_session);
1116 _playlist_selector->set_session (_session);
1117 nudge_clock->set_session (_session);
1118 _summary->set_session (_session);
1119 _group_tabs->set_session (_session);
1120 _route_groups->set_session (_session);
1121 _regions->set_session (_session);
1122 _snapshots->set_session (_session);
1123 _routes->set_session (_session);
1124 _locations->set_session (_session);
1126 if (rhythm_ferret) {
1127 rhythm_ferret->set_session (_session);
1130 if (analysis_window) {
1131 analysis_window->set_session (_session);
1135 sfbrowser->set_session (_session);
1138 compute_fixed_ruler_scale ();
1140 /* Make sure we have auto loop and auto punch ranges */
1142 Location* loc = _session->locations()->auto_loop_location();
1144 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1146 if (loc->start() == loc->end()) {
1147 loc->set_end (loc->start() + 1);
1150 _session->locations()->add (loc, false);
1151 _session->set_auto_loop_location (loc);
1154 loc->set_name (_("Loop"));
1157 loc = _session->locations()->auto_punch_location();
1160 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1162 if (loc->start() == loc->end()) {
1163 loc->set_end (loc->start() + 1);
1166 _session->locations()->add (loc, false);
1167 _session->set_auto_punch_location (loc);
1170 loc->set_name (_("Punch"));
1173 refresh_location_display ();
1175 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1176 the selected Marker; this needs the LocationMarker list to be available.
1178 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1179 set_state (*node, Stateful::loading_state_version);
1181 /* catch up with the playhead */
1183 _session->request_locate (playhead_cursor->current_frame);
1184 _pending_initial_locate = true;
1188 /* These signals can all be emitted by a non-GUI thread. Therefore the
1189 handlers for them must not attempt to directly interact with the GUI,
1190 but use Gtkmm2ext::UI::instance()->call_slot();
1193 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1194 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1195 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1196 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1197 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1198 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1199 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1200 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1201 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1202 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1203 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1204 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1205 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display, this), gui_context());
1206 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1208 if (Profile->get_sae()) {
1209 Timecode::BBT_Time bbt;
1213 framepos_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1214 nudge_clock->set_mode(AudioClock::BBT);
1215 nudge_clock->set (pos, true);
1218 nudge_clock->set_mode (AudioClock::Timecode);
1219 nudge_clock->set (_session->frame_rate() * 5, true);
1222 playhead_cursor->canvas_item.show ();
1224 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1225 Config->map_parameters (pc);
1226 _session->config.map_parameters (pc);
1228 restore_ruler_visibility ();
1229 //tempo_map_changed (PropertyChange (0));
1230 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1232 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1233 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1236 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1237 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1240 switch (_snap_type) {
1241 case SnapToRegionStart:
1242 case SnapToRegionEnd:
1243 case SnapToRegionSync:
1244 case SnapToRegionBoundary:
1245 build_region_boundary_cache ();
1252 /* register for undo history */
1253 _session->register_with_memento_command_factory(id(), this);
1255 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1257 start_updating_meters ();
1261 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1263 if (a->get_name() == "RegionMenu") {
1264 /* When the main menu's region menu is opened, we setup the actions so that they look right
1265 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1266 so we resensitize all region actions when the entered regionview or the region selection
1267 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1268 happens after the region context menu is opened. So we set a flag here, too.
1272 sensitize_the_right_region_actions ();
1273 _last_region_menu_was_main = true;
1277 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1279 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1281 using namespace Menu_Helpers;
1282 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1285 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1289 MenuList& items (fade_context_menu.items());
1293 switch (item_type) {
1295 case FadeInHandleItem:
1296 if (arv->audio_region()->fade_in_active()) {
1297 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1299 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1302 items.push_back (SeparatorElem());
1304 if (Profile->get_sae()) {
1306 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1307 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1314 *_fade_in_images[FadeLinear],
1315 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1319 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1324 *_fade_in_images[FadeFast],
1325 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1328 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1333 *_fade_in_images[FadeLogB],
1334 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1337 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1342 *_fade_in_images[FadeLogA],
1343 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1346 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1351 *_fade_in_images[FadeSlow],
1352 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1355 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1361 case FadeOutHandleItem:
1362 if (arv->audio_region()->fade_out_active()) {
1363 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1365 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1368 items.push_back (SeparatorElem());
1370 if (Profile->get_sae()) {
1371 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1372 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1378 *_fade_out_images[FadeLinear],
1379 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1383 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1388 *_fade_out_images[FadeFast],
1389 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1392 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1397 *_fade_out_images[FadeLogB],
1398 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1401 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1406 *_fade_out_images[FadeLogA],
1407 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1410 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1415 *_fade_out_images[FadeSlow],
1416 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1419 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1425 fatal << _("programming error: ")
1426 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1431 fade_context_menu.popup (button, time);
1435 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1437 using namespace Menu_Helpers;
1438 Menu* (Editor::*build_menu_function)();
1441 switch (item_type) {
1443 case RegionViewName:
1444 case RegionViewNameHighlight:
1445 case LeftFrameHandle:
1446 case RightFrameHandle:
1447 if (with_selection) {
1448 build_menu_function = &Editor::build_track_selection_context_menu;
1450 build_menu_function = &Editor::build_track_region_context_menu;
1455 if (with_selection) {
1456 build_menu_function = &Editor::build_track_selection_context_menu;
1458 build_menu_function = &Editor::build_track_context_menu;
1462 case CrossfadeViewItem:
1463 build_menu_function = &Editor::build_track_crossfade_context_menu;
1467 if (clicked_routeview->track()) {
1468 build_menu_function = &Editor::build_track_context_menu;
1470 build_menu_function = &Editor::build_track_bus_context_menu;
1475 /* probably shouldn't happen but if it does, we don't care */
1479 menu = (this->*build_menu_function)();
1480 menu->set_name ("ArdourContextMenu");
1482 /* now handle specific situations */
1484 switch (item_type) {
1486 case RegionViewName:
1487 case RegionViewNameHighlight:
1488 case LeftFrameHandle:
1489 case RightFrameHandle:
1490 if (!with_selection) {
1491 if (region_edit_menu_split_item) {
1492 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1493 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1495 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1498 if (region_edit_menu_split_multichannel_item) {
1499 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1500 region_edit_menu_split_multichannel_item->set_sensitive (true);
1502 region_edit_menu_split_multichannel_item->set_sensitive (false);
1511 case CrossfadeViewItem:
1518 /* probably shouldn't happen but if it does, we don't care */
1522 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1524 /* Bounce to disk */
1526 using namespace Menu_Helpers;
1527 MenuList& edit_items = menu->items();
1529 edit_items.push_back (SeparatorElem());
1531 switch (clicked_routeview->audio_track()->freeze_state()) {
1532 case AudioTrack::NoFreeze:
1533 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1536 case AudioTrack::Frozen:
1537 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1540 case AudioTrack::UnFrozen:
1541 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1547 if (item_type == StreamItem && clicked_routeview) {
1548 clicked_routeview->build_underlay_menu(menu);
1551 /* When the region menu is opened, we setup the actions so that they look right
1554 sensitize_the_right_region_actions ();
1555 _last_region_menu_was_main = false;
1557 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1558 menu->popup (button, time);
1562 Editor::build_track_context_menu ()
1564 using namespace Menu_Helpers;
1566 MenuList& edit_items = track_context_menu.items();
1569 add_dstream_context_items (edit_items);
1570 return &track_context_menu;
1574 Editor::build_track_bus_context_menu ()
1576 using namespace Menu_Helpers;
1578 MenuList& edit_items = track_context_menu.items();
1581 add_bus_context_items (edit_items);
1582 return &track_context_menu;
1586 Editor::build_track_region_context_menu ()
1588 using namespace Menu_Helpers;
1589 MenuList& edit_items = track_region_context_menu.items();
1592 /* we've just cleared the track region context menu, so the menu that these
1593 two items were on will have disappeared; stop them dangling.
1595 region_edit_menu_split_item = 0;
1596 region_edit_menu_split_multichannel_item = 0;
1598 /* we might try to use items that are currently attached to a crossfade menu,
1601 track_crossfade_context_menu.items().clear ();
1603 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1606 boost::shared_ptr<Track> tr;
1607 boost::shared_ptr<Playlist> pl;
1609 if ((tr = rtv->track())) {
1610 add_region_context_items (edit_items, tr);
1614 add_dstream_context_items (edit_items);
1616 return &track_region_context_menu;
1620 Editor::build_track_crossfade_context_menu ()
1622 using namespace Menu_Helpers;
1623 MenuList& edit_items = track_crossfade_context_menu.items();
1624 edit_items.clear ();
1626 /* we might try to use items that are currently attached to a crossfade menu,
1629 track_region_context_menu.items().clear ();
1631 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1634 boost::shared_ptr<Track> tr;
1635 boost::shared_ptr<Playlist> pl;
1636 boost::shared_ptr<AudioPlaylist> apl;
1638 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1640 AudioPlaylist::Crossfades xfades;
1644 /* The xfade menu is a bit of a special case, as we always use the mouse position
1645 to decide whether or not to display it (rather than the edit point). No particularly
1646 strong reasons for this, other than it is a bit surprising to right-click on a xfade
1649 mouse_frame (where, ignored);
1650 apl->crossfades_at (where, xfades);
1652 bool const many = xfades.size() > 1;
1654 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1655 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1658 add_region_context_items (edit_items, tr);
1662 add_dstream_context_items (edit_items);
1664 return &track_crossfade_context_menu;
1668 Editor::analyze_region_selection ()
1670 if (analysis_window == 0) {
1671 analysis_window = new AnalysisWindow();
1674 analysis_window->set_session(_session);
1676 analysis_window->show_all();
1679 analysis_window->set_regionmode();
1680 analysis_window->analyze();
1682 analysis_window->present();
1686 Editor::analyze_range_selection()
1688 if (analysis_window == 0) {
1689 analysis_window = new AnalysisWindow();
1692 analysis_window->set_session(_session);
1694 analysis_window->show_all();
1697 analysis_window->set_rangemode();
1698 analysis_window->analyze();
1700 analysis_window->present();
1704 Editor::build_track_selection_context_menu ()
1706 using namespace Menu_Helpers;
1707 MenuList& edit_items = track_selection_context_menu.items();
1708 edit_items.clear ();
1710 add_selection_context_items (edit_items);
1711 // edit_items.push_back (SeparatorElem());
1712 // add_dstream_context_items (edit_items);
1714 return &track_selection_context_menu;
1717 /** Add context menu items relevant to crossfades.
1718 * @param edit_items List to add the items to.
1721 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1723 using namespace Menu_Helpers;
1724 Menu *xfade_menu = manage (new Menu);
1725 MenuList& items = xfade_menu->items();
1726 xfade_menu->set_name ("ArdourContextMenu");
1729 if (xfade->active()) {
1735 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1736 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1738 if (xfade->can_follow_overlap()) {
1740 if (xfade->following_overlap()) {
1741 str = _("Convert to Short");
1743 str = _("Convert to Full");
1746 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1750 str = xfade->out()->name();
1752 str += xfade->in()->name();
1754 str = _("Crossfade");
1757 edit_items.push_back (MenuElem (str, *xfade_menu));
1758 edit_items.push_back (SeparatorElem());
1762 Editor::xfade_edit_left_region ()
1764 if (clicked_crossfadeview) {
1765 clicked_crossfadeview->left_view.show_region_editor ();
1770 Editor::xfade_edit_right_region ()
1772 if (clicked_crossfadeview) {
1773 clicked_crossfadeview->right_view.show_region_editor ();
1778 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1780 using namespace Menu_Helpers;
1782 /* OK, stick the region submenu at the top of the list, and then add
1786 RegionSelection rs = get_regions_from_selection_and_entered ();
1788 string::size_type pos = 0;
1789 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1791 /* we have to hack up the region name because "_" has a special
1792 meaning for menu titles.
1795 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1796 menu_item_name.replace (pos, 1, "__");
1800 if (_popup_region_menu_item == 0) {
1801 _popup_region_menu_item = new MenuItem (menu_item_name);
1802 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1803 _popup_region_menu_item->show ();
1805 _popup_region_menu_item->set_label (menu_item_name);
1808 const framepos_t position = get_preferred_edit_position (false, true);
1810 edit_items.push_back (*_popup_region_menu_item);
1811 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1812 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1814 edit_items.push_back (SeparatorElem());
1817 /** Add context menu items relevant to selection ranges.
1818 * @param edit_items List to add the items to.
1821 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1823 using namespace Menu_Helpers;
1825 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1826 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1828 edit_items.push_back (SeparatorElem());
1829 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1831 edit_items.push_back (SeparatorElem());
1833 edit_items.push_back (
1835 _("Move Range Start to Previous Region Boundary"),
1836 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1840 edit_items.push_back (
1842 _("Move Range Start to Next Region Boundary"),
1843 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1847 edit_items.push_back (
1849 _("Move Range End to Previous Region Boundary"),
1850 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1854 edit_items.push_back (
1856 _("Move Range End to Next Region Boundary"),
1857 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1861 edit_items.push_back (SeparatorElem());
1862 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1863 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1865 edit_items.push_back (SeparatorElem());
1866 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1868 edit_items.push_back (SeparatorElem());
1869 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1870 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1872 edit_items.push_back (SeparatorElem());
1873 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1875 edit_items.push_back (SeparatorElem());
1876 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1877 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1878 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1880 edit_items.push_back (SeparatorElem());
1881 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1882 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1883 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1884 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1885 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1890 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1892 using namespace Menu_Helpers;
1896 Menu *play_menu = manage (new Menu);
1897 MenuList& play_items = play_menu->items();
1898 play_menu->set_name ("ArdourContextMenu");
1900 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1901 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1902 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1903 play_items.push_back (SeparatorElem());
1904 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1906 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1910 Menu *select_menu = manage (new Menu);
1911 MenuList& select_items = select_menu->items();
1912 select_menu->set_name ("ArdourContextMenu");
1914 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1915 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1916 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1917 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1918 select_items.push_back (SeparatorElem());
1919 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1920 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1921 select_items.push_back (SeparatorElem());
1922 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1923 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1924 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1925 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1926 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1927 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1928 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1930 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1934 Menu *cutnpaste_menu = manage (new Menu);
1935 MenuList& cutnpaste_items = cutnpaste_menu->items();
1936 cutnpaste_menu->set_name ("ArdourContextMenu");
1938 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1939 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1940 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1942 cutnpaste_items.push_back (SeparatorElem());
1944 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1945 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1947 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1949 /* Adding new material */
1951 edit_items.push_back (SeparatorElem());
1952 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1953 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1957 Menu *nudge_menu = manage (new Menu());
1958 MenuList& nudge_items = nudge_menu->items();
1959 nudge_menu->set_name ("ArdourContextMenu");
1961 edit_items.push_back (SeparatorElem());
1962 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1963 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1964 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1965 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1967 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1971 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1973 using namespace Menu_Helpers;
1977 Menu *play_menu = manage (new Menu);
1978 MenuList& play_items = play_menu->items();
1979 play_menu->set_name ("ArdourContextMenu");
1981 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1982 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1983 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1987 Menu *select_menu = manage (new Menu);
1988 MenuList& select_items = select_menu->items();
1989 select_menu->set_name ("ArdourContextMenu");
1991 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1992 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1993 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1994 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1995 select_items.push_back (SeparatorElem());
1996 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1997 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1998 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1999 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2001 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2005 Menu *cutnpaste_menu = manage (new Menu);
2006 MenuList& cutnpaste_items = cutnpaste_menu->items();
2007 cutnpaste_menu->set_name ("ArdourContextMenu");
2009 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2010 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2011 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2013 Menu *nudge_menu = manage (new Menu());
2014 MenuList& nudge_items = nudge_menu->items();
2015 nudge_menu->set_name ("ArdourContextMenu");
2017 edit_items.push_back (SeparatorElem());
2018 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2019 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2020 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2021 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2023 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2027 Editor::snap_type() const
2033 Editor::snap_mode() const
2039 Editor::set_snap_to (SnapType st)
2041 unsigned int snap_ind = (unsigned int)st;
2045 if (snap_ind > snap_type_strings.size() - 1) {
2047 _snap_type = (SnapType)snap_ind;
2050 string str = snap_type_strings[snap_ind];
2052 if (str != snap_type_selector.get_active_text()) {
2053 snap_type_selector.set_active_text (str);
2058 switch (_snap_type) {
2059 case SnapToBeatDiv32:
2060 case SnapToBeatDiv28:
2061 case SnapToBeatDiv24:
2062 case SnapToBeatDiv20:
2063 case SnapToBeatDiv16:
2064 case SnapToBeatDiv14:
2065 case SnapToBeatDiv12:
2066 case SnapToBeatDiv10:
2067 case SnapToBeatDiv8:
2068 case SnapToBeatDiv7:
2069 case SnapToBeatDiv6:
2070 case SnapToBeatDiv5:
2071 case SnapToBeatDiv4:
2072 case SnapToBeatDiv3:
2073 case SnapToBeatDiv2:
2074 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2075 update_tempo_based_rulers ();
2078 case SnapToRegionStart:
2079 case SnapToRegionEnd:
2080 case SnapToRegionSync:
2081 case SnapToRegionBoundary:
2082 build_region_boundary_cache ();
2090 SnapChanged (); /* EMIT SIGNAL */
2094 Editor::set_snap_mode (SnapMode mode)
2097 string str = snap_mode_strings[(int)mode];
2099 if (str != snap_mode_selector.get_active_text ()) {
2100 snap_mode_selector.set_active_text (str);
2106 Editor::set_edit_point_preference (EditPoint ep, bool force)
2108 bool changed = (_edit_point != ep);
2111 string str = edit_point_strings[(int)ep];
2113 if (str != edit_point_selector.get_active_text ()) {
2114 edit_point_selector.set_active_text (str);
2117 set_canvas_cursor ();
2119 if (!force && !changed) {
2123 const char* action=NULL;
2125 switch (_edit_point) {
2126 case EditAtPlayhead:
2127 action = "edit-at-playhead";
2129 case EditAtSelectedMarker:
2130 action = "edit-at-marker";
2133 action = "edit-at-mouse";
2137 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2139 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2143 bool in_track_canvas;
2145 if (!mouse_frame (foo, in_track_canvas)) {
2146 in_track_canvas = false;
2149 reset_canvas_action_sensitivity (in_track_canvas);
2155 Editor::set_state (const XMLNode& node, int /*version*/)
2157 const XMLProperty* prop;
2164 g.base_width = default_width;
2165 g.base_height = default_height;
2169 if ((geometry = find_named_node (node, "geometry")) != 0) {
2173 if ((prop = geometry->property("x_size")) == 0) {
2174 prop = geometry->property ("x-size");
2177 g.base_width = atoi(prop->value());
2179 if ((prop = geometry->property("y_size")) == 0) {
2180 prop = geometry->property ("y-size");
2183 g.base_height = atoi(prop->value());
2186 if ((prop = geometry->property ("x_pos")) == 0) {
2187 prop = geometry->property ("x-pos");
2190 x = atoi (prop->value());
2193 if ((prop = geometry->property ("y_pos")) == 0) {
2194 prop = geometry->property ("y-pos");
2197 y = atoi (prop->value());
2201 set_default_size (g.base_width, g.base_height);
2204 if (_session && (prop = node.property ("playhead"))) {
2206 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2207 playhead_cursor->set_position (pos);
2209 playhead_cursor->set_position (0);
2212 if ((prop = node.property ("mixer-width"))) {
2213 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2216 if ((prop = node.property ("zoom-focus"))) {
2217 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2220 if ((prop = node.property ("zoom"))) {
2221 reset_zoom (PBD::atof (prop->value()));
2223 reset_zoom (frames_per_unit);
2226 if ((prop = node.property ("snap-to"))) {
2227 set_snap_to ((SnapType) atoi (prop->value()));
2230 if ((prop = node.property ("snap-mode"))) {
2231 set_snap_mode ((SnapMode) atoi (prop->value()));
2234 if ((prop = node.property ("mouse-mode"))) {
2235 MouseMode m = str2mousemode(prop->value());
2236 set_mouse_mode (m, true);
2238 set_mouse_mode (MouseObject, true);
2241 if ((prop = node.property ("left-frame")) != 0) {
2243 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2247 reset_x_origin (pos);
2251 if ((prop = node.property ("y-origin")) != 0) {
2252 reset_y_origin (atof (prop->value ()));
2255 if ((prop = node.property ("internal-edit"))) {
2256 bool yn = string_is_affirmative (prop->value());
2257 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2259 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2260 tact->set_active (!yn);
2261 tact->set_active (yn);
2265 if ((prop = node.property ("join-object-range"))) {
2266 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2269 if ((prop = node.property ("edit-point"))) {
2270 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2273 if ((prop = node.property ("show-measures"))) {
2274 bool yn = string_is_affirmative (prop->value());
2275 _show_measures = yn;
2276 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2278 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2279 /* do it twice to force the change */
2280 tact->set_active (!yn);
2281 tact->set_active (yn);
2285 if ((prop = node.property ("follow-playhead"))) {
2286 bool yn = string_is_affirmative (prop->value());
2287 set_follow_playhead (yn);
2288 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2290 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2291 if (tact->get_active() != yn) {
2292 tact->set_active (yn);
2297 if ((prop = node.property ("stationary-playhead"))) {
2298 bool yn = string_is_affirmative (prop->value());
2299 set_stationary_playhead (yn);
2300 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2302 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2303 if (tact->get_active() != yn) {
2304 tact->set_active (yn);
2309 if ((prop = node.property ("region-list-sort-type"))) {
2310 RegionListSortType st;
2311 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2314 if ((prop = node.property ("xfades-visible"))) {
2315 bool yn = string_is_affirmative (prop->value());
2316 _xfade_visibility = !yn;
2317 // set_xfade_visibility (yn);
2320 if ((prop = node.property ("show-editor-mixer"))) {
2322 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2325 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2326 bool yn = string_is_affirmative (prop->value());
2328 /* do it twice to force the change */
2330 tact->set_active (!yn);
2331 tact->set_active (yn);
2334 if ((prop = node.property ("show-editor-list"))) {
2336 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2339 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2340 bool yn = string_is_affirmative (prop->value());
2342 /* do it twice to force the change */
2344 tact->set_active (!yn);
2345 tact->set_active (yn);
2348 if ((prop = node.property (X_("editor-list-page")))) {
2349 _the_notebook.set_current_page (atoi (prop->value ()));
2352 if ((prop = node.property (X_("show-marker-lines")))) {
2353 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2355 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2356 bool yn = string_is_affirmative (prop->value ());
2358 tact->set_active (!yn);
2359 tact->set_active (yn);
2362 XMLNodeList children = node.children ();
2363 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2364 selection->set_state (**i, Stateful::current_state_version);
2365 _regions->set_state (**i);
2368 if ((prop = node.property ("maximised"))) {
2369 bool yn = string_is_affirmative (prop->value());
2371 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2379 Editor::get_state ()
2381 XMLNode* node = new XMLNode ("Editor");
2384 id().print (buf, sizeof (buf));
2385 node->add_property ("id", buf);
2387 if (is_realized()) {
2388 Glib::RefPtr<Gdk::Window> win = get_window();
2390 int x, y, width, height;
2391 win->get_root_origin(x, y);
2392 win->get_size(width, height);
2394 XMLNode* geometry = new XMLNode ("geometry");
2396 snprintf(buf, sizeof(buf), "%d", width);
2397 geometry->add_property("x-size", string(buf));
2398 snprintf(buf, sizeof(buf), "%d", height);
2399 geometry->add_property("y-size", string(buf));
2400 snprintf(buf, sizeof(buf), "%d", x);
2401 geometry->add_property("x-pos", string(buf));
2402 snprintf(buf, sizeof(buf), "%d", y);
2403 geometry->add_property("y-pos", string(buf));
2404 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2405 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2406 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2407 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2408 geometry->add_property("edit-vertical-pane-pos", string(buf));
2410 node->add_child_nocopy (*geometry);
2413 maybe_add_mixer_strip_width (*node);
2415 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2416 node->add_property ("zoom-focus", buf);
2417 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2418 node->add_property ("zoom", buf);
2419 snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2420 node->add_property ("snap-to", buf);
2421 snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2422 node->add_property ("snap-mode", buf);
2424 node->add_property ("edit-point", enum_2_string (_edit_point));
2426 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2427 node->add_property ("playhead", buf);
2428 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2429 node->add_property ("left-frame", buf);
2430 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2431 node->add_property ("y-origin", buf);
2433 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2434 node->add_property ("maximised", _maximised ? "yes" : "no");
2435 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2436 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2437 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2438 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2439 node->add_property ("mouse-mode", enum2str(mouse_mode));
2440 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2441 node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2443 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2445 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2446 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2449 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2451 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2452 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2455 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2456 node->add_property (X_("editor-list-page"), buf);
2458 if (button_bindings) {
2459 XMLNode* bb = new XMLNode (X_("Buttons"));
2460 button_bindings->save (*bb);
2461 node->add_child_nocopy (*bb);
2464 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2466 node->add_child_nocopy (selection->get_state ());
2467 node->add_child_nocopy (_regions->get_state ());
2474 /** @param y y offset from the top of all trackviews.
2475 * @return pair: TimeAxisView that y is over, layer index.
2476 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2477 * in stacked or expanded region display mode, otherwise 0.
2479 std::pair<TimeAxisView *, double>
2480 Editor::trackview_by_y_position (double y)
2482 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2484 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2490 return std::make_pair ( (TimeAxisView *) 0, 0);
2493 /** Snap a position to the grid, if appropriate, taking into account current
2494 * grid settings and also the state of any snap modifier keys that may be pressed.
2495 * @param start Position to snap.
2496 * @param event Event to get current key modifier information from, or 0.
2499 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2501 if (!_session || !event) {
2505 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2506 if (_snap_mode == SnapOff) {
2507 snap_to_internal (start, direction, for_mark);
2510 if (_snap_mode != SnapOff) {
2511 snap_to_internal (start, direction, for_mark);
2517 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2519 if (!_session || _snap_mode == SnapOff) {
2523 snap_to_internal (start, direction, for_mark);
2527 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2529 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2530 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2532 switch (_snap_type) {
2533 case SnapToTimecodeFrame:
2534 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2535 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2537 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2541 case SnapToTimecodeSeconds:
2542 if (_session->config.get_timecode_offset_negative()) {
2543 start += _session->config.get_timecode_offset ();
2545 start -= _session->config.get_timecode_offset ();
2547 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2548 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2550 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2553 if (_session->config.get_timecode_offset_negative()) {
2554 start -= _session->config.get_timecode_offset ();
2556 start += _session->config.get_timecode_offset ();
2560 case SnapToTimecodeMinutes:
2561 if (_session->config.get_timecode_offset_negative()) {
2562 start += _session->config.get_timecode_offset ();
2564 start -= _session->config.get_timecode_offset ();
2566 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2567 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2569 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2571 if (_session->config.get_timecode_offset_negative()) {
2572 start -= _session->config.get_timecode_offset ();
2574 start += _session->config.get_timecode_offset ();
2578 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2584 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2586 const framepos_t one_second = _session->frame_rate();
2587 const framepos_t one_minute = _session->frame_rate() * 60;
2588 framepos_t presnap = start;
2592 switch (_snap_type) {
2593 case SnapToTimecodeFrame:
2594 case SnapToTimecodeSeconds:
2595 case SnapToTimecodeMinutes:
2596 return timecode_snap_to_internal (start, direction, for_mark);
2599 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2600 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2602 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2607 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2608 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2610 start = (framepos_t) floor ((double) start / one_second) * one_second;
2615 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2616 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2618 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2623 start = _session->tempo_map().round_to_bar (start, direction);
2627 start = _session->tempo_map().round_to_beat (start, direction);
2630 case SnapToBeatDiv32:
2631 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2633 case SnapToBeatDiv28:
2634 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2636 case SnapToBeatDiv24:
2637 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2639 case SnapToBeatDiv20:
2640 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2642 case SnapToBeatDiv16:
2643 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2645 case SnapToBeatDiv14:
2646 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2648 case SnapToBeatDiv12:
2649 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2651 case SnapToBeatDiv10:
2652 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2654 case SnapToBeatDiv8:
2655 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2657 case SnapToBeatDiv7:
2658 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2660 case SnapToBeatDiv6:
2661 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2663 case SnapToBeatDiv5:
2664 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2666 case SnapToBeatDiv4:
2667 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2669 case SnapToBeatDiv3:
2670 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2672 case SnapToBeatDiv2:
2673 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2681 _session->locations()->marks_either_side (start, before, after);
2683 if (before == max_framepos) {
2685 } else if (after == max_framepos) {
2687 } else if (before != max_framepos && after != max_framepos) {
2688 /* have before and after */
2689 if ((start - before) < (after - start)) {
2698 case SnapToRegionStart:
2699 case SnapToRegionEnd:
2700 case SnapToRegionSync:
2701 case SnapToRegionBoundary:
2702 if (!region_boundary_cache.empty()) {
2704 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2705 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2707 if (direction > 0) {
2708 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2710 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2713 if (next != region_boundary_cache.begin ()) {
2718 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2719 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2721 if (start > (p + n) / 2) {
2730 switch (_snap_mode) {
2736 if (presnap > start) {
2737 if (presnap > (start + unit_to_frame(snap_threshold))) {
2741 } else if (presnap < start) {
2742 if (presnap < (start - unit_to_frame(snap_threshold))) {
2748 /* handled at entry */
2756 Editor::setup_toolbar ()
2758 HBox* mode_box = manage(new HBox);
2759 mode_box->set_border_width (2);
2760 mode_box->set_spacing(4);
2762 /* table containing mode buttons */
2764 HBox* mouse_mode_button_box = manage (new HBox ());
2765 mouse_mode_button_box->set_spacing (2);
2767 if (Profile->get_sae()) {
2768 mouse_mode_button_box->pack_start (mouse_move_button);
2770 mouse_mode_button_box->pack_start (mouse_move_button);
2771 mouse_mode_button_box->pack_start (join_object_range_button);
2772 mouse_mode_button_box->pack_start (mouse_select_button);
2775 mouse_mode_button_box->pack_start (mouse_zoom_button);
2777 if (!Profile->get_sae()) {
2778 mouse_mode_button_box->pack_start (mouse_gain_button);
2781 mouse_mode_button_box->pack_start (mouse_timefx_button);
2782 mouse_mode_button_box->pack_start (mouse_audition_button);
2783 mouse_mode_button_box->pack_start (mouse_draw_button);
2784 mouse_mode_button_box->pack_start (internal_edit_button);
2786 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2787 if (!Profile->get_sae()) {
2788 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2790 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2792 edit_mode_selector.set_name ("EditModeSelector");
2793 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2794 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2796 mode_box->pack_start (edit_mode_selector, false, false);
2797 mode_box->pack_start (*mouse_mode_button_box, false, false);
2799 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2800 _mouse_mode_tearoff->set_name ("MouseModeBase");
2801 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2803 if (Profile->get_sae()) {
2804 _mouse_mode_tearoff->set_can_be_torn_off (false);
2807 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2808 &_mouse_mode_tearoff->tearoff_window()));
2809 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2810 &_mouse_mode_tearoff->tearoff_window(), 1));
2811 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2812 &_mouse_mode_tearoff->tearoff_window()));
2813 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2814 &_mouse_mode_tearoff->tearoff_window(), 1));
2818 _zoom_box.set_spacing (2);
2819 _zoom_box.set_border_width (2);
2823 zoom_in_button.set_name ("zoom button");
2824 zoom_in_button.set_image (::get_icon ("zoom_in"));
2825 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2826 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2827 zoom_in_button.set_related_action (act);
2829 zoom_out_button.set_name ("zoom button");
2830 zoom_out_button.set_image (::get_icon ("zoom_out"));
2831 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2832 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2833 zoom_out_button.set_related_action (act);
2835 zoom_out_full_button.set_name ("zoom button");
2836 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2837 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2838 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2839 zoom_out_full_button.set_related_action (act);
2841 zoom_focus_selector.set_name ("ZoomFocusSelector");
2842 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2843 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2845 _zoom_box.pack_start (zoom_out_button, false, false);
2846 _zoom_box.pack_start (zoom_in_button, false, false);
2847 _zoom_box.pack_start (zoom_out_full_button, false, false);
2849 _zoom_box.pack_start (zoom_focus_selector, false, false);
2851 /* Track zoom buttons */
2852 tav_expand_button.set_name ("TrackHeightButton");
2853 tav_expand_button.set_size_request (-1, 20);
2854 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2855 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2856 act->connect_proxy (tav_expand_button);
2858 tav_shrink_button.set_name ("TrackHeightButton");
2859 tav_shrink_button.set_size_request (-1, 20);
2860 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2861 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2862 act->connect_proxy (tav_shrink_button);
2864 _zoom_box.pack_start (tav_shrink_button);
2865 _zoom_box.pack_start (tav_expand_button);
2867 _zoom_tearoff = manage (new TearOff (_zoom_box));
2869 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2870 &_zoom_tearoff->tearoff_window()));
2871 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2872 &_zoom_tearoff->tearoff_window(), 0));
2873 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2874 &_zoom_tearoff->tearoff_window()));
2875 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2876 &_zoom_tearoff->tearoff_window(), 0));
2878 snap_box.set_spacing (1);
2879 snap_box.set_border_width (2);
2881 snap_type_selector.set_name ("SnapTypeSelector");
2882 set_popdown_strings (snap_type_selector, snap_type_strings);
2883 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2885 snap_mode_selector.set_name ("SnapModeSelector");
2886 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2887 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2889 edit_point_selector.set_name ("EditPointSelector");
2890 set_popdown_strings (edit_point_selector, edit_point_strings);
2891 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2893 snap_box.pack_start (snap_mode_selector, false, false);
2894 snap_box.pack_start (snap_type_selector, false, false);
2895 snap_box.pack_start (edit_point_selector, false, false);
2899 HBox *nudge_box = manage (new HBox);
2900 nudge_box->set_spacing (2);
2901 nudge_box->set_border_width (2);
2903 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2904 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2906 nudge_box->pack_start (nudge_backward_button, false, false);
2907 nudge_box->pack_start (nudge_forward_button, false, false);
2908 nudge_box->pack_start (*nudge_clock, false, false);
2911 /* Pack everything in... */
2913 HBox* hbox = manage (new HBox);
2914 hbox->set_spacing(10);
2916 _tools_tearoff = manage (new TearOff (*hbox));
2917 _tools_tearoff->set_name ("MouseModeBase");
2918 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2920 if (Profile->get_sae()) {
2921 _tools_tearoff->set_can_be_torn_off (false);
2924 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2925 &_tools_tearoff->tearoff_window()));
2926 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2927 &_tools_tearoff->tearoff_window(), 0));
2928 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2929 &_tools_tearoff->tearoff_window()));
2930 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2931 &_tools_tearoff->tearoff_window(), 0));
2933 toolbar_hbox.set_spacing (10);
2934 toolbar_hbox.set_border_width (1);
2936 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2937 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2938 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2940 hbox->pack_start (snap_box, false, false);
2941 if (!Profile->get_small_screen()) {
2942 hbox->pack_start (*nudge_box, false, false);
2944 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2946 hbox->pack_start (panic_box, false, false);
2950 toolbar_base.set_name ("ToolBarBase");
2951 toolbar_base.add (toolbar_hbox);
2953 _toolbar_viewport.add (toolbar_base);
2954 /* stick to the required height but allow width to vary if there's not enough room */
2955 _toolbar_viewport.set_size_request (1, -1);
2957 toolbar_frame.set_shadow_type (SHADOW_OUT);
2958 toolbar_frame.set_name ("BaseFrame");
2959 toolbar_frame.add (_toolbar_viewport);
2963 Editor::setup_tooltips ()
2965 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2966 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
2967 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
2968 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
2969 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
2970 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
2971 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2972 ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
2973 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
2974 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
2975 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
2976 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
2977 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
2978 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
2979 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
2980 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
2981 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
2982 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
2983 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
2984 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2985 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
2986 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
2990 Editor::convert_drop_to_paths (
2991 vector<string>& paths,
2992 const RefPtr<Gdk::DragContext>& /*context*/,
2995 const SelectionData& data,
2999 if (_session == 0) {
3003 vector<string> uris = data.get_uris();
3007 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3008 are actually URI lists. So do it by hand.
3011 if (data.get_target() != "text/plain") {
3015 /* Parse the "uri-list" format that Nautilus provides,
3016 where each pathname is delimited by \r\n.
3018 THERE MAY BE NO NULL TERMINATING CHAR!!!
3021 string txt = data.get_text();
3025 p = (const char *) malloc (txt.length() + 1);
3026 txt.copy ((char *) p, txt.length(), 0);
3027 ((char*)p)[txt.length()] = '\0';
3033 while (g_ascii_isspace (*p))
3037 while (*q && (*q != '\n') && (*q != '\r')) {
3044 while (q > p && g_ascii_isspace (*q))
3049 uris.push_back (string (p, q - p + 1));
3053 p = strchr (p, '\n');
3065 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3067 if ((*i).substr (0,7) == "file://") {
3070 PBD::url_decode (p);
3072 // scan forward past three slashes
3074 string::size_type slashcnt = 0;
3075 string::size_type n = 0;
3076 string::iterator x = p.begin();
3078 while (slashcnt < 3 && x != p.end()) {
3081 } else if (slashcnt == 3) {
3088 if (slashcnt != 3 || x == p.end()) {
3089 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3093 paths.push_back (p.substr (n - 1));
3101 Editor::new_tempo_section ()
3107 Editor::map_transport_state ()
3109 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3111 if (_session && _session->transport_stopped()) {
3112 have_pending_keyboard_selection = false;
3115 update_loop_range_view (true);
3120 Editor::State::State (PublicEditor const * e)
3122 selection = new Selection (e);
3125 Editor::State::~State ()
3131 Editor::begin_reversible_command (string name)
3134 _session->begin_reversible_command (name);
3139 Editor::begin_reversible_command (GQuark q)
3142 _session->begin_reversible_command (q);
3147 Editor::commit_reversible_command ()
3150 _session->commit_reversible_command ();
3155 Editor::history_changed ()
3159 if (undo_action && _session) {
3160 if (_session->undo_depth() == 0) {
3161 label = S_("Command|Undo");
3163 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3165 undo_action->property_label() = label;
3168 if (redo_action && _session) {
3169 if (_session->redo_depth() == 0) {
3172 label = string_compose(_("Redo (%1)"), _session->next_redo());
3174 redo_action->property_label() = label;
3179 Editor::duplicate_dialog (bool with_dialog)
3183 if (mouse_mode == MouseRange) {
3184 if (selection->time.length() == 0) {
3189 RegionSelection rs = get_regions_from_selection_and_entered ();
3191 if (mouse_mode != MouseRange && rs.empty()) {
3197 ArdourDialog win (_("Duplicate"));
3198 Label label (_("Number of duplications:"));
3199 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3200 SpinButton spinner (adjustment, 0.0, 1);
3203 win.get_vbox()->set_spacing (12);
3204 win.get_vbox()->pack_start (hbox);
3205 hbox.set_border_width (6);
3206 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3208 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3209 place, visually. so do this by hand.
3212 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3213 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3214 spinner.grab_focus();
3220 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3221 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3222 win.set_default_response (RESPONSE_ACCEPT);
3224 win.set_position (WIN_POS_MOUSE);
3226 spinner.grab_focus ();
3228 switch (win.run ()) {
3229 case RESPONSE_ACCEPT:
3235 times = adjustment.get_value();
3238 if (mouse_mode == MouseRange) {
3239 duplicate_selection (times);
3241 duplicate_some_regions (rs, times);
3246 Editor::set_edit_mode (EditMode m)
3248 Config->set_edit_mode (m);
3252 Editor::cycle_edit_mode ()
3254 switch (Config->get_edit_mode()) {
3256 if (Profile->get_sae()) {
3257 Config->set_edit_mode (Lock);
3259 Config->set_edit_mode (Splice);
3263 Config->set_edit_mode (Lock);
3266 Config->set_edit_mode (Slide);
3272 Editor::edit_mode_selection_done ()
3274 string s = edit_mode_selector.get_active_text ();
3277 Config->set_edit_mode (string_to_edit_mode (s));
3282 Editor::snap_type_selection_done ()
3284 string choice = snap_type_selector.get_active_text();
3285 SnapType snaptype = SnapToBeat;
3287 if (choice == _("Beats/2")) {
3288 snaptype = SnapToBeatDiv2;
3289 } else if (choice == _("Beats/3")) {
3290 snaptype = SnapToBeatDiv3;
3291 } else if (choice == _("Beats/4")) {
3292 snaptype = SnapToBeatDiv4;
3293 } else if (choice == _("Beats/5")) {
3294 snaptype = SnapToBeatDiv5;
3295 } else if (choice == _("Beats/6")) {
3296 snaptype = SnapToBeatDiv6;
3297 } else if (choice == _("Beats/7")) {
3298 snaptype = SnapToBeatDiv7;
3299 } else if (choice == _("Beats/8")) {
3300 snaptype = SnapToBeatDiv8;
3301 } else if (choice == _("Beats/10")) {
3302 snaptype = SnapToBeatDiv10;
3303 } else if (choice == _("Beats/12")) {
3304 snaptype = SnapToBeatDiv12;
3305 } else if (choice == _("Beats/14")) {
3306 snaptype = SnapToBeatDiv14;
3307 } else if (choice == _("Beats/16")) {
3308 snaptype = SnapToBeatDiv16;
3309 } else if (choice == _("Beats/20")) {
3310 snaptype = SnapToBeatDiv20;
3311 } else if (choice == _("Beats/24")) {
3312 snaptype = SnapToBeatDiv24;
3313 } else if (choice == _("Beats/28")) {
3314 snaptype = SnapToBeatDiv28;
3315 } else if (choice == _("Beats/32")) {
3316 snaptype = SnapToBeatDiv32;
3317 } else if (choice == _("Beats")) {
3318 snaptype = SnapToBeat;
3319 } else if (choice == _("Bars")) {
3320 snaptype = SnapToBar;
3321 } else if (choice == _("Marks")) {
3322 snaptype = SnapToMark;
3323 } else if (choice == _("Region starts")) {
3324 snaptype = SnapToRegionStart;
3325 } else if (choice == _("Region ends")) {
3326 snaptype = SnapToRegionEnd;
3327 } else if (choice == _("Region bounds")) {
3328 snaptype = SnapToRegionBoundary;
3329 } else if (choice == _("Region syncs")) {
3330 snaptype = SnapToRegionSync;
3331 } else if (choice == _("CD Frames")) {
3332 snaptype = SnapToCDFrame;
3333 } else if (choice == _("Timecode Frames")) {
3334 snaptype = SnapToTimecodeFrame;
3335 } else if (choice == _("Timecode Seconds")) {
3336 snaptype = SnapToTimecodeSeconds;
3337 } else if (choice == _("Timecode Minutes")) {
3338 snaptype = SnapToTimecodeMinutes;
3339 } else if (choice == _("Seconds")) {
3340 snaptype = SnapToSeconds;
3341 } else if (choice == _("Minutes")) {
3342 snaptype = SnapToMinutes;
3345 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3347 ract->set_active ();
3352 Editor::snap_mode_selection_done ()
3354 string choice = snap_mode_selector.get_active_text();
3355 SnapMode mode = SnapNormal;
3357 if (choice == _("No Grid")) {
3359 } else if (choice == _("Grid")) {
3361 } else if (choice == _("Magnetic")) {
3362 mode = SnapMagnetic;
3365 RefPtr<RadioAction> ract = snap_mode_action (mode);
3368 ract->set_active (true);
3373 Editor::cycle_edit_point (bool with_marker)
3375 switch (_edit_point) {
3377 set_edit_point_preference (EditAtPlayhead);
3379 case EditAtPlayhead:
3381 set_edit_point_preference (EditAtSelectedMarker);
3383 set_edit_point_preference (EditAtMouse);
3386 case EditAtSelectedMarker:
3387 set_edit_point_preference (EditAtMouse);
3393 Editor::edit_point_selection_done ()
3395 string choice = edit_point_selector.get_active_text();
3396 EditPoint ep = EditAtSelectedMarker;
3398 if (choice == _("Marker")) {
3399 set_edit_point_preference (EditAtSelectedMarker);
3400 } else if (choice == _("Playhead")) {
3401 set_edit_point_preference (EditAtPlayhead);
3403 set_edit_point_preference (EditAtMouse);
3406 RefPtr<RadioAction> ract = edit_point_action (ep);
3409 ract->set_active (true);
3414 Editor::zoom_focus_selection_done ()
3416 string choice = zoom_focus_selector.get_active_text();
3417 ZoomFocus focus_type = ZoomFocusLeft;
3419 if (choice == _("Left")) {
3420 focus_type = ZoomFocusLeft;
3421 } else if (choice == _("Right")) {
3422 focus_type = ZoomFocusRight;
3423 } else if (choice == _("Center")) {
3424 focus_type = ZoomFocusCenter;
3425 } else if (choice == _("Playhead")) {
3426 focus_type = ZoomFocusPlayhead;
3427 } else if (choice == _("Mouse")) {
3428 focus_type = ZoomFocusMouse;
3429 } else if (choice == _("Edit point")) {
3430 focus_type = ZoomFocusEdit;
3433 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3436 ract->set_active ();
3441 Editor::edit_controls_button_release (GdkEventButton* ev)
3443 if (Keyboard::is_context_menu_event (ev)) {
3444 ARDOUR_UI::instance()->add_route (this);
3445 } else if (ev->button == 1) {
3446 selection->clear_tracks ();
3453 Editor::mouse_select_button_release (GdkEventButton* ev)
3455 /* this handles just right-clicks */
3457 if (ev->button != 3) {
3465 Editor::set_zoom_focus (ZoomFocus f)
3467 string str = zoom_focus_strings[(int)f];
3469 if (str != zoom_focus_selector.get_active_text()) {
3470 zoom_focus_selector.set_active_text (str);
3473 if (zoom_focus != f) {
3480 Editor::ensure_float (Window& win)
3482 win.set_transient_for (*this);
3486 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3488 /* recover or initialize pane positions. do this here rather than earlier because
3489 we don't want the positions to change the child allocations, which they seem to do.
3495 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3504 XMLNode* geometry = find_named_node (*node, "geometry");
3506 if (which == static_cast<Paned*> (&edit_pane)) {
3508 if (done & Horizontal) {
3512 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3513 _notebook_shrunk = string_is_affirmative (prop->value ());
3516 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3517 /* initial allocation is 90% to canvas, 10% to notebook */
3518 pos = (int) floor (alloc.get_width() * 0.90f);
3519 snprintf (buf, sizeof(buf), "%d", pos);
3521 pos = atoi (prop->value());
3524 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3525 edit_pane.set_position (pos);
3528 done = (Pane) (done | Horizontal);
3530 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3532 if (done & Vertical) {
3536 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3537 /* initial allocation is 90% to canvas, 10% to summary */
3538 pos = (int) floor (alloc.get_height() * 0.90f);
3539 snprintf (buf, sizeof(buf), "%d", pos);
3542 pos = atoi (prop->value());
3545 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3546 editor_summary_pane.set_position (pos);
3549 done = (Pane) (done | Vertical);
3554 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3556 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3557 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3558 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3559 top_hbox.remove (toolbar_frame);
3564 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3566 if (toolbar_frame.get_parent() == 0) {
3567 top_hbox.pack_end (toolbar_frame);
3572 Editor::set_show_measures (bool yn)
3574 if (_show_measures != yn) {
3577 if ((_show_measures = yn) == true) {
3579 tempo_lines->show();
3587 Editor::toggle_follow_playhead ()
3589 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3591 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3592 set_follow_playhead (tact->get_active());
3596 /** @param yn true to follow playhead, otherwise false.
3597 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3600 Editor::set_follow_playhead (bool yn, bool catch_up)
3602 if (_follow_playhead != yn) {
3603 if ((_follow_playhead = yn) == true && catch_up) {
3605 reset_x_origin_to_follow_playhead ();
3612 Editor::toggle_stationary_playhead ()
3614 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3616 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3617 set_stationary_playhead (tact->get_active());
3622 Editor::set_stationary_playhead (bool yn)
3624 if (_stationary_playhead != yn) {
3625 if ((_stationary_playhead = yn) == true) {
3627 // FIXME need a 3.0 equivalent of this 2.X call
3628 // update_current_screen ();
3635 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3637 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3639 xfade->clear_changes ();
3640 xfade->set_active (!xfade->active());
3641 _session->begin_reversible_command (_("Change crossfade active state"));
3642 _session->add_command (new StatefulDiffCommand (xfade));
3643 _session->commit_reversible_command ();
3648 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3650 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3652 XMLNode& before = xfade->get_state ();
3653 xfade->set_follow_overlap (!xfade->following_overlap());
3654 XMLNode& after = xfade->get_state ();
3656 /* This can't be a StatefulDiffCommand as the fade shapes are not
3657 managed by the Stateful properties system.
3659 _session->begin_reversible_command (_("Change crossfade length"));
3660 _session->add_command (new MementoCommand<Crossfade> (*xfade.get(), &before, &after));
3661 _session->commit_reversible_command ();
3666 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3668 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3674 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3678 switch (cew.run ()) {
3679 case RESPONSE_ACCEPT:
3686 PropertyChange all_crossfade_properties;
3687 all_crossfade_properties.add (ARDOUR::Properties::active);
3688 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3689 xfade->PropertyChanged (all_crossfade_properties);
3693 Editor::playlist_selector () const
3695 return *_playlist_selector;
3699 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3703 switch (_snap_type) {
3708 case SnapToBeatDiv32:
3711 case SnapToBeatDiv28:
3714 case SnapToBeatDiv24:
3717 case SnapToBeatDiv20:
3720 case SnapToBeatDiv16:
3723 case SnapToBeatDiv14:
3726 case SnapToBeatDiv12:
3729 case SnapToBeatDiv10:
3732 case SnapToBeatDiv8:
3735 case SnapToBeatDiv7:
3738 case SnapToBeatDiv6:
3741 case SnapToBeatDiv5:
3744 case SnapToBeatDiv4:
3747 case SnapToBeatDiv3:
3750 case SnapToBeatDiv2:
3756 return _session->tempo_map().meter_at (position).divisions_per_bar();
3761 case SnapToTimecodeFrame:
3762 case SnapToTimecodeSeconds:
3763 case SnapToTimecodeMinutes:
3766 case SnapToRegionStart:
3767 case SnapToRegionEnd:
3768 case SnapToRegionSync:
3769 case SnapToRegionBoundary:
3779 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3783 ret = nudge_clock->current_duration (pos);
3784 next = ret + 1; /* XXXX fix me */
3790 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3792 ArdourDialog dialog (_("Playlist Deletion"));
3793 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3794 "If it is kept, its audio files will not be cleaned.\n"
3795 "If it is deleted, audio files used by it alone will be cleaned."),
3798 dialog.set_position (WIN_POS_CENTER);
3799 dialog.get_vbox()->pack_start (label);
3803 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3804 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3805 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3807 switch (dialog.run ()) {
3808 case RESPONSE_ACCEPT:
3809 /* delete the playlist */
3813 case RESPONSE_REJECT:
3814 /* keep the playlist */
3826 Editor::audio_region_selection_covers (framepos_t where)
3828 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3829 if ((*a)->region()->covers (where)) {
3838 Editor::prepare_for_cleanup ()
3840 cut_buffer->clear_regions ();
3841 cut_buffer->clear_playlists ();
3843 selection->clear_regions ();
3844 selection->clear_playlists ();
3846 _regions->suspend_redisplay ();
3850 Editor::finish_cleanup ()
3852 _regions->resume_redisplay ();
3856 Editor::transport_loop_location()
3859 return _session->locations()->auto_loop_location();
3866 Editor::transport_punch_location()
3869 return _session->locations()->auto_punch_location();
3876 Editor::control_layout_scroll (GdkEventScroll* ev)
3878 if (Keyboard::some_magic_widget_has_focus()) {
3882 switch (ev->direction) {
3884 scroll_tracks_up_line ();
3888 case GDK_SCROLL_DOWN:
3889 scroll_tracks_down_line ();
3893 /* no left/right handling yet */
3901 Editor::session_state_saved (string)
3904 _snapshots->redisplay ();
3908 Editor::maximise_editing_space ()
3916 if (!Config->get_keep_tearoffs()) {
3917 /* these calls will leave each tearoff visible *if* it is torn off,
3918 but invisible otherwise.
3920 _mouse_mode_tearoff->set_visible (false);
3921 _tools_tearoff->set_visible (false);
3922 _zoom_tearoff->set_visible (false);
3929 Editor::restore_editing_space ()
3937 if (!Config->get_keep_tearoffs()) {
3938 _mouse_mode_tearoff->set_visible (true);
3939 _tools_tearoff->set_visible (true);
3940 _zoom_tearoff->set_visible (true);
3947 * Make new playlists for a given track and also any others that belong
3948 * to the same active route group with the `edit' property.
3953 Editor::new_playlists (TimeAxisView* v)
3955 begin_reversible_command (_("new playlists"));
3956 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3957 _session->playlists->get (playlists);
3958 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3959 commit_reversible_command ();
3963 * Use a copy of the current playlist for a given track and also any others that belong
3964 * to the same active route group with the `edit' property.
3969 Editor::copy_playlists (TimeAxisView* v)
3971 begin_reversible_command (_("copy playlists"));
3972 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3973 _session->playlists->get (playlists);
3974 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3975 commit_reversible_command ();
3978 /** Clear the current playlist for a given track and also any others that belong
3979 * to the same active route group with the `edit' property.
3984 Editor::clear_playlists (TimeAxisView* v)
3986 begin_reversible_command (_("clear playlists"));
3987 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3988 _session->playlists->get (playlists);
3989 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
3990 commit_reversible_command ();
3994 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3996 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4000 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4002 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4006 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4008 atv.clear_playlist ();
4012 Editor::on_key_press_event (GdkEventKey* ev)
4014 return key_press_focus_accelerator_handler (*this, ev);
4018 Editor::on_key_release_event (GdkEventKey* ev)
4020 return Gtk::Window::on_key_release_event (ev);
4021 // return key_press_focus_accelerator_handler (*this, ev);
4024 /** Queue up a change to the viewport x origin.
4025 * @param frame New x origin.
4028 Editor::reset_x_origin (framepos_t frame)
4030 queue_visual_change (frame);
4034 Editor::reset_y_origin (double y)
4036 queue_visual_change_y (y);
4040 Editor::reset_zoom (double fpu)
4042 queue_visual_change (fpu);
4046 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4048 reset_x_origin (frame);
4051 if (!no_save_visual) {
4052 undo_visual_stack.push_back (current_visual_state(false));
4056 Editor::VisualState::VisualState ()
4057 : gui_state (new GUIObjectState)
4061 Editor::VisualState::~VisualState ()
4066 Editor::VisualState*
4067 Editor::current_visual_state (bool with_tracks)
4069 VisualState* vs = new VisualState;
4070 vs->y_position = vertical_adjustment.get_value();
4071 vs->frames_per_unit = frames_per_unit;
4072 vs->leftmost_frame = leftmost_frame;
4073 vs->zoom_focus = zoom_focus;
4076 *(vs->gui_state) = *ARDOUR_UI::instance()->gui_object_state;
4083 Editor::undo_visual_state ()
4085 if (undo_visual_stack.empty()) {
4089 redo_visual_stack.push_back (current_visual_state());
4091 VisualState* vs = undo_visual_stack.back();
4092 undo_visual_stack.pop_back();
4093 use_visual_state (*vs);
4097 Editor::redo_visual_state ()
4099 if (redo_visual_stack.empty()) {
4103 undo_visual_stack.push_back (current_visual_state());
4105 VisualState* vs = redo_visual_stack.back();
4106 redo_visual_stack.pop_back();
4107 use_visual_state (*vs);
4111 Editor::swap_visual_state ()
4113 if (undo_visual_stack.empty()) {
4114 redo_visual_state ();
4116 undo_visual_state ();
4121 Editor::use_visual_state (VisualState& vs)
4123 no_save_visual = true;
4125 _routes->suspend_redisplay ();
4127 vertical_adjustment.set_value (vs.y_position);
4129 set_zoom_focus (vs.zoom_focus);
4130 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4132 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4134 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4135 (*i)->reset_visual_state ();
4138 _routes->update_visibility ();
4139 _routes->resume_redisplay ();
4141 no_save_visual = false;
4145 Editor::set_frames_per_unit (double fpu)
4147 /* this is the core function that controls the zoom level of the canvas. it is called
4148 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4151 if (fpu == frames_per_unit) {
4160 /* don't allow zooms that fit more than the maximum number
4161 of frames into an 800 pixel wide space.
4164 if (max_framepos / fpu < 800.0) {
4169 tempo_lines->tempo_map_changed();
4171 frames_per_unit = fpu;
4176 Editor::post_zoom ()
4178 // convert fpu to frame count
4180 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4182 if (frames_per_unit != zoom_range_clock->current_duration()) {
4183 zoom_range_clock->set (frames);
4186 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4187 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4188 (*i)->reshow_selection (selection->time);
4192 ZoomChanged (); /* EMIT_SIGNAL */
4194 //reset_scrolling_region ();
4196 if (playhead_cursor) {
4197 playhead_cursor->set_position (playhead_cursor->current_frame);
4200 refresh_location_display();
4201 _summary->set_overlays_dirty ();
4203 update_marker_labels ();
4209 Editor::queue_visual_change (framepos_t where)
4211 pending_visual_change.add (VisualChange::TimeOrigin);
4212 pending_visual_change.time_origin = where;
4213 ensure_visual_change_idle_handler ();
4217 Editor::queue_visual_change (double fpu)
4219 pending_visual_change.add (VisualChange::ZoomLevel);
4220 pending_visual_change.frames_per_unit = fpu;
4222 ensure_visual_change_idle_handler ();
4226 Editor::queue_visual_change_y (double y)
4228 pending_visual_change.add (VisualChange::YOrigin);
4229 pending_visual_change.y_origin = y;
4231 ensure_visual_change_idle_handler ();
4235 Editor::ensure_visual_change_idle_handler ()
4237 if (pending_visual_change.idle_handler_id < 0) {
4238 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4243 Editor::_idle_visual_changer (void* arg)
4245 return static_cast<Editor*>(arg)->idle_visual_changer ();
4249 Editor::idle_visual_changer ()
4251 VisualChange::Type p = pending_visual_change.pending;
4252 pending_visual_change.pending = (VisualChange::Type) 0;
4254 double const last_time_origin = horizontal_position ();
4256 if (p & VisualChange::TimeOrigin) {
4257 /* This is a bit of a hack, but set_frames_per_unit
4258 below will (if called) end up with the
4259 CrossfadeViews looking at Editor::leftmost_frame,
4260 and if we're changing origin and zoom in the same
4261 operation it will be the wrong value unless we
4265 leftmost_frame = pending_visual_change.time_origin;
4266 assert (leftmost_frame >= 0);
4269 if (p & VisualChange::ZoomLevel) {
4270 set_frames_per_unit (pending_visual_change.frames_per_unit);
4272 compute_fixed_ruler_scale ();
4273 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4274 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4275 update_tempo_based_rulers ();
4277 if (p & VisualChange::TimeOrigin) {
4278 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4280 if (p & VisualChange::YOrigin) {
4281 vertical_adjustment.set_value (pending_visual_change.y_origin);
4284 if (last_time_origin == horizontal_position ()) {
4285 /* changed signal not emitted */
4286 update_fixed_rulers ();
4287 redisplay_tempo (true);
4290 _summary->set_overlays_dirty ();
4292 pending_visual_change.idle_handler_id = -1;
4293 return 0; /* this is always a one-shot call */
4296 struct EditorOrderTimeAxisSorter {
4297 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4298 return a->order () < b->order ();
4303 Editor::sort_track_selection (TrackViewList& sel)
4305 EditorOrderTimeAxisSorter cmp;
4310 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4313 framepos_t where = 0;
4314 EditPoint ep = _edit_point;
4316 if (from_context_menu && (ep == EditAtMouse)) {
4317 return event_frame (&context_click_event, 0, 0);
4320 if (entered_marker) {
4321 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4322 return entered_marker->position();
4325 if (ignore_playhead && ep == EditAtPlayhead) {
4326 ep = EditAtSelectedMarker;
4330 case EditAtPlayhead:
4331 where = _session->audible_frame();
4332 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4335 case EditAtSelectedMarker:
4336 if (!selection->markers.empty()) {
4338 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4341 where = loc->start();
4345 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4353 if (!mouse_frame (where, ignored)) {
4354 /* XXX not right but what can we do ? */
4358 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4366 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4368 if (!_session) return;
4370 begin_reversible_command (cmd);
4374 if ((tll = transport_loop_location()) == 0) {
4375 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4376 XMLNode &before = _session->locations()->get_state();
4377 _session->locations()->add (loc, true);
4378 _session->set_auto_loop_location (loc);
4379 XMLNode &after = _session->locations()->get_state();
4380 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4382 XMLNode &before = tll->get_state();
4383 tll->set_hidden (false, this);
4384 tll->set (start, end);
4385 XMLNode &after = tll->get_state();
4386 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4389 commit_reversible_command ();
4393 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4395 if (!_session) return;
4397 begin_reversible_command (cmd);
4401 if ((tpl = transport_punch_location()) == 0) {
4402 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4403 XMLNode &before = _session->locations()->get_state();
4404 _session->locations()->add (loc, true);
4405 _session->set_auto_loop_location (loc);
4406 XMLNode &after = _session->locations()->get_state();
4407 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4410 XMLNode &before = tpl->get_state();
4411 tpl->set_hidden (false, this);
4412 tpl->set (start, end);
4413 XMLNode &after = tpl->get_state();
4414 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4417 commit_reversible_command ();
4420 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4421 * @param rs List to which found regions are added.
4422 * @param where Time to look at.
4423 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4426 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4428 const TrackViewList* tracks;
4431 tracks = &track_views;
4436 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4438 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4441 boost::shared_ptr<Track> tr;
4442 boost::shared_ptr<Playlist> pl;
4444 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4446 boost::shared_ptr<RegionList> regions = pl->regions_at (
4447 (framepos_t) floor ( (double) where * tr->speed()));
4449 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4450 RegionView* rv = rtv->view()->find_view (*i);
4461 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4463 const TrackViewList* tracks;
4466 tracks = &track_views;
4471 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4472 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4474 boost::shared_ptr<Track> tr;
4475 boost::shared_ptr<Playlist> pl;
4477 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4479 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4480 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4482 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4484 RegionView* rv = rtv->view()->find_view (*i);
4495 /** Start with regions that are selected. Then add equivalent regions
4496 * on tracks in the same active edit-enabled route group as any of
4497 * the regions that we started with.
4501 Editor::get_regions_from_selection ()
4503 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4506 /** Get regions using the following method:
4508 * Make an initial region list using the selected regions, unless
4509 * the edit point is `mouse' and the mouse is over an unselected
4510 * region. In this case, start with just that region.
4512 * Then, make an initial track list of the tracks that these
4513 * regions are on, and if the edit point is not `mouse', add the
4516 * Look at this track list and add any other tracks that are on the
4517 * same active edit-enabled route group as one of the initial tracks.
4519 * Finally take the initial region list and add any regions that are
4520 * under the edit point on one of the tracks on the track list to get
4521 * the returned region list.
4523 * The rationale here is that the mouse edit point is special in that
4524 * its position describes both a time and a track; the other edit
4525 * modes only describe a time. Hence if the edit point is `mouse' we
4526 * ignore selected tracks, as we assume the user means something by
4527 * pointing at a particular track. Also in this case we take note of
4528 * the region directly under the edit point, as there is always just one
4529 * (rather than possibly several with non-mouse edit points).
4533 Editor::get_regions_from_selection_and_edit_point ()
4535 RegionSelection regions;
4537 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4538 regions.add (entered_regionview);
4540 regions = selection->regions;
4543 TrackViewList tracks;
4545 if (_edit_point != EditAtMouse) {
4546 tracks = selection->tracks;
4549 /* Add any other tracks that have regions that are in the same
4550 edit-activated route group as one of our regions.
4552 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4554 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4556 if (g && g->is_active() && g->is_edit()) {
4557 tracks.add (axis_views_from_routes (g->route_list()));
4561 if (!tracks.empty()) {
4562 /* now find regions that are at the edit position on those tracks */
4563 framepos_t const where = get_preferred_edit_position ();
4564 get_regions_at (regions, where, tracks);
4570 /** Start with regions that are selected, or the entered regionview if none are selected.
4571 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4572 * of the regions that we started with.
4576 Editor::get_regions_from_selection_and_entered ()
4578 RegionSelection regions = selection->regions;
4580 if (regions.empty() && entered_regionview) {
4581 regions.add (entered_regionview);
4584 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4588 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4590 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4592 RouteTimeAxisView* tatv;
4594 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4596 boost::shared_ptr<Playlist> pl;
4597 vector<boost::shared_ptr<Region> > results;
4599 boost::shared_ptr<Track> tr;
4601 if ((tr = tatv->track()) == 0) {
4606 if ((pl = (tr->playlist())) != 0) {
4607 pl->get_region_list_equivalent_regions (region, results);
4610 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4611 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4612 regions.push_back (marv);
4621 Editor::show_rhythm_ferret ()
4623 if (rhythm_ferret == 0) {
4624 rhythm_ferret = new RhythmFerret(*this);
4627 rhythm_ferret->set_session (_session);
4628 rhythm_ferret->show ();
4629 rhythm_ferret->present ();
4633 Editor::first_idle ()
4635 MessageDialog* dialog = 0;
4637 if (track_views.size() > 1) {
4638 dialog = new MessageDialog (
4640 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4644 ARDOUR_UI::instance()->flush_pending ();
4647 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4651 // first idle adds route children (automation tracks), so we need to redisplay here
4652 _routes->redisplay ();
4659 Editor::_idle_resize (gpointer arg)
4661 return ((Editor*)arg)->idle_resize ();
4665 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4667 if (resize_idle_id < 0) {
4668 resize_idle_id = g_idle_add (_idle_resize, this);
4669 _pending_resize_amount = 0;
4672 /* make a note of the smallest resulting height, so that we can clamp the
4673 lower limit at TimeAxisView::hSmall */
4675 int32_t min_resulting = INT32_MAX;
4677 _pending_resize_amount += h;
4678 _pending_resize_view = view;
4680 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4682 if (selection->tracks.contains (_pending_resize_view)) {
4683 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4684 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4688 if (min_resulting < 0) {
4693 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4694 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4698 /** Handle pending resizing of tracks */
4700 Editor::idle_resize ()
4702 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4704 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4705 selection->tracks.contains (_pending_resize_view)) {
4707 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4708 if (*i != _pending_resize_view) {
4709 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4714 _pending_resize_amount = 0;
4716 _group_tabs->set_dirty ();
4717 resize_idle_id = -1;
4725 ENSURE_GUI_THREAD (*this, &Editor::located);
4727 playhead_cursor->set_position (_session->audible_frame ());
4728 if (_follow_playhead && !_pending_initial_locate) {
4729 reset_x_origin_to_follow_playhead ();
4732 _pending_locate_request = false;
4733 _pending_initial_locate = false;
4737 Editor::region_view_added (RegionView *)
4739 _summary->set_dirty ();
4743 Editor::region_view_removed ()
4745 _summary->set_dirty ();
4749 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4751 TrackViewList::const_iterator j = track_views.begin ();
4752 while (j != track_views.end()) {
4753 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4754 if (rtv && rtv->route() == r) {
4765 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4769 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4770 TimeAxisView* tv = axis_view_from_route (*i);
4781 Editor::handle_new_route (RouteList& routes)
4783 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4785 RouteTimeAxisView *rtv;
4786 list<RouteTimeAxisView*> new_views;
4788 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4789 boost::shared_ptr<Route> route = (*x);
4791 if (route->is_hidden() || route->is_monitor()) {
4795 DataType dt = route->input()->default_type();
4797 if (dt == ARDOUR::DataType::AUDIO) {
4798 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4799 rtv->set_route (route);
4800 } else if (dt == ARDOUR::DataType::MIDI) {
4801 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4802 rtv->set_route (route);
4804 throw unknown_type();
4807 new_views.push_back (rtv);
4808 track_views.push_back (rtv);
4810 rtv->effective_gain_display ();
4812 if (internal_editing()) {
4813 rtv->enter_internal_edit_mode ();
4815 rtv->leave_internal_edit_mode ();
4818 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4819 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4822 _routes->routes_added (new_views);
4823 _summary->routes_added (new_views);
4825 if (show_editor_mixer_when_tracks_arrive) {
4826 show_editor_mixer (true);
4829 editor_list_button.set_sensitive (true);
4833 Editor::timeaxisview_deleted (TimeAxisView *tv)
4835 if (_session && _session->deletion_in_progress()) {
4836 /* the situation is under control */
4840 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4842 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4844 _routes->route_removed (tv);
4846 if (tv == entered_track) {
4850 TimeAxisView::Children c = tv->get_child_list ();
4851 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4852 if (entered_track == i->get()) {
4857 /* remove it from the list of track views */
4859 TrackViewList::iterator i;
4861 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4862 i = track_views.erase (i);
4865 /* update whatever the current mixer strip is displaying, if revelant */
4867 boost::shared_ptr<Route> route;
4870 route = rtav->route ();
4873 if (current_mixer_strip && current_mixer_strip->route() == route) {
4875 TimeAxisView* next_tv;
4877 if (track_views.empty()) {
4879 } else if (i == track_views.end()) {
4880 next_tv = track_views.front();
4887 set_selected_mixer_strip (*next_tv);
4889 /* make the editor mixer strip go away setting the
4890 * button to inactive (which also unticks the menu option)
4893 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4899 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4901 if (apply_to_selection) {
4902 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4904 TrackSelection::iterator j = i;
4907 hide_track_in_display (*i, false);
4912 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4914 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4915 // this will hide the mixer strip
4916 set_selected_mixer_strip (*tv);
4919 _routes->hide_track_in_display (*tv);
4924 Editor::sync_track_view_list_and_routes ()
4926 track_views = TrackViewList (_routes->views ());
4928 _summary->set_dirty ();
4929 _group_tabs->set_dirty ();
4931 return false; // do not call again (until needed)
4935 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4937 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4942 /** Find a RouteTimeAxisView by the ID of its route */
4944 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4946 RouteTimeAxisView* v;
4948 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4949 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4950 if(v->route()->id() == id) {
4960 Editor::fit_route_group (RouteGroup *g)
4962 TrackViewList ts = axis_views_from_routes (g->route_list ());
4967 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4969 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4972 _session->cancel_audition ();
4976 if (_session->is_auditioning()) {
4977 _session->cancel_audition ();
4978 if (r == last_audition_region) {
4983 _session->audition_region (r);
4984 last_audition_region = r;
4989 Editor::hide_a_region (boost::shared_ptr<Region> r)
4991 r->set_hidden (true);
4995 Editor::show_a_region (boost::shared_ptr<Region> r)
4997 r->set_hidden (false);
5001 Editor::audition_region_from_region_list ()
5003 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5007 Editor::hide_region_from_region_list ()
5009 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5013 Editor::show_region_in_region_list ()
5015 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5019 Editor::step_edit_status_change (bool yn)
5022 start_step_editing ();
5024 stop_step_editing ();
5029 Editor::start_step_editing ()
5031 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5035 Editor::stop_step_editing ()
5037 step_edit_connection.disconnect ();
5041 Editor::check_step_edit ()
5043 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5044 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5046 mtv->check_step_edit ();
5050 return true; // do it again, till we stop
5054 Editor::scroll_press (Direction dir)
5056 ++_scroll_callbacks;
5058 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5059 /* delay the first auto-repeat */
5065 scroll_backward (1);
5073 scroll_tracks_up_line ();
5077 scroll_tracks_down_line ();
5081 /* do hacky auto-repeat */
5082 if (!_scroll_connection.connected ()) {
5084 _scroll_connection = Glib::signal_timeout().connect (
5085 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5088 _scroll_callbacks = 0;
5095 Editor::scroll_release ()
5097 _scroll_connection.disconnect ();
5100 /** Queue a change for the Editor viewport x origin to follow the playhead */
5102 Editor::reset_x_origin_to_follow_playhead ()
5104 framepos_t const frame = playhead_cursor->current_frame;
5106 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5108 if (_session->transport_speed() < 0) {
5110 if (frame > (current_page_frames() / 2)) {
5111 center_screen (frame-(current_page_frames()/2));
5113 center_screen (current_page_frames()/2);
5120 if (frame < leftmost_frame) {
5122 if (_session->transport_rolling()) {
5123 /* rolling; end up with the playhead at the right of the page */
5124 l = frame - current_page_frames ();
5126 /* not rolling: end up with the playhead 1/4 of the way along the page */
5127 l = frame - current_page_frames() / 4;
5131 if (_session->transport_rolling()) {
5132 /* rolling: end up with the playhead on the left of the page */
5135 /* not rolling: end up with the playhead 3/4 of the way along the page */
5136 l = frame - 3 * current_page_frames() / 4;
5144 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5150 Editor::super_rapid_screen_update ()
5152 if (!_session || !_session->engine().running()) {
5156 /* METERING / MIXER STRIPS */
5158 /* update track meters, if required */
5159 if (is_mapped() && meters_running) {
5160 RouteTimeAxisView* rtv;
5161 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5162 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5163 rtv->fast_update ();
5168 /* and any current mixer strip */
5169 if (current_mixer_strip) {
5170 current_mixer_strip->fast_update ();
5173 /* PLAYHEAD AND VIEWPORT */
5175 framepos_t const frame = _session->audible_frame();
5177 /* There are a few reasons why we might not update the playhead / viewport stuff:
5179 * 1. we don't update things when there's a pending locate request, otherwise
5180 * when the editor requests a locate there is a chance that this method
5181 * will move the playhead before the locate request is processed, causing
5183 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5184 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5187 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5189 last_update_frame = frame;
5191 if (!_dragging_playhead) {
5192 playhead_cursor->set_position (frame);
5195 if (!_stationary_playhead) {
5197 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5198 reset_x_origin_to_follow_playhead ();
5203 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5207 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5208 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5209 if (target <= 0.0) {
5212 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5213 target = (target * 0.15) + (current * 0.85);
5219 set_horizontal_position (current);
5228 Editor::session_going_away ()
5230 _have_idled = false;
5232 _session_connections.drop_connections ();
5234 super_rapid_screen_update_connection.disconnect ();
5236 selection->clear ();
5237 cut_buffer->clear ();
5239 clicked_regionview = 0;
5240 clicked_axisview = 0;
5241 clicked_routeview = 0;
5242 clicked_crossfadeview = 0;
5243 entered_regionview = 0;
5245 last_update_frame = 0;
5248 playhead_cursor->canvas_item.hide ();
5250 /* rip everything out of the list displays */
5254 _route_groups->clear ();
5256 /* do this first so that deleting a track doesn't reset cms to null
5257 and thus cause a leak.
5260 if (current_mixer_strip) {
5261 if (current_mixer_strip->get_parent() != 0) {
5262 global_hpacker.remove (*current_mixer_strip);
5264 delete current_mixer_strip;
5265 current_mixer_strip = 0;
5268 /* delete all trackviews */
5270 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5273 track_views.clear ();
5275 zoom_range_clock->set_session (0);
5276 nudge_clock->set_session (0);
5278 editor_list_button.set_active(false);
5279 editor_list_button.set_sensitive(false);
5281 /* clear tempo/meter rulers */
5282 remove_metric_marks ();
5284 clear_marker_display ();
5286 current_bbt_points_begin = current_bbt_points_end;
5288 /* get rid of any existing editor mixer strip */
5290 WindowTitle title(Glib::get_application_name());
5291 title += _("Editor");
5293 set_title (title.get_string());
5295 SessionHandlePtr::session_going_away ();
5300 Editor::show_editor_list (bool yn)
5303 _the_notebook.show ();
5305 _the_notebook.hide ();
5310 Editor::change_region_layering_order (bool from_context_menu)
5312 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5314 if (!clicked_routeview) {
5315 if (layering_order_editor) {
5316 layering_order_editor->hide ();
5321 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5327 boost::shared_ptr<Playlist> pl = track->playlist();
5333 if (layering_order_editor == 0) {
5334 layering_order_editor = new RegionLayeringOrderEditor (*this);
5335 layering_order_editor->set_position (WIN_POS_MOUSE);
5338 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5339 layering_order_editor->maybe_present ();
5343 Editor::update_region_layering_order_editor ()
5345 if (layering_order_editor && layering_order_editor->is_visible ()) {
5346 change_region_layering_order (true);
5351 Editor::setup_fade_images ()
5353 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5354 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5355 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5356 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5357 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5359 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5360 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5361 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5362 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5363 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5367 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5369 Editor::action_menu_item (std::string const & name)
5371 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5374 return *manage (a->create_menu_item ());
5378 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5380 EventBox* b = manage (new EventBox);
5381 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5382 Label* l = manage (new Label (name));
5386 _the_notebook.append_page (widget, *b);
5390 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5392 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5393 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5396 if (ev->type == GDK_2BUTTON_PRESS) {
5398 /* double-click on a notebook tab shrinks or expands the notebook */
5400 if (_notebook_shrunk) {
5401 if (pre_notebook_shrink_pane_width) {
5402 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5404 _notebook_shrunk = false;
5406 pre_notebook_shrink_pane_width = edit_pane.get_position();
5408 /* this expands the LHS of the edit pane to cover the notebook
5409 PAGE but leaves the tabs visible.
5411 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5412 _notebook_shrunk = true;
5420 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5422 using namespace Menu_Helpers;
5424 MenuList& items = _control_point_context_menu.items ();
5427 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5428 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5429 if (!can_remove_control_point (item)) {
5430 items.back().set_sensitive (false);
5433 _control_point_context_menu.popup (event->button.button, event->button.time);