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"
47 #include <glibmm/miscutils.h>
48 #include <gtkmm/image.h>
49 #include <gdkmm/color.h>
50 #include <gdkmm/bitmap.h>
52 #include <gtkmm2ext/grouped_buttons.h>
53 #include <gtkmm2ext/gtk_ui.h>
54 #include <gtkmm2ext/tearoff.h>
55 #include <gtkmm2ext/utils.h>
56 #include <gtkmm2ext/window_title.h>
57 #include <gtkmm2ext/choice.h>
58 #include <gtkmm2ext/cell_renderer_pixbuf_toggle.h>
60 #include "ardour/audio_diskstream.h"
61 #include "ardour/audio_track.h"
62 #include "ardour/audioplaylist.h"
63 #include "ardour/audioregion.h"
64 #include "ardour/location.h"
65 #include "ardour/midi_region.h"
66 #include "ardour/plugin_manager.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_directory.h"
70 #include "ardour/session_route.h"
71 #include "ardour/session_state_utils.h"
72 #include "ardour/tempo.h"
73 #include "ardour/utils.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/audioengine.h"
77 #include "control_protocol/control_protocol.h"
82 #include "playlist_selector.h"
83 #include "audio_region_view.h"
84 #include "rgb_macros.h"
85 #include "selection.h"
86 #include "audio_streamview.h"
87 #include "time_axis_view.h"
88 #include "audio_time_axis.h"
90 #include "crossfade_view.h"
91 #include "canvas-noevent-text.h"
93 #include "public_editor.h"
94 #include "crossfade_edit.h"
95 #include "canvas_impl.h"
98 #include "gui_thread.h"
99 #include "simpleline.h"
100 #include "rhythm_ferret.h"
102 #include "tempo_lines.h"
103 #include "analysis_window.h"
104 #include "bundle_manager.h"
105 #include "global_port_matrix.h"
106 #include "editor_drag.h"
107 #include "editor_group_tabs.h"
108 #include "automation_time_axis.h"
109 #include "editor_routes.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "editor_route_groups.h"
113 #include "editor_regions.h"
114 #include "editor_locations.h"
115 #include "editor_snapshots.h"
116 #include "editor_summary.h"
117 #include "region_layering_order_editor.h"
118 #include "mouse_cursors.h"
119 #include "editor_cursors.h"
124 #include "imageframe_socket_handler.h"
128 using namespace ARDOUR;
131 using namespace Glib;
132 using namespace Gtkmm2ext;
133 using namespace Editing;
135 using PBD::internationalize;
137 using Gtkmm2ext::Keyboard;
139 const double Editor::timebar_height = 15.0;
141 static const gchar *_snap_type_strings[] = {
143 N_("Timecode Frames"),
144 N_("Timecode Seconds"),
145 N_("Timecode Minutes"),
173 static const gchar *_snap_mode_strings[] = {
180 static const gchar *_edit_point_strings[] = {
187 static const gchar *_zoom_focus_strings[] = {
197 #ifdef USE_RUBBERBAND
198 static const gchar *_rb_opt_strings[] = {
201 N_("Balanced multitimbral mixture"),
202 N_("Unpitched percussion with stable notes"),
203 N_("Crisp monophonic instrumental"),
204 N_("Unpitched solo percussion"),
205 N_("Resample without preserving pitch"),
211 show_me_the_size (Requisition* r, const char* what)
213 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
218 pane_size_watcher (Paned* pane)
220 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
221 it is no longer accessible. so stop that. this doesn't happen on X11,
222 just the quartz backend.
227 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
229 gint pos = pane->get_position ();
231 if (pos > max_width_of_lhs) {
232 pane->set_position (max_width_of_lhs);
238 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
240 /* time display buttons */
241 , minsec_label (_("Mins:Secs"))
242 , bbt_label (_("Bars:Beats"))
243 , timecode_label (_("Timecode"))
244 , samples_label (_("Samples"))
245 , tempo_label (_("Tempo"))
246 , meter_label (_("Meter"))
247 , mark_label (_("Location Markers"))
248 , range_mark_label (_("Range Markers"))
249 , transport_mark_label (_("Loop/Punch Ranges"))
250 , cd_mark_label (_("CD Markers"))
251 , edit_packer (4, 4, true)
253 /* the values here don't matter: layout widgets
254 reset them as needed.
257 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
259 /* tool bar related */
261 , zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, false, true)
263 , toolbar_selection_clock_table (2,3)
265 , automation_mode_button (_("mode"))
266 , global_automation_button (_("automation"))
268 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
269 , midi_panic_button (_("Panic"))
272 , image_socket_listener(0)
277 , nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, false, true)
278 , meters_running(false)
279 , _pending_locate_request (false)
280 , _pending_initial_locate (false)
281 , _last_cut_copy_source_track (0)
283 , _region_selection_change_updates_region_list (true)
287 /* we are a singleton */
289 PublicEditor::_instance = this;
293 selection = new Selection (this);
294 cut_buffer = new Selection (this);
296 clicked_regionview = 0;
297 clicked_axisview = 0;
298 clicked_routeview = 0;
299 clicked_crossfadeview = 0;
300 clicked_control_point = 0;
301 last_update_frame = 0;
302 pre_press_cursor = 0;
303 _drags = new DragManager (this);
304 current_mixer_strip = 0;
305 current_bbt_points = 0;
308 snap_type_strings = I18N (_snap_type_strings);
309 snap_mode_strings = I18N (_snap_mode_strings);
310 zoom_focus_strings = I18N (_zoom_focus_strings);
311 edit_point_strings = I18N (_edit_point_strings);
312 #ifdef USE_RUBBERBAND
313 rb_opt_strings = I18N (_rb_opt_strings);
317 snap_threshold = 5.0;
318 bbt_beat_subdivision = 4;
321 last_autoscroll_x = 0;
322 last_autoscroll_y = 0;
323 autoscroll_active = false;
324 autoscroll_timeout_tag = -1;
329 current_interthread_info = 0;
330 _show_measures = true;
331 show_gain_after_trim = false;
332 verbose_cursor_on = true;
333 last_item_entered = 0;
335 have_pending_keyboard_selection = false;
336 _follow_playhead = true;
337 _stationary_playhead = false;
338 _xfade_visibility = true;
339 editor_ruler_menu = 0;
340 no_ruler_shown_update = false;
342 range_marker_menu = 0;
343 marker_menu_item = 0;
344 tempo_or_meter_marker_menu = 0;
345 transport_marker_menu = 0;
346 new_transport_marker_menu = 0;
347 editor_mixer_strip_width = Wide;
348 show_editor_mixer_when_tracks_arrive = false;
349 region_edit_menu_split_multichannel_item = 0;
350 region_edit_menu_split_item = 0;
353 current_stepping_trackview = 0;
355 entered_regionview = 0;
357 clear_entered_track = false;
360 button_release_can_deselect = true;
361 _dragging_playhead = false;
362 _dragging_edit_point = false;
363 select_new_marker = false;
365 layering_order_editor = 0;
367 no_save_visual = false;
370 scrubbing_direction = 0;
374 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
375 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
376 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
377 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
378 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
380 _edit_point = EditAtMouse;
381 _internal_editing = false;
382 current_canvas_cursor = 0;
384 frames_per_unit = 2048; /* too early to use reset_zoom () */
386 _scroll_callbacks = 0;
388 zoom_focus = ZoomFocusLeft;
389 set_zoom_focus (ZoomFocusLeft);
390 zoom_range_clock.ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
392 bbt_label.set_name ("EditorTimeButton");
393 bbt_label.set_size_request (-1, (int)timebar_height);
394 bbt_label.set_alignment (1.0, 0.5);
395 bbt_label.set_padding (5,0);
397 bbt_label.set_no_show_all();
398 minsec_label.set_name ("EditorTimeButton");
399 minsec_label.set_size_request (-1, (int)timebar_height);
400 minsec_label.set_alignment (1.0, 0.5);
401 minsec_label.set_padding (5,0);
402 minsec_label.hide ();
403 minsec_label.set_no_show_all();
404 timecode_label.set_name ("EditorTimeButton");
405 timecode_label.set_size_request (-1, (int)timebar_height);
406 timecode_label.set_alignment (1.0, 0.5);
407 timecode_label.set_padding (5,0);
408 timecode_label.hide ();
409 timecode_label.set_no_show_all();
410 samples_label.set_name ("EditorTimeButton");
411 samples_label.set_size_request (-1, (int)timebar_height);
412 samples_label.set_alignment (1.0, 0.5);
413 samples_label.set_padding (5,0);
414 samples_label.hide ();
415 samples_label.set_no_show_all();
417 tempo_label.set_name ("EditorTimeButton");
418 tempo_label.set_size_request (-1, (int)timebar_height);
419 tempo_label.set_alignment (1.0, 0.5);
420 tempo_label.set_padding (5,0);
422 tempo_label.set_no_show_all();
424 meter_label.set_name ("EditorTimeButton");
425 meter_label.set_size_request (-1, (int)timebar_height);
426 meter_label.set_alignment (1.0, 0.5);
427 meter_label.set_padding (5,0);
429 meter_label.set_no_show_all();
431 mark_label.set_name ("EditorTimeButton");
432 mark_label.set_size_request (-1, (int)timebar_height);
433 mark_label.set_alignment (1.0, 0.5);
434 mark_label.set_padding (5,0);
436 mark_label.set_no_show_all();
438 cd_mark_label.set_name ("EditorTimeButton");
439 cd_mark_label.set_size_request (-1, (int)timebar_height);
440 cd_mark_label.set_alignment (1.0, 0.5);
441 cd_mark_label.set_padding (5,0);
442 cd_mark_label.hide();
443 cd_mark_label.set_no_show_all();
445 range_mark_label.set_name ("EditorTimeButton");
446 range_mark_label.set_size_request (-1, (int)timebar_height);
447 range_mark_label.set_alignment (1.0, 0.5);
448 range_mark_label.set_padding (5,0);
449 range_mark_label.hide();
450 range_mark_label.set_no_show_all();
452 transport_mark_label.set_name ("EditorTimeButton");
453 transport_mark_label.set_size_request (-1, (int)timebar_height);
454 transport_mark_label.set_alignment (1.0, 0.5);
455 transport_mark_label.set_padding (5,0);
456 transport_mark_label.hide();
457 transport_mark_label.set_no_show_all();
459 initialize_rulers ();
460 initialize_canvas ();
462 _summary = new EditorSummary (this);
464 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
465 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
467 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
469 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
470 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
472 edit_controls_vbox.set_spacing (0);
473 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
474 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
476 HBox* h = manage (new HBox);
477 _group_tabs = new EditorGroupTabs (this);
478 h->pack_start (*_group_tabs, PACK_SHRINK);
479 h->pack_start (edit_controls_vbox);
480 controls_layout.add (*h);
482 controls_layout.set_name ("EditControlsBase");
483 controls_layout.add_events (Gdk::SCROLL_MASK);
484 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
486 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
487 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
488 controls_layout_size_request_connection = controls_layout.signal_size_request().connect (sigc::mem_fun (*this, &Editor::controls_layout_size_request));
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 post_maximal_editor_width = 0;
560 post_maximal_horizontal_pane_position = 0;
561 post_maximal_editor_height = 0;
562 post_maximal_vertical_pane_position = 0;
563 _notebook_shrunk = false;
565 editor_summary_pane.pack1(edit_packer);
567 Button* summary_arrows_left_left = manage (new Button);
568 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
569 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press)));
570 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release));
572 Button* summary_arrows_left_right = manage (new Button);
573 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
574 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press)));
575 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release));
577 VBox* summary_arrows_left = manage (new VBox);
578 summary_arrows_left->pack_start (*summary_arrows_left_left);
579 summary_arrows_left->pack_start (*summary_arrows_left_right);
581 Button* summary_arrows_right_left = manage (new Button);
582 summary_arrows_right_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
583 summary_arrows_right_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press)));
584 summary_arrows_right_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release));
586 Button* summary_arrows_right_right = manage (new Button);
587 summary_arrows_right_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
588 summary_arrows_right_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press)));
589 summary_arrows_right_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release));
591 VBox* summary_arrows_right = manage (new VBox);
592 summary_arrows_right->pack_start (*summary_arrows_right_left);
593 summary_arrows_right->pack_start (*summary_arrows_right_right);
595 Frame* summary_frame = manage (new Frame);
596 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
598 summary_frame->add (*_summary);
599 summary_frame->show ();
601 _summary_hbox.pack_start (*summary_arrows_left, false, false);
602 _summary_hbox.pack_start (*summary_frame, true, true);
603 _summary_hbox.pack_start (*summary_arrows_right, false, false);
605 editor_summary_pane.pack2 (_summary_hbox);
607 edit_pane.pack1 (editor_summary_pane, true, true);
608 edit_pane.pack2 (_the_notebook, false, true);
610 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
612 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
614 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
616 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
617 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
619 top_hbox.pack_start (toolbar_frame);
621 HBox *hbox = manage (new HBox);
622 hbox->pack_start (edit_pane, true, true);
624 global_vpacker.pack_start (top_hbox, false, false);
625 global_vpacker.pack_start (*hbox, true, true);
627 global_hpacker.pack_start (global_vpacker, true, true);
629 set_name ("EditorWindow");
630 add_accel_group (ActionManager::ui_manager->get_accel_group());
632 status_bar_hpacker.show ();
634 vpacker.pack_end (status_bar_hpacker, false, false);
635 vpacker.pack_end (global_hpacker, true, true);
637 /* register actions now so that set_state() can find them and set toggles/checks etc */
642 setup_midi_toolbar ();
644 _snap_type = SnapToBeat;
645 set_snap_to (_snap_type);
646 _snap_mode = SnapOff;
647 set_snap_mode (_snap_mode);
648 set_mouse_mode (MouseObject, true);
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 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
707 /* problematic: has to return a value and thus cannot be x-thread */
709 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
711 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
713 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
715 _ignore_region_action = false;
716 _last_region_menu_was_main = false;
717 _popup_region_menu_item = 0;
719 _show_marker_lines = false;
720 _over_region_trim_target = false;
725 setup_fade_images ();
731 if(image_socket_listener) {
732 if(image_socket_listener->is_connected())
734 image_socket_listener->close_connection() ;
737 delete image_socket_listener ;
738 image_socket_listener = 0 ;
743 delete _route_groups;
749 Editor::add_toplevel_controls (Container& cont)
751 vpacker.pack_start (cont, false, false);
756 Editor::catch_vanishing_regionview (RegionView *rv)
758 /* note: the selection will take care of the vanishing
759 audioregionview by itself.
762 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
766 if (clicked_regionview == rv) {
767 clicked_regionview = 0;
770 if (entered_regionview == rv) {
771 set_entered_regionview (0);
774 if (!_all_region_actions_sensitized) {
775 sensitize_all_region_actions (true);
780 Editor::set_entered_regionview (RegionView* rv)
782 if (rv == entered_regionview) {
786 if (entered_regionview) {
787 entered_regionview->exited ();
790 if ((entered_regionview = rv) != 0) {
791 entered_regionview->entered (internal_editing ());
794 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
795 /* This RegionView entry might have changed what region actions
796 are allowed, so sensitize them all in case a key is pressed.
798 sensitize_all_region_actions (true);
803 Editor::set_entered_track (TimeAxisView* tav)
806 entered_track->exited ();
809 if ((entered_track = tav) != 0) {
810 entered_track->entered ();
815 Editor::show_window ()
817 if (!is_visible ()) {
820 /* re-hide stuff if necessary */
821 editor_list_button_toggled ();
822 parameter_changed ("show-summary");
823 parameter_changed ("show-edit-group-tabs");
824 parameter_changed ("show-zoom-tools");
826 /* now reset all audio_time_axis heights, because widgets might need
832 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
833 tv = (static_cast<TimeAxisView*>(*i));
842 Editor::instant_save ()
844 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
849 _session->add_instant_xml(get_state());
851 Config->add_instant_xml(get_state());
856 Editor::zoom_adjustment_changed ()
862 double fpu = zoom_range_clock.current_duration() / _canvas_width;
866 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
867 } else if (fpu > _session->current_end_frame() / _canvas_width) {
868 fpu = _session->current_end_frame() / _canvas_width;
869 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
876 Editor::control_scroll (float fraction)
878 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
884 double step = fraction * current_page_frames();
887 _control_scroll_target is an optional<T>
889 it acts like a pointer to an framepos_t, with
890 a operator conversion to boolean to check
891 that it has a value could possibly use
892 playhead_cursor->current_frame to store the
893 value and a boolean in the class to know
894 when it's out of date
897 if (!_control_scroll_target) {
898 _control_scroll_target = _session->transport_frame();
899 _dragging_playhead = true;
902 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
903 *_control_scroll_target = 0;
904 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
905 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
907 *_control_scroll_target += (framepos_t) floor (step);
910 /* move visuals, we'll catch up with it later */
912 playhead_cursor->set_position (*_control_scroll_target);
913 UpdateAllTransportClocks (*_control_scroll_target);
915 if (*_control_scroll_target > (current_page_frames() / 2)) {
916 /* try to center PH in window */
917 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
923 Now we do a timeout to actually bring the session to the right place
924 according to the playhead. This is to avoid reading disk buffers on every
925 call to control_scroll, which is driven by ScrollTimeline and therefore
926 probably by a control surface wheel which can generate lots of events.
928 /* cancel the existing timeout */
930 control_scroll_connection.disconnect ();
932 /* add the next timeout */
934 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
938 Editor::deferred_control_scroll (framepos_t /*target*/)
940 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
941 // reset for next stream
942 _control_scroll_target = boost::none;
943 _dragging_playhead = false;
948 Editor::access_action (std::string action_group, std::string action_item)
954 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
957 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
965 Editor::on_realize ()
967 Window::on_realize ();
972 Editor::map_position_change (framepos_t frame)
974 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
980 if (_follow_playhead) {
981 center_screen (frame);
984 playhead_cursor->set_position (frame);
988 Editor::center_screen (framepos_t frame)
990 double page = _canvas_width * frames_per_unit;
992 /* if we're off the page, then scroll.
995 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
996 center_screen_internal (frame, page);
1001 Editor::center_screen_internal (framepos_t frame, float page)
1006 frame -= (framepos_t) page;
1011 reset_x_origin (frame);
1016 Editor::update_title ()
1018 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1021 bool dirty = _session->dirty();
1023 string session_name;
1025 if (_session->snap_name() != _session->name()) {
1026 session_name = _session->snap_name();
1028 session_name = _session->name();
1032 session_name = "*" + session_name;
1035 WindowTitle title(session_name);
1036 title += Glib::get_application_name();
1037 set_title (title.get_string());
1042 Editor::set_session (Session *t)
1044 SessionHandlePtr::set_session (t);
1050 zoom_range_clock.set_session (_session);
1051 _playlist_selector->set_session (_session);
1052 nudge_clock.set_session (_session);
1053 _summary->set_session (_session);
1054 _group_tabs->set_session (_session);
1055 _route_groups->set_session (_session);
1056 _regions->set_session (_session);
1057 _snapshots->set_session (_session);
1058 _routes->set_session (_session);
1059 _locations->set_session (_session);
1061 if (rhythm_ferret) {
1062 rhythm_ferret->set_session (_session);
1065 if (analysis_window) {
1066 analysis_window->set_session (_session);
1070 sfbrowser->set_session (_session);
1073 compute_fixed_ruler_scale ();
1075 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1076 set_state (*node, Stateful::loading_state_version);
1078 /* catch up with the playhead */
1080 _session->request_locate (playhead_cursor->current_frame);
1081 _pending_initial_locate = true;
1085 /* These signals can all be emitted by a non-GUI thread. Therefore the
1086 handlers for them must not attempt to directly interact with the GUI,
1087 but use Gtkmm2ext::UI::instance()->call_slot();
1090 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1091 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1092 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1093 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1094 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1095 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1096 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1097 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1098 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1099 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1100 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1101 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1102 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display_s, this, _1), gui_context());
1103 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1105 if (Profile->get_sae()) {
1106 Timecode::BBT_Time bbt;
1110 framepos_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1111 nudge_clock.set_mode(AudioClock::BBT);
1112 nudge_clock.set (pos, true, 0, AudioClock::BBT);
1115 nudge_clock.set (_session->frame_rate() * 5, true, 0, AudioClock::Timecode); // default of 5 seconds
1118 playhead_cursor->canvas_item.show ();
1120 Location* loc = _session->locations()->auto_loop_location();
1122 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1124 if (loc->start() == loc->end()) {
1125 loc->set_end (loc->start() + 1);
1128 _session->locations()->add (loc, false);
1129 _session->set_auto_loop_location (loc);
1132 loc->set_name (_("Loop"));
1135 loc = _session->locations()->auto_punch_location();
1138 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1140 if (loc->start() == loc->end()) {
1141 loc->set_end (loc->start() + 1);
1144 _session->locations()->add (loc, false);
1145 _session->set_auto_punch_location (loc);
1148 loc->set_name (_("Punch"));
1151 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1152 Config->map_parameters (pc);
1153 _session->config.map_parameters (pc);
1155 refresh_location_display ();
1157 restore_ruler_visibility ();
1158 //tempo_map_changed (PropertyChange (0));
1159 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1161 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1162 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1165 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1166 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1169 switch (_snap_type) {
1170 case SnapToRegionStart:
1171 case SnapToRegionEnd:
1172 case SnapToRegionSync:
1173 case SnapToRegionBoundary:
1174 build_region_boundary_cache ();
1181 /* register for undo history */
1182 _session->register_with_memento_command_factory(_id, this);
1184 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1186 start_updating_meters ();
1190 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1192 if (a->get_name() == "RegionMenu") {
1193 /* When the main menu's region menu is opened, we setup the actions so that they look right
1194 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1195 so we resensitize all region actions when the entered regionview or the region selection
1196 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1197 happens after the region context menu is opened. So we set a flag here, too.
1201 sensitize_the_right_region_actions ();
1202 _last_region_menu_was_main = true;
1206 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1208 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1210 using namespace Menu_Helpers;
1211 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1214 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1218 MenuList& items (fade_context_menu.items());
1222 switch (item_type) {
1224 case FadeInHandleItem:
1225 if (arv->audio_region()->fade_in_active()) {
1226 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1228 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1231 items.push_back (SeparatorElem());
1233 if (Profile->get_sae()) {
1235 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1236 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1243 *_fade_in_images[FadeLinear],
1244 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1248 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1253 *_fade_in_images[FadeFast],
1254 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1257 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1262 *_fade_in_images[FadeLogB],
1263 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1266 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1271 *_fade_in_images[FadeLogA],
1272 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1275 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1280 *_fade_in_images[FadeSlow],
1281 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1284 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1290 case FadeOutHandleItem:
1291 if (arv->audio_region()->fade_out_active()) {
1292 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1294 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1297 items.push_back (SeparatorElem());
1299 if (Profile->get_sae()) {
1300 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1301 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1307 *_fade_out_images[FadeLinear],
1308 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1312 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1317 *_fade_out_images[FadeFast],
1318 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1321 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1326 *_fade_out_images[FadeLogB],
1327 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1330 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1335 *_fade_out_images[FadeLogA],
1336 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1339 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1344 *_fade_out_images[FadeSlow],
1345 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1348 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1354 fatal << _("programming error: ")
1355 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1360 fade_context_menu.popup (button, time);
1364 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1366 using namespace Menu_Helpers;
1367 Menu* (Editor::*build_menu_function)();
1370 switch (item_type) {
1372 case RegionViewName:
1373 case RegionViewNameHighlight:
1374 case LeftFrameHandle:
1375 case RightFrameHandle:
1376 if (with_selection) {
1377 build_menu_function = &Editor::build_track_selection_context_menu;
1379 build_menu_function = &Editor::build_track_region_context_menu;
1384 if (with_selection) {
1385 build_menu_function = &Editor::build_track_selection_context_menu;
1387 build_menu_function = &Editor::build_track_context_menu;
1391 case CrossfadeViewItem:
1392 build_menu_function = &Editor::build_track_crossfade_context_menu;
1396 if (clicked_routeview->track()) {
1397 build_menu_function = &Editor::build_track_context_menu;
1399 build_menu_function = &Editor::build_track_bus_context_menu;
1404 /* probably shouldn't happen but if it does, we don't care */
1408 menu = (this->*build_menu_function)();
1409 menu->set_name ("ArdourContextMenu");
1411 /* now handle specific situations */
1413 switch (item_type) {
1415 case RegionViewName:
1416 case RegionViewNameHighlight:
1417 case LeftFrameHandle:
1418 case RightFrameHandle:
1419 if (!with_selection) {
1420 if (region_edit_menu_split_item) {
1421 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1422 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1424 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1427 if (region_edit_menu_split_multichannel_item) {
1428 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1429 region_edit_menu_split_multichannel_item->set_sensitive (true);
1431 region_edit_menu_split_multichannel_item->set_sensitive (false);
1440 case CrossfadeViewItem:
1447 /* probably shouldn't happen but if it does, we don't care */
1451 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1453 /* Bounce to disk */
1455 using namespace Menu_Helpers;
1456 MenuList& edit_items = menu->items();
1458 edit_items.push_back (SeparatorElem());
1460 switch (clicked_routeview->audio_track()->freeze_state()) {
1461 case AudioTrack::NoFreeze:
1462 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1465 case AudioTrack::Frozen:
1466 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1469 case AudioTrack::UnFrozen:
1470 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1476 if (item_type == StreamItem && clicked_routeview) {
1477 clicked_routeview->build_underlay_menu(menu);
1480 /* When the region menu is opened, we setup the actions so that they look right
1483 sensitize_the_right_region_actions ();
1484 _last_region_menu_was_main = false;
1486 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1487 menu->popup (button, time);
1491 Editor::build_track_context_menu ()
1493 using namespace Menu_Helpers;
1495 MenuList& edit_items = track_context_menu.items();
1498 add_dstream_context_items (edit_items);
1499 return &track_context_menu;
1503 Editor::build_track_bus_context_menu ()
1505 using namespace Menu_Helpers;
1507 MenuList& edit_items = track_context_menu.items();
1510 add_bus_context_items (edit_items);
1511 return &track_context_menu;
1515 Editor::build_track_region_context_menu ()
1517 using namespace Menu_Helpers;
1518 MenuList& edit_items = track_region_context_menu.items();
1521 /* we've just cleared the track region context menu, so the menu that these
1522 two items were on will have disappeared; stop them dangling.
1524 region_edit_menu_split_item = 0;
1525 region_edit_menu_split_multichannel_item = 0;
1527 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1530 boost::shared_ptr<Track> tr;
1531 boost::shared_ptr<Playlist> pl;
1533 /* Don't offer a region submenu if we are in internal edit mode, as we don't select regions in this
1534 mode and so offering region context is somewhat confusing.
1536 if ((tr = rtv->track()) && ((pl = tr->playlist())) && !internal_editing()) {
1537 framepos_t const framepos = (framepos_t) floor ((double) get_preferred_edit_position() * tr->speed());
1538 uint32_t regions_at = pl->count_regions_at (framepos);
1539 add_region_context_items (edit_items, regions_at > 1);
1543 add_dstream_context_items (edit_items);
1545 return &track_region_context_menu;
1549 Editor::build_track_crossfade_context_menu ()
1551 using namespace Menu_Helpers;
1552 MenuList& edit_items = track_crossfade_context_menu.items();
1553 edit_items.clear ();
1555 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1558 boost::shared_ptr<Track> tr;
1559 boost::shared_ptr<Playlist> pl;
1560 boost::shared_ptr<AudioPlaylist> apl;
1562 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1564 AudioPlaylist::Crossfades xfades;
1566 apl->crossfades_at (get_preferred_edit_position (), xfades);
1568 bool many = xfades.size() > 1;
1570 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1571 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1574 framepos_t framepos = (framepos_t) floor ((double) get_preferred_edit_position() * tr->speed());
1575 uint32_t regions_at = pl->count_regions_at (framepos);
1576 add_region_context_items (edit_items, regions_at > 1);
1580 add_dstream_context_items (edit_items);
1582 return &track_crossfade_context_menu;
1586 Editor::analyze_region_selection ()
1588 if (analysis_window == 0) {
1589 analysis_window = new AnalysisWindow();
1592 analysis_window->set_session(_session);
1594 analysis_window->show_all();
1597 analysis_window->set_regionmode();
1598 analysis_window->analyze();
1600 analysis_window->present();
1604 Editor::analyze_range_selection()
1606 if (analysis_window == 0) {
1607 analysis_window = new AnalysisWindow();
1610 analysis_window->set_session(_session);
1612 analysis_window->show_all();
1615 analysis_window->set_rangemode();
1616 analysis_window->analyze();
1618 analysis_window->present();
1622 Editor::build_track_selection_context_menu ()
1624 using namespace Menu_Helpers;
1625 MenuList& edit_items = track_selection_context_menu.items();
1626 edit_items.clear ();
1628 add_selection_context_items (edit_items);
1629 // edit_items.push_back (SeparatorElem());
1630 // add_dstream_context_items (edit_items);
1632 return &track_selection_context_menu;
1635 /** Add context menu items relevant to crossfades.
1636 * @param edit_items List to add the items to.
1639 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1641 using namespace Menu_Helpers;
1642 Menu *xfade_menu = manage (new Menu);
1643 MenuList& items = xfade_menu->items();
1644 xfade_menu->set_name ("ArdourContextMenu");
1647 if (xfade->active()) {
1653 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1654 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1656 if (xfade->can_follow_overlap()) {
1658 if (xfade->following_overlap()) {
1659 str = _("Convert to Short");
1661 str = _("Convert to Full");
1664 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1668 str = xfade->out()->name();
1670 str += xfade->in()->name();
1672 str = _("Crossfade");
1675 edit_items.push_back (MenuElem (str, *xfade_menu));
1676 edit_items.push_back (SeparatorElem());
1680 Editor::xfade_edit_left_region ()
1682 if (clicked_crossfadeview) {
1683 clicked_crossfadeview->left_view.show_region_editor ();
1688 Editor::xfade_edit_right_region ()
1690 if (clicked_crossfadeview) {
1691 clicked_crossfadeview->right_view.show_region_editor ();
1696 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, bool multiple_regions_at_position)
1698 using namespace Menu_Helpers;
1700 /* OK, stick the region submenu at the top of the list, and then add
1704 /* we have to hack up the region name because "_" has a special
1705 meaning for menu titles.
1708 RegionSelection rs = get_regions_from_selection_and_entered ();
1710 string::size_type pos = 0;
1711 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1713 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1714 menu_item_name.replace (pos, 1, "__");
1718 if (_popup_region_menu_item == 0) {
1719 _popup_region_menu_item = new MenuItem (menu_item_name);
1720 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1721 _popup_region_menu_item->show ();
1723 _popup_region_menu_item->set_label (menu_item_name);
1726 edit_items.push_back (*_popup_region_menu_item);
1727 if (multiple_regions_at_position && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1728 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region")->create_menu_item ()));
1730 edit_items.push_back (SeparatorElem());
1733 /** Add context menu items relevant to selection ranges.
1734 * @param edit_items List to add the items to.
1737 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1739 using namespace Menu_Helpers;
1741 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1742 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1744 edit_items.push_back (SeparatorElem());
1745 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1747 if (!selection->regions.empty()) {
1748 edit_items.push_back (SeparatorElem());
1749 edit_items.push_back (MenuElem (_("Extend Range to End of Region"), sigc::bind (sigc::mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1750 edit_items.push_back (MenuElem (_("Extend Range to Start of Region"), sigc::bind (sigc::mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1753 edit_items.push_back (SeparatorElem());
1754 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1755 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1757 edit_items.push_back (SeparatorElem());
1758 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1760 edit_items.push_back (SeparatorElem());
1761 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1762 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1764 edit_items.push_back (SeparatorElem());
1765 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1767 edit_items.push_back (SeparatorElem());
1768 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1769 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1770 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1772 edit_items.push_back (SeparatorElem());
1773 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1774 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1775 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1776 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1777 edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection)));
1782 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1784 using namespace Menu_Helpers;
1788 Menu *play_menu = manage (new Menu);
1789 MenuList& play_items = play_menu->items();
1790 play_menu->set_name ("ArdourContextMenu");
1792 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1793 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1794 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1795 play_items.push_back (SeparatorElem());
1796 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1798 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1802 Menu *select_menu = manage (new Menu);
1803 MenuList& select_items = select_menu->items();
1804 select_menu->set_name ("ArdourContextMenu");
1806 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1807 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1808 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1809 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1810 select_items.push_back (SeparatorElem());
1811 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1812 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1813 select_items.push_back (SeparatorElem());
1814 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1815 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1816 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1817 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1818 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1819 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1820 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1822 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1826 Menu *cutnpaste_menu = manage (new Menu);
1827 MenuList& cutnpaste_items = cutnpaste_menu->items();
1828 cutnpaste_menu->set_name ("ArdourContextMenu");
1830 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1831 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1832 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1834 cutnpaste_items.push_back (SeparatorElem());
1836 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1837 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1839 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1841 /* Adding new material */
1843 edit_items.push_back (SeparatorElem());
1844 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1845 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1849 Menu *nudge_menu = manage (new Menu());
1850 MenuList& nudge_items = nudge_menu->items();
1851 nudge_menu->set_name ("ArdourContextMenu");
1853 edit_items.push_back (SeparatorElem());
1854 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1855 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1856 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1857 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1859 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1863 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1865 using namespace Menu_Helpers;
1869 Menu *play_menu = manage (new Menu);
1870 MenuList& play_items = play_menu->items();
1871 play_menu->set_name ("ArdourContextMenu");
1873 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1874 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1875 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1879 Menu *select_menu = manage (new Menu);
1880 MenuList& select_items = select_menu->items();
1881 select_menu->set_name ("ArdourContextMenu");
1883 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1884 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1885 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1886 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1887 select_items.push_back (SeparatorElem());
1888 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1889 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1890 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1891 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1893 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1897 Menu *cutnpaste_menu = manage (new Menu);
1898 MenuList& cutnpaste_items = cutnpaste_menu->items();
1899 cutnpaste_menu->set_name ("ArdourContextMenu");
1901 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1902 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1903 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1905 Menu *nudge_menu = manage (new Menu());
1906 MenuList& nudge_items = nudge_menu->items();
1907 nudge_menu->set_name ("ArdourContextMenu");
1909 edit_items.push_back (SeparatorElem());
1910 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1911 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1912 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1913 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1915 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1919 Editor::snap_type() const
1925 Editor::snap_mode() const
1931 Editor::set_snap_to (SnapType st)
1933 unsigned int snap_ind = (unsigned int)st;
1937 if (snap_ind > snap_type_strings.size() - 1) {
1939 _snap_type = (SnapType)snap_ind;
1942 string str = snap_type_strings[snap_ind];
1944 if (str != snap_type_selector.get_active_text()) {
1945 snap_type_selector.set_active_text (str);
1950 switch (_snap_type) {
1951 case SnapToBeatDiv32:
1952 case SnapToBeatDiv28:
1953 case SnapToBeatDiv24:
1954 case SnapToBeatDiv20:
1955 case SnapToBeatDiv16:
1956 case SnapToBeatDiv14:
1957 case SnapToBeatDiv12:
1958 case SnapToBeatDiv10:
1959 case SnapToBeatDiv8:
1960 case SnapToBeatDiv7:
1961 case SnapToBeatDiv6:
1962 case SnapToBeatDiv5:
1963 case SnapToBeatDiv4:
1964 case SnapToBeatDiv3:
1965 case SnapToBeatDiv2:
1966 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
1967 update_tempo_based_rulers ();
1970 case SnapToRegionStart:
1971 case SnapToRegionEnd:
1972 case SnapToRegionSync:
1973 case SnapToRegionBoundary:
1974 build_region_boundary_cache ();
1982 SnapChanged (); /* EMIT SIGNAL */
1986 Editor::set_snap_mode (SnapMode mode)
1989 string str = snap_mode_strings[(int)mode];
1991 if (str != snap_mode_selector.get_active_text ()) {
1992 snap_mode_selector.set_active_text (str);
1998 Editor::set_edit_point_preference (EditPoint ep, bool force)
2000 bool changed = (_edit_point != ep);
2003 string str = edit_point_strings[(int)ep];
2005 if (str != edit_point_selector.get_active_text ()) {
2006 edit_point_selector.set_active_text (str);
2009 set_canvas_cursor ();
2011 if (!force && !changed) {
2015 const char* action=NULL;
2017 switch (_edit_point) {
2018 case EditAtPlayhead:
2019 action = "edit-at-playhead";
2021 case EditAtSelectedMarker:
2022 action = "edit-at-marker";
2025 action = "edit-at-mouse";
2029 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2031 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2035 bool in_track_canvas;
2037 if (!mouse_frame (foo, in_track_canvas)) {
2038 in_track_canvas = false;
2041 reset_canvas_action_sensitivity (in_track_canvas);
2047 Editor::set_state (const XMLNode& node, int /*version*/)
2049 const XMLProperty* prop;
2051 int x, y, xoff, yoff;
2054 if ((prop = node.property ("id")) != 0) {
2055 _id = prop->value ();
2058 g.base_width = default_width;
2059 g.base_height = default_height;
2065 if ((geometry = find_named_node (node, "geometry")) != 0) {
2069 if ((prop = geometry->property("x_size")) == 0) {
2070 prop = geometry->property ("x-size");
2073 g.base_width = atoi(prop->value());
2075 if ((prop = geometry->property("y_size")) == 0) {
2076 prop = geometry->property ("y-size");
2079 g.base_height = atoi(prop->value());
2082 if ((prop = geometry->property ("x_pos")) == 0) {
2083 prop = geometry->property ("x-pos");
2086 x = atoi (prop->value());
2089 if ((prop = geometry->property ("y_pos")) == 0) {
2090 prop = geometry->property ("y-pos");
2093 y = atoi (prop->value());
2096 if ((prop = geometry->property ("x_off")) == 0) {
2097 prop = geometry->property ("x-off");
2100 xoff = atoi (prop->value());
2102 if ((prop = geometry->property ("y_off")) == 0) {
2103 prop = geometry->property ("y-off");
2106 yoff = atoi (prop->value());
2110 set_default_size (g.base_width, g.base_height);
2113 if (_session && (prop = node.property ("playhead"))) {
2115 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2116 playhead_cursor->set_position (pos);
2118 playhead_cursor->set_position (0);
2121 if ((prop = node.property ("mixer-width"))) {
2122 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2125 if ((prop = node.property ("zoom-focus"))) {
2126 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2129 if ((prop = node.property ("zoom"))) {
2130 reset_zoom (PBD::atof (prop->value()));
2132 reset_zoom (frames_per_unit);
2135 if ((prop = node.property ("snap-to"))) {
2136 set_snap_to ((SnapType) atoi (prop->value()));
2139 if ((prop = node.property ("snap-mode"))) {
2140 set_snap_mode ((SnapMode) atoi (prop->value()));
2143 if ((prop = node.property ("mouse-mode"))) {
2144 MouseMode m = str2mousemode(prop->value());
2145 set_mouse_mode (m, true);
2147 set_mouse_mode (MouseObject, true);
2150 if ((prop = node.property ("left-frame")) != 0) {
2152 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2153 reset_x_origin (pos);
2157 if ((prop = node.property ("y-origin")) != 0) {
2158 reset_y_origin (atof (prop->value ()));
2161 if ((prop = node.property ("internal-edit"))) {
2162 bool yn = string_is_affirmative (prop->value());
2163 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2165 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2166 tact->set_active (!yn);
2167 tact->set_active (yn);
2171 if ((prop = node.property ("join-object-range"))) {
2172 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2175 if ((prop = node.property ("edit-point"))) {
2176 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2179 if ((prop = node.property ("show-measures"))) {
2180 bool yn = string_is_affirmative (prop->value());
2181 _show_measures = yn;
2182 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2184 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2185 /* do it twice to force the change */
2186 tact->set_active (!yn);
2187 tact->set_active (yn);
2191 if ((prop = node.property ("follow-playhead"))) {
2192 bool yn = string_is_affirmative (prop->value());
2193 set_follow_playhead (yn);
2194 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2196 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2197 if (tact->get_active() != yn) {
2198 tact->set_active (yn);
2203 if ((prop = node.property ("stationary-playhead"))) {
2204 bool yn = (prop->value() == "yes");
2205 set_stationary_playhead (yn);
2206 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2208 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2209 if (tact->get_active() != yn) {
2210 tact->set_active (yn);
2215 if ((prop = node.property ("region-list-sort-type"))) {
2216 RegionListSortType st;
2217 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2220 if ((prop = node.property ("xfades-visible"))) {
2221 bool yn = string_is_affirmative (prop->value());
2222 _xfade_visibility = !yn;
2223 // set_xfade_visibility (yn);
2226 if ((prop = node.property ("show-editor-mixer"))) {
2228 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2231 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2232 bool yn = string_is_affirmative (prop->value());
2234 /* do it twice to force the change */
2236 tact->set_active (!yn);
2237 tact->set_active (yn);
2240 if ((prop = node.property ("show-editor-list"))) {
2242 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2245 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2246 bool yn = string_is_affirmative (prop->value());
2248 /* do it twice to force the change */
2250 tact->set_active (!yn);
2251 tact->set_active (yn);
2254 if ((prop = node.property (X_("editor-list-page")))) {
2255 _the_notebook.set_current_page (atoi (prop->value ()));
2258 if ((prop = node.property (X_("show-marker-lines")))) {
2259 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2261 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2262 bool yn = string_is_affirmative (prop->value ());
2264 tact->set_active (!yn);
2265 tact->set_active (yn);
2268 XMLNodeList children = node.children ();
2269 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2270 selection->set_state (**i, Stateful::current_state_version);
2271 _regions->set_state (**i);
2278 Editor::get_state ()
2280 XMLNode* node = new XMLNode ("Editor");
2283 _id.print (buf, sizeof (buf));
2284 node->add_property ("id", buf);
2286 if (is_realized()) {
2287 Glib::RefPtr<Gdk::Window> win = get_window();
2289 int x, y, xoff, yoff, width, height;
2290 win->get_root_origin(x, y);
2291 win->get_position(xoff, yoff);
2292 win->get_size(width, height);
2294 XMLNode* geometry = new XMLNode ("geometry");
2296 snprintf(buf, sizeof(buf), "%d", width);
2297 geometry->add_property("x-size", string(buf));
2298 snprintf(buf, sizeof(buf), "%d", height);
2299 geometry->add_property("y-size", string(buf));
2300 snprintf(buf, sizeof(buf), "%d", x);
2301 geometry->add_property("x-pos", string(buf));
2302 snprintf(buf, sizeof(buf), "%d", y);
2303 geometry->add_property("y-pos", string(buf));
2304 snprintf(buf, sizeof(buf), "%d", xoff);
2305 geometry->add_property("x-off", string(buf));
2306 snprintf(buf, sizeof(buf), "%d", yoff);
2307 geometry->add_property("y-off", string(buf));
2308 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2309 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2310 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2311 snprintf(buf,sizeof(buf), "%d",pre_maximal_horizontal_pane_position);
2312 geometry->add_property("pre-maximal-horizontal-pane-position", string(buf));
2313 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2314 geometry->add_property("edit-vertical-pane-pos", string(buf));
2316 node->add_child_nocopy (*geometry);
2319 maybe_add_mixer_strip_width (*node);
2321 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2322 node->add_property ("zoom-focus", buf);
2323 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2324 node->add_property ("zoom", buf);
2325 snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2326 node->add_property ("snap-to", buf);
2327 snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2328 node->add_property ("snap-mode", buf);
2330 node->add_property ("edit-point", enum_2_string (_edit_point));
2332 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2333 node->add_property ("playhead", buf);
2334 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2335 node->add_property ("left-frame", buf);
2336 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2337 node->add_property ("y-origin", buf);
2339 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2340 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2341 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2342 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2343 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2344 node->add_property ("mouse-mode", enum2str(mouse_mode));
2345 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2346 node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2348 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2350 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2351 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2354 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2356 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2357 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2360 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2361 node->add_property (X_("editor-list-page"), buf);
2363 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2365 node->add_child_nocopy (selection->get_state ());
2366 node->add_child_nocopy (_regions->get_state ());
2373 /** @param y y offset from the top of all trackviews.
2374 * @return pair: TimeAxisView that y is over, layer index.
2375 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2376 * in stacked region display mode, otherwise 0.
2378 std::pair<TimeAxisView *, layer_t>
2379 Editor::trackview_by_y_position (double y)
2381 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2383 std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
2389 return std::make_pair ( (TimeAxisView *) 0, 0);
2392 /** Snap a position to the grid, if appropriate, taking into account current
2393 * grid settings and also the state of any snap modifier keys that may be pressed.
2394 * @param start Position to snap.
2395 * @param event Event to get current key modifier information from, or 0.
2398 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2400 if (!_session || !event) {
2404 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2405 if (_snap_mode == SnapOff) {
2406 snap_to_internal (start, direction, for_mark);
2409 if (_snap_mode != SnapOff) {
2410 snap_to_internal (start, direction, for_mark);
2416 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2418 if (!_session || _snap_mode == SnapOff) {
2422 snap_to_internal (start, direction, for_mark);
2426 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2428 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2429 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2431 switch (_snap_type) {
2432 case SnapToTimecodeFrame:
2433 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2434 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2436 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2440 case SnapToTimecodeSeconds:
2441 if (_session->config.get_timecode_offset_negative()) {
2442 start += _session->config.get_timecode_offset ();
2444 start -= _session->config.get_timecode_offset ();
2446 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2447 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2449 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2452 if (_session->config.get_timecode_offset_negative()) {
2453 start -= _session->config.get_timecode_offset ();
2455 start += _session->config.get_timecode_offset ();
2459 case SnapToTimecodeMinutes:
2460 if (_session->config.get_timecode_offset_negative()) {
2461 start += _session->config.get_timecode_offset ();
2463 start -= _session->config.get_timecode_offset ();
2465 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2466 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2468 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2470 if (_session->config.get_timecode_offset_negative()) {
2471 start -= _session->config.get_timecode_offset ();
2473 start += _session->config.get_timecode_offset ();
2477 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2483 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2485 const framepos_t one_second = _session->frame_rate();
2486 const framepos_t one_minute = _session->frame_rate() * 60;
2487 framepos_t presnap = start;
2491 switch (_snap_type) {
2492 case SnapToTimecodeFrame:
2493 case SnapToTimecodeSeconds:
2494 case SnapToTimecodeMinutes:
2495 return timecode_snap_to_internal (start, direction, for_mark);
2498 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2499 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2501 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2506 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2507 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2509 start = (framepos_t) floor ((double) start / one_second) * one_second;
2514 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2515 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2517 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2522 start = _session->tempo_map().round_to_bar (start, direction);
2526 start = _session->tempo_map().round_to_beat (start, direction);
2529 case SnapToBeatDiv32:
2530 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2532 case SnapToBeatDiv28:
2533 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2535 case SnapToBeatDiv24:
2536 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2538 case SnapToBeatDiv20:
2539 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2541 case SnapToBeatDiv16:
2542 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2544 case SnapToBeatDiv14:
2545 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2547 case SnapToBeatDiv12:
2548 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2550 case SnapToBeatDiv10:
2551 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2553 case SnapToBeatDiv8:
2554 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2556 case SnapToBeatDiv7:
2557 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2559 case SnapToBeatDiv6:
2560 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2562 case SnapToBeatDiv5:
2563 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2565 case SnapToBeatDiv4:
2566 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2568 case SnapToBeatDiv3:
2569 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2571 case SnapToBeatDiv2:
2572 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2580 _session->locations()->marks_either_side (start, before, after);
2582 if (before == max_framepos) {
2584 } else if (after == max_framepos) {
2586 } else if (before != max_framepos && after != max_framepos) {
2587 /* have before and after */
2588 if ((start - before) < (after - start)) {
2597 case SnapToRegionStart:
2598 case SnapToRegionEnd:
2599 case SnapToRegionSync:
2600 case SnapToRegionBoundary:
2601 if (!region_boundary_cache.empty()) {
2603 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2604 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2606 if (direction > 0) {
2607 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2609 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2612 if (next != region_boundary_cache.begin ()) {
2617 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2618 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2620 if (start > (p + n) / 2) {
2629 switch (_snap_mode) {
2635 if (presnap > start) {
2636 if (presnap > (start + unit_to_frame(snap_threshold))) {
2640 } else if (presnap < start) {
2641 if (presnap < (start - unit_to_frame(snap_threshold))) {
2647 /* handled at entry */
2655 Editor::setup_toolbar ()
2659 /* Mode Buttons (tool selection) */
2661 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2662 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2663 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2664 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2665 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2666 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2667 // internal_edit_button.set_relief(Gtk::RELIEF_NONE);
2668 join_object_range_button.set_relief(Gtk::RELIEF_NONE);
2670 HBox* mode_box = manage(new HBox);
2671 mode_box->set_border_width (2);
2672 mode_box->set_spacing(4);
2674 /* table containing mode buttons */
2676 HBox* mouse_mode_button_box = manage (new HBox ());
2678 if (Profile->get_sae()) {
2679 mouse_mode_button_box->pack_start (mouse_move_button);
2681 mouse_mode_button_box->pack_start (mouse_move_button);
2682 mouse_mode_button_box->pack_start (join_object_range_button);
2683 mouse_mode_button_box->pack_start (mouse_select_button);
2686 mouse_mode_button_box->pack_start (mouse_zoom_button);
2688 if (!Profile->get_sae()) {
2689 mouse_mode_button_box->pack_start (mouse_gain_button);
2692 mouse_mode_button_box->pack_start (mouse_timefx_button);
2693 mouse_mode_button_box->pack_start (mouse_audition_button);
2694 mouse_mode_button_box->pack_start (internal_edit_button);
2696 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2697 if (!Profile->get_sae()) {
2698 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2700 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2702 edit_mode_selector.set_name ("EditModeSelector");
2703 set_popdown_strings (edit_mode_selector, edit_mode_strings, true);
2704 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2706 mode_box->pack_start (edit_mode_selector);
2707 mode_box->pack_start (*mouse_mode_button_box);
2709 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2710 _mouse_mode_tearoff->set_name ("MouseModeBase");
2711 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2713 if (Profile->get_sae()) {
2714 _mouse_mode_tearoff->set_can_be_torn_off (false);
2717 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2718 &_mouse_mode_tearoff->tearoff_window()));
2719 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2720 &_mouse_mode_tearoff->tearoff_window(), 1));
2721 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2722 &_mouse_mode_tearoff->tearoff_window()));
2723 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2724 &_mouse_mode_tearoff->tearoff_window(), 1));
2726 mouse_move_button.set_mode (false);
2727 mouse_select_button.set_mode (false);
2728 mouse_gain_button.set_mode (false);
2729 mouse_zoom_button.set_mode (false);
2730 mouse_timefx_button.set_mode (false);
2731 mouse_audition_button.set_mode (false);
2732 join_object_range_button.set_mode (false);
2734 mouse_move_button.set_name ("MouseModeButton");
2735 mouse_select_button.set_name ("MouseModeButton");
2736 mouse_gain_button.set_name ("MouseModeButton");
2737 mouse_zoom_button.set_name ("MouseModeButton");
2738 mouse_timefx_button.set_name ("MouseModeButton");
2739 mouse_audition_button.set_name ("MouseModeButton");
2740 internal_edit_button.set_name ("MouseModeButton");
2741 join_object_range_button.set_name ("MouseModeButton");
2743 mouse_move_button.unset_flags (CAN_FOCUS);
2744 mouse_select_button.unset_flags (CAN_FOCUS);
2745 mouse_gain_button.unset_flags (CAN_FOCUS);
2746 mouse_zoom_button.unset_flags (CAN_FOCUS);
2747 mouse_timefx_button.unset_flags (CAN_FOCUS);
2748 mouse_audition_button.unset_flags (CAN_FOCUS);
2749 internal_edit_button.unset_flags (CAN_FOCUS);
2750 join_object_range_button.unset_flags (CAN_FOCUS);
2754 _zoom_box.set_spacing (1);
2755 _zoom_box.set_border_width (0);
2757 zoom_in_button.set_name ("EditorTimeButton");
2758 zoom_in_button.set_image (*(manage (new Image (Stock::ZOOM_IN, Gtk::ICON_SIZE_MENU))));
2759 zoom_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), false));
2761 zoom_out_button.set_name ("EditorTimeButton");
2762 zoom_out_button.set_image (*(manage (new Image (Stock::ZOOM_OUT, Gtk::ICON_SIZE_MENU))));
2763 zoom_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), true));
2765 zoom_out_full_button.set_name ("EditorTimeButton");
2766 zoom_out_full_button.set_image (*(manage (new Image (Stock::ZOOM_100, Gtk::ICON_SIZE_MENU))));
2767 zoom_out_full_button.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session));
2769 zoom_focus_selector.set_name ("ZoomFocusSelector");
2770 set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true);
2771 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2773 _zoom_box.pack_start (zoom_out_button, false, false);
2774 _zoom_box.pack_start (zoom_in_button, false, false);
2775 _zoom_box.pack_start (zoom_out_full_button, false, false);
2777 _zoom_box.pack_start (zoom_focus_selector);
2779 /* Track zoom buttons */
2780 tav_expand_button.set_name ("TrackHeightButton");
2781 tav_expand_button.set_size_request(-1,20);
2782 tav_expand_button.add (*(manage (new Image (::get_icon("tav_exp")))));
2783 tav_expand_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), true));
2785 tav_shrink_button.set_name ("TrackHeightButton");
2786 tav_shrink_button.set_size_request(-1,20);
2787 tav_shrink_button.add (*(manage (new Image (::get_icon("tav_shrink")))));
2788 tav_shrink_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), false));
2790 _zoom_box.pack_start (tav_shrink_button);
2791 _zoom_box.pack_start (tav_expand_button);
2793 _zoom_tearoff = manage (new TearOff (_zoom_box));
2795 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2796 &_zoom_tearoff->tearoff_window()));
2797 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2798 &_zoom_tearoff->tearoff_window(), 0));
2799 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2800 &_zoom_tearoff->tearoff_window()));
2801 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2802 &_zoom_tearoff->tearoff_window(), 0));
2804 snap_box.set_spacing (1);
2805 snap_box.set_border_width (2);
2807 snap_type_selector.set_name ("SnapTypeSelector");
2808 set_popdown_strings (snap_type_selector, snap_type_strings, true);
2809 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2811 snap_mode_selector.set_name ("SnapModeSelector");
2812 set_popdown_strings (snap_mode_selector, snap_mode_strings, true);
2813 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2815 edit_point_selector.set_name ("EditPointSelector");
2816 set_popdown_strings (edit_point_selector, edit_point_strings, true);
2817 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2819 snap_box.pack_start (snap_mode_selector, false, false);
2820 snap_box.pack_start (snap_type_selector, false, false);
2821 snap_box.pack_start (edit_point_selector, false, false);
2825 HBox *nudge_box = manage (new HBox);
2826 nudge_box->set_spacing(1);
2827 nudge_box->set_border_width (2);
2829 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2830 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2832 nudge_box->pack_start (nudge_backward_button, false, false);
2833 nudge_box->pack_start (nudge_forward_button, false, false);
2834 nudge_box->pack_start (nudge_clock, false, false);
2837 /* Pack everything in... */
2839 HBox* hbox = manage (new HBox);
2840 hbox->set_spacing(10);
2842 _tools_tearoff = manage (new TearOff (*hbox));
2843 _tools_tearoff->set_name ("MouseModeBase");
2844 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2846 if (Profile->get_sae()) {
2847 _tools_tearoff->set_can_be_torn_off (false);
2850 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2851 &_tools_tearoff->tearoff_window()));
2852 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2853 &_tools_tearoff->tearoff_window(), 0));
2854 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2855 &_tools_tearoff->tearoff_window()));
2856 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2857 &_tools_tearoff->tearoff_window(), 0));
2859 toolbar_hbox.set_spacing (10);
2860 toolbar_hbox.set_border_width (1);
2862 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2863 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2864 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2866 hbox->pack_start (snap_box, false, false);
2867 hbox->pack_start (*nudge_box, false, false);
2868 hbox->pack_start (panic_box, false, false);
2872 toolbar_base.set_name ("ToolBarBase");
2873 toolbar_base.add (toolbar_hbox);
2875 _toolbar_viewport.add (toolbar_base);
2876 /* stick to the required height but allow width to vary if there's not enough room */
2877 _toolbar_viewport.set_size_request (1, -1);
2879 toolbar_frame.set_shadow_type (SHADOW_OUT);
2880 toolbar_frame.set_name ("BaseFrame");
2881 toolbar_frame.add (_toolbar_viewport);
2883 DPIReset.connect (sigc::mem_fun (*this, &Editor::resize_text_widgets));
2887 Editor::setup_tooltips ()
2889 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2890 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
2891 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
2892 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
2893 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2894 ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
2895 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
2896 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
2897 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
2898 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
2899 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
2900 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
2901 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
2902 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
2903 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
2904 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
2905 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
2906 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2907 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
2908 ARDOUR_UI::instance()->set_tip (midi_sound_notes, _("Sound Notes"));
2909 ARDOUR_UI::instance()->set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels"));
2910 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
2914 Editor::midi_panic ()
2916 cerr << "MIDI panic\n";
2919 _session->midi_panic();
2924 Editor::setup_midi_toolbar ()
2928 /* Midi sound notes */
2929 midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
2930 midi_sound_notes.set_relief(Gtk::RELIEF_NONE);
2931 midi_sound_notes.unset_flags (CAN_FOCUS);
2935 act = ActionManager::get_action (X_("MIDI"), X_("panic"));
2936 midi_panic_button.set_name("MidiPanicButton");
2937 act->connect_proxy (midi_panic_button);
2939 panic_box.pack_start (midi_sound_notes , true, true);
2940 panic_box.pack_start (midi_panic_button, true, true);
2944 Editor::convert_drop_to_paths (
2945 vector<string>& paths,
2946 const RefPtr<Gdk::DragContext>& /*context*/,
2949 const SelectionData& data,
2953 if (_session == 0) {
2957 vector<string> uris = data.get_uris();
2961 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2962 are actually URI lists. So do it by hand.
2965 if (data.get_target() != "text/plain") {
2969 /* Parse the "uri-list" format that Nautilus provides,
2970 where each pathname is delimited by \r\n.
2972 THERE MAY BE NO NULL TERMINATING CHAR!!!
2975 string txt = data.get_text();
2979 p = (const char *) malloc (txt.length() + 1);
2980 txt.copy ((char *) p, txt.length(), 0);
2981 ((char*)p)[txt.length()] = '\0';
2987 while (g_ascii_isspace (*p))
2991 while (*q && (*q != '\n') && (*q != '\r')) {
2998 while (q > p && g_ascii_isspace (*q))
3003 uris.push_back (string (p, q - p + 1));
3007 p = strchr (p, '\n');
3019 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3021 if ((*i).substr (0,7) == "file://") {
3024 PBD::url_decode (p);
3026 // scan forward past three slashes
3028 string::size_type slashcnt = 0;
3029 string::size_type n = 0;
3030 string::iterator x = p.begin();
3032 while (slashcnt < 3 && x != p.end()) {
3035 } else if (slashcnt == 3) {
3042 if (slashcnt != 3 || x == p.end()) {
3043 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3047 paths.push_back (p.substr (n - 1));
3055 Editor::new_tempo_section ()
3061 Editor::map_transport_state ()
3063 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3065 if (_session && _session->transport_stopped()) {
3066 have_pending_keyboard_selection = false;
3069 update_loop_range_view (true);
3074 Editor::State::State (PublicEditor const * e)
3076 selection = new Selection (e);
3079 Editor::State::~State ()
3085 Editor::begin_reversible_command (string name)
3088 _session->begin_reversible_command (name);
3093 Editor::begin_reversible_command (GQuark q)
3096 _session->begin_reversible_command (q);
3101 Editor::commit_reversible_command ()
3104 _session->commit_reversible_command ();
3109 Editor::history_changed ()
3113 if (undo_action && _session) {
3114 if (_session->undo_depth() == 0) {
3117 label = string_compose(_("Undo (%1)"), _session->next_undo());
3119 undo_action->property_label() = label;
3122 if (redo_action && _session) {
3123 if (_session->redo_depth() == 0) {
3126 label = string_compose(_("Redo (%1)"), _session->next_redo());
3128 redo_action->property_label() = label;
3133 Editor::duplicate_dialog (bool with_dialog)
3137 if (mouse_mode == MouseRange) {
3138 if (selection->time.length() == 0) {
3143 RegionSelection rs = get_regions_from_selection_and_entered ();
3145 if (mouse_mode != MouseRange && rs.empty()) {
3151 ArdourDialog win (_("Duplicate"));
3152 Label label (_("Number of duplications:"));
3153 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3154 SpinButton spinner (adjustment, 0.0, 1);
3157 win.get_vbox()->set_spacing (12);
3158 win.get_vbox()->pack_start (hbox);
3159 hbox.set_border_width (6);
3160 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3162 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3163 place, visually. so do this by hand.
3166 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3167 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3168 spinner.grab_focus();
3174 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3175 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3176 win.set_default_response (RESPONSE_ACCEPT);
3178 win.set_position (WIN_POS_MOUSE);
3180 spinner.grab_focus ();
3182 switch (win.run ()) {
3183 case RESPONSE_ACCEPT:
3189 times = adjustment.get_value();
3192 if (mouse_mode == MouseRange) {
3193 duplicate_selection (times);
3195 duplicate_some_regions (rs, times);
3200 Editor::show_verbose_canvas_cursor ()
3202 verbose_canvas_cursor->raise_to_top();
3203 verbose_canvas_cursor->show();
3204 verbose_cursor_visible = true;
3208 Editor::hide_verbose_canvas_cursor ()
3210 verbose_canvas_cursor->hide();
3211 verbose_cursor_visible = false;
3215 Editor::clamp_verbose_cursor_x (double x)
3220 x = min (_canvas_width - 200.0, x);
3226 Editor::clamp_verbose_cursor_y (double y)
3228 if (y < canvas_timebars_vsize) {
3229 y = canvas_timebars_vsize;
3231 y = min (_canvas_height - 50, y);
3237 Editor::show_verbose_canvas_cursor_with (const string & txt, int32_t xoffset, int32_t yoffset)
3239 verbose_canvas_cursor->property_text() = txt.c_str();
3244 track_canvas->get_pointer (x, y);
3245 track_canvas->window_to_world (x, y, wx, wy);
3250 /* don't get too close to the edge */
3251 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (wx);
3252 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (wy);
3254 show_verbose_canvas_cursor ();
3258 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3260 verbose_canvas_cursor->property_text() = txt.c_str();
3261 /* don't get too close to the edge */
3262 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (x);
3263 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (y);
3267 Editor::set_verbose_canvas_cursor_text (const string & txt)
3269 verbose_canvas_cursor->property_text() = txt.c_str();
3273 Editor::set_edit_mode (EditMode m)
3275 Config->set_edit_mode (m);
3279 Editor::cycle_edit_mode ()
3281 switch (Config->get_edit_mode()) {
3283 if (Profile->get_sae()) {
3284 Config->set_edit_mode (Lock);
3286 Config->set_edit_mode (Splice);
3290 Config->set_edit_mode (Lock);
3293 Config->set_edit_mode (Slide);
3299 Editor::edit_mode_selection_done ()
3301 string s = edit_mode_selector.get_active_text ();
3304 Config->set_edit_mode (string_to_edit_mode (s));
3309 Editor::snap_type_selection_done ()
3311 string choice = snap_type_selector.get_active_text();
3312 SnapType snaptype = SnapToBeat;
3314 if (choice == _("Beats/2")) {
3315 snaptype = SnapToBeatDiv2;
3316 } else if (choice == _("Beats/3")) {
3317 snaptype = SnapToBeatDiv3;
3318 } else if (choice == _("Beats/4")) {
3319 snaptype = SnapToBeatDiv4;
3320 } else if (choice == _("Beats/5")) {
3321 snaptype = SnapToBeatDiv5;
3322 } else if (choice == _("Beats/6")) {
3323 snaptype = SnapToBeatDiv6;
3324 } else if (choice == _("Beats/7")) {
3325 snaptype = SnapToBeatDiv7;
3326 } else if (choice == _("Beats/8")) {
3327 snaptype = SnapToBeatDiv8;
3328 } else if (choice == _("Beats/10")) {
3329 snaptype = SnapToBeatDiv10;
3330 } else if (choice == _("Beats/12")) {
3331 snaptype = SnapToBeatDiv12;
3332 } else if (choice == _("Beats/14")) {
3333 snaptype = SnapToBeatDiv14;
3334 } else if (choice == _("Beats/16")) {
3335 snaptype = SnapToBeatDiv16;
3336 } else if (choice == _("Beats/20")) {
3337 snaptype = SnapToBeatDiv20;
3338 } else if (choice == _("Beats/24")) {
3339 snaptype = SnapToBeatDiv24;
3340 } else if (choice == _("Beats/28")) {
3341 snaptype = SnapToBeatDiv28;
3342 } else if (choice == _("Beats/32")) {
3343 snaptype = SnapToBeatDiv32;
3344 } else if (choice == _("Beats")) {
3345 snaptype = SnapToBeat;
3346 } else if (choice == _("Bars")) {
3347 snaptype = SnapToBar;
3348 } else if (choice == _("Marks")) {
3349 snaptype = SnapToMark;
3350 } else if (choice == _("Region starts")) {
3351 snaptype = SnapToRegionStart;
3352 } else if (choice == _("Region ends")) {
3353 snaptype = SnapToRegionEnd;
3354 } else if (choice == _("Region bounds")) {
3355 snaptype = SnapToRegionBoundary;
3356 } else if (choice == _("Region syncs")) {
3357 snaptype = SnapToRegionSync;
3358 } else if (choice == _("CD Frames")) {
3359 snaptype = SnapToCDFrame;
3360 } else if (choice == _("Timecode Frames")) {
3361 snaptype = SnapToTimecodeFrame;
3362 } else if (choice == _("Timecode Seconds")) {
3363 snaptype = SnapToTimecodeSeconds;
3364 } else if (choice == _("Timecode Minutes")) {
3365 snaptype = SnapToTimecodeMinutes;
3366 } else if (choice == _("Seconds")) {
3367 snaptype = SnapToSeconds;
3368 } else if (choice == _("Minutes")) {
3369 snaptype = SnapToMinutes;
3372 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3374 ract->set_active ();
3379 Editor::snap_mode_selection_done ()
3381 string choice = snap_mode_selector.get_active_text();
3382 SnapMode mode = SnapNormal;
3384 if (choice == _("No Grid")) {
3386 } else if (choice == _("Grid")) {
3388 } else if (choice == _("Magnetic")) {
3389 mode = SnapMagnetic;
3392 RefPtr<RadioAction> ract = snap_mode_action (mode);
3395 ract->set_active (true);
3400 Editor::cycle_edit_point (bool with_marker)
3402 switch (_edit_point) {
3404 set_edit_point_preference (EditAtPlayhead);
3406 case EditAtPlayhead:
3408 set_edit_point_preference (EditAtSelectedMarker);
3410 set_edit_point_preference (EditAtMouse);
3413 case EditAtSelectedMarker:
3414 set_edit_point_preference (EditAtMouse);
3420 Editor::edit_point_selection_done ()
3422 string choice = edit_point_selector.get_active_text();
3423 EditPoint ep = EditAtSelectedMarker;
3425 if (choice == _("Marker")) {
3426 set_edit_point_preference (EditAtSelectedMarker);
3427 } else if (choice == _("Playhead")) {
3428 set_edit_point_preference (EditAtPlayhead);
3430 set_edit_point_preference (EditAtMouse);
3433 RefPtr<RadioAction> ract = edit_point_action (ep);
3436 ract->set_active (true);
3441 Editor::zoom_focus_selection_done ()
3443 string choice = zoom_focus_selector.get_active_text();
3444 ZoomFocus focus_type = ZoomFocusLeft;
3446 if (choice == _("Left")) {
3447 focus_type = ZoomFocusLeft;
3448 } else if (choice == _("Right")) {
3449 focus_type = ZoomFocusRight;
3450 } else if (choice == _("Center")) {
3451 focus_type = ZoomFocusCenter;
3452 } else if (choice == _("Playhead")) {
3453 focus_type = ZoomFocusPlayhead;
3454 } else if (choice == _("Mouse")) {
3455 focus_type = ZoomFocusMouse;
3456 } else if (choice == _("Edit point")) {
3457 focus_type = ZoomFocusEdit;
3460 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3463 ract->set_active ();
3468 Editor::edit_controls_button_release (GdkEventButton* ev)
3470 if (Keyboard::is_context_menu_event (ev)) {
3471 ARDOUR_UI::instance()->add_route (this);
3477 Editor::mouse_select_button_release (GdkEventButton* ev)
3479 /* this handles just right-clicks */
3481 if (ev->button != 3) {
3489 Editor::set_zoom_focus (ZoomFocus f)
3491 string str = zoom_focus_strings[(int)f];
3493 if (str != zoom_focus_selector.get_active_text()) {
3494 zoom_focus_selector.set_active_text (str);
3497 if (zoom_focus != f) {
3500 ZoomFocusChanged (); /* EMIT_SIGNAL */
3507 Editor::ensure_float (Window& win)
3509 win.set_transient_for (*this);
3513 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3515 /* recover or initialize pane positions. do this here rather than earlier because
3516 we don't want the positions to change the child allocations, which they seem to do.
3522 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3534 width = default_width;
3535 height = default_height;
3537 if ((geometry = find_named_node (*node, "geometry")) != 0) {
3539 prop = geometry->property ("x-size");
3541 width = atoi (prop->value());
3543 prop = geometry->property ("y-size");
3545 height = atoi (prop->value());
3549 if (which == static_cast<Paned*> (&edit_pane)) {
3551 if (done & Horizontal) {
3555 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3556 _notebook_shrunk = string_is_affirmative (prop->value ());
3559 if (geometry && (prop = geometry->property ("pre-maximal-horizontal-pane-position"))) {
3560 pre_maximal_horizontal_pane_position = atoi (prop->value ());
3563 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3564 /* initial allocation is 90% to canvas, 10% to notebook */
3565 pos = (int) floor (alloc.get_width() * 0.90f);
3566 snprintf (buf, sizeof(buf), "%d", pos);
3568 pos = atoi (prop->value());
3571 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3572 edit_pane.set_position (pos);
3573 if (pre_maximal_horizontal_pane_position == 0) {
3574 pre_maximal_horizontal_pane_position = pos;
3578 done = (Pane) (done | Horizontal);
3580 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3582 if (done & Vertical) {
3586 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3587 /* initial allocation is 90% to canvas, 10% to summary */
3588 pos = (int) floor (alloc.get_height() * 0.90f);
3589 snprintf (buf, sizeof(buf), "%d", pos);
3591 pos = atoi (prop->value());
3594 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3595 editor_summary_pane.set_position (pos);
3596 pre_maximal_vertical_pane_position = pos;
3599 done = (Pane) (done | Vertical);
3604 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3606 if (_tools_tearoff->torn_off() && _mouse_mode_tearoff->torn_off()) {
3607 top_hbox.remove (toolbar_frame);
3612 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3614 if (toolbar_frame.get_parent() == 0) {
3615 top_hbox.pack_end (toolbar_frame);
3620 Editor::set_show_measures (bool yn)
3622 if (_show_measures != yn) {
3625 if ((_show_measures = yn) == true) {
3627 tempo_lines->show();
3635 Editor::toggle_follow_playhead ()
3637 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3639 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3640 set_follow_playhead (tact->get_active());
3644 /** @param yn true to follow playhead, otherwise false.
3645 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3648 Editor::set_follow_playhead (bool yn, bool catch_up)
3650 if (_follow_playhead != yn) {
3651 if ((_follow_playhead = yn) == true && catch_up) {
3653 reset_x_origin_to_follow_playhead ();
3660 Editor::toggle_stationary_playhead ()
3662 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3664 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3665 set_stationary_playhead (tact->get_active());
3670 Editor::set_stationary_playhead (bool yn)
3672 if (_stationary_playhead != yn) {
3673 if ((_stationary_playhead = yn) == true) {
3675 // FIXME need a 3.0 equivalent of this 2.X call
3676 // update_current_screen ();
3683 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3685 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3687 xfade->set_active (!xfade->active());
3692 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3694 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3696 xfade->set_follow_overlap (!xfade->following_overlap());
3701 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3703 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3709 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3713 switch (cew.run ()) {
3714 case RESPONSE_ACCEPT:
3721 PropertyChange all_crossfade_properties;
3722 all_crossfade_properties.add (ARDOUR::Properties::active);
3723 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3724 xfade->PropertyChanged (all_crossfade_properties);
3728 Editor::playlist_selector () const
3730 return *_playlist_selector;
3734 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3738 switch (_snap_type) {
3743 case SnapToBeatDiv32:
3746 case SnapToBeatDiv28:
3749 case SnapToBeatDiv24:
3752 case SnapToBeatDiv20:
3755 case SnapToBeatDiv16:
3758 case SnapToBeatDiv14:
3761 case SnapToBeatDiv12:
3764 case SnapToBeatDiv10:
3767 case SnapToBeatDiv8:
3770 case SnapToBeatDiv7:
3773 case SnapToBeatDiv6:
3776 case SnapToBeatDiv5:
3779 case SnapToBeatDiv4:
3782 case SnapToBeatDiv3:
3785 case SnapToBeatDiv2:
3791 return _session->tempo_map().meter_at (position).beats_per_bar();
3796 case SnapToTimecodeFrame:
3797 case SnapToTimecodeSeconds:
3798 case SnapToTimecodeMinutes:
3801 case SnapToRegionStart:
3802 case SnapToRegionEnd:
3803 case SnapToRegionSync:
3804 case SnapToRegionBoundary:
3814 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3818 ret = nudge_clock.current_duration (pos);
3819 next = ret + 1; /* XXXX fix me */
3825 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3827 ArdourDialog dialog (_("Playlist Deletion"));
3828 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3829 "If left alone, no audio files used by it will be cleaned.\n"
3830 "If deleted, audio files used by it alone by will cleaned."),
3833 dialog.set_position (WIN_POS_CENTER);
3834 dialog.get_vbox()->pack_start (label);
3838 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3839 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3840 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3842 switch (dialog.run ()) {
3843 case RESPONSE_ACCEPT:
3844 /* delete the playlist */
3848 case RESPONSE_REJECT:
3849 /* keep the playlist */
3861 Editor::audio_region_selection_covers (framepos_t where)
3863 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3864 if ((*a)->region()->covers (where)) {
3873 Editor::prepare_for_cleanup ()
3875 cut_buffer->clear_regions ();
3876 cut_buffer->clear_playlists ();
3878 selection->clear_regions ();
3879 selection->clear_playlists ();
3881 _regions->suspend_redisplay ();
3885 Editor::finish_cleanup ()
3887 _regions->resume_redisplay ();
3891 Editor::transport_loop_location()
3894 return _session->locations()->auto_loop_location();
3901 Editor::transport_punch_location()
3904 return _session->locations()->auto_punch_location();
3911 Editor::control_layout_scroll (GdkEventScroll* ev)
3913 if (Keyboard::some_magic_widget_has_focus()) {
3917 switch (ev->direction) {
3919 scroll_tracks_up_line ();
3923 case GDK_SCROLL_DOWN:
3924 scroll_tracks_down_line ();
3928 /* no left/right handling yet */
3936 Editor::session_state_saved (string)
3939 _snapshots->redisplay ();
3943 Editor::maximise_editing_space ()
3945 _mouse_mode_tearoff->set_visible (false);
3946 _tools_tearoff->set_visible (false);
3947 _zoom_tearoff->set_visible (false);
3949 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
3950 pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
3951 pre_maximal_editor_width = this->get_width ();
3952 pre_maximal_editor_height = this->get_height ();
3954 if (post_maximal_horizontal_pane_position == 0) {
3955 post_maximal_horizontal_pane_position = edit_pane.get_width();
3958 if (post_maximal_vertical_pane_position == 0) {
3959 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
3964 if (post_maximal_editor_width) {
3965 edit_pane.set_position (post_maximal_horizontal_pane_position -
3966 abs(post_maximal_editor_width - pre_maximal_editor_width));
3968 edit_pane.set_position (post_maximal_horizontal_pane_position);
3971 if (post_maximal_editor_height) {
3972 editor_summary_pane.set_position (post_maximal_vertical_pane_position -
3973 abs(post_maximal_editor_height - pre_maximal_editor_height));
3975 editor_summary_pane.set_position (post_maximal_vertical_pane_position);
3978 if (Config->get_keep_tearoffs()) {
3979 _mouse_mode_tearoff->set_visible (true);
3980 _tools_tearoff->set_visible (true);
3981 if (Config->get_show_zoom_tools ()) {
3982 _zoom_tearoff->set_visible (true);
3989 Editor::restore_editing_space ()
3991 // user changed width/height of panes during fullscreen
3993 if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
3994 post_maximal_horizontal_pane_position = edit_pane.get_position();
3997 if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
3998 post_maximal_vertical_pane_position = editor_summary_pane.get_position();
4003 _mouse_mode_tearoff->set_visible (true);
4004 _tools_tearoff->set_visible (true);
4005 if (Config->get_show_zoom_tools ()) {
4006 _zoom_tearoff->set_visible (true);
4008 post_maximal_editor_width = this->get_width();
4009 post_maximal_editor_height = this->get_height();
4011 edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
4012 editor_summary_pane.set_position (pre_maximal_vertical_pane_position + abs(this->get_height() - pre_maximal_editor_height));
4016 * Make new playlists for a given track and also any others that belong
4017 * to the same active route group with the `edit' property.
4022 Editor::new_playlists (TimeAxisView* v)
4024 begin_reversible_command (_("new playlists"));
4025 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4026 _session->playlists->get (playlists);
4027 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4028 commit_reversible_command ();
4032 * Use a copy of the current playlist for a given track and also any others that belong
4033 * to the same active route group with the `edit' property.
4038 Editor::copy_playlists (TimeAxisView* v)
4040 begin_reversible_command (_("copy playlists"));
4041 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4042 _session->playlists->get (playlists);
4043 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4044 commit_reversible_command ();
4047 /** Clear the current playlist for a given track and also any others that belong
4048 * to the same active route group with the `edit' property.
4053 Editor::clear_playlists (TimeAxisView* v)
4055 begin_reversible_command (_("clear playlists"));
4056 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4057 _session->playlists->get (playlists);
4058 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4059 commit_reversible_command ();
4063 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4065 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4069 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4071 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4075 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4077 atv.clear_playlist ();
4081 Editor::on_key_press_event (GdkEventKey* ev)
4083 return key_press_focus_accelerator_handler (*this, ev);
4087 Editor::on_key_release_event (GdkEventKey* ev)
4089 return Gtk::Window::on_key_release_event (ev);
4090 // return key_press_focus_accelerator_handler (*this, ev);
4093 /** Queue up a change to the viewport x origin.
4094 * @param frame New x origin.
4097 Editor::reset_x_origin (framepos_t frame)
4099 queue_visual_change (frame);
4103 Editor::reset_y_origin (double y)
4105 queue_visual_change_y (y);
4109 Editor::reset_zoom (double fpu)
4111 queue_visual_change (fpu);
4115 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4117 reset_x_origin (frame);
4120 if (!no_save_visual) {
4121 undo_visual_stack.push_back (current_visual_state(false));
4125 Editor::VisualState*
4126 Editor::current_visual_state (bool with_tracks)
4128 VisualState* vs = new VisualState;
4129 vs->y_position = vertical_adjustment.get_value();
4130 vs->frames_per_unit = frames_per_unit;
4131 vs->leftmost_frame = leftmost_frame;
4132 vs->zoom_focus = zoom_focus;
4135 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4136 vs->track_states.push_back (TAVState ((*i), &(*i)->get_state()));
4144 Editor::undo_visual_state ()
4146 if (undo_visual_stack.empty()) {
4150 redo_visual_stack.push_back (current_visual_state());
4152 VisualState* vs = undo_visual_stack.back();
4153 undo_visual_stack.pop_back();
4154 use_visual_state (*vs);
4158 Editor::redo_visual_state ()
4160 if (redo_visual_stack.empty()) {
4164 undo_visual_stack.push_back (current_visual_state());
4166 VisualState* vs = redo_visual_stack.back();
4167 redo_visual_stack.pop_back();
4168 use_visual_state (*vs);
4172 Editor::swap_visual_state ()
4174 if (undo_visual_stack.empty()) {
4175 redo_visual_state ();
4177 undo_visual_state ();
4182 Editor::use_visual_state (VisualState& vs)
4184 no_save_visual = true;
4186 _routes->suspend_redisplay ();
4188 vertical_adjustment.set_value (vs.y_position);
4190 set_zoom_focus (vs.zoom_focus);
4191 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4193 for (list<TAVState>::iterator i = vs.track_states.begin(); i != vs.track_states.end(); ++i) {
4194 TrackViewList::iterator t;
4196 /* check if the track still exists - it could have been deleted */
4198 if ((t = find (track_views.begin(), track_views.end(), i->first)) != track_views.end()) {
4199 (*t)->set_state (*(i->second), Stateful::loading_state_version);
4204 if (!vs.track_states.empty()) {
4205 _routes->update_visibility ();
4208 _routes->resume_redisplay ();
4210 no_save_visual = false;
4214 Editor::set_frames_per_unit (double fpu)
4216 /* this is the core function that controls the zoom level of the canvas. it is called
4217 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4220 if (fpu == frames_per_unit) {
4229 /* don't allow zooms that fit more than the maximum number
4230 of frames into an 800 pixel wide space.
4233 if (max_framepos / fpu < 800.0) {
4238 tempo_lines->tempo_map_changed();
4240 frames_per_unit = fpu;
4245 Editor::post_zoom ()
4247 // convert fpu to frame count
4249 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4251 if (frames_per_unit != zoom_range_clock.current_duration()) {
4252 zoom_range_clock.set (frames);
4255 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4256 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4257 (*i)->reshow_selection (selection->time);
4261 ZoomChanged (); /* EMIT_SIGNAL */
4263 //reset_scrolling_region ();
4265 if (playhead_cursor) {
4266 playhead_cursor->set_position (playhead_cursor->current_frame);
4269 refresh_location_display();
4270 _summary->set_overlays_dirty ();
4272 update_marker_labels ();
4278 Editor::queue_visual_change (framepos_t where)
4280 pending_visual_change.add (VisualChange::TimeOrigin);
4281 pending_visual_change.time_origin = where;
4282 ensure_visual_change_idle_handler ();
4286 Editor::queue_visual_change (double fpu)
4288 pending_visual_change.add (VisualChange::ZoomLevel);
4289 pending_visual_change.frames_per_unit = fpu;
4291 ensure_visual_change_idle_handler ();
4295 Editor::queue_visual_change_y (double y)
4297 pending_visual_change.add (VisualChange::YOrigin);
4298 pending_visual_change.y_origin = y;
4300 ensure_visual_change_idle_handler ();
4304 Editor::ensure_visual_change_idle_handler ()
4306 if (pending_visual_change.idle_handler_id < 0) {
4307 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4312 Editor::_idle_visual_changer (void* arg)
4314 return static_cast<Editor*>(arg)->idle_visual_changer ();
4318 Editor::idle_visual_changer ()
4320 VisualChange::Type p = pending_visual_change.pending;
4321 pending_visual_change.pending = (VisualChange::Type) 0;
4323 double const last_time_origin = horizontal_position ();
4325 if (p & VisualChange::TimeOrigin) {
4326 /* This is a bit of a hack, but set_frames_per_unit
4327 below will (if called) end up with the
4328 CrossfadeViews looking at Editor::leftmost_frame,
4329 and if we're changing origin and zoom in the same
4330 operation it will be the wrong value unless we
4334 leftmost_frame = pending_visual_change.time_origin;
4337 if (p & VisualChange::ZoomLevel) {
4338 set_frames_per_unit (pending_visual_change.frames_per_unit);
4340 compute_fixed_ruler_scale ();
4341 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4342 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4343 update_tempo_based_rulers ();
4345 if (p & VisualChange::TimeOrigin) {
4346 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4348 if (p & VisualChange::YOrigin) {
4349 vertical_adjustment.set_value (pending_visual_change.y_origin);
4352 if (last_time_origin == horizontal_position ()) {
4353 /* changed signal not emitted */
4354 update_fixed_rulers ();
4355 redisplay_tempo (true);
4358 _summary->set_overlays_dirty ();
4360 pending_visual_change.idle_handler_id = -1;
4361 return 0; /* this is always a one-shot call */
4364 struct EditorOrderTimeAxisSorter {
4365 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4366 return a->order () < b->order ();
4371 Editor::sort_track_selection (TrackViewList* sel)
4373 EditorOrderTimeAxisSorter cmp;
4378 selection->tracks.sort (cmp);
4383 Editor::get_preferred_edit_position (bool ignore_playhead)
4386 framepos_t where = 0;
4387 EditPoint ep = _edit_point;
4389 if (entered_marker) {
4390 return entered_marker->position();
4393 if (ignore_playhead && ep == EditAtPlayhead) {
4394 ep = EditAtSelectedMarker;
4398 case EditAtPlayhead:
4399 where = _session->audible_frame();
4402 case EditAtSelectedMarker:
4403 if (!selection->markers.empty()) {
4405 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4408 where = loc->start();
4419 if (!mouse_frame (where, ignored)) {
4420 /* XXX not right but what can we do ? */
4431 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4433 if (!_session) return;
4435 begin_reversible_command (cmd);
4439 if ((tll = transport_loop_location()) == 0) {
4440 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4441 XMLNode &before = _session->locations()->get_state();
4442 _session->locations()->add (loc, true);
4443 _session->set_auto_loop_location (loc);
4444 XMLNode &after = _session->locations()->get_state();
4445 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4447 XMLNode &before = tll->get_state();
4448 tll->set_hidden (false, this);
4449 tll->set (start, end);
4450 XMLNode &after = tll->get_state();
4451 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4454 commit_reversible_command ();
4458 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4460 if (!_session) return;
4462 begin_reversible_command (cmd);
4466 if ((tpl = transport_punch_location()) == 0) {
4467 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4468 XMLNode &before = _session->locations()->get_state();
4469 _session->locations()->add (loc, true);
4470 _session->set_auto_loop_location (loc);
4471 XMLNode &after = _session->locations()->get_state();
4472 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4475 XMLNode &before = tpl->get_state();
4476 tpl->set_hidden (false, this);
4477 tpl->set (start, end);
4478 XMLNode &after = tpl->get_state();
4479 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4482 commit_reversible_command ();
4485 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4486 * @param rs List to which found regions are added.
4487 * @param where Time to look at.
4488 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4491 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4493 const TrackViewList* tracks;
4496 tracks = &track_views;
4501 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4503 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4506 boost::shared_ptr<Track> tr;
4507 boost::shared_ptr<Playlist> pl;
4509 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4511 Playlist::RegionList* regions = pl->regions_at (
4512 (framepos_t) floor ( (double) where * tr->speed()));
4514 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4515 RegionView* rv = rtv->view()->find_view (*i);
4528 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4530 const TrackViewList* tracks;
4533 tracks = &track_views;
4538 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4539 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4541 boost::shared_ptr<Track> tr;
4542 boost::shared_ptr<Playlist> pl;
4544 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4546 Playlist::RegionList* regions = pl->regions_touched (
4547 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4549 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4551 RegionView* rv = rtv->view()->find_view (*i);
4564 /** Start with regions that are selected. Then add equivalent regions
4565 * on tracks in the same active edit-enabled route group as any of
4566 * the regions that we started with.
4570 Editor::get_regions_from_selection ()
4572 return add_route_group_regions_to_selection (selection->regions);
4575 /** Get regions using the following method:
4577 * Make an initial region list using the selected regions, unless
4578 * the edit point is `mouse' and the mouse is over an unselected
4579 * region. In this case, start with just that region.
4581 * Then, make an initial track list of the tracks that these
4582 * regions are on, and if the edit point is not `mouse', add the
4585 * Look at this track list and add any other tracks that are on the
4586 * same active edit-enabled route group as one of the initial tracks.
4588 * Finally take the initial region list and add any regions that are
4589 * under the edit point on one of the tracks on the track list to get
4590 * the returned region list.
4592 * The rationale here is that the mouse edit point is special in that
4593 * its position describes both a time and a track; the other edit
4594 * modes only describe a time. Hence if the edit point is `mouse' we
4595 * ignore selected tracks, as we assume the user means something by
4596 * pointing at a particular track. Also in this case we take note of
4597 * the region directly under the edit point, as there is always just one
4598 * (rather than possibly several with non-mouse edit points).
4602 Editor::get_regions_from_selection_and_edit_point ()
4604 RegionSelection regions;
4606 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4607 regions.add (entered_regionview);
4609 regions = selection->regions;
4612 TrackViewList tracks;
4614 if (_edit_point != EditAtMouse) {
4615 tracks = selection->tracks;
4618 /* Add any other tracks that have regions that are in the same
4619 edit-activated route group as one of our regions.
4621 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4623 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4625 if (g && g->is_active() && g->is_edit()) {
4626 tracks.add (axis_views_from_routes (g->route_list()));
4630 if (!tracks.empty()) {
4631 /* now find regions that are at the edit position on those tracks */
4632 framepos_t const where = get_preferred_edit_position ();
4633 get_regions_at (regions, where, tracks);
4639 /** Start with regions that are selected, or the entered regionview if none are selected.
4640 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4641 * of the regions that we started with.
4645 Editor::get_regions_from_selection_and_entered ()
4647 RegionSelection regions = selection->regions;
4649 if (regions.empty() && entered_regionview) {
4650 regions.add (entered_regionview);
4653 regions = add_route_group_regions_to_selection (regions);
4659 Editor::add_route_group_regions_to_selection (RegionSelection regions)
4661 TrackViewList tracks;
4663 vector<boost::shared_ptr<Region> > equivalent_regions;
4664 RegionSelection edit_group_regions;
4666 /* Add any other tracks that have regions that are in the same
4667 edit-activated route group as one of our regions.
4669 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4671 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4673 if (g && g->is_active() && g->is_edit()) {
4674 /* get tracks in the group */
4675 tracks.add (axis_views_from_routes (g->route_list()));
4678 /* iterate over the track list and get the equivalent regions for the current region */
4679 for (TrackViewList::iterator tr = tracks.begin (); tr != tracks.end(); ++tr) {
4681 if ( (*tr) == &(*i)->get_time_axis_view()) {
4682 /* looking in same track as the original */
4686 boost::shared_ptr<Playlist> pl;
4688 if ((pl = (*tr)->playlist()) != 0) {
4689 pl->get_equivalent_regions ((*i)->region(), equivalent_regions);
4692 /* convert the regions to region views */
4693 for (vector<boost::shared_ptr<Region> >::iterator r = equivalent_regions.begin(); r != equivalent_regions.end(); ++r) {
4697 if ((rv = (*tr)->view()->find_view (*r)) != 0) {
4698 edit_group_regions.add (rv);
4703 equivalent_regions.clear();
4707 regions.merge(edit_group_regions);
4713 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4715 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4717 RouteTimeAxisView* tatv;
4719 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4721 boost::shared_ptr<Playlist> pl;
4722 vector<boost::shared_ptr<Region> > results;
4724 boost::shared_ptr<Track> tr;
4726 if ((tr = tatv->track()) == 0) {
4731 if ((pl = (tr->playlist())) != 0) {
4732 pl->get_region_list_equivalent_regions (region, results);
4735 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4736 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4737 regions.push_back (marv);
4746 Editor::show_rhythm_ferret ()
4748 if (rhythm_ferret == 0) {
4749 rhythm_ferret = new RhythmFerret(*this);
4752 rhythm_ferret->set_session (_session);
4753 rhythm_ferret->show ();
4754 rhythm_ferret->present ();
4758 Editor::first_idle ()
4760 MessageDialog* dialog = 0;
4762 if (track_views.size() > 1) {
4763 dialog = new MessageDialog (*this,
4764 string_compose (_("Please wait while %1 loads visual data"), PROGRAM_NAME),
4769 ARDOUR_UI::instance()->flush_pending ();
4772 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4776 // first idle adds route children (automation tracks), so we need to redisplay here
4777 _routes->redisplay ();
4785 Editor::_idle_resize (gpointer arg)
4787 return ((Editor*)arg)->idle_resize ();
4791 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4793 if (resize_idle_id < 0) {
4794 resize_idle_id = g_idle_add (_idle_resize, this);
4795 _pending_resize_amount = 0;
4798 /* make a note of the smallest resulting height, so that we can clamp the
4799 lower limit at TimeAxisView::hSmall */
4801 int32_t min_resulting = INT32_MAX;
4803 _pending_resize_amount += h;
4804 _pending_resize_view = view;
4806 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4808 if (selection->tracks.contains (_pending_resize_view)) {
4809 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4810 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4814 if (min_resulting < 0) {
4819 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4820 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4824 /** Handle pending resizing of tracks */
4826 Editor::idle_resize ()
4828 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4830 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4831 selection->tracks.contains (_pending_resize_view)) {
4833 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4834 if (*i != _pending_resize_view) {
4835 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4840 _pending_resize_amount = 0;
4842 _group_tabs->set_dirty ();
4843 resize_idle_id = -1;
4851 ENSURE_GUI_THREAD (*this, &Editor::located);
4853 playhead_cursor->set_position (_session->audible_frame ());
4854 if (_follow_playhead && !_pending_initial_locate) {
4855 reset_x_origin_to_follow_playhead ();
4858 _pending_locate_request = false;
4859 _pending_initial_locate = false;
4863 Editor::region_view_added (RegionView *)
4865 _summary->set_dirty ();
4869 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4871 TrackViewList::const_iterator j = track_views.begin ();
4872 while (j != track_views.end()) {
4873 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4874 if (rtv && rtv->route() == r) {
4885 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4889 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4890 TimeAxisView* tv = axis_view_from_route (*i);
4901 Editor::handle_new_route (RouteList& routes)
4903 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4905 RouteTimeAxisView *rtv;
4906 list<RouteTimeAxisView*> new_views;
4908 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4909 boost::shared_ptr<Route> route = (*x);
4911 if (route->is_hidden() || route->is_monitor()) {
4915 DataType dt = route->input()->default_type();
4917 if (dt == ARDOUR::DataType::AUDIO) {
4918 rtv = new AudioTimeAxisView (*this, _session, route, *track_canvas);
4919 } else if (dt == ARDOUR::DataType::MIDI) {
4920 rtv = new MidiTimeAxisView (*this, _session, route, *track_canvas);
4922 throw unknown_type();
4925 new_views.push_back (rtv);
4926 track_views.push_back (rtv);
4928 rtv->effective_gain_display ();
4930 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4933 _routes->routes_added (new_views);
4934 _summary->routes_added (new_views);
4936 if (show_editor_mixer_when_tracks_arrive) {
4937 show_editor_mixer (true);
4940 editor_list_button.set_sensitive (true);
4944 Editor::timeaxisview_deleted (TimeAxisView *tv)
4946 if (_session && _session->deletion_in_progress()) {
4947 /* the situation is under control */
4951 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4953 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4955 _routes->route_removed (tv);
4957 if (tv == entered_track) {
4961 TimeAxisView::Children c = tv->get_child_list ();
4962 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4963 if (entered_track == i->get()) {
4968 /* remove it from the list of track views */
4970 TrackViewList::iterator i;
4972 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4973 i = track_views.erase (i);
4976 /* update whatever the current mixer strip is displaying, if revelant */
4978 boost::shared_ptr<Route> route;
4981 route = rtav->route ();
4984 if (current_mixer_strip && current_mixer_strip->route() == route) {
4986 TimeAxisView* next_tv;
4988 if (track_views.empty()) {
4990 } else if (i == track_views.end()) {
4991 next_tv = track_views.front();
4998 set_selected_mixer_strip (*next_tv);
5000 /* make the editor mixer strip go away setting the
5001 * button to inactive (which also unticks the menu option)
5004 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5010 Editor::hide_track_in_display (TimeAxisView* tv, bool /*temponly*/)
5012 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5014 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5015 // this will hide the mixer strip
5016 set_selected_mixer_strip (*tv);
5019 _routes->hide_track_in_display (*tv);
5023 Editor::sync_track_view_list_and_routes ()
5025 track_views = TrackViewList (_routes->views ());
5027 _summary->set_dirty ();
5028 _group_tabs->set_dirty ();
5030 return false; // do not call again (until needed)
5034 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5036 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5041 /** Find a RouteTimeAxisView by the ID of its route */
5043 Editor::get_route_view_by_route_id (PBD::ID& id) const
5045 RouteTimeAxisView* v;
5047 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5048 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5049 if(v->route()->id() == id) {
5059 Editor::fit_route_group (RouteGroup *g)
5061 TrackViewList ts = axis_views_from_routes (g->route_list ());
5066 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5068 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5071 _session->cancel_audition ();
5075 if (_session->is_auditioning()) {
5076 _session->cancel_audition ();
5077 if (r == last_audition_region) {
5082 _session->audition_region (r);
5083 last_audition_region = r;
5088 Editor::hide_a_region (boost::shared_ptr<Region> r)
5090 r->set_hidden (true);
5094 Editor::show_a_region (boost::shared_ptr<Region> r)
5096 r->set_hidden (false);
5100 Editor::audition_region_from_region_list ()
5102 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5106 Editor::hide_region_from_region_list ()
5108 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5112 Editor::show_region_in_region_list ()
5114 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5118 Editor::step_edit_status_change (bool yn)
5121 start_step_editing ();
5123 stop_step_editing ();
5128 Editor::start_step_editing ()
5130 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5134 Editor::stop_step_editing ()
5136 step_edit_connection.disconnect ();
5140 Editor::check_step_edit ()
5142 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5143 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5145 mtv->check_step_edit ();
5149 return true; // do it again, till we stop
5153 Editor::horizontal_scroll_left_press ()
5155 ++_scroll_callbacks;
5157 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5158 /* delay the first auto-repeat */
5162 double x = leftmost_position() - current_page_frames() / 5;
5169 /* do hacky auto-repeat */
5170 if (!_scroll_connection.connected ()) {
5171 _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press), 100);
5172 _scroll_callbacks = 0;
5179 Editor::horizontal_scroll_left_release ()
5181 _scroll_connection.disconnect ();
5185 Editor::horizontal_scroll_right_press ()
5187 ++_scroll_callbacks;
5189 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5190 /* delay the first auto-repeat */
5194 reset_x_origin (leftmost_position() + current_page_frames() / 5);
5196 /* do hacky auto-repeat */
5197 if (!_scroll_connection.connected ()) {
5198 _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press), 100);
5199 _scroll_callbacks = 0;
5206 Editor::horizontal_scroll_right_release ()
5208 _scroll_connection.disconnect ();
5211 /** Queue a change for the Editor viewport x origin to follow the playhead */
5213 Editor::reset_x_origin_to_follow_playhead ()
5215 framepos_t const frame = playhead_cursor->current_frame;
5217 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5219 if (_session->transport_speed() < 0) {
5221 if (frame > (current_page_frames() / 2)) {
5222 center_screen (frame-(current_page_frames()/2));
5224 center_screen (current_page_frames()/2);
5229 if (frame < leftmost_frame) {
5232 if (_session->transport_rolling()) {
5233 /* rolling; end up with the playhead at the right of the page */
5234 l = frame - current_page_frames ();
5236 /* not rolling: end up with the playhead 3/4 of the way along the page */
5237 l = frame - (3 * current_page_frames() / 4);
5244 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5247 if (_session->transport_rolling()) {
5248 /* rolling: end up with the playhead on the left of the page */
5249 center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ());
5251 /* not rolling: end up with the playhead 1/4 of the way along the page */
5252 center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ());
5260 Editor::super_rapid_screen_update ()
5262 if (!_session || !_session->engine().running()) {
5266 /* METERING / MIXER STRIPS */
5268 /* update track meters, if required */
5269 if (is_mapped() && meters_running) {
5270 RouteTimeAxisView* rtv;
5271 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5272 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5273 rtv->fast_update ();
5278 /* and any current mixer strip */
5279 if (current_mixer_strip) {
5280 current_mixer_strip->fast_update ();
5283 /* PLAYHEAD AND VIEWPORT */
5285 framepos_t const frame = _session->audible_frame();
5287 /* There are a few reasons why we might not update the playhead / viewport stuff:
5289 * 1. we don't update things when there's a pending locate request, otherwise
5290 * when the editor requests a locate there is a chance that this method
5291 * will move the playhead before the locate request is processed, causing
5293 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5294 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5297 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5299 last_update_frame = frame;
5301 if (!_dragging_playhead) {
5302 playhead_cursor->set_position (frame);
5305 if (!_stationary_playhead) {
5307 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5308 reset_x_origin_to_follow_playhead ();
5313 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5317 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5318 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5319 if (target <= 0.0) {
5322 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5323 target = (target * 0.15) + (current * 0.85);
5329 set_horizontal_position (current);
5338 Editor::session_going_away ()
5340 _have_idled = false;
5342 _session_connections.drop_connections ();
5344 super_rapid_screen_update_connection.disconnect ();
5346 selection->clear ();
5347 cut_buffer->clear ();
5349 clicked_regionview = 0;
5350 clicked_axisview = 0;
5351 clicked_routeview = 0;
5352 clicked_crossfadeview = 0;
5353 entered_regionview = 0;
5355 last_update_frame = 0;
5358 playhead_cursor->canvas_item.hide ();
5360 /* rip everything out of the list displays */
5364 _route_groups->clear ();
5366 /* do this first so that deleting a track doesn't reset cms to null
5367 and thus cause a leak.
5370 if (current_mixer_strip) {
5371 if (current_mixer_strip->get_parent() != 0) {
5372 global_hpacker.remove (*current_mixer_strip);
5374 delete current_mixer_strip;
5375 current_mixer_strip = 0;
5378 /* delete all trackviews */
5380 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5383 track_views.clear ();
5385 zoom_range_clock.set_session (0);
5386 nudge_clock.set_session (0);
5388 editor_list_button.set_active(false);
5389 editor_list_button.set_sensitive(false);
5391 /* clear tempo/meter rulers */
5392 remove_metric_marks ();
5394 clear_marker_display ();
5396 delete current_bbt_points;
5397 current_bbt_points = 0;
5399 /* get rid of any existing editor mixer strip */
5401 WindowTitle title(Glib::get_application_name());
5402 title += _("Editor");
5404 set_title (title.get_string());
5406 SessionHandlePtr::session_going_away ();
5411 Editor::show_editor_list (bool yn)
5414 _the_notebook.show ();
5416 _the_notebook.hide ();
5421 Editor::change_region_layering_order ()
5423 framepos_t const position = get_preferred_edit_position ();
5425 if (!clicked_routeview) {
5426 if (layering_order_editor) {
5427 layering_order_editor->hide ();
5432 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5438 boost::shared_ptr<Playlist> pl = track->playlist();
5444 if (layering_order_editor == 0) {
5445 layering_order_editor = new RegionLayeringOrderEditor(*this);
5448 layering_order_editor->set_context (clicked_routeview->name(), _session, pl, position);
5449 layering_order_editor->maybe_present ();
5453 Editor::update_region_layering_order_editor ()
5455 if (layering_order_editor && layering_order_editor->is_visible ()) {
5456 change_region_layering_order ();
5461 Editor::setup_fade_images ()
5463 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5464 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5465 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5466 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5467 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5469 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5470 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5471 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5472 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5473 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5477 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5479 Editor::action_menu_item (std::string const & name)
5481 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5484 return *manage (a->create_menu_item ());
5488 Editor::resize_text_widgets ()
5490 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_FUDGE+10, 15);
5491 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_FUDGE+10, 15);
5492 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_FUDGE+10, 15);
5493 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_FUDGE+10, 15);
5494 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_FUDGE+10, 15);
5498 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5500 EventBox* b = manage (new EventBox);
5501 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5502 Label* l = manage (new Label (name));
5506 _the_notebook.append_page (widget, *b);
5510 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5512 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5513 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5516 if (ev->type == GDK_2BUTTON_PRESS) {
5518 /* double-click on a notebook tab shrinks or expands the notebook */
5520 if (_notebook_shrunk) {
5521 edit_pane.set_position (pre_maximal_horizontal_pane_position);
5522 _notebook_shrunk = false;
5524 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
5525 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5526 _notebook_shrunk = true;